Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lack of callback mechanism in gateway makes cube and buttons integration impossible #699

Open
bskaplou opened this issue May 20, 2020 · 37 comments

Comments

@bskaplou
Copy link
Contributor

I'm trying to make xiaomi cube and xiaomi square button work.
Pub/Sub mechanism is necessary to make these devices work properly
While investigating the way to implement it I've found no subscription mechanism in python-miio ;(

I've also looked at nodejs miio implementation and found it uses developer-api https://github.com/aholstenson/miio/blob/master/lib/devices/gateway/developer-api.js
instead of miio protocol for event subscription. Which is akward and doesn't help to avoid soldering of gateway...

I've sniffed traffic between Mi Home app and gateway and found what when I create Mi Home automation involving cube as source and other wi-fi device in local network as destination Mi Home app sends to gateway a script as follows:

-> 192.168.2.17 data= {"id":2666,"method":"send_data_frame","params":{"cur":0,"data":"[[\"x.scene.2732711973\",[\"1.0\",1589956238,[\"0\",{\"src\":\"device\",\"key\":\"event.lumi.sensor_cube.v1.move\",\"did\":\"lumi.158d000103ec74\",\"model\":\"lumi.sensor_cube.v1\",\"token\":\"\",\"extra\":\"[1,18,2,85,[6,256],0,0]\",\"timespan\":[\"0 0 * * 0,1,2,3,4,5,6\",\"0 0 * * 0,1,2,3,4,5,6\"]}],[{\"id\":0,\"did\":\"120009025\",\"token\":\"XXXX\",\"ip\":\"192.168.2.94\",\"command\":\"chuangmi.plug.v3.set_usb_on\",\"value\":\"\",\"model\":\"chuangmi.plug.v3\",\"extra\":\"\"}]]]]","data_tkn":46567,"total":1,"type":"scene"}}

This message even includes token of destination device :) It makes possible extraction of any token if you know gateway token...

Anyway, my idea here is implement subscription as follows:

  1. Send send_data_frame to gateway with destination ip address of python-miio host
  2. Bind 54321/udp on python-miio host and listen for incoming messages from gateway
  3. Decrypt/unpack message for further processing

I'm new at miio hacking.... Can you tell me if you already tried this way of subscription or have some other way to implement pub/sub?

@syssi
Copy link
Collaborator

syssi commented May 20, 2020

Sounds good! Let's give it a try! A capture of incoming events/messages would be helpful, too.

@rytilahti
Copy link
Owner

If I'm understanding it correctly, the idea would be basically to create a listener that acts like a miio device to the gateway? I don't think anyone has explored that possibility so far, but it is probably also a lot of work to pull this off. If you want to give it a go, feel free to do so :-)

I have the cube myself, too, but instead of using the gateway, I'm using zigbee2mqtt which makes it all very simple.

@starkillerOG
Copy link
Contributor

Everyone is aware that there is already an official HomeAssistant integration specifically for the xiaomi aqara gateway that uses the UDP protocol using pushes (instant updates of sub devices including the cube)
https://www.home-assistant.io/integrations/xiaomi_aqara/
That integration uses the UDP protocol specific to the gateway. However that protocol does not support all possibilities of the gateway as far as I am aware of.
For instance the Alarm feature of the gateway is not supported by the UDP protocol and is supported by the miio protocol. That was the initial reason I started to work on the Miio implementation of the gateway

@starkillerOG
Copy link
Contributor

If I understand correctly that this is a different protecol/way to subscribe to events that would be awesome and worth exploring.
I am wondering if this would allow to subscribe to more events/propertie changes than when using the UDP developer API (https://github.com/Danielhiversen/PyXiaomiGateway)

@bskaplou
Copy link
Contributor Author

@starkillerOG
Currently I use xiaomi_aqara and it works, but:

With xiaomi_miio for some gateway features and xiaomi_aqara for other we'll get two gateways in system, this will work but looks awkward and definitely not commodity solution ...

Then I found fresh gateway support in xiaomi_miio component of hass I decided that xiomi_miio gateway should replace xiaomi_aqara and I'm trying to help with this move :)

@rytilahti Ok good. I'll try to implement this approach

@starkillerOG
Copy link
Contributor

Sounds good, very excited to test this new subscription method if you have some initial code working!

@bskaplou
Copy link
Contributor Author

bskaplou commented May 23, 2020

@starkillerOG @rytilahti
It works :)
you can look at code here
https://github.com/bskaplou/python-miio/tree/fake_device

fake_device.py is implementation of miio server which:

  1. responds to miio HELO which are sent by gateway to make sure device is online
  2. responds to action messages from gateway to avoid resends

How to run:

  1. Run python3 fake_device.py on one terminal
  2. Put your cube model and sid into miio/gateway_scripts.py
  3. Install scripts into gateway with commands
miiocli gateway --ip 192.168.2.109 --token XXX install_cube_rotate_script your_cube_lumi_sid
miiocli gateway --ip 192.168.2.109 --token XXX install_cube_move_script your_cube_lumi_sid
  1. Look for pings sent by gateway in fake_device.py stdout
  2. Move and rotate xiaomi cube
  3. Look at fake_device.py stdout to make sure gateway's callbacks are received
  4. Uninstall gateway scripts
miiocli gateway --ip 192.168.2.109 --token XXX x_del x.scene.2732711973
miiocli gateway --ip 192.168.2.109 --token XXX x_del x.scene.2732711975

Output of fake_device.py looks as follows:

192.168.2.109:54321=>PING
192.168.2.109:54321<=ACK(device_id=120009025)
192.168.2.109:54321=>{'method': 'move', 'params': [], 'from': 'nbl.134550490', 'id': 619969141}
192.168.2.109:54321<={'result': 0, 'id': 619969141}
192.168.2.109:54321=>PING
192.168.2.109:54321<=ACK(device_id=120009025)
192.168.2.109:54321=>PING
192.168.2.109:54321<=ACK(device_id=120009025)
192.168.2.109:54321=>PING
192.168.2.109:54321<=ACK(device_id=120009025)
192.168.2.109:54321=>PING
192.168.2.109:54321<=ACK(device_id=120009025)
192.168.2.109:54321=>{'method': 'rotate', 'params': [-39, 500], 'from': 'nbl.134550490', 'id': 620237685}
192.168.2.109:54321<={'result': 0, 'id': 620237685}
192.168.2.109:54321=>{'method': 'rotate', 'params': [32, 380], 'from': 'nbl.134550490', 'id': 620238918}
192.168.2.109:54321<={'result': 0, 'id': 620238918}
192.168.2.109:54321=>{'method': 'move', 'params': [], 'from': 'nbl.134550490', 'id': 620240647}
192.168.2.109:54321<={'result': 0, 'id': 620240647}
192.168.2.109:54321=>PING
192.168.2.109:54321<=ACK(device_id=120009025)

Here we can see:

  1. Pings sent by gateway after script installation
  2. Callbacks sent by gateway on cube interaction
  3. Gateway stops to send PING after script uninstallation

@bskaplou
Copy link
Contributor Author

But there are problems ....
script:

{"id":4994,"method":"send_data_frame","params":{"cur":0,"data":"[[\"x.scene.2732711973\",[\"1.0\",1590158978,[\"0\",{\"src\":\"device\",\"key\":\"event.lumi.sensor_cube.v1.move\",\"did\":\"lumi.158d000103ec74\",\"model\":\"lumi.sensor_cube.v1\",\"token\":\"\",\"extra\":\"[1,18,2,85,[6,256],0,0]\",\"timespan\":[\"0 0 * * 0,1,2,3,4,5,6\",\"0 0 * * 0,1,2,3,4,5,6\"]}],[{\"id\":0,\"did\":\"120009025\",\"token\":\"79cf21b08fb051499389f23c113477a4\",\"ip\":\"192.168.2.94\",\"command\":\"chuangmi.plug.v3.set_usb_on\",\"value\":\"\",\"model\":\"chuangmi.plug.v3\",\"extra\":\"\"}]]]]","data_tkn":45293,"total":1,"type":"scene"}}

this script contains token 79cf21b08fb051499389f23c113477a4, but this token differs from real device token which is 9bc7c7ce6291d3e443fd7708608b9892.

I use token 9bc7c7ce6291d3e443fd7708608b9892 in fake_server for decryption and 79cf21b08fb051499389f23c113477a4 in script ...
Method of creation of script token from device token is required ...
Maybe data_tkn somehow used to create script token ...

Any ideas are more then welcome :)

@rytilahti
Copy link
Owner

That's pretty cool! 💯 I'm wondering if the system supports wildcards for events? I'm thinking about something like "subscribe all events on all devices" which could allow generic event support?

Unfortunately I don't have ideas on that token issue, nor really any time to help with these efforts.. You may want to have a take a look at dustcloud (or at least the dummycloud impl https://github.com/dgiese/dustcloud/tree/master/dummycloud) if there's something relevant.

@bskaplou
Copy link
Contributor Author

@rytilahti
Right now callback receives source_device/action/params
But I use method_name to pass source device to callback (the only way I found to identify source of event). So it will willingly process any callback but name should be encoded as f"{action}_{device_sid}"

INFO:__main__:fake miio device started with  address=0.0.0.0 device_id=120009025 callback=<function callback at 0x10dbf9378> token=****
DEBUG:__main__:192.168.2.109:54321=>PING
DEBUG:__main__:192.168.2.109:54321<=ACK(device_id=120009025)
DEBUG:__main__:192.168.2.109:54321=>{'method': 'move_158d000103ec74', 'params': [], 'from': 'nbl.134550490', 'id': 655700828}
DEBUG:__main__:CALLBACK lumi.158d000103ec74=>move([])
DEBUG:__main__:192.168.2.109:54321<={'result': 0, 'id': 655700828}
DEBUG:__main__:192.168.2.109:54321=>PING
DEBUG:__main__:192.168.2.109:54321<=ACK(device_id=120009025)
DEBUG:__main__:192.168.2.109:54321=>{'method': 'rotate_158d000103ec74', 'params': [23, 500], 'from': 'nbl.134550490', 'id': 655702095}
DEBUG:__main__:CALLBACK lumi.158d000103ec74=>rotate([23, 500])
DEBUG:__main__:192.168.2.109:54321<={'result': 0, 'id': 655702095}
DEBUG:__main__:192.168.2.109:54321=>{'method': 'rotate_158d000103ec74', 'params': [13, 460], 'from': 'nbl.134550490', 'id': 655702575}
DEBUG:__main__:CALLBACK lumi.158d000103ec74=>rotate([13, 460])
DEBUG:__main__:192.168.2.109:54321<={'result': 0, 'id': 655702575}
DEBUG:__main__:192.168.2.109:54321=>{'method': 'move_158d000103ec74', 'params': [], 'from': 'nbl.134550490', 'id': 655700828}
DEBUG:__main__:CALLBACK lumi.158d000103ec74=>move([])
DEBUG:__main__:192.168.2.109:54321<={'result': 0, 'id': 655700828}
DEBUG:__main__:192.168.2.109:54321=>{'method': 'move_158d000103ec74', 'params': [], 'from': 'nbl.134550490', 'id': 655703870}
DEBUG:__main__:CALLBACK lumi.158d000103ec74=>move([])
DEBUG:__main__:192.168.2.109:54321<={'result': 0, 'id': 655703870}
DEBUG:__main__:192.168.2.109:54321=>PING
DEBUG:__main__:192.168.2.109:54321<=ACK(device_id=120009025)

@bskaplou
Copy link
Contributor Author

bskaplou commented May 23, 2020

It seems PR is almost here please drop a look
https://github.com/bskaplou/python-miio/tree/fake_device

https://github.com/rytilahti/python-miio/compare/master...bskaplou:fake_device?expand=1

Meanwhile I'll capture remaining actions of cube and square button and add their support into scripts .

Afterwards I'll beg for release :)

@rytilahti
Copy link
Owner

Please feel free to create a PR already (you can mark it as WIP/draft if you want), it is much easier to comment on it.

How do you plan this feature should be exposed? How would you propose to integrate this with the gateway support?

@bskaplou
Copy link
Contributor Author

I'm wondering if the system supports wildcards for events

Ammm ... I understood your question... No...

Right now it works as follows:

  1. Start fake server with device_id and token
  2. Install scripts into gateway with tokens and device_id same as in step 1
    NB each action and device requires installation of separate script
    script_install_count = actions * devices
  3. FakeDevice responds to PINGs and events
  4. Uninstall scripts
    NB there is no known way to get list of scripts installed, I haven't found data in dumps

Unfortunately right now I have no idea how to implement wildcards...
Problem:

  1. We can't start more then one fake device per ip address because of static 54321 port
  2. PING request doesn't contain device_id client searches for
  3. ACK request contains device_id
  4. If device_id in ACK doesn't match device_id in script client will not send actual method call

@bskaplou
Copy link
Contributor Author

@rytilahti
How to make it work in hass:

  1. Start fake_device in separate thread if cube/square_button found among device
  2. Install scripts for all supported action X for all supported devices into gateway
  3. Capture fake_device callbacks and forward them as hass events

@bskaplou bskaplou mentioned this issue May 23, 2020
@rezmus
Copy link

rezmus commented May 23, 2020

is your gw still connected to xiaomi cloud? gw can refresh ip/token of wifi devices it runs automation on via cloud api (_sync.neighborDevInfo). i checked on my (newer) hub and it gets current token with send_data_frame. extra field is lumi encoded automation trigger. it's used (NOT human readable key field) for lan automations. they use this method for most hubs, only last one lumi.gateway.mgl03 dropped it.

@bskaplou
Copy link
Contributor Author

@rezmus Yes gateway is connected to the cloud.
BTW did you sniffed cloud traffic?

@rezmus
Copy link

rezmus commented May 24, 2020

yeah it kinda use the same encryption as local miio but with cloud did/key credentials which you can get via shell (linux mi global hub or aqara).

https://github.com/dgiese/dustcloud/wiki/Lumi-Aqara-Gateway-Root
https://github.com/roth-m/miioclient-mqtt

@starkillerOG
Copy link
Contributor

@rezmus, still trying to figure out a way to get the token that needs to be sent with "send_data_frame" which is diffrent from the token used for the rest of the communication.

It sounds like you know a lot about those tokens, could you help me with devoloping a method to obtain that token?

@starkillerOG
Copy link
Contributor

I did figure out that the "data_tkn" does not have to match, for me both "29576" or "52507" work just as fine.
So I guess that if we always set "data_tkn" to "29576" as was done in the original PR of @bskaplou it will be fine.

Just need to figure out how to get that "send_data_frame" token, the rest I know how to implement and get it in HomeAssistant.

@starkillerOG
Copy link
Contributor

@xcray I see you have quite some experiance with the Xiaomi Miio protecol since you wrote a CSharp implementation. Do you have any ideas on how to obtain the token needed for "send_data_frame"?

@xcray
Copy link

xcray commented Jun 11, 2020

@xcray I see you have quite some experiance with the Xiaomi Miio protecol since you wrote a CSharp implementation. Do you have any ideas on how to obtain the token needed for "send_data_frame"?

My C# implementation was based on this: https://github.com/OpenMiHome/mihome-binary-protocol/blob/master/doc/PROTOCOL.md, and from only a few devices it could obtain token directly.

@rezmus
Copy link

rezmus commented Jun 12, 2020

@starkillerOG if there is some hashing algo for tokens you need to reverse engineer it from hubs firmware.

@starkillerOG
Copy link
Contributor

Alright, thanks for your info.
If you happen to come accross new commands for the gateway, please let me know.

On a side node, do you happen to know how to get any of the following properties:

  • the model of a subdevice
  • the zigbee id of a subdevice
  • the name of a subdevice as defined in the MiHome app
    I cant seem to find a command that will give me those values...

@rezmus
Copy link

rezmus commented Jun 12, 2020

i haven't used lumi.gateway.v3 for a long time so i'm not sure what it does return as device list. mgl03 returns such list

> {"method":"get_device_list","params":[],"id":1}
< {"code":0,"result":[{"did":"lumi.a","model":"lumi.sensor_motion.aq2","num":1,"total":3},{"did":"lumi.b","model":"lumi.plug.mmeu01","num":2,"total":3},{"did":"lumi.c","model":"lumi.remote.b686opcn01","num":3,"total":3}],"id":1}

so you have sid/model.

lumi.curtain.aq3 - Aqara Blind Controller
lumi.eemeter.rs485ecn01 - RS485 Connector(Electric meter)
lumi.eemeter.zbtecn01 - Zigbee Connector
lumi.curtain.aq1 - Aqara Curtain Controller 3.0
lumi.airrtc.tcpco2ecn01 - Aqara Thermostat(CO2)
lumi.plug.maeu01 - Aqara Smart Plug
lumi.plug.saus01 - Aqara Wall Outlet
lumi.dimmer.rgbegl01 - Dimmer(Multicolor)
lumi.dimmer.c3egl01 - Dimmer(3 Channels)
lumi.dimmer.cwegl01 - Dimmer(Tunable White)
lumi.switch.b1laus01 - Aqara Wall Switch(No Neutral, Single Rocker)
lumi.switch.b2laus01 - Aqara Wall Switch (No Neutral, Double Rocker)
lumi.light.aqcn01 - Aqara LED Light Bulb(Dimmable)
lumi.plug.maus01 - Aqara Smart Plug
lumi.plug.mitw01 - Mi Smart Plug
lumi.remote.b1acn02 - Aqara Wireless Mini Switch T1
lumi.flood.agl02 - Aqara Water Leak Sensor T1
lumi.magnet.agl02 - Aqara Door and Window Sensor T1
lumi.motion.agl02 - Aqara Motion Sensor T1
lumi.plug.maus02 - Aqara Smart Plug S2
lumi.switch.b1lacn01 - Aqara Wall Switch T1 (No Neutral, Single Rocker)
lumi.switch.b2lacn01 - Aqara Wall Switch T1 (No Neutral, Double Rocker)
lumi.switch.b1nacn01 - Aqara Wall Switch T1 (With Neutral, Single Rocker)
lumi.switch.b2nacn01 - Aqara Wall Switch T1 (With Neutral, Double Rocker)
lumi.plug.sacn02 - Aqara Smart Wall Outlet T1
lumi.gateway.mgl04 - Mi Smart Home Hub
lumi.switch.b1naus01 - Aqara Smart Wall Switch (With Neutral, Single Rocker)
lumi.gateway.irabr01 - Aqara Hub M2
lumi.curtain.vagl02 - Aqara Roller Shade Controller T1
lumi.curtain.hagl07 - Aqara Curtain Controller C2
lumi.switch.b2naus01 - Aqara Smart Wall Switch (With Neutral, Double Rocker)
lumi.gateway.iragl01 - Aqara Hub S2
lumi.gateway.mihk01 - Mi Control Hub
lumi.gateway.mieu01 - Mi Control Hub
lumi.gateway.lmuk01 - Mi Control Hub
lumi.gateway.mitw01 - Mi Control Hub
lumi.gateway.aqhm02 - Aqara Hub
lumi.sen_ill.agl01 - Aqara Light Detection Sensor T1
lumi.curtain.hagl05 - Xiaomiyoupin Curtain Controller (Wi-Fi)
lumi.sensor_ht.agl02 - Aqara Temperature and Humidity Sensor T1
lumi.sen_ill.mgl01 - Mi Light Detection Sensor
lumi.switch.b3l01 - Aqara Wall Switch T1 (No Neutral, Three Rocker)
lumi.switch.b3n01 - Aqara Wall Switch T1 (With Neutral, Three Rocker)
lumi.lock.bmcn02 - Mi Smart Door Lock
lumi.sensor_smoke.acn01 - Aqara Smart Smoke Detector(NB-IoT)
lumi.airmonitor.acn01 - Aqara TVOC Sensor
lumi.plug.macn01 - Aqara Smart Plug T1
lumi.remote.cagl01 - Aqara Cube T1
lumi.plug.mmeu01 - Mi Smart Plug (Zigbee)
lumi.gateway.aqhm03 - Aqara Hub
lumi.gateway.mgl03 - Mi Smart Home Hub
lumi.remote.b186acn01 - Aqara Wireless Remote Switch (Single Rocker)
lumi.remote.b286acn01 - Aqara Wireless Remote Switch (Double Rocker)
lumi.lock.acn03 - Aqara Door lock S2 Pro
lumi.gateway.v1 - Mi Control Hub
lumi.sensor_switch.v1 - Wireless switch
lumi.sensor_magnet.v1 - Door & window sensor
lumi.sensor_motion.v1 - Body sensor
lumi.sensor_switch.v2 - Mi Wireless Switch
lumi.ctrl_neutral2.v1 - Aqara Wall Switch (No Neutral, Double Rocker)
lumi.ctrl_neutral1.v1 - Aqara Wall Switch(No Neutral, Single Rocker)
lumi.sensor_ht.v1 - Mi Temperature and Humidity Sensor
lumi.plug.v1 - Mi Smart Plug
lumi.sensor_86sw1.v1 - Aqara Wireless Remote Switch (Single Rocker)
lumi.sensor_86sw2.v1 - Aqara Wireless Remote Switch (Double Rocker)
lumi.curtain.v1 - Aqara Curtain Controller
lumi.sensor_smoke.v1 - Mi Smart Smoke Detector
lumi.sensor_natgas.v1 - Mi Smart Natural Gas Detector
lumi.weather.v1 - Aqara Temperature and Humidity Sensor
lumi.ctrl_86plug.v1 - Aqara Wall Outlet
lumi.ctrl_ln2.v1 - Aqara Wall Switch (With Neutral, Double Rocker)
lumi.sensor_wleak.aq1 - Water Leak Sensor
lumi.ctrl_ln1.v1 - Aqara Wall Switch (With Neutral, Single Rocker)
lumi.vibration.aq1 - Aqara Vibration Sensor
lumi.curtain.aq2 - Aqara Roller Shade Controller
lumi.lock.v1 - Door lock
lumi.sensor_switch.aq2 - Aqara Wireless Mini Switch
lumi.lock.aq1 - Aqara Door Lock
lumi.sensor_switch.aq3 - Aqara Wireless Mini Switch(Advanced)
lumi.ctrl_ln2.aq1 - Aqara Wall Switch (With Neutral, Double Rocker)
lumi.ctrl_86plug.aq1 - Aqara Wall Outlet
lumi.light.aqcn02 - Aqara LED Light Bulb (Tunable White)
lumi.relay.c2acn01 - Aqara Wireless Relay Controller(2 Channels)
lumi.airrtc.vrfegl01 - VRF Air Conditioning Controller
lumi.airrtc.tcpecn01 - Thermostat
lumi.lock.acn02 - Aqara Door Lock S2
lumi.remote.b1acn01 - Aqara Wireless Mini Switch
lumi.curtain.hagl04 - Aqara Curtain Controller B1
lumi.ctrl_ln1.aq1 - Aqara Wall Switch (With Neutral, Single Rocker)
lumi.acpartner.mcn02 - Mi Smart Air Conditioner Controller 2
lumi.lock.mcn01 - Mi Smart Door Lock
lumi.sensor_cube.aqgl01 - Aqara Cube
lumi.sensor_cube.v1 - Mi Cube
lumi.switch.b2lacn02 - Aqara Wall Switch D1 (No Neutral, Double Rocker)
lumi.remote.b286acn02 - Aqara Wireless Remote Switch D1 (Double Rocker)
lumi.remote.b186acn02 - Aqara Wireless Remote Switch D1 (Single Rocker)
lumi.gateway.v2 - Mi Control Hub
lumi.gateway.v3 - Mi Control Hub
lumi.gateway.aqhm01 - Aqara Hub
lumi.camera.aq1 - Camera Hub
lumi.acpartner.v1 - Air Conditioning Controller
lumi.acpartner.v2 - Mi Smart Air Conditioner Controller
lumi.acpartner.v3 - Air Conditioning Controller(Advanced)
lumi.camera.gwagl01 - Camera Hub G2
lumi.airer.acn01 - Aqara Smart Clothes Drying Rack
lumi.sensor_motion.aq2 - Aqara Motion Sensor
lumi.sensor_motion.v2 - Mi Motion Sensor
lumi.airrtc.tcpecn02 - Thermostat S2
lumi.sensor_magnet.aq2 - Aqara Door and Window Sensor
lumi.sensor_magnet.v2 - Mi Window and Door Sensor
lumi.switch.b1nacn02 - Aqara Wall Switch D1 (With Neutral, Single Rocker)
lumi.switch.b1lacn02 - Aqara Wall Switch D1 (No Neutral, Single Rocker)
lumi.switch.b2nacn02 - Aqara Wall Switch D1 (With Neutral, Double Rocker)
lumi.light.cbacn1 - Aqara Smart Constant Current Driver T1-1
lumi.lock.bzacn2 - Aqara smart door lock N100
lumi.lock.bzacn1 - Aqara smart door lock N200
lumi.switch.l3acn3 - Aqara Smart Wall Switch D1 (No Neutral, Triple Rocker)
lumi.switch.n3acn3 - Aqara Smart Wall Switch D1(With Neutral, Triple Rocker)
lumi.switch.n0acn2 - Aqara Single Switch Module T1 (With Neutral)
lumi.switch.l0acn1 - Aqara Single Switch Module T1 (No Neutral)
lumi.switch.l1acn1 - Aqara Smart Wall Switch H1 (No Neutral, Single Rocker)
lumi.switch.l2acn1 - Aqara Smart Wall Switch H1 (No Neutral, Double Rocker)
lumi.switch.l3acn1 - Aqara Smart Wall Switch H1 (No Neutral, Triple Rocker)
lumi.switch.n1acn1 - Aqara Smart Wall Switch H1 (With Neutral, Single Rocker)
lumi.switch.n2acn1 - Smart Wall Switch H1 (With Neutral, Double Rocker)
lumi.switch.n3acn1 - Smart Wall Switch H1 (With Neutral, Triple Rocker)
lumi.light.rgbac1 - Aqara Smart Dimmer Controllor T1
lumi.airrtc.pcacn2 - Aqara Thermostat S2 Pro
lumi.remote.b486opcn01 - Wireless Scene Switch (Four Button Edition)
lumi.light.cwopcn01 - Ceiling Light MX960 (Adjustable Color Temperature)
lumi.light.cwopcn03 - Ceiling Light MX480 (Adjustable Color Temperature)
lumi.light.cwopcn02 - Ceiling Light MX650 (Adjustable Color Temperature)
lumi.remote.b686opcn01 - Wireless Scene Switch (Six Button Edition)
lumi.remote.b286opcn01 - Wireless Scene Switch (Two Button Edition)
lumi.curtain.hmcn01 - Mi Smart Motorized Curtain
lumi.lock.bmcn03 - Mi Smart Door Lock E
lumi.remote.b186acn03 - Aqara Wireless Remote Switch T1 (Single Rocker)
lumi.remote.b286acn03 - Aqara Wireless Remote Switch T1 (Double Rocker)
lumi.camera.gwakr1 - Camera G2
lumi.flood.bmcn01 - Mi Flood Detector
lumi.motion.agl04 - Aqara High Precision Motion Sensor
lumi.gateway.acn01 - Aqara Hub M1S
lumi.plug.sacn03 - Aqara Smart Wall Outlet H1 (USB)
lumi.vibration.agl01 - Aqara Vibration Sensor T1
lumi.sensor_smoke.mcn02 - Mi Smoke Detector
lumi.airer.acn02 - Aqara Smart Clothes Drying Rack Lite
lumi.sensor_gas.mcn02 - Mi Natural Gas Detector
lumi.curtain.hagl08 - Aqara Curtain Controller A1
lumi.aircondition.acn05 - Aqara Air Conditioning Controller P3
lumi.gateway.aeu01 - Aqara Hub M1S (EU)
lumi.camera.gwag03 - Camera Hub G2H

custom name you give is part of xiaomi cloud api not related to device.

@starkillerOG
Copy link
Contributor

just tryed the get_device_list command but does not work on lumi.gateway.v3 I get miio.exceptions.DeviceError: {'code': -32601, 'message': 'Method not found.'}

I can get devices using
self.send("get_device_prop", ["lumi.0", "device_list"])
and that gives:
["lumi.a",1,2,3,4]
where 1 is a number representing the model
2 and 3 are unknown variables
and 4 is the firmware version

@rezmus
Copy link

rezmus commented Jun 12, 2020

id - model map

0 - lumi.gateway
1 - lumi.sensor_switch
2 - lumi.sensor_motion
3 - lumi.sensor_magnet
7 - lumi.ctrl_neutral2
8 - lumi.sensor_cube
9 - lumi.ctrl_neutral1
10 - lumi.sensor_ht
11 - lumi.plug
12 - lumi.sensor_86sw2
13 - lumi.curtain
14 - lumi.sensor_86sw1
15 - lumi.sensor_smoke
17 - lumi.ctrl_86plug
18 - lumi.sensor_natgas
19 - lumi.weather
20 - lumi.ctrl_ln1
21 - lumi.ctrl_ln2
51 - lumi.sensor_switch.aq2
52 - lumi.sensor_motion.aq2
53 - lumi.sensor_magnet.aq2
54 - lumi.relay.c2acn01
55 - lumi.sensor_wleak.aq1
56 - lumi.vibration.aq1
59 - lumi.lock.aq1
62 - lumi.sensor_switch.aq3
63 - lumi.ctrl_ln1.aq1
64 - lumi.ctrl_ln2.aq1
65 - lumi.ctrl_86plug.aq1
66 - lumi.light.aqcn02
68 - lumi.sensor_cube.aqgl01
70 - lumi.lock.acn02
71 - lumi.curtain.aq2
72 - lumi.curtain.hagl04
81 - lumi.lock.v1
82 - ikea.light.led1545g12
83 - ikea.light.led1546g12
84 - ikea.light.led1536g5
85 - ikea.light.led1537r6
86 - ikea.light.led1623g12
87 - ikea.light.led1650r5
88 - ikea.light.led1649c5
133 - lumi.remote.b1acn01
134 - lumi.remote.b186acn01
135 - lumi.remote.b286acn01
163 - lumi.lock.acn03
166 - lumi.lock.acn05
167 - lumi.switch.b1lacn02
168 - lumi.switch.b2lacn02
169 - lumi.switch.b1nacn02
170 - lumi.switch.b2nacn02
171 - lumi.remote.b186acn02
172 - lumi.remote.b286acn02
176 - lumi.switch.n3acn3
177 - lumi.switch.l3acn3
202 - lumi.dimmer.rgbegl01
203 - lumi.dimmer.c3egl01
204 - lumi.dimmer.cwegl01
205 - lumi.airrtc.vrfegl01
206 - lumi.airrtc.tcpecn01
207 - lumi.airrtc.tcpecn02

@starkillerOG
Copy link
Contributor

@rezmus you are amazing, that is incredibly helpfull!!!
I will emidiatly start adding all those device ids

How did you get that model map, where is that documented?

@rezmus
Copy link

rezmus commented Jun 12, 2020

firmware dump.

@starkillerOG
Copy link
Contributor

@rezmus is that firmware dump available somewhere (on github) in readable text format?

@rezmus
Copy link

rezmus commented Jun 13, 2020

here is some older version

https://github.com/dgiese/dustcloud-documentation/tree/master/lumi.gateway.v3

it's firmware so if you plan to do some reverse engineering you have to use ida/ghidra or similar.

@starkillerOG
Copy link
Contributor

@starkillerOG if there is some hashing algo for tokens you need to reverse engineer it from hubs firmware.

@rezmus I tried looking at the firmware dump you provided, but that goes a little above my head....
Would you be willing to look if you can figure out where the "send_data_frame" token comes from? And maybe see if there is some way to get that token using some hashing algoritm or get it in some other way from the gateway or from the cloud?

@rezmus
Copy link

rezmus commented Aug 6, 2020

sorry, i took a look some time ago but without success. however i'm not really good at decompiled code analysis.

@starkillerOG
Copy link
Contributor

Alright, do you happen to know someone who might be able to help with this?

@rytilahti
Copy link
Owner

Maybe @dgiese has an idea about the gateway <-> subdevice intercomms? He has some deep knowledge on how xiaomi devices tick ;-)

@stefunkk
Copy link

stefunkk commented Dec 3, 2020

Any chance to add lumi.curtain.hagl08? Seems like it's the same as lumi.curtain.hagl05

@starkillerOG
Copy link
Contributor

I finished a PR for including this callback mechanism into python miio.
The only problem left is obtaining the encrypted_token from the normal token.
See #699 (comment)

If someone has any idea how to obtain the encrypted_token (besides packet capture/sniffing), help is more than welcome!

@starkillerOG
Copy link
Contributor

I just found a way to get the "encrypted token":

from miio.protocol import Utils

token = "TokenTokenToken"

def calculated_token_enc(token):
    token_bytes = bytes.fromhex(token)
    encrypted_token = Utils.encrypt(token_bytes, token_bytes)
    encrypted_token_hex = encrypted_token.hex()
    return encrypted_token_hex[0:32]

print(calculated_token_enc(token))

It works for the tokens of both my 2 gateways.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

7 participants