rgerganov / py-air-control

Command line app for controlling Philips air purifiers
MIT License
256 stars 52 forks source link

Accessory not responding #58

Open JekleFPV opened 3 years ago

JekleFPV commented 3 years ago

I'm running air control on a raspi zero W running the homebridge image, along with homebridge Philips Air but Homekit keeps giving telling me "No response". I've tried to figure it out with the maker of homebridge air control (https://github.com/Sunoo/homebridge-philips-air/issues/31#issue-678654254), but it seems it has to do with py air control.

When I run airctrl --ipaddr 192.168.1.18 --protocol coap, what I get is below, any clues as to how to fix this?

Give up on message From None, To ('192.168.1.18', 5683), CON-56159, POST-cx, [Uri-Path: sys, Uri-Path: dev, Uri-Path: sync, ] C543FAD1...8 bytes Traceback (most recent call last): File "/usr/local/bin/airctrl", line 10, in sys.exit(main()) File "/usr/local/lib/python3.7/dist-packages/pyairctrl/airctrl.py", line 448, in main c = CoAPCli(device["ip"], debug=args.debug) File "/usr/local/lib/python3.7/dist-packages/pyairctrl/airctrl.py", line 15, in init self._client = CoAPAirClient(host, port, debug) File "/usr/local/lib/python3.7/dist-packages/pyairctrl/coap_client.py", line 80, in init self._sync() File "/usr/local/lib/python3.7/dist-packages/pyairctrl/coap_client.py", line 91, in _sync self.client_key = self.client.post("/sys/dev/sync", self.syncrequest).payload AttributeError: 'NoneType' object has no attribute 'payload'

inwaar commented 3 years ago

Got the same, airctrl works for a while and then gives Give up on message. Any further runs of the tool give the same error. The device is PHILIPS 3000i AC3829/10.

I run the following command every 2 minutes to get actual pm2.5 and humidity.

airctrl --ipaddr 192.168.1.101 --protocol coap

It works fine for less than an hour and then starts giving the error. More interesting is that the AC3829/10 also stops responding to the Air matters app. So it seems airctrl makes the device hang after a while. If i turn off and on the device it starts working and everything repeats after a while.

rgerganov commented 3 years ago

That sounds a lot like issue #63. Unfortunately I don't have a coap device and I can't troubleshoot myself.

metebalci commented 3 years ago

I did not see this issue before opening #63, so just to keep it here, I had exactly the same problem with AC1214 using coap protocol.

GSzabados commented 3 years ago

I have experienced the same issue as @inwaar explained it. Some people on the HA forum see similar messages.

By looking at the CoAPthon3 repo, it hasn't been maintained well for the past 3 years, and has some old unresolved issues:

Quite similar to this issue: https://github.com/Tanganelli/CoAPthon3/issues/6

And maybe matching the previous issue with this one: https://github.com/Tanganelli/CoAPthon3/issues/16

Otherwise there are a few forks which are a bit ahead of the original one:

https://github.com/8749236/CoAPthon3/commits/master

https://github.com/jnoor/CoAPthon3/commits/master

https://github.com/michieldwitte/CoAPthon3/commits/master https://github.com/magnev/CoAPthon3/commits/master

https://github.com/tadodotcom/CoAPthon3/commits/master (This is TADO's branch!!!)

https://github.com/WAvdBeek/CoAPthon3/commits/master

Some of them tries to fix the aforementioned issues, so has other improvements. It might would worth to change the CoAPthon3 to another branch and use it to fix this issue.

rgerganov commented 3 years ago

Agree, there are many issues with CoAPthon3 and apparently it's no longer maintained. People with CoAP devices feel free to experiment with these forks and let me know if any them solves this particular issue.

GSzabados commented 3 years ago

Just don't forget to add the fix for the length of the "increase reception buffer size" commit if it wasn't implemented yet. ;)

flash447 commented 3 years ago

I have also noticed this issue and I have made an additional observation. Instead of calling the "py-air-control" script periodically, i made a local copy where i "loop-sleep" around .get_status(..). This way I have been able to poll the PPM2.5 for days without the issue triggering. This seem to result in other problems, like the fan speed not updating, but the PPM2.5 looks okay.

Without knowing anything about the underlying protocol, but could it be that the "py-air-control" leaves like "half-open sessions" against the air purifier when closing? Perhaps the air purifier only have a fixed number of "concurrent sessions" and don't utilize any like "timeout cleanup". Once the sessions are out it doesn't accept any new connections until the air-purifier is power cycled. Just a theory.

rgerganov commented 3 years ago

@flash447 This is an interesting observation, thanks. I see that the CoAP client is stopped in a __del__ method and there is a TODO:

class CoAPAirClient(HTTPAirClientBase):

    def __del__(self):
        # TODO call a close method explicitly instead
        self.client.stop()

I guess the original idea was that this client is created once and then destroyed when the object is garbage collected. You can try two things:

  1. Call self.client.stop() explicitly at the end and see if this fixes the problem
  2. Instead of creating the client once in the constructor, create and destroy it for each and every operation. This is how the PlainCoAPAirClient works. I don't know if reusing the same client for multiple operations is OK or not.

This code was contributed by other people and I have no way to debug and test it because I don't have CoAP device. If any of the above fixes the problem, submit a PR and I will merge it.

flash447 commented 3 years ago

You can try two things:

I have tried your suggestions, but neither helped.

Is this issue a problem for all devices using the "encrypted coap client" or is it device/firmware specific?

GSzabados commented 3 years ago

I am just leaving this here, this is the documentation of the COAP protocol:

https://tools.ietf.org/html/rfc7252

roldoe commented 3 years ago

The problem is not related to the COAP library but to the fundamental wrong way that py-air-control deals with the COAP protocol.

After capturing some network packets and using Wireshark I noticed that the observe option is set on each request. This means that the device expects the client to keep receiving packets for updates about the sensor values. This seems to be the only way to get the sensor values from the device.

How this is implemented in py-air-control is wrong. If you don't explicitly close the connection the update messages will get pushed on a queue. Only one item of the (FIFO) queue is read for each time the get_status is called. Which makes no sense since this queue contains after an hour about 100 messages. This will result in a get_status call that provides you old data. If you do explicitly close the connection by either stopping the software or explicitly calling stop, the connection will be closed and the handshake will start again. Somehow the Philips device doesn't like this if you do this too often. The network stack of the device might crash and you have to disconnect it from power to recover.

Conclusion: py-air-ctrl in combination with COAP is nice if you use it only once in a while. Don't use it for continuously polling like homebridge, Domoticz or other domtica software that wants to receive updated sensor values. For this you need to implement an observer that will keep listening for updates. There is no easy way to modify py-air-control to this behavior.

I pushed my solution for Domoticz on https://github.com/roldoe/domoticz-philips-air

Sunoo commented 3 years ago

Oh great, so looks like my homebridge-philips-air would require updates.

I should probably try to find a new maintainer, as I never had access to a CoAP unit, and I have gotten rid of my HTTP unit at this point as well.

rgerganov commented 3 years ago

@roldoe Thanks for the analysis! We need to implement a py-air-control daemon which runs in the background and listens for updates. The CLI tool will query the daemon instead of opening connections to the device. I don't think this is hard to implement but I don't have a CoAP device and I cannot do it myself. If anyone is willing to implement and contribute this, PRs are welcome!

Cyber1000 commented 3 years ago

Maybe a daemon running in background providing the data per rest-api and/or mqqt would be the best solution. The cli could interact via the rest-interface (for example), this should work for coap and non coap devices. Maybe this would diminish the need of an own library #34, since rest/mqqt would be well known and can be losely coupled to homeautomation-servers. I'll look into this the next few days, other thoughts are welcome.

GSzabados commented 3 years ago

@Cyber1000, this Home Assistant integration works like that. No issues with non responding device anymore. It subscribes to changes from the airpurifier.

https://github.com/betaboon/philips-airpurifier-coap

Cyber1000 commented 3 years ago

Thanks for pointing that out, it seems to have a more up-to-date coap implementation (https://github.com/chrysn/aiocoap) too. The fan is "home assistant"-centric, I think, but will be a good starting point for me.

Cyber1000 commented 3 years ago

Well I looked deeper in the code:

Cyber1000 commented 3 years ago

I'll give a update soon

Cyber1000 commented 3 years ago

I've added (hopefully) a fix in PR #85 , If someone could try it before merge:

pip3 uninstall py-air-control
git clone https://github.com/Cyber1000/py-air-control.git -b observe
cd py-air-control
pip3 install .

Afterwards you could do pip3 uninstall py-air-control and install the official plugin again with pip3 install py-air-control

My problem is that I have a coap device, but it doesn't run into this problem. Model is AC2889/10 and swversion is 1.0.7 Maybe my device cleans up unused observes over the time, at least it doesn't brick and always returns the wanted information.

rgerganov commented 3 years ago

@Cyber1000 thanks for looking into this, I think PR #85 has all the chances to fix this issue but I cannot test it myself. I'd ask people having the issue to try this patch and tell us if it works.

Cyber1000 commented 3 years ago

86 would be an alternative to #85

Basically it uses the same cancel_observing-method, but reduces the code (baseclass for both planin_coap and coap)