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
Install
From PyPI:
pip install gree-rc-encoder
From a local checkout (editable, with test deps):
pip install -e ".[dev]"
Quick start
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.
GreeState fields
Fields marked model-dependent exist only on some units (the remote protocol
still carries the bits; unsupported hardware ignores them). Per the manual:
wifi_on / wifi_reset, cold_plasma, uvc_lamp, soft_sound, fast_cool,
start_auto_clean, fresh_air.
| Field | Meaning |
|---|---|
is_on |
Unit power on/off |
mode |
cool / dry / fan_only / heat / auto |
temperature |
Setpoint, 16–31.5 in 0.5 steps |
units |
"C" or "F" |
fan_speed |
auto, speed_1…speed_5, silent, turbo |
x_fan |
X-FAN: after off in Cool/Dry, indoor fan keeps running briefly to dry the evaporator. Not available in Auto/Fan/Heat. Defaults off after the unit is powered. |
cold_plasma |
Model-dependent. Cold Plasma health function. Requires is_on. |
uvc_lamp |
Model-dependent. UVC lamp health function. Requires is_on. Both may be on together. |
humidity_level_set |
Manual humidity control via the Humidity button (Cool/Dry only). |
humidity_level |
Target humidity % when set manually (None if unused). Cool: 40–80; Dry: 30–70; multiples of 5. |
humidity_level_auto |
Humidity button “auto” mode — meaning depends on mode: in Cool, smart dehumidification (Ao); in Dry, continuous dehumidification (Co). Mutually exclusive with humidity_level_set. |
vertical_swing_mode |
Vertical louvre: off, full swing, or fixed positions 1–5 |
horizontal_swing_mode |
Horizontal louvre: off, full/double swing, positions, or pos_1_5 |
swing_started |
Poorly understood (empirical). Changes when automatic movement of vertical or horizontal swing is turned on or off (louvre moving, not fixed). Value is the result of that last toggle: True ≈ some swing was started, False ≈ some swing was stopped. |
ifeel_mode |
I Feel: remote sends ambient-temperature frames from its built-in sensor (see Protocol notes). |
timer_set |
Timer armed (True iff timer_mode is not disabled) |
timer_mode |
disabled / off (turn off later) / on (turn on later) |
timer_hours_set |
Timer duration in hours (0.5 steps) |
timer_off_left_mins / timer_on_left_mins |
Remaining minutes for off/on timers (wire fields) |
wifi_on |
Model-dependent. Wi-Fi module enabled |
wifi_reset |
Model-dependent. One-shot: True only in a single frame; clears Wi-Fi settings so the network can be reconfigured |
soft_sound |
Model-dependent. Manual name: Volume control of IDU Buzzer — quieter indoor-unit beeps |
power_down_level |
Power limiting: 0 = off, 1 = level 1, 2 = level 2 (stricter than 1). Cleared when the remote turns the unit off. With two indoor units, the outdoor unit follows the stricter limit. Independent of energy_saving. |
energy_saving |
Energy-saving (SE on the remote): Cool only; requires fan_speed=auto and sleep_mode_level=0. The unit applies a factory energy-saving setpoint — the encoded temperature is still sent but ignored. Independent of power_down_level. |
light_on / light_auto |
Display light on; auto dimming (light_auto requires light_on) |
fresh_air |
Model-dependent. Manual name: two-way ventilation; fan speed follows the AC / fan button |
sleep_mode_level |
0 = cancel; 1/2 = preset sleep curves; 3 = DIY hourly schedule (see Protocol notes; schedule payload not fully implemented) |
display_indoor_temperature / display_indoor_humidity |
What the indoor display shows (mutually exclusive) |
reset_clean_reminder |
One-shot: toggle/reset the filter clean-reminder function |
fast_cool |
Model-dependent. Fast cool (Cool only): temporary 25°C or 16°C boost for ~20 minutes, then restore previous state |
start_auto_clean |
Model-dependent. One-shot: start auto clean; unit must be off |
Hardware demo
Real receive/transmit via ir-ctl lives in
examples/ir_ctl_demo.py:
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
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.
Metadata
Release files for gree-rc-encoder 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| gree_rc_encoder-0.1.2.tar.gz | 34.1 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| gree_rc_encoder-0.1.2-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 66.1 kB
Release files / gree_rc_encoder-0.1.2.tar.gz
| Download URL | gree_rc_encoder-0.1.2.tar.gz |
|---|---|
| Size | 34.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
fa917ce7609ea9e49d02fe1c99064d3232f9c6dff75ec7017093ebfdc2ed054a
|
|
BLAKE2b-256 checksum How to use checksums |
79055ba1c6bd56ba5bb4250ee9a711280e5e67189b974380d6a21165f2d5a281
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.4
|
Release files / gree_rc_encoder-0.1.2-py3-none-any.whl
| Download URL | gree_rc_encoder-0.1.2-py3-none-any.whl |
|---|---|
| Size | 32.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
69553282823edd92d3c9d04034aea1d1283252970cb396f9e5117091fcd8e447
|
|
BLAKE2b-256 checksum How to use checksums |
8dceb76c627c3020305bbbf463bc376d7a6407bc08ab6f849e9366f0066944f2
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.4
|