[PRE-RELEASE] Unofficial Dyson Air Treatment drivers (local only)

Unofficial Dyson Air Treatment drivers

I took a cut at creating a HE driver for my Dyson Pure Hot/Cool Link and went on to take some guesses at how to possibly support additional models. The result is 3 Dyson Air Treatment Drivers; however, I have only tested one of the drivers and with only a single device. Code supporting other devices were based on my interpretation of code, postings, and discussion from others. So...It may not work. There may be problems.

These drivers are local network only. As currently implemented, they will not go online to Dyson to look up the connection information. You will need to enter it yourself.

That said, hopefully even with problems it may be helpful. Feel free to create a PR and contribute to making it better.

The drivers are as follows:

Unofficial Dyson Pure Hot Cool Link driver: dyson-pure-hotcool-link-driver.groovy

This driver is intended to work with Dyson Pure Cool Link/Dyson Pure Cool Link Desk/Dyson Pure Hot Cool Link. However, I have only tested it with the latter, an HP02 (455) unit.

Devices this driver tries to support (the number corresponds to the last part of the number at the end of the Device's WiFi SSID sticker):

  • PURE COOL LINK "475"
  • PURE COOL LINK DESK "469"
  • PURE HOT COOL LINK "455" or "455A"

Unofficial Dyson Pure Hot Cool driver: dyson-pure-hotcool-driver.groovy

This driver is intended to work with Dyson Pure Cool/Dyson Pure Cool Desk/Dyson Pure Cool Formaldehyde/Dyson Pure Hot Cool. I do not own or have access to any of these units. I do not know if this code will work.

Devices this driver tries to support (the number corresponds to the last part of the number at the end of the Device's WiFi SSID sticker):

  • PURE COOL "438"
  • PURE COOL FORMALDEHYDE "438E"
  • PURE COOL DESK "520"
  • PURE HOT COOL "527" or "527E"

Unofficial Dyson Pure Humidify Cool driver: dyson-pure-humidify-driver.groovy

This driver is intended to work with Dyson Pure Humidify Cool. I do not own or have access to this type of unit. I do not know if this code will work.

Devices this driver tries to support (the number corresponds to the last part of the number at the end of the Device's WiFi SSID sticker):

  • PURE HUMIDIFY COOL "358"

Instructions:

  • Login to your Hubitat and go to Advanced -> Drivers Code
  • Choose new driver to add this driver
  • Go to Devices -> Add Virtual Device - give it a name and select this driver
  • Save and configure the device. You will need to enter the Unit's WiFi SSID (not your home network), WiFi Password (not your home network), and IP address.
  1. Where do I find the unit's WiFi SSID? On the sticker, either on the outside of the unit or perhaps on the body of the unit under the filter or maybe with the documentation. (this is not your home's SSID)
  2. Where do I find the unit's WiFi Password? On the sticker, either on the outside of the unit or perhaps on the body of the unit under the filter or maybe with the documentation. (this is not your home's Wifi WPA password) (If you don't have a sticker see this post)
  3. Where do I find the unit's IP address? (look it up on your home's wifi router)
  4. My model looks like HP02 or something else, not a 3 digit number...? See the last 3 (or 4) digits of the WiFi SSID sticker. On the image below its the "455".
  5. What does the sticker looks like?
    Screen Shot 2021-11-01
    (If you don't have a sticker see this post)

To use this with Rule Machine, it will present itself as a Fan and Thermostat; however, there is more functionality available through driver specific commands. These are accessible in Rule Machine via Run Custom Action -> Actuator. Then any custom command can be selected. If the selected custom command takes a parameter on the drivers page, the same parameter value can be specified here. Note: specify "string" - all custom commands for this driver assume the data entered are strings.

A note regarding "polling" - Polling should not be necessary for normal operation. Even if disconnected, if you send a command, the driver will reconnect and maintain a persistent MQTT connection and subscribe/receive data events. However, if you are capturing data points, graphing, etc. and reboot or otherwise lose the MQTT connection, polling is an option to cause an automatic reconnect.

Thank You to:

@g.shepperd for helping to test
Home Assistant had a head start.
@AlmostSerious Marcus Peters
https://community.home-assistant.io/t/dyson-pure-cool-link-local-mqtt-control/217263
@shenex Xiaonan Shen
https://github.com/shenxn/libdyson for ideas and know how

7 Likes

I own the 455 unit, your driver works like a charm with it, great job, thank you! :slightly_smiling_face:

1 Like

Nice! works with my HP03 unit but can't seem to figure out how to get the password and SSID for my other HP04 unit. Not sure if it ever had the SSID sticker

@bendarklighter - re:HP04 or units w/out a sticker- not sure you will like this answer, but I read here, that "For Newer Generation that don’t have the sticker its apparently possible to sniff the password via wireshark"

some additional details: the ssid and password used for the connection are technically retrievable from Dyson online; however, Dyson modified their online service to a multi-factor style flow. It looks possible to implement but would take some work.

1 Like

Good morning,

I just noticed I'm getting a lot of log entries. I do have it set to poll every minute. Is that the recommendation? Anyway, they are debug messages and I don't see a way to turn off debugging.

dev:44822021-11-27 04:39:02.246 debugDYSON Received an environmental message
dev:44822021-11-27 04:39:02.134 debugDYSON Received an environmental message
dev:44822021-11-27 04:39:02.034 debugDYSON Received a current state message
dev:44822021-11-27 04:38:02.242 debugDYSON Received an environmental message
dev:44822021-11-27 04:38:02.142 debugDYSON Received an environmental message
dev:44822021-11-27 04:38:02.033 debugDYSON Received a current state message
dev:44822021-11-27 04:37:02.241 debugDYSON Received an environmental message
dev:44822021-11-27 04:37:02.135 debugDYSON Received an environmental message
dev:44822021-11-27 04:37:02.036 debugDYSON Received a current state message
dev:44822021-11-27 04:36:02.145 debugDYSON Received an environmental message
dev:44822021-11-27 04:36:02.028 debugDYSON Received an environmental message
dev:44822021-11-27 04:36:01.932 debugDYSON Received a current state message
dev:44822021-11-27 04:35:02.164 debugDYSON Received an environmental message
dev:44822021-11-27 04:35:02.025 debugDYSON Received an environmental message
dev:44822021-11-27 04:35:01.928 debugDYSON Received a current state message
dev:44822021-11-27 04:34:02.136 debugDYSON Received an environmental message
dev:44822021-11-27 04:34:02.034 debugDYSON Received an environmental message
dev:44822021-11-27 04:34:01.924 debugDYSON Received a current state message
dev:44822021-11-27 04:33:02.120 debugDYSON Received an environmental message
dev:44822021-11-27 04:33:02.034 debugDYSON Received an environmental message
dev:44822021-11-27 04:33:01.954 debugDYSON Received a current state message

@pdupper See the note in the original post regarding "polling"
essentially: no need to poll so frequently (or perhaps even at all). Dyson will send events when data changes. The only real advantage to polling is if something causes the connection from HE to the Dyson to disconnect, e.g. power cycle/reboot hubitat or unplug/replug the dyson itself, the poll will cause hubitat to reconnect automatically. Otherwise, there really isn't a need for the polling and Hubitat will reconnect on the next operation issued to control the Dyson.

Ok, thank you!

Is any of the drivers work with the new Dyson TP07 Cool Purifying Tower Fan (Wifi)?

@taysnet sort of.. the " Unofficial Dyson Pure Hot Cool driver" here should work with it (not sure if the device id would need to be added), but I'm guessing the real challenge is there is no sticker with the information necessary for local configuration. For newer models, that info is available, but complicated to retrieve from Dyson's cloud servers because Dyson now requires a multi-factor authentication (username/password/emailOTP). If that is your limitation, it should be possible to implement as it looks like home-assistant did it in python, but right now, I just don't have the time to do it myself for hubitat.

@dpasirst

Thank you for creating this drivers! I have a couple of HP02 and one HP07. I was very disappointed when I purchased the HP07 and discovered that setting heat through the Dyson App was not supported due to UL standard (ul1278)

The Dyson Pure Hot Cool Link driver works perfectly with my HP02 devices OOB.

For the HP07 I just needed to do some very minor adjustments to the Dyson Pure Hot Cool driver to enable full support in Hubitat (i.e. controlling heating etc)

  1. SSID and Credential - I obtained the HP07 SSID and Credentials using the get_devices.py script in https://github.com/shenxn/libdyson that you mentioned above.
    For connecting to they HP07 I then put the Credential in the Unit Password field and changed the script to utilize the UNIT_PASSWD directly instead of hashing the password to get the credential.

  2. Modify client id. - After connecting to the HP07, the next issue was that of an invalid client id, as the UUID method state.clientId = UUID.randomUUID().toString(). which works with the HP02 in Dyson Pure Hot Cool Link driver. To address this I implemented similar code as in the client.py in paho-mqtt · PyPI . I'm assuming that the needed change is because the HP07 is using MQTT3.1? Here's the code from the python client

    # [MQTT-3.1.3-4] Client Id must be UTF-8 encoded string.
     if client_id == "" or client_id is None:
         if protocol == MQTTv31:
             self._client_id = base62(uuid.uuid4().int, padding=22)
    

In the driver I then inserted a base62 method to create the client id, which I took from here and made some slight modifications.

def static BASE62() {(('a'..'z')+('A'..'Z')+('0'..'9')).join()}

def base62encode(value) {

    def base10 = new BigInteger(value)
    def digitMax = BASE62().size().toInteger()

    def tiny = new StringBuilder()

    while (base10 != 0) {
        def digit = base10.mod(digitMax)
        base10 = base10.divide(digitMax)
        tiny << BASE62()[digit]
    }

    tiny = tiny.reverse()
}

I then changed setting the client_id to:

   def lUUID = String.format("%040d", new BigInteger(UUID.randomUUID().toString().replace("-", ""), 16))
   state.clientId = base62encode(lUUID as String)
  1. The last issue was with carbonFilterLifePct which was returning a value of 'INV'. I did the below hack which may cause issues checking if the filter needs to be replaced?

    if (device.currentValue("carbonFilterLifePct")== "INV") {
         def cfl = 1
    }
    else {
         def cfl = device.currentValue("carbonFilterLifePct")?.toString()?.toInteger()
    }
    

Thank you once again for putting these drivers together!

1 Like

@mbutler01 great job! Awesome in figuring that out! I don't have access to anything other than an HP02 so everything else was best guess. I did not know about the HP07 app heat limitation, I too would be very disappointed to discover that. It looks like you have some important enhancements. Is there any chance you would like to contribute a pull request with those enhancements so they can easily be available/included for others?

@dpasirst

Thank you for your kind words! I would be more than honored to do the pull request and add in my minor changes! I'll most likely be able to get to it this weekend.

@mbutler01 - I have been really tied up with other things, but I found some time to read up more on this topic. The solution may actually be much easier.

MQTT 3.1 seems to want the following:

  1. The ClientID MUST be a UTF-8 Encoded String.
  2. The Server MUST allow ClientID’s which are between 1 and 23 UTF-8 encoded bytes in length, and that contain only the characters "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".
  3. The Server MAY allow ClientID’s that contain more than 23 encoded bytes. The Server MAY allow ClientID’s that contain characters not included in the list given above.

okay - so I believe we are UTF-8.
The base62 that you have shared aligns to the string above - but UUIDs are hexadecimal which is base62 PLUS a "-". so just removing the "-" would make it base62, without needing the base62 encode.

However, I suspect the problem is with the 2 "MAY" parts which you have pointed out that newer Dysons seem to have decided to not support optional characters like a "-". It may also be limited in the length as it's optional to support more than 23 bytes.

Anyway, I suspect the fix can probably be done much easier - just a one line modification. Perhaps change this line from:
state.clientId = UUID.randomUUID().toString()
to
state.clientId = UUID.randomUUID().toString().tokenize('-').last()

Any chance you would be willing to test that and confirm? (one minor thing, the state variable may need to be reset for the test. so in connectToUnit(), you may need to comment out the if line: if (state.clientId == null) { just for the test...

I'm super excited to see about this integration! I tried it out on my 3 Dyson fans (1 HP02 - 455, 2 TP02 - 475). I can get the virtual devices up and going, it seems like they're connecting, but it's not initializing/updating current states/communicating with the fans. See below for logs... Thoughts on what's going on/what I should try to get this up and running?

Hi @nathaniel.knautz - you may be running into the issue mentioned in the two posts above your post. I have not had a chance to integrate the changes and test from the post directly above your post but I hope to get to it soon.

So I'm looking at buying my first dyson fan. Model I'm looking at is the tp04. Can't see reference to it on here, so assuming heading into store and seeing if the display model has the wifi Ssid sticker. If it had that then should work. If it doesn't, then likely a bit of effort for a hobbiest?

Ok so I bought the tp04... Sorta blind folded. Was hoping as it isn't the tp07 it had the wifi Ssid sticker.. Seems I only have a mac address hmm. So seems it's some effort than hoped to get it working with hubitat. I can use the schedules in the app but maybe I'll get the temptation to include things like if the light goes off and it's after 8pm in the bedroom to turn night mode on etc.

posted updated drivers changes as follows:

  1. MQTT fixes per posts above. Also included a mechanism to apply the id change to older units
  2. various .toInteger fixes

As before, I only have an HP02 to test with...

Hi @peterbrown77.pb - for now, it's a bit complicated. Without the sticker, we would have to implement the multi-factor authentication mechanism used by Dyson to obtain the details from the Dyson servers. It's not impossible but would take some time to implement. I hoped to eventually do it, but finding and dedicating the time has just not been possible.

1 Like

I searched high and low but unfortunately couldn't see the sticker still. Even scavenged the bin to make sure it wasn't in the manual.. I guess if there's a mac address sticker with no other deails it's unlikely I have just overlooked it. I get there's life outside Hubitat development :wink: