Repository navigation
Conversation
A Gree zone controller (seen: LE60-13/GH with a ME31-00/C13 WiFi module) drives the dampers of one ducted unit. It answers like a VRF gateway, but its sub-units are the ducted unit (MAC suffix 00) and up to eight zones (01 to 08), and they behave differently from VRF indoor units. Protocol layer: - GreeDevice detects the role of a sub-unit after the info fetch: it reports the name of the controller (GR-ZCntrlr...), and the MAC suffix tells the ducted unit from a zone. - The ducted unit numbers its modes 1 Cool, 2 Heat, 3 Dry, 4 Fan, 5 Auto. Before this, Fan showed as Heat and Auto raised. operation_mode and set_operation_mode convert for every unit with a zone role. - It has no Tur column. Turbo is fan speed 6, only in Cool and Heat. - A zone has a target temperature, StTem, in degrees Celsius minus 16. Only zones poll it, so other units send the same columns as before. - Discovery names the sub-units "AC unit" and "Zone 1" to "Zone 8" instead of "zone" for every one of them. Home Assistant layer: - A zone gets no climate entity. It gets a switch with the name of the zone and a Target Temperature number. - The switch is the optional feature Zone Switch, so it can be left out for a zone that must always stay open. It is only offered on zones, and zones do not show the climate options. - GreeEntityDescription.device_filter limits an entity to some kinds of device when the props alone cannot tell. Tested against a real LE60-13/GH (firmware 362001062617 V1.27) and against a new fake controller in tests/fakes/zone.py.
ZoneRole only knew the sub-units of a zone controller. It is now DeviceType and every device gets one after the info fetch: ac_unit (a standalone unit), vrf_unit (an indoor unit behind a VRF gateway), zone_controller (the ducted unit, sub-unit 00 of a zone controller) and zone. Only the two zone controller types change behaviour, so standalone and VRF units work as before. The type is in the device diagnostics. Suggested by @p-monteiro in RobHofmann#549. The controller device of a zone controller was labelled "VRF gateway". It is now "Zone controller", taken from the type of a bound sub-unit. With no bound sub-unit the registry keeps what it has. The lookup moved into a small helper, so reconcile_vrf_controllers stays simple.
Every fan mode change called set_feature_quiet and set_feature_turbo, also on a unit without those columns. The state then logged "Property Quiet is unsupported on this device" at error level on every change. Seen on the ducted unit of a zone controller, but any unit without Quiet or Turbo did it. Units that have them work as before.
RobHofmann
left a comment
There was a problem hiding this comment.
Thanks for this, and for taking in the DeviceType idea. I ran the PR in my dev instance against my standalone test unit (encryption v1). The start is clean: same 29-column probe, Device type: ac_unit, and the poll still sends the same 20 columns, without StTem. A fan change still sends Quiet and Tur as before. pytest gives 272 passed. I could not test the zone parts myself, because I have no zone controller.
One blocker and one question.
1. translation_key=UNDEFINED breaks setup when no sub-unit is bound (blocker)
In reconcile_vrf_controllers(), when the controller device already exists and _controller_info() finds no bound sub-unit, model and translation_key stay UNDEFINED and go into async_get_or_create(). That works for model, but translation_key is typed str | None, and Home Assistant does this:
if translation_key:
name = self._resolve_translated_name(config_entry, translation_key, translation_placeholders)UNDEFINED is truthy, so the name lookup falls back to the key itself and then calls .format() on it. I ran Home Assistant's own _resolve_translated_name() with UNDEFINED in my dev container:
'vrf_controller' -> 'vrf_controller'
<UndefinedType._singleton: 0> -> RAISES AttributeError 'UndefinedType' object has no attribute 'format'
The call in async_setup_entry() has no try around it. So when a local VRF gateway is offline at Home Assistant start, I expect the whole entry to fail, including standalone units in the same entry, and without a retry because it is not ConfigEntryNotReady. That also hits plain VRF users, not only zone controllers. I did not run that full scenario end to end; the crash itself is reproduced. Mypy flags the same line (helpers.py:475, arg-type), and it is the only new mypy error in the changed files.
A simple fix: only pass model, translation_key and translation_placeholders when the type is known, for example by building the kwargs and leaving those keys out when they are UNDEFINED. A test with an existing controller device and no bound sub-unit would cover it.
2. Zone Switch default in a new setup (question)
async_step_device_options() uses the options of the previous sub-unit of the same controller as defaults (_options_by_controller), and the features default is defaults.get(CONF_FEATURES, valid_features). If the AC unit is configured first, its feature list has no zone, so as far as I can read it, Zone 1 opens with Zone Switch unticked. The other way round, the AC unit could get zone as a default that is not in its options. Did you see this on your controller, or did you tick it by hand? If it is real, filtering the copied defaults against valid_features would solve both cases.
When an existing controller device had no bound sub-unit at start, for example a VRF gateway that is offline, reconcile_vrf_controllers passed UNDEFINED as translation_key. Home Assistant types it str | None and checks it with "if translation_key:", so it tried to format UNDEFINED and the whole entry failed with AttributeError, with no retry. Found in review. The model and the name arguments are now left out when the type is not known, so the registry keeps what it has. A new device still gets the VRF label. The decision moved into _controller_label. Reproduced on Home Assistant 2026.10 with a VRF device whose gateway never answers: before, the entry stayed in setup_error with every entity unavailable; after, the entry loads and the other devices work.
When the device options step starts from the options of the device of the same controller set up before, it copied all of them. So each sub-unit's form showed the name of the device before it, and the features came from a device of another kind: a zone after the AC unit started with Zone Switch off, and the AC unit after a zone got a "zone" default it cannot take. Found in review. - Only the mode and feature lists are copied now, the same lists the copy by model already used. The name stays the device's own. - The Zone Switch is never copied, because only an always open zone goes without it: a zone starts with it on, any other device without it. - The feature default is filtered against the features the device has.
cleanup_device_connection_issues deleted issues from the issue registry while it looped over registry.issues. After a device that had a "connection failed" issue was removed from the config, the next setup deleted that issue and then failed with "RuntimeError: dictionary changed size during iteration", so the entry stayed in setup_error. A second stale issue was never reached. Found while testing the controller label fix: a VRF device whose gateway never answers was removed from the YAML again, and the entry failed at the next start. A manual reload worked, because the issue was already gone.
|
Thanks for testing it on your standalone unit. Both points are fixed, plus a bug I found while testing. 1. Confirmed end to end on Home Assistant 2026.10: with a VRF device whose gateway never answers in the same entry as the zone controller, the entry failed on every start, all its entities were unavailable, and there was no retry. Fixed in 5bfa6cb. The new Mypy missed it on my side because I had only tested in my Home Assistant instance, not with a local one in the dev environment, so every Home Assistant type was Question: A test for 2. Zone Switch default (question) It is real. I had ticked it by hand. My sub-units report no
3. Bug found while testing (already on
|
The name prefix, the MAC suffix of the ducted unit and the two model ids in the sub-device list were separate constants, so another model with other values meant changing the code that uses them. Asked in review: are all zone controllers 5000/5001? The values come from the WiFi module, not from the units: they are fixed in its firmware (v1.21, v1.27 and v1.28 checked). Every sub-unit answers the info request with the name and model id (3017) of the controller, so detection keeps using the name and only discovery uses the model ids. ZONE_CONTROLLER_MODELS now has one entry per model. The entry with the longest matching name prefix is used, so the order does not matter and a more specific entry wins over a general one. The table has a general GR-ZCntrlr entry, and a GR-ZCntrlr_5000_ entry for the LE60-13/GH as an example of a more specific one.
Asked in review. A zone now reads and sets its target through target_temperature and set_target_temperature, like every other device, and the zone number uses them. The zone-only properties are gone. The column stays StTem, in whole degrees Celsius minus 16, clamped to 16 to 30. target_temperature is None until a zone is read, so its number shows unknown and not 0. A unit gives a value as before.
The wall panel can show Fahrenheit, and the controller has its own columns for it: TemUnit for the unit (not TemUn) and StFahFlg for the Fahrenheit bit of a zone. Checked on a LE60-13/GH by switching TemUnit over WiFi and setting zones on the panel and over WiFi: StTem + 16 and StFahFlg follow the same table as SetTem and TemRec (64 F is 2 and 0, 66 F is 3 and 0, 67 F is 3 and 1, 70 F is 5 and 1). When only StTem is sent, the controller keeps the old bit, so both are always sent. - The sub-units of a zone controller poll TemUnit, zones also StFahFlg (ZONE_CONTROLLER_PROPS). Other units send the same columns as before. - target_temperature_unit uses TemUnit on a zone controller, so the Temperature Units select works on its ducted unit and switches the whole controller, the wall panel included. Zones get no select. - The zone number follows the unit: 16 to 30 C or 61 to 86 F. Home Assistant shows it in the user's unit. - A number value is rounded, not cut, before it is sent: Home Assistant converts 21 C to 69.8 F, which must go out as 70.
Asked in review: GR-ZCntrlr is a zone controller whatever the model ids are, so why the table? Detection already went by the name and the MAC suffix only. The model ids were only used by discovery, to name the sub-units, and discovery has the name of the controller too: the scan reply of the gateway. ZONE_CONTROLLER_MODELS and the model ids are gone. Two constants are left, ZONE_CONTROLLER_NAME_PREFIX and ZONE_CONTROLLER_AC_UNIT_SUFFIX, and discovery names the sub-units from the controller name and the MAC suffix. A test gives the sub-units other model ids and still gets AC unit and Zone 1 to Zone 4.
Asked in review: StTem, StFahFlg and TemUnit were used because a device is a zone controller, but other units may answer them too. The sub-units of the zone controller answer none of SetTem, TemRec, TemUn and Add0.5, and other units do not answer the new columns. So the columns now come from what a device answers, like for the features: - StTem, StFahFlg and TemUnit are in the default poll. The first poll drops them on a unit that does not answer them, like any other column, so after it every other unit sends the same columns as before. The type-based add_polled() is gone. - A device uses TemUn when it answers it, and TemUnit only without it. - A zone sends its bit only when it answers StFahFlg. The type is still used where the columns cannot tell: the mode numbers and turbo of a zone controller, and which entities a sub-unit gets. The ducted unit answers StTem too, always with 0, so only a zone uses StTem as its target temperature.
Asked in review: 25.5 C is valid for units with half degrees, but the number entity rounded every value to a whole number. The rounding now happens in set_target_temperature, as it already did for units: Celsius to the nearest half degree, Fahrenheit to whole degrees. The number entity passes the value on as it is. The humidity number keeps its int(). A zone in Celsius takes half degrees too: StFahFlg is the half degree, like TemRec. Checked on a LE60-13/GH: StTem 2 with StFahFlg 1 was still there after a minute and after using the wall panel, which shows only whole degrees (18). So a zone now uses the same SetTem/TemRec table in both units, and its number steps by 0.5 in Celsius and 1 in Fahrenheit.
|
Thanks for the changes; it's better now. Treat the props like the sensors: The same for the temperature bit and temperature unit Then call This should give a valid Then, in the device properties, do your logic based on which props are supported. In the near future, we will gate half-degrees by a feature option that relies on the device responding to bit or Add0.5, so this keeps it ready for that. Check what we do for temperature sensors on the device, which matches the case of one property being provided by multiple fields. So that we don't need to check support in the device properties and can directly get/set the correct ones. And adjust the target temperature and temperature units accordingly to respond to the correct prop and logic. |
|
Don't ask how I know this, but only mids 5000/5001 answer to those props. |
Asked in review: invalidate_missing_property_group() now returns the property it keeps, or None when none of them has a value. The device saves it for the indoor temperature, the outdoor temperature and the humidity, and reads only that column, instead of looking for the one that is supported every time. Nothing changes for any unit.
Asked in review: the target temperature, its bit and the unit each have two columns, now numbered like the sensors: TARGET_TEMPERATURE_1 and _2 (SetTem, StTem), TARGET_TEMPERATURE_BIT_1 and _2 (TemRec, StFahFlg) and TARGET_TEMPERATURE_UNIT_1 and _2 (TemUn, TemUnit). The ZONE_ names are gone. _remove_unsupported_props() keeps the first column of each group that the device answers and saves it, and the device reads and writes only that one, without checking the device type. 0 is a valid value in all three groups: StTem 0 is 16 C, the bits are 0 or 1, and unit 0 is Celsius. So they use missing_value=-1, and only a column that the device does not answer is dropped. With 0, a zone at 16 C would lose its target temperature, and a unit with TemRec 0 its bit. The ducted unit of a zone controller answers StTem and StFahFlg with 0, the same as a zone at 16 C. Only the type tells them apart, so the ducted unit drops both, and polls two columns less. The bit is only sent to a device that answers one. Before, TemRec always went out with SetTem. A unit that does not report TemRec gets whole degrees. The offset of StTem is in TARGET_TEMPERATURE_OFFSETS. The send order has the new columns next to the old ones: unit, bit, temperature. The docs said the default poll has 30 props; it has 33 since StTem, StFahFlg and TemUnit were added.
|
That's a much cleaner way to do it, thanks for your guidance! Done in two commits:
A few things I ran into:
Tests cover each group keeping the old columns when a unit answers both and the new ones when it doesn't, a zone at 16 °C, the ducted unit dropping its two, and a unit without And thanks for the mid info, that matches the firmware: 5000/5001 are hardcoded in the module's sub-device list. Since 6d4c77b nothing uses the mids (detection is name + suffix), and the temperature columns now only depend on what answers, so an empty mid doesn't matter there. |
|
Code looks clean. Can you test it end-to-end in a cloud-only entry added via UI? |
Asked in review: test a cloud-only entry. Cloud discovery offers only the AC unit, and the bind over MQTT gets no reply, while the Gree+ app can control the controller over the cloud. The firmware of the ME31-00/C13 WiFi module has no MQTT client; it only uses the older Gree TCP cloud. entities.md and supported-devices.md now say that a zone controller is local only. Also from review: has_target_temperature_bit matters in Fahrenheit too. Without the bit, a Fahrenheit target moves in steps of about 2.
|
Tested it end to end with a cloud-only entry added through the UI (Gree Cloud account only, Australia region). Short version: cloud discovery only offers the AC unit, and cloud control doesn't work for this controller at all, because its WiFi module doesn't speak MQTT. The debug log of the whole flow is at the bottom. Discovery. The account lists 6 devices: the gateway (12-char MAC, empty Even if the zones made it through, Control. The AC unit got to the bind step, but the bind over MQTT never got a reply (v1 twice, then v2, 10 s each), so the flow stopped with "Unable to bind the device". The controller was online in Gree+ and I could control it from the app on cellular only, so it's definitely connected to Gree's cloud. The catch is the ME31-00/C13 firmware: its cloud code only talks to Gree's older TCP cloud ( One more thing I noticed: with debug logging on, And thanks for the docstring catch, that's fixed in e21a986 too: Debug log of the cloud-only setup flowRedacted: the login response, the Gree user and home ids, the home name, the account email, the device key, location, SSID and bind time in the device list, and the encrypted payloads. |
|
Thanks. That makes sense, and good catch with the sensitive info About the response processing of But since we don't support TCP for cloud, there's not much we can do about Zone controllers anyway. If you add the entry with cloud+local discovery, do the zones work well? |
Found while testing a cloud setup for review: with debug logging on, the cloud login was logged in clear text in several places, and users are asked to post their debug logs. - GreeCloudApi.login() logged the whole login response, with the session token, the email and the user name, and its errors repeated it. Only r, msg, uid and alive are logged now (LOGIN_LOG_KEYS). - Setting up an entry logged its data with only the device key redacted. For a cloud entry that includes the email, the password and the token. Adding an entry through the UI logged the same. Both now redact TO_REDACT: the device key, the password, the token and the email. - Entry diagnostics redacted the password, but not the token or the email. They use TO_REDACT too. - Some lines logged the email, or the entry title, which holds it. They log the user id or the entry id now. - Discovery logs every device with repr(), which held the device key and the email. GreeDiscoveredDevice leaves both out of its repr. troubleshooting.md and actions.md say what is redacted.
Asked in review: with cloud and local discovery, are the zones offered? They were not. The cloud lists a zone controller as the gateway and its sub-units (AC unit 00, zones 01 to 04), all with one key, and each sub-unit has the gateway MAC as pmac. _filter_duplicate_devices_complete() kept only the MAC ending in 00 of a shared key, so the zones were dropped. With both discovery methods, a local device is only offered when the cloud lists it too, so the zones were dropped there as well. A listed device that other devices point to with their pmac is a gateway now: it is left out, and all its sub-units are kept. Devices without such a link go through the key check as before. Checked on a LE60-13/GH with both discovery methods: the AC unit and the four zones are offered with the names from the Gree app, and all of them are controlled locally. The tests use the cloud list of that controller.
|
Both are in now. Redaction (e33b6f7). I went a bit further than the login lines, because testing turned up a few more spots:
Cloud + local (3f55495). No, the zones didn't show up at first. With both methods, The filter now treats a listed device that other devices point to with their Tested again on the real controller with both methods: the picker offered all 5 (the AC unit as "Zone Controller" and the zones as "Zone1" to "Zone4", the names from the app, all marked Local). Every device bound locally with the key from the cloud, the gateway device showed up as "Zone controller" with all five linked, and a zone setpoint went out fine. So the merge does what it should: cloud names, local connection. The tests use this controller's cloud list as a fixture. If this doesn't align with what you're looking for I can revert the last commit that added it, however, it made most of the functionality largely unusable if a user chose both Cloud and Local as sources for data. Without it I'd imagine a user with multiple Gree devices (including a Zone Controller like I have) would end up pulling in Cloud data only and be stuck with either/or. |
|
I think that is correct; I just need to test against my devices to make sure it is ok. Using cloud+local should do what it implies: Look for devices in the cloud, look for the same devices locally, and offer them through a single If we confirm with someone that cloud discovery of VRF devices returns the subunits with the |
|
My AC units are properly discovered in the cloud and locally and can be controlled as before. |
|
Glad to help! Thanks for taking the time to review and provide feedback. I've got the last 2 branches ready to go to (1) add the memory in for these Zone Controllers and then (2) extend it for every other device. I'll put the first one up once this gets merged. 😄 |
|
About memory, I think it's better to have both in one PR since the logic should be similar across all devices. I'll give you this in advance if you haven't done it yet:
|
RobHofmann
left a comment
There was a problem hiding this comment.
Thanks for the rework, and for the extra fixes along the way (the repair issue loop and the cloud login redaction). I ran 3f55495 in my dev instance against my standalone test unit (encryption v1). I have no zone controller, so the zone parts rest on your tests and the pytest fakes.
Both points from my earlier review are solved. My harness for the offline gateway (an existing controller device with no bound sub-unit) now runs through reconcile_vrf_controllers() without an exception.
What I checked on my test unit
- Bind: the probe still ends on 29 columns, then
Device type: ac_unitandBound to device. - Poll: the first poll also asks for
StTem,StFahFlgandTemUnit. After that, every poll sends the same 20 columns as on5.0-dev, withSetTem,TemRecandTemUn. - 21 °C goes out as
SetTem 21, TemRec 0. A fan change still sendsQuietandTur, which this unit has. - The Temperature Units select sends
TemUn 1. After that, 21 °C in Home Assistant goes out as 70 °F (SetTem 21, TemRec 1), and the unit confirms it. - No errors in the log.
- pytest: 288 passed.
1. Cloud sub-units get their own MAC as controller (should fix)
_filter_duplicate_devices_complete() now keeps the sub-units of a listed gateway. But gree_discover_devices_cloud() still takes the controller MAC from gree_extract_macs(dev.mac), and that only splits a MAC that ends in 00. So a zone such as 9424b8bc5a5f01 gets 9424b8bc5a5f01 as its MQTT controller MAC, not the gateway 9424b8bc5a5f.
For your zones this hardly matters, because the module has no MQTT client. It does matter for a cloud VRF account whose sub-units carry pmac. Those units used to be filtered out, and now they are offered with the wrong controller. I have no cloud VRF listing to confirm that such sub-units have pmac, so this is from reading the code. A simple fix: use dev.pmac as the controller MAC when it is set and differs from dev.mac. That also answers the TODO in gree_extract_macs().
2. The TemRec point in the description (small)
The description and docs/protocol.md say that on 5.0-dev TemRec always went out with SetTem, and that a unit without it now gets whole degrees. As far as I can read, that was already the case. set_target_temperature() goes through DeviceState.update(), and set() drops a prop that the unit did not answer, with the is unsupported error. So the behaviour is the same; only the error line is gone. It would help to say that, so nobody looks for a change in behaviour that is not there.
3. Probe cost (just a note)
The default poll grows from 30 to 33 columns. A firmware with a limit of 30 to 32 columns used to pass the first probe, and now does a few more probe steps at bind. The result is still right, so I am fine with this.
Point 1 is the only one I would like to see changed before merging. The rest can go as it is.
|
@RobHofmann about point 1: We don't know if pmac is the controller MAC, and if it is, we don't know if MQTT answers to it as a controller MAC. We only know that for subunits like |
…note Asked in review: since cloud discovery keeps the sub-units of a gateway, a zone such as 9424b8bc5a5f01 got itself as its MQTT controller, because gree_extract_macs() only splits a MAC that ends in 00. The pmac of a sub-unit is now its controller, but only when it is also the first 12 characters of the sub-unit MAC. Then both readings agree: pmac names the gateway, and the start of the MAC is the controller known to answer. What pmac holds for a VRF is not known yet, so anything else keeps the old rules, and gree_extract_macs() is left as it is. Also from review: docs/protocol.md read as if TemRec used to go out to a unit that does not answer it. It did not: DeviceState.set() already dropped such a column. Only the "is unsupported" error is gone.
|
Thanks for testing it again on your unit, @RobHofmann, and for the thorough check! 1. Cloud sub-units and their controller (c0d0eea). Good catch, that one came in with the filter change. I went with a narrower version of your fix, because of Pedro's point: a sub-unit's Anything else keeps the current rules until someone with a cloud VRF can share a listing. I left @p-monteiro that should match what you described: 2. The 3. Probe cost. Noted, thanks. |
Context
This adds support for Gree zone controllers. It's part of porting the changes I made for my own zone controller (Gree LE60-13/GH) over to this project, and #547, #548 and #549 got things ready for it. It also picks up the
DeviceTypeidea @p-monteiro suggested in #549. Two more PRs build on this one: a per mode memory for the zone target temperatures, and the same memory for every device. Background and the full plan: https://github.com/Twintop/ha-gree-zone-controller/blob/main/upstream/README.mdWhat a zone controller is
A zone controller drives the dampers of one ducted unit. Seen: LE60-13/GH with a ME31-00/C13 WiFi module, firmware
362001062617+U-W05SAV1.27.bin(the Braemar LE60 uses the same module). It answers the scan like a VRF gateway, withsubCntabove zero, but its sub-units aren't indoor units:00is the ducted unit. It answersPow,Mod,WdSpd,AllErrandTemUnit, andStTemandStFahFlgalways as 0. ItsPowis the power of the whole system.01to08are the zones. A zone answersPow(the damper),StTemandStFahFlg(its target temperature),TemUnit, and a copy ofModandWdSpdof the ducted unit.SetTem,TemRec,TemUnorAdd0.5.GR-ZCntrlr_5000_02_..._EC), and the sub-device list calls every unitzone. The name and the00suffix of the ducted unit are fixed in the WiFi module firmware (checked v1.21, v1.27 and v1.28), not taken from the units.StTem+ 16 andStFahFlgwork likeSetTemandTemRec: in °C the bit is the half degree (the wall panel only shows whole degrees), in °F it's the same table. The unit isTemUnit(0 °C, 1 °F), notTemUn. Written to the ducted unit, the whole controller and the wall panel switch.Symptoms on 5.0-dev
zone, and the gateway device is labelled "VRF gateway".ValueErrorfromOperationMode(5).Turcolumn. Turbo is fan speed 6, so turbo is not offered, and fan speed 6 raisesValueErrorfromFanSpeed(6).StTemis not polled.Property Quiet is unsupported on this deviceat error level. This happens on any unit without Quiet.RuntimeError: dictionary changed size during iteration, becausecleanup_device_connection_issues()deletes fromregistry.issueswhile it loops over it._filter_duplicate_devices_complete()keeps only the MAC ending in00, and a local device is only offered when the cloud lists it too.Change
Protocol layer:
DeviceTypefor every device, set after the info fetch:ac_unit(a standalone unit),vrf_unit(an indoor unit behind a VRF gateway),zone_controller(the ducted unit of a zone controller) andzone. A sub-unit whose name starts withZONE_CONTROLLER_NAME_PREFIXbelongs to a zone controller, andZONE_CONTROLLER_AC_UNIT_SUFFIXtells the ducted unit from the zones. Nothing is added to the config entry, so there is no migration. The type is in the device diagnostics.TARGET_TEMPERATURE_1/_2(SetTem,StTem),TARGET_TEMPERATURE_BIT_1/_2(TemRec,StFahFlg) andTARGET_TEMPERATURE_UNIT_1/_2(TemUn,TemUnit). The new columns are in the default poll, and the first poll drops what a device doesn't answer, like any other column._remove_unsupported_props()then keeps the first answered column of each group and saves it on the device, and the getters and setters use only that one. 0 is a valid value in all three groups (StTem0 is 16 °C), so they usemissing_value=-1. Units that answerSetTem,TemRecandTemUnkeep using them.invalidate_missing_property_group()returns the column it keeps, and the sensor groups are saved on the device the same way.DeviceState.set()already droppedTemRecfor a unit that doesn't report it. Only theis unsupportederror log is gone.StTem/StFahFlgof the ducted unit, which are always 0 (the same as a zone at 16 °C), so it drops them.operation_modeandset_operation_mode()convert the zone controller mode numbers.feature_turbo,set_feature_turbo()andsupports_property(FEAT_TURBO_MODE)handle that. Leaving Cool or Heat drops turbo to High.target_temperatureandset_target_temperature()like any other device:StTemwith an offset of 16 (TARGET_TEMPERATURE_OFFSETS), and the sameSetTem/TemRectable in °C and °F.set_target_temperature()rounds °C to the nearest half degree and °F to whole degrees. A zone write sendsStTemandStFahFlgtogether, because the controller keeps the old bit when onlyStTemcomes in.AC unitandZone 1toZone 8, from the controller name and the MAC suffix.pmacis a gateway. It's left out, and all its sub-units are kept. Devices without such a link go through the key check as before. A sub-unit'spmacis used as its MQTT controller MAC only when it's also the first 12 characters of its own MAC (the gateway, as on the zone controller). Otherwise the MAC rules stay as they are, andgree_extract_macs()is unchanged.GreeCloudApi.login()only logsr,msg,uidandaliveof the response, also in its errors.GreeDiscoveredDeviceleaves the key and the account email out of its repr, which discovery logs.Home Assistant layer:
GreeEntityDescription.device_filterlimits an entity to some kinds of device when the props alone can't tell._controller_label()).zone. A zone always starts with Zone Switch ticked, and the features default is filtered against what the device supports.int().cleanup_device_connection_issues()loops over a copy of the issues.TO_REDACT(device key, password, token, email) is used for the entry data in the setup log, the new-entry logs and the entry diagnostics. Lines that logged the email or the entry title log the user id or entry id instead.en.json,icons.json,docs/protocol.md,docs/entities.md,docs/configuration.md,docs/architecture.md,docs/troubleshooting.md,docs/actions.mdandsupported-devices.mdare updated.Testing
pytest: 290 passed (255 on 5.0-dev, plus 35 new).tests/fakes/zone.pyis a fake controller that behaves like the real one:subDevform only, nocid, per unit columns, mode, fan and unit mirrored from the ducted unit to the zones, and an empty result above the column limit.mypy.ini) and Pylint show nothing new compared with 5.0-dev.Pow,Mod,WdSpdandTemUnit, and each zone keepsStTem,StFahFlgandTemUnit.StTem2 withStFahFlg1, and the controller keeps it.StTem5,StFahFlg1). Values set on the panel (64, 66 and 67 °F) read back right.StTem0) keeps its target temperature after a restart.probe_device_limits()measured 29 columns. The module answers 30 with an empty result, and requests far above that (about 40 columns and more) made it reboot.