Aprilaire Thermostat 8800 any MODBUS experts?

It took a few days but it looks like the Entrance/Foyer thermostat is reporting:

I will keep an eye on it to make sure it continues to mirror my thermostats. Great work guys.

Edit: Within a minute of me posting it looks like those entities become unavailable and the thermostat shows zero again:

Any idea what’s causing those entities to be unavailable? I haven’t seen this at all on the bedroom thermostat.

Just sent you a DM with the logs.

If the rest of the integration is working, then Unavailable on the sensor would likely mean that there was a non-zero status from the thermostat.

For temperature, the statuses are:

0: No Error
1: Out of Range Low
2: Out of Range High
3: Not Installed
4: Open
5: Short

For humidity, the statuses are:

0: No Error
1: Reserved
2: Reserved
3: Not Installed
4: Error

I have pushed a release 0.3 which will expose this information for debugging. Install that version, then while it’s in this state, go to the sensor entity and click “Attributes”, then you should see the status which will map to the above values. If it is 0, then check the raw sensor value and make sure that’s a sensible value.

My bet is that the status is non-zero, but I could be wrong.

Edit to add: The climate card uses the Indoor Temperature Controlling Sensor value for the main temperature number it shows, so you really just need to debug that sensor.

Meritage here as well with a 6045M in Texas. Dealing with the hand we’ve been dealt when it comes to the Aprilaire system.

For #1, I have experienced this during development. There are safeguards in the code to work around the flaky socket which seems to help for my install, but I admittedly mostly read the values, I don’t frequently change the values in HA, so I may not notice if there is still flakiness. What happens is the thermostat will silently basically not listen to the socket anymore, but it won’t actually drop, so we don’t know that at the code level. What the integration does to try to prevent this is to preemptively disconnect and reconnect the socket every 60 minutes, which does help a lot. The thermostat is extremely sensitive to trying to connect to the socket multiple times, and if you do the right (wrong) combination of things, it can completely shutdown and require a restart. If you want to adjust that, in the custom integration try changing init.py RECONNECT_INTERVAL to a lower value (in seconds). Otherwise, it’s a matter of trying to identify when the state happens to try to preempt it, but I would need to know more details of the exact conditions.

For #2 if you are referring to when you change the setpoints, that’s probably due to unit conversion and deadbands with the thermostat, which HA doesn’t support. First, the thermostat only allows celsius values, so if you set a setpoint to certain Fahrenheit values, the corresponding celsius value is off by one. Unfortunately that cannot be fixed, because Fahrenheit inherently has more values than celsius, so it’s a pigeonhole problem. Second, the thermostat has a requirement that the setpoints be a certain distance apart, called the deadband. HA doesn’t have a way of controlling this in the UI. So, if you send an updated setpoint, sometimes the thermostat will adjust the values to respect the deadband, and then send an update back. Unless HA adds the deadband functionality, this is unfortunately just a limitation of the system.

Sorry for delayed responses, I don’t get the notification emails from this thread consistently.

I have been seeing a similar status on my outdoor temperature controller. Did you by any chance hook the device up to the AprilAire Cloud prior to switching it back to automation? I have been working with support, and apparently if you have both systems running they sometimes get into a confused state. It is nothing to worry about, as the system will eventually bounce back to normal. However you may start getting a lot of weird status emails from AprilAire Cloud about the thermostat probe being offline.

By the way I see that you have an Outdoor temperature controller installed on both devices. It is nice your builder did this, because mine decided it wasn’t worth it and had to force him to do the install to unlock the extra capabilities.

The automation system does have the ability to write an Outdoor temperature to the device from another service. I am currently trying to figure out how I can get that integrated into HA to make it easy to take a temp from an integration to unlock these outdoor capabilities for all the users of the plugin. Regardless of if they have the probe installed.

No apology needed, we all appreciate your work on this. One of the many reasons this is such a great community.

Yes it was previously connected. Before I stumbled on this thread I had it connected normally to the Aprilaire app with the Google Home integration turned on. Not sure if you watched the video I PM’d you but I still have it integrated with their app. Since the control from HA seems intermittent, I left the app connected to quick temperature changes but I can delete the device from my account if need be

Sometimes I wonder what’s going through a company’s head during development. USA is the world minority when it comes to farenheit use but you’d think based on the sheer size of the country they’d of written a better solution to deal with it. Everything is clearer in hindsight I guess :man_shrugging:

Will do. Armed with this knowledge I’m going to play with it and see if I can “tune” it. The deadband makes sense, I can see when Aprilaire overrides HA if the lower/upper temperature bounds are too close together.

If there’s anything specific I can help with or test for you just let me know. I work from home and can consistently test throughout the day.

I don’t have a Google Home device, only Alexa, but if it works like Alexa then it goes via the internet, the same way that the Aprilaire app does. I don’t believe it uses the socket protocol. From my experience, while only one socket connection is allowed, you can still use the app/other connection as long as its internet based.

The challenge with this failure condition is that it’s extremely hard to detect. The connection isn’t dropped, so we don’t fall into that case which does a reconnect. It also doesn’t seem to actually give an error, it just seems to stop listening. There is a sync call that you can do, which causes the thermostat to resend all of the COS data. It’s the only thing that I can think of using for a heartbeat, but even then it’s hard to correlate that some response was because of the sync. Other than that, I can’t think of a good way to detect that that condition has occurred. I’m open to any ideas.

The best way to know what’s happening is to put the integration up to debug level logging. If you do this, then you’ll be able to see exactly what gets sent and received. You should see the request go out when you do change the setpoint.

The best thing you could do in general would be to monitor generally and see if/when the socket connection stops working, and then, if it starts working again. Since it already reconnects every hour, my hope/expectation would be that even if it stops responding, that it would reconnect in < 1 hour and start working again. If that’s the case, then some tuning would probably help. If it doesn’t then the thermostat may be getting into that other state, which would require some different investigation.

I ran into the same problem, and setup a proxy server between HA and the thermostat to debounce the multiple connection attempts. Since setting up this proxy server, my connection to the thermostat has stayed rock solid for over 2 weeks.

@nberardi Could you tell me what your proxy server does differently than the main integration? I should be able to implement the same logic in the main integration. I think it will be prohibitive in the long term to get people to host a proxy. I’d rather get it right in the integration code.

2 Likes

The proxy was a tool to allow me to do development while allowing HA plug-in to run in parallel. Since only one client is allowed to connect to the thermostat. I wouldn’t recommend deploying it unless you are doing development.

The proxy does nothing fancy, just standard debouncing. I make sure that only one connection attempt can be established with the thermostat every 10 seconds, all others are rejected.

I stumbled into this after discovering that the thermostat gets easily overwhelmed by connection attempts if you don’t give it enough time to recover. The 10 seconds is probably overkill, but kept my thermostat stable for going on 2 weeks now. This is likely due to a CPU or OS limitation on sockets.

Once the connection is established you can send as many commands as you like.

Gotcha, thanks for that info. I think that my changes in the 0.5.0 release will address that issue, then. As I noted in Plugin gets into a tight connection loop · Issue #8 · chamberlain2007/aprilaire-ha · GitHub, I did locate the issue there, it should now respect the reconnect delay (10s) when the connection is dropped, previously it was only respecting this delay when initially trying to establish the connection. For what it’s worth, I did also refactor the logic for the write queue processing, so that is a little less aggressive as well, though probably not the issue you were seeing.

That all said, if there are other issues with the socket doing weird things as you mentioned above with it not doing a FIN, it’s hard to catch and I would need more data about that. It’s using asyncio which wrap Pythons normal sockets, so I don’t see anything that would allow doing anything fancy.

Thanks again for this hard work. Recently I haven’t noticed any connection drops. I’m on the latest version.

Just a separate question: is it possible to add Zone 2 entities for a thermostat? For example my master bedroom thermostat is only reporting zone 1 data but I’d like to see and control zone 2 which is my upstairs area.

Maybe. The problem is that I don’t have one, which makes it pretty difficult for me to do. I’m honestly not even clear what the data for them is. The best that I have seen in the documentation is around “support modules”, which appear to only be to add additional temperature/humidity non-controlling sensors. For a proper zone, I don’t see anything in the documentation about it. I have seen some references in the installer docs, but it’s only about setting the value by the installer.

If you are adept and able to find what it corresponds to in the protocol, I could definitely mock it and implement it. But, as it stands I don’t know enough about it and don’t have a device to test with.

Not sure on the wifi stuff but 8800 uses the 422 protocol so each t stat has it’s own id on the wire I have a lot of documentation on that one and can go into a terminal window and control all my t stats

I am also a Meritage home owner. I have a thermostat downstairs and one upstairs but the house uses one AC Unit. I was able to connect both to HA but only my downstairs thermostat has entities and show a device. Which is awesome, but wondering if there is a reason that the upstairs one is blank. Both thermostats are 800 series. I looked into my HA Logs and I see maybe it’s an issue with the Mac number? I looked at the .5 build and wondering if this is related. Is there anything I can do?

To confirm, you have two thermostats with different IP addresses, correct? And you were able to add both successfully in the integrations UI? If you go to the integration and go to the device (not the entities), does it show any devices? Or, are they all Unavailable?

A screenshot of the device page for the problematic one would help.

The following would do debug logging. You would want to first disable the device, set this in your configuration.yaml, restart Home Assistant, wait till everything is initialized and then clear the log. Then go re-add the device and copy the resulting debug lines from your log. You can comment out the log and reboot once you have logs for the first minute or so after adding.

logger:
  default: error
  logs:
    custom_components.aprilaire: debug

So oddly enough, I added the logger, then enabled the services again and saw that both thermostats have devices and are functioning. I restarted Home Assistant again just to check and then saw that my second thermostat retains the device and entities but now all unavailable. Looking at the logs, possible it has to do with the NACK?

The first thermostat still has all the entities and is functional

2023-03-15 16:07:08.442 DEBUG (MainThread) [custom_components.aprilaire] Manually updated aprilaire data
2023-03-15 16:07:08.457 DEBUG (MainThread) [custom_components.aprilaire] Manually updated aprilaire data
2023-03-15 16:07:08.457 DEBUG (MainThread) [custom_components.aprilaire] Manually updated aprilaire data
2023-03-15 16:07:08.506 INFO (MainThread) [custom_components.aprilaire] Aprilaire connection made
2023-03-15 16:07:08.508 DEBUG (MainThread) [custom_components.aprilaire] Manually updated aprilaire data
2023-03-15 16:07:10.508 DEBUG (MainThread) [custom_components.aprilaire] Queuing data, sequence=1, action=Action.READ_REQUEST, functional_domain=FunctionalDomain.IDENTIFICATION, attribute=2
2023-03-15 16:07:10.508 DEBUG (MainThread) [custom_components.aprilaire] Queuing data, sequence=2, action=Action.READ_REQUEST, functional_domain=FunctionalDomain.CONTROL, attribute=7
2023-03-15 16:07:10.509 DEBUG (MainThread) [custom_components.aprilaire] Queuing data, sequence=3, action=Action.READ_REQUEST, functional_domain=FunctionalDomain.CONTROL, attribute=1
2023-03-15 16:07:10.509 DEBUG (MainThread) [custom_components.aprilaire] Queuing data, sequence=4, action=Action.READ_REQUEST, functional_domain=FunctionalDomain.SENSORS, attribute=2
2023-03-15 16:07:10.509 DEBUG (MainThread) [custom_components.aprilaire] Queuing data, sequence=5, action=Action.READ_REQUEST, functional_domain=FunctionalDomain.IDENTIFICATION, attribute=5
2023-03-15 16:07:10.509 DEBUG (MainThread) [custom_components.aprilaire] Queuing data, sequence=6, action=Action.WRITE, functional_domain=FunctionalDomain.STATUS, attribute=1
2023-03-15 16:07:10.509 DEBUG (MainThread) [custom_components.aprilaire] Queuing data, sequence=7, action=Action.WRITE, functional_domain=FunctionalDomain.STATUS, attribute=2
2023-03-15 16:07:10.513 INFO (MainThread) [custom_components.aprilaire] Sent data: 01 01 00 03 02 08 02 fb
2023-03-15 16:07:10.514 INFO (MainThread) [custom_components.aprilaire] Sent data: 01 02 00 03 02 02 07 19
2023-03-15 16:07:10.514 INFO (MainThread) [custom_components.aprilaire] Sent data: 01 03 00 03 02 02 01 e8
2023-03-15 16:07:10.515 INFO (MainThread) [custom_components.aprilaire] Sent data: 01 04 00 03 02 05 02 81
2023-03-15 16:07:10.515 INFO (MainThread) [custom_components.aprilaire] Sent data: 01 05 00 03 02 08 05 01
2023-03-15 16:07:10.516 INFO (MainThread) [custom_components.aprilaire] Sent data: 01 06 00 20 01 07 01 01 00 00 00 00 01 00 00 00 00 01 00 00 00 01 00 00 00 00 00 01 00 01 00 01 01 01 00 00 6f
2023-03-15 16:07:10.517 INFO (MainThread) [custom_components.aprilaire] Sent data: 01 07 00 04 01 07 02 01 3b
2023-03-15 16:07:10.520 INFO (MainThread) [custom_components.aprilaire] Aprilaire data received 01 03 00 02 06 03 96
2023-03-15 16:07:10.520 DEBUG (MainThread) [custom_components.aprilaire] Received data, action=Action.NACK, functional_domain=FunctionalDomain.NACK, attribute=0
2023-03-15 16:07:10.520 ERROR (MainThread) [custom_components.aprilaire] Received NACK for attribute 3
2023-03-15 16:07:10.522 INFO (MainThread) [custom_components.aprilaire] Aprilaire data received 01 04 00 02 06 03 cd 01 01 00 11 03 08 02 b4 82 55 50 93 6d 01 49 02 01 02 0d 04 0e 51
2023-03-15 16:07:10.522 DEBUG (MainThread) [custom_components.aprilaire] Received data, action=Action.NACK, functional_domain=FunctionalDomain.NACK, attribute=0
2023-03-15 16:07:10.522 ERROR (MainThread) [custom_components.aprilaire] Received NACK for attribute 3
2023-03-15 16:07:10.524 INFO (MainThread) [custom_components.aprilaire] Aprilaire data received 01 02 00 08 03 02 07 04 01 00 00 00 ef
2023-03-15 16:07:10.524 DEBUG (MainThread) [custom_components.aprilaire] Received data, action=Action.READ_RESPONSE, functional_domain=FunctionalDomain.CONTROL, attribute=7
2023-03-15 16:07:10.524 DEBUG (MainThread) [custom_components.aprilaire] Manually updated aprilaire data
2023-03-15 16:07:10.529 INFO (MainThread) [custom_components.aprilaire] Aprilaire data received 01 80 00 2f 05 01 01 01 01 00 00 00 00 00 01 00 00 04 05 00 01 00 00 00 00 01 02 02 04 00 03 00 00 00 00 00 02 00 3d 51 00 0d 01 01 01 00 00 00 0d 0d 00 d3
2023-03-15 16:07:10.530 DEBUG (MainThread) [custom_components.aprilaire] Received data, action=Action.COS, functional_domain=FunctionalDomain.SETUP, attribute=1
2023-03-15 16:07:10.530 DEBUG (MainThread) [custom_components.aprilaire] Manually updated aprilaire data
2023-03-15 16:07:10.530 INFO (MainThread) [custom_components.aprilaire] Aprilaire data received 01 80 00 07 05 02 01 03 03 18 55 bc
2023-03-15 16:07:10.530 DEBUG (MainThread) [custom_components.aprilaire] Received data, action=Action.COS, functional_domain=FunctionalDomain.CONTROL, attribute=1
2023-03-15 16:07:10.531 DEBUG (MainThread) [custom_components.aprilaire] Manually updated aprilaire data
2023-03-15 16:07:10.533 INFO (MainThread) [custom_components.aprilaire] Aprilaire data received 01 80 00 08 05 02 07 04 01 00 00 00 3e
2023-03-15 16:07:10.534 DEBUG (MainThread) [custom_components.aprilaire] Received data, action=Action.COS, functional_domain=FunctionalDomain.CONTROL, attribute=7
2023-03-15 16:07:10.534 DEBUG (MainThread) [custom_components.aprilaire] Manually updated aprilaire data
2023-03-15 16:07:10.534 INFO (MainThread) [custom_components.aprilaire] Aprilaire data received 01 80 00 0d 05 03 04 01 03 18 55 ff 1e 13 0f 03 17 ff
2023-03-15 16:07:10.535 DEBUG (MainThread) [custom_components.aprilaire] Received data, action=Action.COS, functional_domain=FunctionalDomain.SCHEDULING, attribute=4
2023-03-15 16:07:10.535 DEBUG (MainThread) [custom_components.aprilaire] Manually updated aprilaire data
2023-03-15 16:07:10.537 INFO (MainThread) [custom_components.aprilaire] Aprilaire data received 01 80 00 0b 05 05 02 00 55 03 92 04 00 03 00 f6
2023-03-15 16:07:10.537 DEBUG (MainThread) [custom_components.aprilaire] Received data, action=Action.COS, functional_domain=FunctionalDomain.SENSORS, attribute=2
2023-03-15 16:07:10.538 DEBUG (MainThread) [custom_components.aprilaire] Manually updated aprilaire data
2023-03-15 16:07:10.539 INFO (MainThread) [custom_components.aprilaire] Aprilaire data received 01 80 00 07 05 07 06 00 00 00 00 59 01 80 00 07 05 07 07 00 00 00 00 8a
2023-03-15 16:07:10.539 DEBUG (MainThread) [custom_components.aprilaire] Received data, action=Action.COS, functional_domain=FunctionalDomain.STATUS, attribute=6
2023-03-15 16:07:10.539 DEBUG (MainThread) [custom_components.aprilaire] Received data, action=Action.COS, functional_domain=FunctionalDomain.STATUS, attribute=7
2023-03-15 16:07:10.539 DEBUG (MainThread) [custom_components.aprilaire] Manually updated aprilaire data
2023-03-15 16:07:10.539 DEBUG (MainThread) [custom_components.aprilaire] Manually updated aprilaire data
2023-03-15 16:07:10.541 INFO (MainThread) [custom_components.aprilaire] Aprilaire data received 01 80 00 0a 05 08 01 49 02 01 02 0d 04 0e b0
2023-03-15 16:07:10.541 DEBUG (MainThread) [custom_components.aprilaire] Received data, action=Action.COS, functional_domain=FunctionalDomain.IDENTIFICATION, attribute=1
2023-03-15 16:07:10.542 DEBUG (MainThread) [custom_components.aprilaire] Manually updated aprilaire data
2023-03-15 16:07:10.542 INFO (MainThread) [custom_components.aprilaire] Aprilaire data received 01 80 00 04 05 07 08 00 ab 01 80 00 04 05 07 02 01 74
2023-03-15 16:07:10.542 DEBUG (MainThread) [custom_components.aprilaire] Received data, action=Action.COS, functional_domain=FunctionalDomain.STATUS, attribute=8
2023-03-15 16:07:10.542 DEBUG (MainThread) [custom_components.aprilaire] Received data, action=Action.COS, functional_domain=FunctionalDomain.STATUS, attribute=2
2023-03-15 16:07:10.542 DEBUG (MainThread) [custom_components.aprilaire] Manually updated aprilaire data
2023-03-15 16:07:10.542 DEBUG (MainThread) [custom_components.aprilaire] Manually updated aprilaire data

Thank you! That helped me see the issue. tl;dr there is a prerelease 0.5.2 in HACS, update to that and let me know if that fixes your issue. I’ll be running it for the next bit to make sure it doesn’t have issues.

Longer explanation, the thermostat can send multiple packets in the same response. If you look at this one:

01 04 00 02 06 03 cd 01 01 00 11 03 08 02 b4 82 55 50 93 6d 01 49 02 01 02 0d 04 0e 51

It is actually multiple packets:

01 04 00 02 06 03 cd
01 01 00 11 03 08 02 b4 82 55 50 93 6d 01 49 02 01 02 0d 04 0e 51

The first one is a NACK, but the second one is the MAC address (03 08 02)

There was a bug that aborted the processing of other packets if a NACK is received, so it got the MAC address but then didn’t pass it along. In 0.5.2 that will be fixed and you should be good to go.

That is awesome! I am very excited. Thank you thank you thank you for building this. Ill keep an eye out for 0.5.2

If you’d like to use it now, you can enable the pre-release option on the repo in HACS and it will show you 0.5.2. Otherwise, expect it in the next couple days as a stable release.

1 Like