Metadata-Version: 2.4
Name: gree-rc-encoder
Version: 0.1.0
Summary: Encode and decode Gree air-conditioner IR remote control signals
Author-email: Alexey Cluster <cluster@cluster.wtf>
License: GPL-3.0-or-later
Project-URL: Homepage, https://github.com/ClusterM/gree-rc-encoder
Project-URL: Repository, https://github.com/ClusterM/gree-rc-encoder
Project-URL: Issues, https://github.com/ClusterM/gree-rc-encoder/issues
Project-URL: PyPI, https://pypi.org/project/gree-rc-encoder/
Keywords: gree,ir,remote,air-conditioner,lirc
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: GNU General Public License v3 or later (GPLv3+)
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Home Automation
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Dynamic: license-file

# gree-rc-encoder

Python library to encode and decode Gree air-conditioner IR remote-control
signals (pulse timings ↔ high-level state).

- **GitHub:** https://github.com/ClusterM/gree-rc-encoder
- **PyPI:** https://pypi.org/project/gree-rc-encoder/
- **License:** [GPLv3](LICENSE)

## Install

From [PyPI](https://pypi.org/project/gree-rc-encoder/):

```bash
pip install gree-rc-encoder
```

From a local checkout (editable, with test deps):

```bash
pip install -e ".[dev]"
```

## Quick start

```python
from gree_rc import (
    GreeState,
    Mode,
    FanSpeed,
    encode_control,
    encode_temperature,
    decode,
    to_ir_ctl,
)

state = GreeState(
    is_on=True,
    mode=Mode.COOL,
    temperature=24,
    fan_speed=FanSpeed.AUTO,
    light_on=True,
)

timings = encode_control(state)       # list[int] durations in microseconds
print(to_ir_ctl(timings))             # "+9000 -4500 +655 ..." for ir-ctl

result = decode(timings)
assert result.state.temperature == 24

# I Feel: remote sensor reading (sent periodically while ifeel_mode is on)
temp_frame = encode_temperature(27)
assert decode(temp_frame).temperature == 27
```

## API overview

| Function | Purpose |
|----------|---------|
| `encode_control(state)` | `GreeState` → 559 timing values |
| `decode_control(timings)` | timings / ir-ctl string → `GreeState` |
| `encode_temperature(temp)` | I Feel ambient °C (0–255) → 35 timing values |
| `decode_temperature(timings)` | → int °C |
| `decode(timings)` | auto-detect control / temperature / combined → `DecodeResult` |
| `to_ir_ctl` / `from_ir_ctl` | convert to/from ir-ctl pulse strings |
| `encode_gree` / `parse_gree` | nibble-level frame without IR timings |

The library performs no I/O and does not print; raise `GreeEncodeError`,
`GreeDecodeError`, or `GreeValidationError` on failure.

## Hardware demo

Real receive/transmit via `ir-ctl` lives in
[`examples/ir_ctl_demo.py`](examples/ir_ctl_demo.py):

```bash
python3 examples/ir_ctl_demo.py receive
python3 examples/ir_ctl_demo.py send --dry-run
python3 examples/ir_ctl_demo.py temperature --dry-run
```

## Tests

```bash
pytest
```

## Protocol notes

### Control frame

A typical control frame is four subsignals (139 timings each) separated by
~40 ms spaces. Each subsignal carries 16 nibbles (LSB-first bits), a `0,1,0`
delimiter with a 20 ms space in the middle, a **marker** nibble, and a CRC
nibble.

Markers identify the logical signal index (0..4). Captures may include more
than four subsignals and may list them in any order; the decoder places each
subsignal into a fixed 5-slot array by marker before parsing `GreeState`.

### I Feel (ambient temperature)

When **I Feel** is enabled (`GreeState.ifeel_mode`), the remote periodically
sends a short 35-sample frame with a different leading pulse. That frame
carries the reading from the remote’s built-in temperature sensor so the
indoor unit can hold the setpoint at the remote’s location rather than only
at the AC.

### Sleep mode level 3

`sleep_mode_level` values 1–2 are fixed sleep curves. Level **3** lets the
user program an automatic temperature change every hour for up to eight
hours. That schedule needs an extra subsignal (logical slot 4 / ~699-sample
capture). This library decodes the level flag and will accept/arrange the
extra subsignal by marker, but **encoding and full parsing of the eight
hourly setpoints is not implemented yet**.
