So, it looks like something can be done. I was able to sniff the communication between the Dream Maker servers and the fan, as it is not encrypted (WTF?). To me it looks like the protocol is just JSON over a TCP socket. This is what my fan does after it connects to my local WiFi (if it has been provisioned through the Dream Maker app):
- Request IP over DHCP (obviously)
- DNS lookup for cloud1.dm-maker.com
- Contact cloud1.dm-maker.com at port 31270 over TCP
- After an initial handshake (which looks a bit weird to me: SYN, SYN-ACK, ACK, FIN-ACK, ACK, FIN-ACK, ACK) a persistent TCP connection is established between the fan and the server. Data is pushed around between the fan and the server using PSH packets. This how the communication starts (server pushes):
{"action":81,"resource_id":127,"version":"zeico_3.0.0","code":0}
The fan then sends the following data to the server:
{"action": 1,"resource_id":2001,"version":"zeico_3.0.0","code":0,"msg_id":0,"data":{"product_id":"XXXXXX","device_id":"XXXXX","device_key":"XXXXX","comm_version":"dmiot_v1.1.0","rf_version":"v3.1.6","mcu_version":"fan_0001"}}
So this looks like the authentication. Unfortunately I could not find how device_id
/device_key
relate to any settings in the Dream Maker app. For now this is not important anyway I think.
The fan periodically pushes updates to the server. This is pushed through the same TCP stream, so no reauthentication is required:
{"action": 1,"resource_id":127,"version":"zeico_3.0.0","data":{"comm_version":"dmiot_v1.1.0","rf_version":"v3.1.6","mcu_version":"fan_0001","signal":38}}
The server always replies with:
{"action":81,"resource_id":127,"version":"zeico_3.0.0","code":0}
The server also pushes data to the fan like this (when turning on through the app):
{"action":4,"resource_id":9031,"version":"zeico_3.0.0","data":{"source":"manual","power":1},"msg_id":47912}
And the fan replies:
{"action": 84, "version":"zeico_3.0.0","resource_id":9031,"msg_id":47912,"code":0,"data":{"source":"manual","deviceException":0,"useException":0,"power":1,"mode":0,"speed":1,"roll_enable":0,"roll_angle":90,"power_delay":0,"sound":1,"light":1,"child_lock":0,"temperature":25.0,"humidity":59.0,"ext1":97,"ext2":102,"ext3":24884,"ext4":25137,"ext5":943206968,"ext6":1630823777}}
So this looks like a rather simple protocol. The question is: does the protocol look familiar to anybody? Ideally we could reuse some existing implementation of it.
Rewriting a TCP server from scratch would definitely be doable, but it’s still quite a lot of work. Integrating that thing into Home Assistant is probably the least problem, once a little implementation for this exists. Maybe we could also go the MQTT way, which translates the JSON requests into MQTT topics and commands.
If somebody want’s to get started, just provision your fan through the official app and change the DNS record for cloud1.dm-maker.com
later to point to a local dev machine. Writing a little Python TCP server which listens on port 31270 and does the JSON magic is definitely possible.
Only once this is done it makes sense to look at the provisioning of the fan I think. As I said earlier this is done over BLE. From my observations it’s just writing to 4 different attributes using GATT (SSID at handle 0x002a, Wifi-Password at handle 0x002c, unknown 6 byte value at handle 0x002e and unknown 4 byte value at handle 0x0030).
I will be gone for a longer time as we are expecting a child very very soon. Does anybody accept the challenge?