Since recently Dyson broke the librepurecoollink lib that makes the Dyson component work in HomeAssistant I lost access to the Fan Control (This was not the first time).
I was reading that the fans actually do support completely local MQTT Support. So I finally changed my setup to migrate away from the Dyson Component, and to simply send the commands via MQTT. No Cloud access required anymore.
NOTE: This may only work if you have the older generation that has the following SSID and PW. (For Newer Generation that don’t have the sticker its apparently possible to sniff the password via wireshark)
Sticker:
Basically you simply connect to Fan on Port 1883 with the SSID as the Username, and the WiFi PW (hashed) as the Password.
To get the PW hash I found a tool somebody wrote that just transforms your PW. Its a python3 script so you can just execute it by running:
python3 pwd.py
Content of the script:
'''
Transfers the password from the sticker to the needed hash.
'''
import base64
import hashlib
# Ask for the password
pwd = input("Product WiFi Password (e.g.: adgjsfhk):")
# Transfer password to hash version
hash = hashlib.sha512()
hash.update(pwd.encode('utf-8'))
pwd_hash = base64.b64encode(hash.digest()).decode('utf-8')
# Print out password hash
print(pwd_hash)
On the Sticker there are several informations. Your Username, your Password as well as the Devicetype. In my case the device type is 475.
That means that my Dyson Fan will publish all updates on that MQTT Topic:
475/"YOUR SSID"/status/current
All Commands need to be sent to the following MQTT Topic:
475/"YOUR SSID"/command
The basic capabilities of the Dyson Fan are 4 commands and the corresponding MQTT command:
Power = fmod
Oscillation = oson
Speed = fnsp
Night Mode = nmod
I am actually simply using NodeRed to make it easy for myself. With the following function node I can simply set the values to my liking with:
msg.oson = Oscilation. Accepted Commands: ON / OFF
msg.speed = Speed. Accepted Commands: 0001 - 0010
msg.night = Night Mode. Accepted Commands: ON / OFF
msg.power = Power. Accepted Commands: FAN / OFF
var now = new Date();
// convert date to a string in UTC timezone format:
console.log(now.toUTCString());
var oson = msg.osc
var speed = msg.speed
var night = msg.night
var power = msg.power
msg.payload = {
"msg": "STATE-SET",
"time": now,
"data": {
"oson": oson,
"fnsp": speed,
"nmod": night,
"fmod": power
}
}
return msg;
I then created several helpers:
Input Boolean for: Power, Oscillation & Night Mode
Input Number for: Speed and Timer
The timer actually is completely separate from the Fan itself, I’m using my own logic that simply turns off the fan when the timer reaches zero.
I hope that this may help somebody who also doesn’t want to rely on the Dyson Cloud anymore to control the Fan via HA.
My complete NodeRed Logic:
[{"id":"762b3846.4a5a18","type":"server-state-changed","z":"f28a8271.df143","name":"Timer","version":1,"entityidfilter":"input_number.bedroom_fantime","entityidfiltertype":"exact","outputinitially":false,"state_type":"str","haltifstate":"0","halt_if_type":"num","halt_if_compare":"lte","outputs":2,"output_only_on_state_change":true,"x":90,"y":980,"wires":[[],["efed7a03.a97558"]]},{"id":"e39884b5.6590b8","type":"server-state-changed","z":"f28a8271.df143","name":"Abkühlen","version":"1","entityidfilter":"input_boolean.abkuhlenbr","entityidfiltertype":"exact","outputinitially":true,"state_type":"str","haltifstate":"","halt_if_type":"str","halt_if_compare":"is","outputs":1,"output_only_on_state_change":true,"x":100,"y":1200,"wires":[["f2777dde.3abb9"]]},{"id":"efed7a03.a97558","type":"function","z":"f28a8271.df143","name":"on/off?","func":"newmsg = {};\nif (msg.payload == \"1.0\")\n{\n newmsg.payload = \"True\";\n}else {\n newmsg.payload = \"STOP\";\n}\n\nreturn newmsg;","outputs":1,"noerr":0,"x":310,"y":980,"wires":[["29e2b309.8447dc"]]},{"id":"29e2b309.8447dc","type":"stoptimer","z":"f28a8271.df143","duration":"1","units":"Minute","payloadtype":"num","payloadval":"1","name":"","x":700,"y":980,"wires":[["3e6cc84d.89de78"],[]]},{"id":"f2777dde.3abb9","type":"switch","z":"f28a8271.df143","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"on","vt":"str"},{"t":"eq","v":"off","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":550,"y":1200,"wires":[["77da2a83.6a98f4","2f57fda5.d17702","d12ee5bd.6501d8"],["3980cc08.77ebd4"]]},{"id":"2260ddca.06d482","type":"comment","z":"f28a8271.df143","name":"Dyson Bedroom Control","info":"","x":140,"y":80,"wires":[]},{"id":"77da2a83.6a98f4","type":"api-call-service","z":"f28a8271.df143","name":"Fan oscillate","version":1,"debugenabled":false,"service_domain":"input_boolean","service":"turn_on","entityId":"input_boolean.bedroomfanoscillate","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":910,"y":1260,"wires":[[]]},{"id":"d12ee5bd.6501d8","type":"api-call-service","z":"f28a8271.df143","name":"Set Speed to 4","version":1,"debugenabled":false,"service_domain":"input_number","service":"set_value","entityId":"input_number.bedroom_fanspeed","data":"{\"value\":\"4\"}","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":920,"y":1200,"wires":[[]]},{"id":"2f57fda5.d17702","type":"api-call-service","z":"f28a8271.df143","name":"Fan Time to 30","version":1,"debugenabled":false,"service_domain":"input_number","service":"set_value","entityId":"input_number.bedroom_fantime","data":"{\"value\":\"30\"}","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":920,"y":1320,"wires":[[]]},{"id":"f397f3e0.7e85d","type":"server-state-changed","z":"f28a8271.df143","name":"Fantime On?","version":1,"entityidfilter":"input_number.bedroom_fantime","entityidfiltertype":"exact","outputinitially":true,"state_type":"str","haltifstate":"0","halt_if_type":"num","halt_if_compare":"lte","outputs":2,"output_only_on_state_change":false,"x":370,"y":1100,"wires":[[],["9e15b410.66c768"]]},{"id":"6a7eb16e.13243","type":"api-call-service","z":"f28a8271.df143","name":"Fan Time","version":1,"debugenabled":false,"service_domain":"input_number","service":"set_value","entityId":"input_number.bedroom_fantime","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":900,"y":1060,"wires":[[]]},{"id":"145ddf1c.554511","type":"function","z":"f28a8271.df143","name":"Fantime - 1","func":"newmsg = {}\n\nnewmsg.payload = { data: { \"value\":(msg.payload - 1)} }\n\nreturn newmsg;\n","outputs":1,"noerr":0,"x":710,"y":1060,"wires":[["6a7eb16e.13243"]]},{"id":"d7308d63.2c81","type":"status","z":"f28a8271.df143","name":"","scope":["f397f3e0.7e85d"],"x":100,"y":1060,"wires":[["267f5c0b.2ec884"]]},{"id":"267f5c0b.2ec884","type":"switch","z":"f28a8271.df143","name":"","property":"status.text","propertyType":"msg","rules":[{"t":"eq","v":"connected","vt":"str"}],"checkall":"true","repair":false,"outputs":1,"x":230,"y":1060,"wires":[["af3188bd.4d1168"]]},{"id":"af3188bd.4d1168","type":"api-current-state","z":"f28a8271.df143","name":"Fantime?","version":1,"outputs":2,"halt_if":"0","halt_if_type":"num","halt_if_compare":"lte","override_topic":false,"entity_id":"input_number.bedroom_fantime","state_type":"str","state_location":"payload","override_payload":"msg","entity_location":"data","override_data":"msg","blockInputOverrides":false,"x":360,"y":1060,"wires":[[],["9e15b410.66c768"]]},{"id":"9e15b410.66c768","type":"stoptimer","z":"f28a8271.df143","duration":"1","units":"Minute","payloadtype":"num","payloadval":"0","name":"1m","x":530,"y":1060,"wires":[["145ddf1c.554511"],[]]},{"id":"80f6bd2e.85a27","type":"comment","z":"f28a8271.df143","name":"DYSON MQTT CONTROL","info":"","x":110,"y":20,"wires":[]},{"id":"6387f72a.5aeb98","type":"mqtt in","z":"f28a8271.df143","name":"","topic":"475/SSID/status/current","qos":"0","datatype":"auto","broker":"fe653f5f.645af","x":190,"y":560,"wires":[["699d8320.029dfc"]]},{"id":"699d8320.029dfc","type":"json","z":"f28a8271.df143","name":"","property":"payload","action":"","pretty":false,"x":410,"y":560,"wires":[["9e416d29.17f6a","f0bcd3da.aa1b4","46b6f6ad.4972d8","e2f5f10d.6ebba"]]},{"id":"9e416d29.17f6a","type":"switch","z":"f28a8271.df143","name":"","property":"payload[\"product-state\"].oson[1]","propertyType":"msg","rules":[{"t":"eq","v":"ON","vt":"str"},{"t":"eq","v":"OFF","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":550,"y":560,"wires":[["dc3b54e2.493f18"],["a33680f4.1e898"]]},{"id":"f0bcd3da.aa1b4","type":"switch","z":"f28a8271.df143","name":"","property":"payload[\"product-state\"].fmod[1]","propertyType":"msg","rules":[{"t":"eq","v":"FAN","vt":"str"},{"t":"eq","v":"OFF","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":550,"y":680,"wires":[["7e481cda.2d9ac4"],["11628f40.1aac21","7e822617.0d6b78"]]},{"id":"7e481cda.2d9ac4","type":"api-call-service","z":"f28a8271.df143","name":"Schlafzimmer On","version":1,"debugenabled":false,"service_domain":"input_boolean","service":"turn_on","entityId":"input_boolean.schlafzimmer","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":930,"y":680,"wires":[[]]},{"id":"11628f40.1aac21","type":"api-call-service","z":"f28a8271.df143","name":"Schlafzimmer Off","version":1,"debugenabled":false,"service_domain":"input_boolean","service":"turn_off","entityId":"input_boolean.schlafzimmer","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":930,"y":740,"wires":[[]]},{"id":"41115e5d.36e2f","type":"server-state-changed","z":"f28a8271.df143","name":"Bedroom Nightmode","version":1,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"input_boolean.bedroomfannightmode","entityidfiltertype":"exact","outputinitially":false,"state_type":"str","haltifstate":"","halt_if_type":"str","halt_if_compare":"is","outputs":1,"output_only_on_state_change":true,"x":130,"y":420,"wires":[["f5bcfd4b.a84b"]]},{"id":"f5bcfd4b.a84b","type":"switch","z":"f28a8271.df143","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"on","vt":"str"},{"t":"eq","v":"off","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":310,"y":420,"wires":[["442547e1.cd57e8"],["54dbadcb.2fc3c4"]]},{"id":"442547e1.cd57e8","type":"change","z":"f28a8271.df143","name":"","rules":[{"t":"set","p":"night","pt":"msg","to":"ON","tot":"str"},{"t":"delete","p":"payload","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":460,"y":420,"wires":[["b53e2452.55fdc8"]]},{"id":"54dbadcb.2fc3c4","type":"change","z":"f28a8271.df143","name":"","rules":[{"t":"set","p":"night","pt":"msg","to":"OFF","tot":"str"},{"t":"delete","p":"payload","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":460,"y":460,"wires":[["b53e2452.55fdc8"]]},{"id":"46b6f6ad.4972d8","type":"switch","z":"f28a8271.df143","name":"","property":"payload[\"product-state\"].nmod[1]","propertyType":"msg","rules":[{"t":"eq","v":"ON","vt":"str"},{"t":"eq","v":"OFF","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":550,"y":800,"wires":[["395f4f71.cbea8"],["dba49e22.00dc2"]]},{"id":"e2f5f10d.6ebba","type":"function","z":"f28a8271.df143","name":"Speed","func":"newmsg = {}\n\nnewmsg.speed = (parseFloat(msg.payload[\"product-state\"].fnsp[1]).toFixed(0))\n\nnewmsg.payload = { data: { \"value\":newmsg.speed} }\n\n\nreturn newmsg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":550,"y":920,"wires":[["345b51ae.0d880e"]]},{"id":"fbaae508.968878","type":"server-state-changed","z":"f28a8271.df143","name":"Power FAN","version":1,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"input_boolean.schlafzimmer","entityidfiltertype":"exact","outputinitially":false,"state_type":"str","haltifstate":"","halt_if_type":"str","halt_if_compare":"is","outputs":1,"output_only_on_state_change":true,"x":110,"y":120,"wires":[["3e9f97f9.86fa38"]]},{"id":"3e9f97f9.86fa38","type":"switch","z":"f28a8271.df143","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"on","vt":"str"},{"t":"eq","v":"off","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":310,"y":120,"wires":[["8ca14117.45739"],["47f415ec.4d405c"]]},{"id":"8ca14117.45739","type":"change","z":"f28a8271.df143","name":"","rules":[{"t":"set","p":"power","pt":"msg","to":"FAN","tot":"str"},{"t":"delete","p":"payload","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":460,"y":120,"wires":[["b53e2452.55fdc8"]]},{"id":"47f415ec.4d405c","type":"change","z":"f28a8271.df143","name":"","rules":[{"t":"set","p":"power","pt":"msg","to":"OFF","tot":"str"},{"t":"delete","p":"payload","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":460,"y":160,"wires":[["b53e2452.55fdc8"]]},{"id":"d8f57227.67915","type":"switch","z":"f28a8271.df143","name":"","property":"payload","propertyType":"msg","rules":[{"t":"eq","v":"on","vt":"str"},{"t":"eq","v":"off","vt":"str"}],"checkall":"true","repair":false,"outputs":2,"x":310,"y":240,"wires":[["639681f9.cbbc8"],["5eec97e.14df468"]]},{"id":"639681f9.cbbc8","type":"change","z":"f28a8271.df143","name":"","rules":[{"t":"set","p":"osc","pt":"msg","to":"ON","tot":"str"},{"t":"delete","p":"payload","pt":"msg"},{"t":"set","p":"power","pt":"msg","to":"FAN","tot":"str"}],"action":"","property":"","from":"","to":"","reg":false,"x":470,"y":240,"wires":[["b53e2452.55fdc8"]]},{"id":"5eec97e.14df468","type":"change","z":"f28a8271.df143","name":"","rules":[{"t":"set","p":"osc","pt":"msg","to":"OFF","tot":"str"},{"t":"delete","p":"payload","pt":"msg"}],"action":"","property":"","from":"","to":"","reg":false,"x":470,"y":280,"wires":[["b53e2452.55fdc8"]]},{"id":"47e44243.f08fac","type":"server-state-changed","z":"f28a8271.df143","name":"Bedroom Oscillate","version":1,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"input_boolean.bedroomfanoscillate","entityidfiltertype":"exact","outputinitially":false,"state_type":"str","haltifstate":"","halt_if_type":"str","halt_if_compare":"is","outputs":1,"output_only_on_state_change":true,"x":130,"y":240,"wires":[["d8f57227.67915"]]},{"id":"5aaf7631.f108b8","type":"server-state-changed","z":"f28a8271.df143","name":"Bedroom Speed","version":1,"exposeToHomeAssistant":false,"haConfig":[{"property":"name","value":""},{"property":"icon","value":""}],"entityidfilter":"input_number.bedroom_fanspeed","entityidfiltertype":"exact","outputinitially":false,"state_type":"str","haltifstate":"","halt_if_type":"str","halt_if_compare":"is","outputs":1,"output_only_on_state_change":true,"x":120,"y":340,"wires":[["e9f37c0c.2f956"]]},{"id":"c69481b7.f8e26","type":"function","z":"f28a8271.df143","name":"Speed","func":"newmsg = {}\n\nnewmsg.speed = (parseFloat(msg.payload).toFixed(0)).toString().padStart(4,\"0\")\n\nreturn newmsg;\n","outputs":1,"noerr":0,"initialize":"","finalize":"","x":500,"y":340,"wires":[["b53e2452.55fdc8"]]},{"id":"b53e2452.55fdc8","type":"function","z":"f28a8271.df143","name":"","func":"var now = new Date();\n// convert date to a string in UTC timezone format:\nconsole.log(now.toUTCString());\n\nvar oson = msg.osc\nvar speed = msg.speed\nvar night = msg.night\nvar power = msg.power\n\nmsg.payload = {\n \"msg\": \"STATE-SET\",\n \"time\": now,\n \"data\": {\n \"oson\": oson,\n \"fnsp\": speed,\n \"nmod\": night,\n \"fmod\": power\n }\n}\n\n\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","x":680,"y":120,"wires":[["c9d7b975.307318"]]},{"id":"c9d7b975.307318","type":"mqtt out","z":"f28a8271.df143","name":"","topic":"475/SSID/command","qos":"","retain":"","broker":"fe653f5f.645af","x":920,"y":120,"wires":[]},{"id":"dc3b54e2.493f18","type":"api-call-service","z":"f28a8271.df143","name":"Bedroom Oscillate","version":1,"service_domain":"input_boolean","service":"turn_on","entityId":"input_boolean.bedroomfanoscillate","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":930,"y":560,"wires":[[]]},{"id":"a33680f4.1e898","type":"api-call-service","z":"f28a8271.df143","name":"Bedroom Oscillate Off","version":"1","service_domain":"input_boolean","service":"turn_off","entityId":"input_boolean.bedroomfanoscillate","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":940,"y":620,"wires":[[]]},{"id":"395f4f71.cbea8","type":"api-call-service","z":"f28a8271.df143","name":"Bedroom Night Mode","version":"1","service_domain":"input_boolean","service":"turn_on","entityId":"input_boolean.bedroomfannightmode","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":940,"y":800,"wires":[[]]},{"id":"dba49e22.00dc2","type":"api-call-service","z":"f28a8271.df143","name":"Bedroom Night Mode Off","version":"1","service_domain":"input_boolean","service":"turn_off","entityId":"input_boolean.bedroomfannightmode","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":950,"y":860,"wires":[[]]},{"id":"345b51ae.0d880e","type":"api-call-service","z":"f28a8271.df143","name":"Bedroom Speed","version":1,"service_domain":"input_number","service":"set_value","entityId":"input_number.bedroom_fanspeed","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":920,"y":920,"wires":[[]]},{"id":"e9f37c0c.2f956","type":"delay","z":"f28a8271.df143","name":"1msg/s","pauseType":"rate","timeout":"5","timeoutUnits":"seconds","rate":"1","nbRateUnits":"1","rateUnits":"second","randomFirst":"1","randomLast":"5","randomUnits":"seconds","drop":true,"x":320,"y":340,"wires":[["c69481b7.f8e26"]]},{"id":"3e6cc84d.89de78","type":"api-call-service","z":"f28a8271.df143","name":"Schlafzimmer Off","version":1,"debugenabled":false,"service_domain":"input_boolean","service":"turn_off","entityId":"input_boolean.schlafzimmer","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":930,"y":980,"wires":[[]]},{"id":"3980cc08.77ebd4","type":"api-call-service","z":"f28a8271.df143","name":"Schlafzimmer Off","version":1,"debugenabled":false,"service_domain":"input_boolean","service":"turn_off","entityId":"input_boolean.schlafzimmer","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":930,"y":1380,"wires":[[]]},{"id":"7e822617.0d6b78","type":"api-call-service","z":"f28a8271.df143","name":"Abkühlen Off","version":1,"service_domain":"input_boolean","service":"turn_off","entityId":"input_boolean.abkuhlenbr","data":"","dataType":"json","mergecontext":"","output_location":"","output_location_type":"none","mustacheAltTags":false,"x":1130,"y":740,"wires":[[]]},{"id":"5fdfd70d.322428","type":"comment","z":"f28a8271.df143","name":"Dyson Bedroom Status","info":"","x":140,"y":520,"wires":[]},{"id":"979f3486.2acd28","type":"comment","z":"f28a8271.df143","name":"Dyson Bedroom Timer","info":"","x":140,"y":940,"wires":[]},{"id":"c8522ae.9b038d8","type":"comment","z":"f28a8271.df143","name":"Quick Scene ","info":"","x":110,"y":1160,"wires":[]},{"id":"fe653f5f.645af","type":"mqtt-broker","z":"","name":"Dyson Schlafzimmer","broker":"192.168.10.35","port":"1883","clientid":"","usetls":false,"compatmode":false,"keepalive":"60","cleansession":true,"birthTopic":"","birthQos":"0","birthPayload":"","closeTopic":"","closeQos":"0","closePayload":"","willTopic":"","willQos":"0","willPayload":""}]