Binding request: Philips air purifier

@markuslaube I personally have AC2889/10. It would be interesting to see if there are some differences in responses :wink: Like the sample I posted above.

@michalboronski Thanks a lot.
As soon as this appears in milestone builds (thatā€™s what I use), I will test and feed back to you.

My initial findings:

  • the binding seems to discover philips hue bridges and samsung tvā€™s as well. log:
Attempt to create things (RemoteDevice) Identity .....)
Device not recognized (RemoteDevice) Identity .....)
  • When I push the scan button in the PaperUI Inbox I see in the list the small description of the binding, but not the (bold) title
  • Iā€™m missing the water level, temperature, humidity and some other (sensor) readings
  • Messages in my openhab.log:
Philips Air Purifier device response: status = 200, content = '{"name":"Living Room","type":"AC3829","modelid":"AC3829/10","swversion":"0.1.9"}'
Philips Air Purifier device response: status = 200, content = '{"om":"0","pwr":"0","cl":false,"aqil":100,"uil":"0","dt":0,"dtrs":0,"mode":"P","func":"PH","rhset":40,"rh":56,"temp":21,"pm25":5,"iaql":2,"aqit":7,"ddp":"0","err":49408,"wl":0}'
Philips Air Purifier device response: status = 200, content = '{"fltt1":"A3","fltt2":"C7","fltsts0":264,"fltsts1":2894,"fltsts2":2894,"wicksts":2894}'

Performance and response are great, keep up the good work!

1 Like

Great feedback @duiffie! Iā€™ll make improvements based on it and with your extra (which I lack in mine model) sensor information. Iā€™ll let you know once I update the code and have new Pull Request build . One question : I see a non-zero value of ā€œerrā€ parameter - does that mean you actually have some error visible on your purifierā€™s display?

yes, the water tank of the purifier was empty at that moment. From the original airctrl script:

err_str = {49408: 'no water', 32768: 'water tank open', 49155: 'pre-filter must be cleaned'}

Hi @duiffie , latest PR build of the binding is available (under same link) with fixes to your previous feedback

  • fixed description in Paper UI
  • Removed confusing logs during discovery process
  • Added AC3829/10 channels configuration (channels for water level, temperature, humidity, humidity setpoint, purifier/humidifier mode)
  • error codes handling

Again thanks for any feedback! :slight_smile:

Thanks! Findings:

  • Description is fixed, nice
  • Some (confusing, non-philipsair devices) logs are still there:
2019-12-09 16:09:17.330 [DEBUG] [y.PhilipsAirUpnpDiscoveryParticipant] - Device not recognized (RemoteDevice) Identity: (RemoteDeviceIdentity) UDN: 
  • When I add the discovered thing, itā€™s added as a philipsair:universal type. When I try to add AC3829_10 manually in paperui, the newly thing is created, but stays UNINITIALIZED. I see this error in the log:
Cannot create thing. No binding found that supports creating a thing of type 'philipsair:ac3829_10'.

Hi again @duiffie , new build of the PR has been droped to the Artifactory (same link above), I hope this time it will recognize and automatically name correctly your model :wink:

2 Likes

Great, the device is now recognized as a AC3829 device. Everything seems perfect now (response is really great!), except for one small bug: enabling/disabling the child lock generates the following error in openhab.log:

2019-12-12 10:46:43.884 [INFO ] [hilipsair.internal.PhilipsAirHandler] - Sending controls#cl as ON
2019-12-12 10:46:43.884 [INFO ] [l.connection.PhilipsAirAPIConnection] - {"cl":"1"}
2019-12-12 10:46:43.896 [ERROR] [l.connection.PhilipsAirAPIConnection] - Unexpected exception occurred during execution: Illegal base64 character 7b
java.lang.IllegalArgumentException: Illegal base64 character 7b
	at java.util.Base64$Decoder.decode0(Base64.java:714) ~[?:1.8.0_232]
	at java.util.Base64$Decoder.decode(Base64.java:526) ~[?:1.8.0_232]
	at java.util.Base64$Decoder.decode(Base64.java:549) ~[?:1.8.0_232]
	at org.openhab.binding.philipsair.internal.connection.PhilipsAirCipher.decrypt(PhilipsAirCipher.java:126) ~[bundleFile:?]
	at org.openhab.binding.philipsair.internal.connection.PhilipsAirAPIConnection.getResponse(PhilipsAirAPIConnection.java:169) [bundleFile:?]
	at org.openhab.binding.philipsair.internal.connection.PhilipsAirAPIConnection.sendCommand(PhilipsAirAPIConnection.java:238) [bundleFile:?]
	at org.openhab.binding.philipsair.internal.PhilipsAirHandler.sendCommand(PhilipsAirHandler.java:133) [bundleFile:?]
	at org.openhab.binding.philipsair.internal.PhilipsAirHandler.handleCommand(PhilipsAirHandler.java:113) [bundleFile:?]
	at sun.reflect.GeneratedMethodAccessor329.invoke(Unknown Source) ~[?:?]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_232]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_232]
	at org.eclipse.smarthome.core.internal.common.AbstractInvocationHandler.invokeDirect(AbstractInvocationHandler.java:152) [bundleFile:?]
	at org.eclipse.smarthome.core.internal.common.InvocationHandlerSync.invoke(InvocationHandlerSync.java:59) [bundleFile:?]
	at com.sun.proxy.$Proxy6506.handleCommand(Unknown Source) [?:?]
	at org.eclipse.smarthome.core.thing.internal.profiles.ProfileCallbackImpl.handleCommand(ProfileCallbackImpl.java:74) [bundleFile:?]
	at org.eclipse.smarthome.core.thing.internal.profiles.SystemDefaultProfile.onCommandFromItem(SystemDefaultProfile.java:48) [bundleFile:?]
	at sun.reflect.GeneratedMethodAccessor328.invoke(Unknown Source) ~[?:?]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_232]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_232]
	at org.eclipse.smarthome.core.internal.common.AbstractInvocationHandler.invokeDirect(AbstractInvocationHandler.java:152) [bundleFile:?]
	at org.eclipse.smarthome.core.internal.common.Invocation.call(Invocation.java:52) [bundleFile:?]
	at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:1.8.0_232]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_232]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_232]
	at java.lang.Thread.run(Thread.java:748) [?:1.8.0_232]

I guess the value of ā€˜clā€™ should be a boolean instead of the 0/1 thatā€™s currently sent to the device:

2019-12-12 10:45:42.009 [INFO ] [l.connection.PhilipsAirAPIConnection] - {"om":"s","pwr":"1","cl":false,"aqil":100,"uil":"1","dt":0,"dtrs":0,"mode":"P","func":"PH","rhset":50,"rh":52,"temp":23,"pm25":10,"iaql":3,"aqit":7,"ddp":"1","err":0,"wl":100}

I see that a new build has arrived, but same error, except for the fact that the binding now sends ā€œtrueā€ instead of ā€œ1ā€. Is ā€œtrueā€ maybe a string here, and should the code (line 100) in PhilipsAirHandler.java maybe be:

value = ((OnOffType) command) == OnOffType.ON ? true : false;

instead of

value = ((OnOffType) command) == OnOffType.ON ? "true" : "false";

Current error:

2019-12-13 12:57:39.471 [INFO ] [hilipsair.internal.PhilipsAirHandler] - Sending controls#cl as ON
2019-12-13 12:57:39.471 [INFO ] [l.connection.PhilipsAirAPIConnection] - {"cl":"true"}
2019-12-13 12:57:39.484 [ERROR] [l.connection.PhilipsAirAPIConnection] - Unexpected exception occurred during execution: Illegal base64 character 7b
java.lang.IllegalArgumentException: Illegal base64 character 7b
	at java.util.Base64$Decoder.decode0(Base64.java:714) ~[?:1.8.0_232]
	at java.util.Base64$Decoder.decode(Base64.java:526) ~[?:1.8.0_232]
	at java.util.Base64$Decoder.decode(Base64.java:549) ~[?:1.8.0_232]
	at org.openhab.binding.philipsair.internal.connection.PhilipsAirCipher.decrypt(PhilipsAirCipher.java:128) ~[bundleFile:?]
	at org.openhab.binding.philipsair.internal.connection.PhilipsAirAPIConnection.getResponse(PhilipsAirAPIConnection.java:165) [bundleFile:?]
	at org.openhab.binding.philipsair.internal.connection.PhilipsAirAPIConnection.sendCommand(PhilipsAirAPIConnection.java:238) [bundleFile:?]
	at org.openhab.binding.philipsair.internal.PhilipsAirHandler.sendCommand(PhilipsAirHandler.java:112) [bundleFile:?]
	at org.openhab.binding.philipsair.internal.PhilipsAirHandler.handleCommand(PhilipsAirHandler.java:91) [bundleFile:?]
	at sun.reflect.GeneratedMethodAccessor329.invoke(Unknown Source) ~[?:?]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_232]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_232]
	at org.eclipse.smarthome.core.internal.common.AbstractInvocationHandler.invokeDirect(AbstractInvocationHandler.java:152) [bundleFile:?]
	at org.eclipse.smarthome.core.internal.common.InvocationHandlerSync.invoke(InvocationHandlerSync.java:59) [bundleFile:?]
	at com.sun.proxy.$Proxy14918.handleCommand(Unknown Source) [?:?]
	at org.eclipse.smarthome.core.thing.internal.profiles.ProfileCallbackImpl.handleCommand(ProfileCallbackImpl.java:74) [bundleFile:?]
	at org.eclipse.smarthome.core.thing.internal.profiles.SystemDefaultProfile.onCommandFromItem(SystemDefaultProfile.java:48) [bundleFile:?]
	at sun.reflect.GeneratedMethodAccessor328.invoke(Unknown Source) ~[?:?]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_232]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_232]
	at org.eclipse.smarthome.core.internal.common.AbstractInvocationHandler.invokeDirect(AbstractInvocationHandler.java:152) [bundleFile:?]
	at org.eclipse.smarthome.core.internal.common.Invocation.call(Invocation.java:52) [bundleFile:?]
	at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:1.8.0_232]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_232]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_232]
	at java.lang.Thread.run(Thread.java:748) [?:1.8.0_232]
2019-12-13 12:57:39.487 [ERROR] [nal.common.AbstractInvocationHandler] - An error occurred while calling method 'ThingHandler.handleCommand()' on 'org.openhab.binding.philipsair.internal.PhilipsAirHandler@1312361': Illegal base64 character 7b
org.openhab.binding.philipsair.internal.connection.PhilipsAirAPIException: Illegal base64 character 7b
	at org.openhab.binding.philipsair.internal.connection.PhilipsAirAPIConnection.getResponse(PhilipsAirAPIConnection.java:198) ~[?:?]
	at org.openhab.binding.philipsair.internal.connection.PhilipsAirAPIConnection.sendCommand(PhilipsAirAPIConnection.java:238) ~[?:?]
	at org.openhab.binding.philipsair.internal.PhilipsAirHandler.sendCommand(PhilipsAirHandler.java:112) ~[?:?]
	at org.openhab.binding.philipsair.internal.PhilipsAirHandler.handleCommand(PhilipsAirHandler.java:91) ~[?:?]
	at sun.reflect.GeneratedMethodAccessor329.invoke(Unknown Source) ~[?:?]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_232]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_232]
	at org.eclipse.smarthome.core.internal.common.AbstractInvocationHandler.invokeDirect(AbstractInvocationHandler.java:152) [bundleFile:?]
	at org.eclipse.smarthome.core.internal.common.InvocationHandlerSync.invoke(InvocationHandlerSync.java:59) [bundleFile:?]
	at com.sun.proxy.$Proxy14918.handleCommand(Unknown Source) [?:?]
	at org.eclipse.smarthome.core.thing.internal.profiles.ProfileCallbackImpl.handleCommand(ProfileCallbackImpl.java:74) [bundleFile:?]
	at org.eclipse.smarthome.core.thing.internal.profiles.SystemDefaultProfile.onCommandFromItem(SystemDefaultProfile.java:48) [bundleFile:?]
	at sun.reflect.GeneratedMethodAccessor328.invoke(Unknown Source) ~[?:?]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_232]
	at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_232]
	at org.eclipse.smarthome.core.internal.common.AbstractInvocationHandler.invokeDirect(AbstractInvocationHandler.java:152) [bundleFile:?]
	at org.eclipse.smarthome.core.internal.common.Invocation.call(Invocation.java:52) [bundleFile:?]
	at java.util.concurrent.FutureTask.run(FutureTask.java:266) [?:1.8.0_232]
	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149) [?:1.8.0_232]
	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624) [?:1.8.0_232]
	at java.lang.Thread.run(Thread.java:748) [?:1.8.0_232]

@duiffie Youā€™re correct! should be just true/false. Nice spot :). New PR build is already underway. Unfortunately my AC2889/10 does not have Child lock function :confused:

Check, thatā€™s fixed too. Still one warning in the log: about a channel type ā€˜philipsair:wickā€™ which could not be added/found. In channel-groups.xml (line 75) a channel with id ā€˜wickā€™ is added to group filters-wicks, but in channels.xml (line 120) the real channel id seems to be ā€˜wickstsā€™. That may be the causeā€¦

2019-12-13 14:54:37.701 [WARN ] [re.thing.internal.ThingFactoryHelper] - Could not create channel 'wick' for thing type 'philipsair:ac3829_10:xxxxxxxxxxxxxx', because channel type 'philipsair:wick' could not be found.

update: tried to fix it myself locally by editing channel-groups.xml and change channel id and typeId to ā€˜wickstsā€™, now the wick channel is visible in PaperUI and returns its status correctly.

Correct, indeed should be wickstsā€¦ and itā€™s rebuilding :slight_smile: Thanks!

Can you somehow start a new Jenkins build? Seems like #16361 failedā€¦

Hi @michalboronski. Firstly, thanks for your work :slight_smile: I have a PHILIPS AC2729/50 and I canā€™t bind with it. I decided to install https://github.com/rgerganov/py-air-control to check where is the problem. Probably I have a new firmware which use COAP protocol. Here are more informations https://github.com/rgerganov/py-air-control/issues/21. Someone prepared py-air-control 2.0.0 which experimentally uses COAP protocol. Does your binding can handle this protocol?

Hi @radek.budzik,
Indeed I wasnā€™t aware about new FW using COAP. Iā€™ll definitely take a look into this in order to provide support for COAP. Thanks for that info :slight_smile:

Thanks! If you need any help with testing I am at your disposal :wink:

It appears that switch to COAP that Philips has done recently might be problematic : https://github.com/rgerganov/py-air-control/issues/21#issuecomment-583476260
It might be that we need to find a way to get the encryption key.

Hi @michalboronski,
if you havenĀ“t noticed yet - the guys over at github reversed the encryption and can now communicate with the device! With their findings I managed to implement a proof-of-concept in java that can query status information from my AC3829/10 and send commands over encrypted coap. If youĀ“re interested, you can find that here.

Indeed, Iā€™ll definitely follow up this thread again. I also will take a look at your code asap and modify the binding.