home-assistant / core

:house_with_garden: Open source home automation that puts local control and privacy first.
https://www.home-assistant.io
Apache License 2.0
71.91k stars 30.13k forks source link

Invalid Lennox E30 pairing flow via HomeKit controller #20885

Closed jeromelaban closed 4 years ago

jeromelaban commented 5 years ago

Home Assistant release with the issue:

0.87.0

Last working Home Assistant release (if known): None

Operating environment (Hass.io/Docker/Windows/etc.): Docker

Component/platform:

Homekit controller

Description of problem: Here's the "normal" flow for pairing a Lennox E30 to home kit:

Pairing a Lennox E30 with home-assistant using the HomeKit Controler does not work properly, for two reasons:

Tracking down the issue in homekit_python, I could create a manual pairing by adding:

    pin = input("PIN: ")

at this line: https://github.com/jlusiardi/homekit_python/blob/9604d76131a9955c8b4dbd9f10dc92394cc61ae3/homekit/protocol/__init__.py#L102

and run it as CLI:

python3 pair.py -d XX:XX:XX:XX:XX:XX -f pairing.json -a "LennoxE30" -p 123456

Blocking the pairing procedure to input the pin at the precise moment (after step 3, the verify request) during the negotiation makes the pairing code appear and stay visible long enough on the Lennox E30 screen to be able to input it at the CLI.

I've yet to be able to reuse the pairing file in home-assistant, and I'm not sure either how to create such an asynchronous flow using the HA UI.

Update 2019-02-09: I was able to reuse in HA the pairing I made using my modified CLI of homekit_python. The name of the pairing has to be the device ID XX:XX:XX:XX:XX:XX (AccessoryPairingID value in the pairing file). I'm only able to see the temperature, modes are not available and setting the temperature does not seem to have any actual effect.

garyak commented 4 years ago

With wider set points set on the S30, HA reports min 40, max 90. Unfortunately these settings, when made from HA, don't reflect back to the S30.

The lovelace card returns to 60 degrees, or 40 depending on your setting at the S30.

GaryOkie commented 4 years ago

Thanks @garyak for testing. Your reported wide min/max setpoint range is different I am seeing and I think that may be because my Tstat was in cool mode and yours was in Heat mode. The default range is 60-90 and the optional wider range is 40-99. I don't think it is correct to have either a 40-90 or 60-99 range reported, regardless of which mode the Tstat is in.

@jc2k - I have the original debug GET_Accessories output from when the S30 first paired and have compared it to the _homekitcontroller-entity-map pairing file, and both agree.

There appear to be two relevant Homekit IID's pertaining to temperature range... IID: 106 (COOL Mode?) shows a range of 15.5-37 C, which is 60-99F, the exact values I'm seeing. IID: 108 (HEAT Mode?) shows a range of 4.5-32 C which is 40-90F, the exact values @garyak gets.

I have since switched from Cool to Heat mode since the pairing was done, but the range has not changed for me - it is still 60-99. Problem is, I need to remotely lower the temp below 60 for an empty vacation cabin that is winterized and can't do it via HA/Homekit, only via the iComfort app which properly honors the wider setpoint range of 40-99.

Formatted debug output follows:

accessories:[ |  
aid:1,"services":[ |  
characteristics:[ |  
format:"bool","iid":2,"perms":["pw"],"type":"14",
format:"string","iid":3,"perms":["pr"],"type":"20","value":"Lennox",
format:"string","iid":4,"perms":["pr"],"type":"21","value":"S30   2B",
format:"string","iid":5,"perms":["pr"],"type":"23","value":"iComfort   S30 xxxxx",
format:"string","iid":6,"perms":["pr"],"type":"30","value":"WL18Exxxxx",
format:"string","iid":7,"perms":["pr"],"type":"52","value":"3.55.626",
format:"string","iid":8,"perms":["pr"],"type":"53","value":"3.0.002"],"iid":1,"type":"3E",

characteristics:[ |  
format:"uint8","iid":101,"maxValue":2,"minStep":1,"minValue":0,"perms":["pr","ev"],"type":"F","value":0,
format:"uint8","iid":102,"maxValue":3,"minStep":1,"minValue":0,"perms":["pr","pw","ev"],"type":"33","value":2,
format:"float","iid":103,"maxValue":100,"minStep":0.1,"minValue":0,"perms":["pr","ev"],"type":"11","unit":"celsius","value":21.5,
format:"float","iid":104,"maxValue":37,"minStep":0.5,"minValue":15.5,"perms":["pr","pw","ev"],"type":"35","unit":"celsius","value":26.5,
format:"uint8","iid":105,"maxValue":1,"minStep":1,"minValue":0,"perms":["pr","pw","ev"],"type":"36","value":1,
format:"float","iid":106,"maxValue":37,"minStep":0.5,"minValue":15.5,"perms":["pr","pw","ev"],"type":"D","unit":"celsius","value":26.5,
format:"float","iid":107,"maxValue":100,"minStep":1,"minValue":0,"perms":["pr","ev"],"type":"10","unit":"percentage","value":60,
format:"float","iid":108,"maxValue":32,"minStep":0.5,"minValue":4.5,"perms":["pr","pw","ev"],"type":"12","unit":"celsius","value":19.5,
format:"string","iid":109,"perms":["pr"],"type":"23","value":"Thermostat"],"iid":100,"primary":true,"type":"4A",

characteristics:[ |  
format:"string","iid":301,"perms":["pr"],"type":"37","value":"1.1.0"],"iid":300,"type":"A2"]]

And a snip from the pairing file...

"iid":   106,
--
"maxValue": 37,
"minStep": 0.5,
"minValue": 15.5,
"type":   "0000000D-0000-1000-8000-0026BB765291",
"unit": "celsius",
"value": 25
  |  
"iid": 108,
"maxValue": 32,
"minStep": 0.5,
"minValue": 4.5,
"type":   "00000012-0000-1000-8000-0026BB765291",
"unit": "celsius",
"value": 19.5

And finally, HA climate.icomfort_s30 entity state:

State: HEAT Attributes: hvac_modes: off,heat,cool,heat_cool current_temperature: 65 min_temp: 60 max_temp: 99 temperature: 60 current_humidity: 55 hvac_action: on friendly_name: Downstairs iComfort S30 supported_features: 1

GaryOkie commented 4 years ago

After restarting HA while the S30 is in Heat mode, I am now getting a min/max range of 40-90, the same as @garyak. I'll just have to remember to restart HA any time the mode is changed to get the new range. Not sure why, but I can live with that.

Evidently Lennox hardcoded their Homekit interface to use the 40-90F min/max range for Heat, and 60-99F for Cool. The option to enable a wider setpoint range regardless of mode is not honored by the Homekit interface and seems to be only relevant for the Tstat and iComfort app the best I can tell.

LOL - I switched back to Cool mode, restarted, and the range is still 40-90. Oh well, that range is fine, even though it beats me how/when this Homekit component refreshes attributes.

Jc2k commented 4 years ago

So what is supposed to happen is the thermostat bumps the c# attribute whenever the attribute database changes. This is broadcast by bonjour and HA should see it and pull the latest "entity map". Could be the comfort is always updating the attributes but not always updating c# in a timely fashion or we aren't noticing. You could use the CLI to see if c# is changing. If it's not, theres not much i can do their implementation is buggy. If it is, its my problem to sort out (:sob:).

RE: The 2 UUID's you posted - they are the cooling and heating thresholds and are apparently only applicable to Auto mode. We don't support them yet, mostly because i don't have a way to test what happens.

GaryOkie commented 4 years ago

Thanks for the info! I have checked the timestamp of _.storage/homekitcontroller-entity-map and noticed that it doesn't change when I change heat/cool modes or temp values from either the HA UI or the iComfort app. It also doesn't change after an HA restart.

So what is this CLI you mention and how do I use it to see if c# is changing? I know of C#, the programming language, but not the "c#" you are referring to.

Do you have a documentation link that describes the UUID's? I've tried, but not found one yet. Still don't understand where HA is getting the temperature ranges from if 106/108 only apply to Auto mode that isn't supported by the component. And since it's not supported, why is "Heat_Cool" being reported as an available mode and show up as a button on the climate card? Isn't that Auto mode?

EDIT: On second thought, by "CLI", you mean the SSH/Bash terminal into HA?

Jc2k commented 4 years ago

The cli ships with the library we use to make the HA integration:

https://github.com/jlusiardi/homekit_python/

It should be already installed in your HA install so it should be enough to do something like:

python3 -m homekit.discover

And after about 30s you should see output like this:

Name: smarthomebridge3._hap._tcp.local.
Url: http://192.168.178.21:51827
Configuration number (c#): 2
Feature Flags (ff): Paired (Flag: 0)
Device ID (id): 12:34:56:78:90:05
Model Name (md): Bridge
Protocol Version (pv): 1.0
State Number (s#): 1
Status Flags (sf): 0
Category Identifier (ci): Other (Id: 1)

(This is the data that we use to detect the devices available to pair)

GaryOkie commented 4 years ago

bash-5.0# python3 -m homekit.discover

Name: iComfort S30 5185f0._hap._tcp.local.
Url: http_impl://192.168.0.53:7373
Configuration number (c#): 2
Feature Flags (ff): Supports HAP Pairing (Flag: 1)
Device ID (id): 4A:D4:7A:95:0A:42
Model Name (md): S30 2B
Protocol Version (pv): 1.1
State Number (s#): 1
Status Flags (sf): Accessory has been paired. (Flag: 0)
Category Identifier (ci): Thermostat (Id: 9)

EDIT: Ah, just now see the c# number!

Jc2k commented 4 years ago

:-) As it is currently 2 it seems it does not change when you change between heat and cool. But you should be able to change settings on the thermostat and verify.

As for the UUID documentation, you can download the official spec here:

https://developer.apple.com/homekit/specification/

You'll need an Apple ID but i don't think you need to be in the paid for developer program or anything like that.

For the 2 you called out it says:

This characteristic describes the cooling threshold in Celsius for devices that support simultaneous heating and cooling. The value of this characteristic represents the 'maximum temperature' that must be reached before cooling is turned on.

For example, if the Target Heating Cooling State (page 161) is set to "Auto" and the current temperature goes above the 'maximum temperature', then the cooling mechanism should turn on to decrease the current temperature until the 'minimum temperature' is reached.

and

This characteristic describes the heating threshold in Celsius for devices that support simultaneous heating and cooling. The value of this characteristic represents the 'minimum temperature' that must be reached before heating is turned on.

For example, if the Target Heating Cooling State (page 161) is set to "Auto" and the current temperature goes below the 'minimum temperature', then the heating mechanism should turn on to increase the current temperature until the 'minimum temperature' is reached.

There are 2 key things in these that have made me reluctant to press ahead with making arbritary changes:

Clearly in some cases we need to respect these characteristics and in others we need to respect the target temperature characteristic (like we do now). But IMO it is vague and it doesn't say it is OK to refer to these threshold characteristics when not using the "auto" ("heat_cool") mode. I would say it implied that you shouldn't But it doesn't explicitly ban that either. My hope is that if the characteristic is present we should just use it for all relevant modes over the "target temperature" one.

Ultimately i'm going to have to build a mock thermostat accessory and verify which characteristics are surfaced in the iPhone UI in which circumstances - but thats a lot more work than i have time to do right now.

garyak commented 4 years ago

@GaryOkie are you able to modify temperature settings from HA? All I can do is On/Off and change modes. HA Current temp and Humidity values accurately reflect thermostat readings.

GaryOkie commented 4 years ago

Hi @Garyak - Yes, I'm able to modify temps from HA - at least according to the iComfort app which updates within several seconds of any HA change. I'm not at the remote S30 site to see it first hand, but the iComfort app must be showing the actual status.

GaryOkie commented 4 years ago

@jc2k - thanks for providing the link to the Apple Homekit docs.

I see in the official doc, that Current Temperature (IID 103) has an Apple-defined min/max range of 0-100 C, and this is exactly the characteristic that is being reported by the S30 and recorded in the pairing file.

format:"float","iid":103,"maxValue":100,"minStep":0.1,"minValue":0,"perms":["pr","ev"],"type":"11","unit":"celsius","value":21.5

Clearly Lennox hardcoded their min/max temp range to match the spec rather than pass the normal min/max ranges set on the thermostat. But why is the Homekit controller component ignoring the current temp range 0-100C and picking up the hardcoded trigger point ranges for the Auto Heat or sometimes Auto Cool instead?

This wouldn't be an issue for me except when the component sometimes decides to set the minimum heat to 60F.

EDIT - my apologies... I should have looked at TARGET Temperature (IID 104), not current temp. I see now the Apple-defined min/max range is 10-38C. The S30 originally passed a range of 15.5-37C (60-99F). However, I see that the S30 Heat state remains at min_temp: 40F and max_temp: 90F. (But that may be because I have changed from cool to heat mode).

format:"float","iid":104,"maxValue":37,"minStep":0.5,"minValue":15.5,"perms":["pr","pw","ev"],"type":"35","unit":"celsius","value":26.5,

Jc2k commented 4 years ago

Your edit is correct, we are currently using the target temperature min and max values.

My next step is to make a mock thermostat with homekit_python which has the target temperature, heating threshold and cooling threshold characteristics. I will give each of the 3 different min and max values. Will then pair with an iOS device and see which of the 3 min/max ranges it uses in each of the 3 operating modes. Hopefully this will show that iOS prefers the heating and cooling thresholds if they are present, regardless of operating mode. This will mean that we have a way forward.

If it shows my narrow interpration of the spec holds, and that the heating and cooling thresholds are only for heat_cool mode (i.e. auto mode) then we are somewhat stuck. I could potentially add a "force reload" service for the characteristics database. But I don't want to dwell on this until we have been able to verify the "nice fix" is a no go.

In the mean time if you delete your homekit_controller-entity-map and restart HA it should fetch the latest one. You could verify this does cause the target temperature to update (without a change to c#). Worth taking a copy just in case it doesn't, i guess.

garyak commented 4 years ago

OK @GaryOkie . For Heat and Cool modes I can adjust temperature set points. For Heat/Cool, I cannot. I believe I understand now what you and @Jc2k are discussing.

GaryOkie commented 4 years ago

That sounds great @jc2k as a potential way forward! I am quite happy with the functionality I now have and greatly appreciate all the attention you have been giving to improve this component.

@garyak - I don't use the Auto (Heat/Cool) mode, but I'll do some testing with it.

EDIT: I see what you mean now - there isn't any way I've found to set the separate heat setpoint and the cool setpoint for heat/cool mode. I currently use the simple-thermostat lovelace card, but it has the same limitation as the official thermostat card. Even though both provide a heat/cool button, there is only a single setpoint.

Now, there is a dual-thermostat card that has a nice dual setpoint capability, and it works just like the iComfort app round slider. I tried using it, but it seems to require two separate entities for heat and cool. Giving it the same S30 entity for both heat/cool didn't work. This has to be a common issue, but I haven't found a solution yet.

ccormier commented 4 years ago

I can also confirm successful pairings and retrieval of the accessory list after updating the homekit firmware on the S30 on HA release code.

GaryOkie commented 4 years ago

Shouldn't it be possible to set the hvac_action attribute as IDLE, instead of OFF, when the HVAC unit is not actually turned off?

garyak commented 4 years ago

Another question. Are the Fan settings exposed by the API?

GaryOkie commented 4 years ago

Nope, looking through the Apple Homekit HAP R2 non-commercial spec, there are no references to Fan settings or status for the Thermostat accessory.

garyak commented 4 years ago

Do without I guess. Thanks for checking.

GaryOkie commented 4 years ago

@Jc2k -
The Homekit "Current Heating/Cooling State" shows possible values of  0=Off; 1=Heat is on; 2=Cooling is on. I think that in this context, "Off" really means the hvac_action should be "Idle".

The "Target Heating/Cooling State" of 0=OFF is what is used to turn off the unit (hvac_mode). I don't see any other setting that can indicate if the unit is actually off, but it would probably be best to set hvac_action to off based on this target 0 value.

Jc2k commented 4 years ago

We should probably take any new issues to new tickets from now on guys, the pairing issue is resolved by the firmware (no one has said otherwise yet) and i'm going to lose track of what else is and isn't resolved. (Feel free to @ me directly for homekit stuff).

I think you are probably right about this @GaryOkie. I don't have any spare cycles right now but if you were to submit a PR to update the mapping here i would be able to review it.

I'm fine with simply replacing CURRENT_HVAC_OFF with CURRENT_HVAC_IDLE, i'm less certain about inferring the hvac_action is CURRENT_HVAC_OFF when the hvac_mode is HVAC_MODE_OFF. I think i'd prefer to not do that now, unless it is causing a reduction in functionality in the Home Assistant UI or someone demonstrates that's what the official HomeKit app is doing for its UI.

GaryOkie commented 4 years ago

Thanks - I've only done a PR on documentation before, not yet for code, but will give it a shot if it's just a simple matter of remapping.

The most important thing is to define hvac_action as idle (or heating, or cooling) when the unit is on, and off otherwise. The thermostat operation state is working properly and shows off, when the unit is off, and heat/cool/heat_cool when on.

EDIT: Another thermostat component I tried returned Hvac_action to Idle (not off) when the system was turned off. So yeah, this simple remapping of 0=CURRENT_HVAC_IDLE should suffice.

And I agree - this original E30 pairing issue should be closed, with the advice that the latest firmware needs to be installed.

Jc2k commented 4 years ago

I'm going to close this because pairing now seems to be working.

If you are waiting for support the temperature ranges in heat/cool mode, you can track this ticket.

Cheers