python-miio icon indicating copy to clipboard operation
python-miio copied to clipboard

Add support for 'lumi.gateway.mieu01' subdevices

Open javicalle opened this issue 5 years ago • 118 comments

The EU version of the gateway is supported in the current versión of the library and can be intergated in HA.

Some tests had been made to evaluate subdevices resolution with no success:

(venv)$ python /tmp/test_miio_gateway/gateway_devices.py
Traceback (most recent call last):
  File "/tmp/test_miio_gateway/gateway_devices.py", line 5, in <module>
    gateway.discover_devices()
  File "/opt/DevelopmentSpace/hassio/home-assistant/venv/lib/python3.7/site-packages/miio/gateway.py", line 168, in discover_devices
    devices_raw = self.get_prop("device_list")
  File "/opt/DevelopmentSpace/hassio/home-assistant/venv/lib/python3.7/site-packages/miio/gateway.py", line 207, in get_prop
    return self.send("get_device_prop", ["lumi.0", property])
  File "/opt/DevelopmentSpace/hassio/home-assistant/venv/lib/python3.7/site-packages/miio/device.py", line 147, in send
    command, parameters, retry_count, extra_parameters=extra_parameters
  File "/opt/DevelopmentSpace/hassio/home-assistant/venv/lib/python3.7/site-packages/miio/miioprotocol.py", line 203, in send
    self._handle_error(payload["error"])
  File "/opt/DevelopmentSpace/hassio/home-assistant/venv/lib/python3.7/site-packages/miio/miioprotocol.py", line 263, in _handle_error
    raise DeviceError(error)
miio.exceptions.DeviceError: {'code': -5005, 'message': 'params error'}

where gateway_devices.py:

from miio import Gateway

gateway = Gateway("192.168.1.IP", "tokentokentoken")

gateway.discover_devices()
devices = gateway.devices

for dev in devices:
    dev.update()
    print(dev)

@starkillerOG sugest (home-assistant/core#22078) a new approach with the get_device_list command.

javicalle avatar Jun 13 '20 12:06 javicalle

@javicalle alright lets see if we can get this working:

  1. try testing this code as a start:
from miio import Gateway
gateway = Gateway("192.168.1.IP", "tokentokentoken")
print(gateway.info())

That will print basic information about your gateway and that will confirm that the communication is okay. (although since it works with the HomeAssistant integration this schould not be a problem)

  1. open the gateway.py file of the miio library that schould be located in your virtuel python enviroment (in my case venv) at a path simular to: venv/lib/python3.7/site-packages/miio/gateway.py

  2. scroll down to line 151 and add this function in between the def devices(self): and def discover_devices(self): functions (actually the postion where you add it does not matter that much):

    @property
    def test(self):
        return self.send("get_device_list")
  1. now try running this test code:
from miio import Gateway
gateway = Gateway("192.168.1.IP", "tokentokentoken")
print(gateway.test())

Hopefully that will print a list of your subdevices..... fingers crossed....

starkillerOG avatar Jun 13 '20 13:06 starkillerOG

@javicalle actually now that I think of it, steps 2 till 4 can simply be replaced by running this test code:

from miio import Gateway gateway = Gateway("192.168.1.IP", "tokentokentoken") print(gateway.send("get_device_list"))

starkillerOG avatar Jun 13 '20 13:06 starkillerOG

Here are the results (some values have been obfuscated):

lumi.gateway.mieu01 v3.5.8_147 (AA:BB:CC:DD:EE:FF) @ 192.168.0.166 - token: 12345678901234567890123456789012

and the gateway.send("get_device_list") part:

Got error when receiving: timed out
Traceback (most recent call last):
  File "/opt/DevelopmentSpace/hassio/home-assistant/venv/lib/python3.7/site-packages/miio/miioprotocol.py", line 182, in send
    data, addr = s.recvfrom(1024)
socket.timeout: timed out

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/opt/DevelopmentSpace/hassio/home-assistant/venv/lib/python3.7/site-packages/miio/miioprotocol.py", line 182, in send
    data, addr = s.recvfrom(1024)
socket.timeout: timed out

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/opt/DevelopmentSpace/hassio/home-assistant/venv/lib/python3.7/site-packages/miio/miioprotocol.py", line 182, in send
    data, addr = s.recvfrom(1024)
socket.timeout: timed out

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/opt/DevelopmentSpace/hassio/home-assistant/venv/lib/python3.7/site-packages/miio/miioprotocol.py", line 182, in send
    data, addr = s.recvfrom(1024)
socket.timeout: timed out

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/tmp/test_miio_gateway/gateway_devices.py", line 8, in <module>
    print(gateway.send("get_device_list"))
  File "/opt/DevelopmentSpace/hassio/home-assistant/venv/lib/python3.7/site-packages/miio/device.py", line 147, in send
    command, parameters, retry_count, extra_parameters=extra_parameters
  File "/opt/DevelopmentSpace/hassio/home-assistant/venv/lib/python3.7/site-packages/miio/miioprotocol.py", line 226, in send
    extra_parameters=extra_parameters,
  File "/opt/DevelopmentSpace/hassio/home-assistant/venv/lib/python3.7/site-packages/miio/miioprotocol.py", line 226, in send
    extra_parameters=extra_parameters,
  File "/opt/DevelopmentSpace/hassio/home-assistant/venv/lib/python3.7/site-packages/miio/miioprotocol.py", line 226, in send
    extra_parameters=extra_parameters,
  File "/opt/DevelopmentSpace/hassio/home-assistant/venv/lib/python3.7/site-packages/miio/miioprotocol.py", line 230, in send
    raise DeviceException("No response from the device") from ex
miio.exceptions.DeviceException: No response from the device

javicalle avatar Jun 13 '20 19:06 javicalle

Also tested with same results:

gateway = Gateway("192.168.0.166", "12345678901234567890123456789012", lazy_discover=False, start_id=1000)

javicalle avatar Jun 13 '20 20:06 javicalle

Also tested with same results:

gateway = Gateway("192.168.0.166", "12345678901234567890123456789012", lazy_discover=False, start_id=1000)

That was indeed what I was going to sugest ;)

Well it does look like your gateway is recognizing the "get_device_list" command. If I run the same command on my gateway.v3 I get a replay of: miio.exceptions.DeviceError: {'code': -32601, 'message': 'Method not found.'}

Could you try running some random fake command like "test123" and see if you then also get the Method not found error, that would comfirm that your gateway recognizes the "get_device_list" command.

How many subdevices do you have connected to your gateway? The timeout error seems to be very simular to the issue we are currently having with PR: https://github.com/rytilahti/python-miio/issues/650

Unfortuanately I do not yet have an idea how to resolve that timeout issue.... Is your gateway updated to the latest firmware available?

starkillerOG avatar Jun 13 '20 22:06 starkillerOG

@rezmus do you have an idea where this timeout is comming from, is it indeed because too many devices are connected and the response message grows too big for the gateway?

Do you have any ideas how to resolve that? (sorry for involving you, but you seem to know a lot about these gateways)

starkillerOG avatar Jun 13 '20 22:06 starkillerOG

lumi.gateway.miXXXX and lumi.gateway.aqhm0X do not provide a way to get subdevices list. you need to define them yourself.

rezmus avatar Jun 13 '20 22:06 rezmus

I get the same error.

Now the file content is:

from miio import Gateway

gateway = Gateway("192.168.0.166", "12345678901234567890123456789012", lazy_discover=False, start_id=1000)

print(gateway.info())
print('-----')

print(gateway.send("no_method"))

And there are 5 devices connected to gateway.

javicalle avatar Jun 13 '20 22:06 javicalle

@javicalle apperently you cannot obtain the device list on the 'lumi.gateway.mieu01' according to @rezmus which is quite a dissapointment... We could at some point see if sniffing traffic using bluestack and wireshark provides us with some way to discover which devices are connected, but since @rezmus knows a lot about the firmware I guess there is no command.

Although I do find it strage that the gateway does not simply give the "method not found" as response to the "get_device_list" so maybe there is still some hope...

For now lets first test if the subdevices actually work the same way, otherwise it is going to be a big effort to get 'lumi.gateway.mieu01' support.

@javicalle do you know the sid and devicetype of your 5 connected subdevices? For me I can see them In the MiHome app -->gateway--> ... --> About --> Hub info (the same place where I can find the gateway token).

If so you can try:

from miio import gateway

hub = gateway.Gateway("192.168.0.166", "12345678901234567890123456789012", lazy_discover=False, start_id=1000)


sid = "lumi.SidSidSidSid"
device_type = 19
subdevice_cls = gateway.AqaraHT


dev_info = gateway.SubDeviceInfo(sid, device_type, 1, 1, 3)
dev = subdevice_cls(hub, dev_info)

dev.update()
print(dev)

where sid is the sid of the subdevice dev_type is the number representing the subdevice type (can be looked up from the model in the gateway.py file in the list on lines 39 to 90 class DeviceType(IntEnum):) and the subdevice class can also be found in this same list, in the example I used the AqaraHT temperature sensor (lumi.weather.v1)

starkillerOG avatar Jun 14 '20 14:06 starkillerOG

I only have 3 different types of devices:

  • Mi Window and Door sensor
  • Mi Motion Sensor
  • Mi Wireless Switch

My "Xiaomi Home" app don't have this option (no 'About' option available), and I have get the device info from others sources.

  • modified "Xiaomi Home" app from 'vevs': https://www.kapiba.ru/2017/11/mi-home.html
  • HA zha integration: I have a sensor integrated through a ZHA bridge and not from the Xiaomi Hub

The modified app gives to me this info:

Did:		lumi.158d000396cb70
Name:		Mi Window and Door Sensor
Model:		lumi.sensor_magnet.v2

Did:		lumi.158d0003a40c79
Name:		Mi Motion Sensor 2
Model:		lumi.sensor_motion.v2

Did:		lumi.158d0003a476f6
Name:		Mi Wireless Switch
Model:		lumi.sensor_switch.v2

If my interpretation is correct, it does not fit with any of the currently implemented models.

Anyway, I have tested the 2 available implementations with the motion sensor:

  • Motion = 2 # lumi.sensor_motion
  • AqaraMotion = 52 # lumi.sensor_motion.aq2

(I had to overwrite my venv's gateway class with the last one from the repository)

In both cases I have had the same error:

(venv)$ python /tmp/test_miio_gateway/gateway_subdevices.py
lumi.gateway.mieu01 v3.5.8_147 (AA:BB:CC:DD:EE:FF) @ 192.168.0.166 - token: 12345678901234567890123456789012
-----
Got error when receiving: timed out
Traceback (most recent call last):
  File "/opt/DevelopmentSpace/hassio/home-assistant/venv/lib/python3.7/site-packages/miio/miioprotocol.py", line 182, in send
    data, addr = s.recvfrom(1024)
socket.timeout: timed out

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/opt/DevelopmentSpace/hassio/home-assistant/venv/lib/python3.7/site-packages/miio/miioprotocol.py", line 182, in send
    data, addr = s.recvfrom(1024)
socket.timeout: timed out

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/opt/DevelopmentSpace/hassio/home-assistant/venv/lib/python3.7/site-packages/miio/miioprotocol.py", line 182, in send
    data, addr = s.recvfrom(1024)
socket.timeout: timed out

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "/opt/DevelopmentSpace/hassio/home-assistant/venv/lib/python3.7/site-packages/miio/miioprotocol.py", line 182, in send
    data, addr = s.recvfrom(1024)
socket.timeout: timed out

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/opt/DevelopmentSpace/hassio/home-assistant/venv/lib/python3.7/site-packages/miio/gateway.py", line 777, in send
    return self._gw.send(command, [self.sid])
  File "/opt/DevelopmentSpace/hassio/home-assistant/venv/lib/python3.7/site-packages/miio/device.py", line 147, in send
    command, parameters, retry_count, extra_parameters=extra_parameters
  File "/opt/DevelopmentSpace/hassio/home-assistant/venv/lib/python3.7/site-packages/miio/miioprotocol.py", line 226, in send
    extra_parameters=extra_parameters,
  File "/opt/DevelopmentSpace/hassio/home-assistant/venv/lib/python3.7/site-packages/miio/miioprotocol.py", line 226, in send
    extra_parameters=extra_parameters,
  File "/opt/DevelopmentSpace/hassio/home-assistant/venv/lib/python3.7/site-packages/miio/miioprotocol.py", line 226, in send
    extra_parameters=extra_parameters,
  File "/opt/DevelopmentSpace/hassio/home-assistant/venv/lib/python3.7/site-packages/miio/miioprotocol.py", line 230, in send
    raise DeviceException("No response from the device") from ex
miio.exceptions.DeviceException: No response from the device

The above exception was the direct cause of the following exception:

Traceback (most recent call last):
  File "/tmp/test_miio_gateway/gateway_subdevices.py", line 20, in <module>
    print(dev)
  File "/opt/DevelopmentSpace/hassio/home-assistant/venv/lib/python3.7/site-packages/miio/gateway.py", line 725, in __repr__
    self.get_battery(),
  File "/opt/DevelopmentSpace/hassio/home-assistant/venv/lib/python3.7/site-packages/miio/gateway.py", line 850, in get_battery
    self._battery = self.send("get_battery").pop()
  File "/opt/DevelopmentSpace/hassio/home-assistant/venv/lib/python3.7/site-packages/miio/gateway.py", line 781, in send
    ) from ex
miio.gateway.GatewayException: Got an exception while sending command get_battery

I continue doing some tests

javicalle avatar Jun 14 '20 18:06 javicalle

I have modified my gateway.py this way:

class DeviceType(IntEnum):
    """DeviceType matching using the values provided by Xiaomi."""

    Unknown = -1
    Gateway = 0  # lumi.0
    Switch = 1  # lumi.sensor_switch
    Motion = 2  # lumi.sensor_motion
    MotionV2 = 222 # lumi.sensor_motion.v2 for testing purposes
    .../...
    @command()
    def discover_devices(self):
        """
        Discovers SubDevices
        and returns a list of the discovered devices.
        """
        # from https://github.com/aholstenson/miio/issues/26
        device_type_mapping = {
            DeviceType.Switch: Switch,
            DeviceType.Motion: Motion,
            DeviceType.MotionV2: MotionV2, # probably not necessary
class MotionV2(SubDevice):
    """Subdevice Motion specific properties and methods."""

    properties = []
    _zigbee_model = "lumi.sensor_motion.v2"
    _model = "RTCGQ01LM"
    _name = "Motion sensor v2"

The _model value is written on the physical device, so I'm sure it's correct.

Now, my test class is the next one:

from miio import gateway

hub = gateway.Gateway("192.168.0.166", "12345678901234567890123456789012", lazy_discover=False, start_id=1000)

print(hub.info())
print('-----')

sid = "lumi.158d0003a40c79"
device_type = 222
subdevice_cls = gateway.MotionV2

dev_info = gateway.SubDeviceInfo(sid, device_type, 1, 1, 3)
dev = subdevice_cls(hub, dev_info)

dev.update()
print(dev)
print('+++++')

With these changes I get exactly the same error.

javicalle avatar Jun 14 '20 20:06 javicalle

get_battery method is not supported by these hubs.

rezmus avatar Jun 14 '20 21:06 rezmus

I just commented the print(dev) commands and no errors are generated. But I can't find a send or get_property to validate it's really working against device.

javicalle avatar Jun 14 '20 21:06 javicalle

@javicalle the motion sensor, door sensor and button do not have specific properties you can get. (only subscriptions to events but that still needs to be implemented).

Besides the get_battery there only are two other general commands known at this point:

dev.get_property("fw_ver") (get the firmware version of the subdevice) dev.send("remove_device") (unpair the device from the gateway, may not want to try this...)

You could try those...

In general there are 5 functions to interact with the device:

dev.send("test_command")
dev.send_arg("test_command", ["argument1", "argument2"])
dev.get_property("property")
dev.get_property_exp(["property"])
dev.set_property("property", "value")

So you can play around with those functions, but you will need to know or be very lucky to guess the commands/properties....

If you truly want to figure out commands/properties you will need to sniff the trafic of the MiHome app and see if you can discover commands/properties that work with this gateway.

I was able to sniff trafic using BlueStack (an android emulator for windows), install MiHome App and then capture packets using wireshark --> export as json and use the miio tool https://github.com/aholstenson/miio to decode the packets.

starkillerOG avatar Jun 15 '20 08:06 starkillerOG

dev.get_property("voltage") dev.get_property("lqi")

rezmus avatar Jun 15 '20 08:06 rezmus

dev.get_property("voltage") dev.get_property("lqi")

@rezmus on my gateway 'lumi.gateway.v3' those two give my empty responses [], the same as if I issue a random non existing property like dev.get_property("this_does_not_exist")

@javicalle but you can certainly try those on your gateway.

starkillerOG avatar Jun 15 '20 09:06 starkillerOG

My results:

  • dev.get_property("fw_ver") --> ERROR
  • dev.get_property("voltage") --> OK: [2995]
  • dev.get_property("lqi") --> ERROR

javicalle avatar Jun 15 '20 09:06 javicalle

aqara hubs can read lqi, mi hubs can't.

rezmus avatar Jun 15 '20 11:06 rezmus

@rezmus my hub 'lumi.gateway.v3' which is to my knowladge an chinese aqara hub gives an empty response on dev.get_property("lqi").

@javicalle intresting that the voltage works on 'lumi.gateway.mieu01' but does not on 'lumi.gateway.v3'

At this point it is pretty clear that the 'lumi.gateway.mieu01' supports different commands than the 'lumi.gateway.v3'. So someone who has acces to a 'lumi.gateway.mieu01' will have to do some development to get it supported with one of the biggest isues beeing there is no way to get the device_list.

If the device_list was the only problem I could have made a workaround by letting users configure a manual device_list, but since there are more commands that differ, that method is going to run into problems. withouth having acces to the device ('lumi.gateway.mieu01') I can therefore not easily implement support.... I am sorry @javicalle.

Of course it would be awesom if you could implement support @javicalle and I am open to helping and giving feedback on PR's for that, but that will be some effort.

starkillerOG avatar Jun 15 '20 14:06 starkillerOG

lumi.gateway.v3 - mi cn (called 2nd gen)

lumi.gateway.miXXXX - mi global hubs lumi.gateway.aqhm0X - aqara hubs

in contrast to mi cn, aqara and mi global have almost similar hardware/firmware and run embedded linux (arm), but aqara is way better supported (new devices).

all 3 hubs should work more or less the same for core methods to get/set props and invoke actions on subdevices, however they may vary on the list of supported models and minor stuff.

rezmus avatar Jun 15 '20 15:06 rezmus

This schould prevent some errors on the 'lumi.gateway.mieu01': https://github.com/rytilahti/python-miio/pull/732

@rezmus do you have any sugestion to get a list of connected devices for 'lumi.gateway.mieu01' (does not matter if we get zigbee_id or the integer mapping values)? Would it be hard/possible to get the device list from the cloud (is there some python libary to do this)?

starkillerOG avatar Jun 17 '20 11:06 starkillerOG

i took a look at firmware and i doubt there is such method. also never seen xiaomi cloud api reverse engineered. i think only solution is custom mi home version which dumps whole devices list to file.

rezmus avatar Jun 17 '20 15:06 rezmus

There are some pieces of the cloud api used by openhab (namely for the token extraction, https://www.openhab.org/addons/bindings/miio/#tokens), so it could be possible to obtain other information the same way.

I don't know about other open source implementations for the API, porting the cloud access would require some serious effort, especially to keep the details similar to openhab's to avoid getting blocked by the servers. As like to keep this library offline-only, such functionality should be externalized to another project.

rytilahti avatar Jun 17 '20 16:06 rytilahti

Thanks for the hint @rytilahti! I looked at the source code of the openhab miio addon and indeed they figured out a cloud connection using the acount name and password that you also use in the app. From the looks of it there is already code to get the tokens and device list (not only for the gateway but also for other general miio devices) The source code is here:

  • https://github.com/openhab/openhab-addons/tree/2.5.x/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/cloud
  • https://github.com/openhab/openhab-addons/blob/2.5.x/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/cloud/CloudConnector.java

Unfortunately the code is written in java which I don't know. I don't have time to deceiver the java and make a python lib from it, but someone will probably have to do that to get the 'lumi.gateway.mieu01' properly supported.

@javicalle do you happen to know java?

starkillerOG avatar Jun 18 '20 08:06 starkillerOG

@rytilahti I agree that online cloud connection code would be best implemented in a separate python library. Would it be alright with you if such a separate library would be used within python-miio as a dependency?

starkillerOG avatar Jun 18 '20 08:06 starkillerOG

@starkillerOG I don't think it's a good idea to make python-miio to be directly dependent, if such library would be created. I think a proper way would be to make it possible to feed a list of available devices to the gateway class, then it wouldn't be dependent on any potential issues with the cloud access. The device list could simply be a simple ini/json configuration file with list of devices (and other things, if needed), which could also be manually filled, e.g., based on the information shown by the official app.

rytilahti avatar Jun 20 '20 13:06 rytilahti

Apologize for being absent all this time. Right now my work has me very busy and I do not have the tranquility to dedicate time to hobbies.

@javicalle do you happen to know java? Yes, I'm more a Java boy than a Python one. But my knowledge is far from being able to create a complete library. I can read and interpret the code, but migrate the library with its dependencies to Python is something that is too big for me.

I want to thank everyone for their dedication in this matter and I regret not being on par with other contributions

javicalle avatar Jun 21 '20 20:06 javicalle

Let me know if I can contribute on this subject. I'm in the same position with @javicalle. Integration works only with "Arm Away" option. I also successfully controlled the LED on the gateway with miiicli. I'm sure that feature can be integrated on home assistant as well. I'm also able to access firmware of the device, as I was using it with hacked "miio_client" into the device. I also have all of the SID's of my subdevices. In addition to @javicalle, I also have the combined temperature/humdity sensor, which may be of help. @starkillerOG

serhatozkara avatar Jul 05 '20 19:07 serhatozkara

@serhatozkara you could try:

from miio import gateway
hub = gateway.Gateway("192.168.1.IP", "tokentokentoken")

sid = "lumi.SidSidSidSid"
device_type = 19
subdevice_cls = gateway.AqaraHT

dev_info = gateway.SubDeviceInfo(sid, device_type, 1, 1, 3)
dev = subdevice_cls(hub, dev_info)

dev.update()
print(dev)

where you need to fill in the IP, token and sid of one of your temperature sensors. If that works and prints the info including the temperature of the sensor we know that device commands are the same for the lumi.gateway.mieu01

starkillerOG avatar Jul 05 '20 21:07 starkillerOG

The gateway light can be integrated into HomeAssistant quite easily, just did not have time to clean-up the code and add it to HomeAssistant.

The big problem for the lumi.gateway.mieu01 is to get the subdevice list in order to add all the devices. See this comment: https://github.com/rytilahti/python-miio/issues/728#issuecomment-645856902. Someone will need to convert that java code to python in order to get the subdevice list from the cloud. As a bonus that will also give us the ability to obtain tokens from the cloud with just the xiaomi account credentials, that would make setting up the integration a lot easier for users and I think that does not only hold for the gateway, but also for all other xiaomi products...

starkillerOG avatar Jul 05 '20 21:07 starkillerOG

Oh boy! Here's the response from sensor: device AqaraHT: lumi.158d00045ad7cd, model: WSDCGQ11LM, zigbee: lumi.weather.v1, fw: 3, bat: None, vol: 3.025, props: {'temperature': 26.02, 'humidity': 66.21, 'pressure': 0.0}>

serhatozkara avatar Jul 05 '20 21:07 serhatozkara

@starkillerOG I don't know java either but many people from work does. Let's see if can get it done there...

serhatozkara avatar Jul 05 '20 21:07 serhatozkara

@serhatozkara great, that means subdevices can indeed be controlled and read with a lumi.gateway.mieu01! So basically we only need to get the subdevice list of connected zigbee devices (probably from the cloud) and we would be good to go.

starkillerOG avatar Jul 05 '20 21:07 starkillerOG

@starkillerOG i dont know if its what you need:

in Mi app go to gateway/.../About click 5 times in empty space go to last Chinese writing with 4 charakter and there is view with settings and list of devices.

So how you add Aqara bulbs to HA?

arekkwi avatar Jul 06 '20 11:07 arekkwi

@arekkwi yes that is basically the list that I need, but I need to get that list using python code. The MiHome app gets that list from the cloud (not through communication with the gateway), so bassicaly the code needs to be written to do the same as the MiHome app and get that list from the cloud. This comment: #728 refers to some Java code that is capable of doing exactly that, so that needs to be rewritten in python to use with HomeAssistant.

Regarding the Aqara bulb, the AqaraSmartBulbE27 is already implemented in the python-miio library. So only the code to add it in HomeAssistant needs to be written (fairly simple to do). Than it would work with the chinese gateways, for the lumi.gateway.mieu01 the above mentioned device list code first needs to be written.

starkillerOG avatar Jul 06 '20 12:07 starkillerOG

@starkillerOG I've made some digging on the Java example and retrieved some useful info. Actual sign in is done on: https://github.com/openhab/openhab-addons/blob/7628135323df6f07e3c2993d7b816a16e334d849/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/cloud/MiCloudConnector.java

With some mitmproxying and inspecting java code, I've successfully signed in to my account with postman. Not only cloud connection gives device list, it also lists the necessary tokens for all of the devices! I've limited knowledge on python, but can provide insight on the development needed. Simple libraries are needed: http client, cookie handling, and HMAC encoding. Hope this points us in the right direction...

serhatozkara avatar Jul 15 '20 09:07 serhatozkara

@serhatozkara That is greath news!

I probably will not have time to write a python lib for this is the near future. But it would greatly help if you could post a list of HTTP commands and responses that you used with postman to get the device list and necesarry tokens!

starkillerOG avatar Jul 15 '20 09:07 starkillerOG

@starkillerOG here is a sample response from device_list service. I'll add simple py codes to sign in to cloud if I can :)

  "code": 0,
  "message": "",
  "result": {
    "list": [
      {
        "did": "27xxx",
        "uid": 1791xxx,
        "token": "TOKEN",
        "name": "Mi Control Hub",
        "pid": 0,
        "localip": "192.168.255.255",
        "mac": "FF:EC:FF:EE:FF:FF",
        "ssid": "SSID",
        "bssid": "FF:FF:27:83:53:FF",
        "longitude": "0.00000000",
        "latitude": "0.00000000",
        "show_mode": 1,
        "model": "lumi.gateway.mieu01",
        "permitLevel": 16,
        "isOnline": true,
        "spec_type": "urn:miot-spec-v2:device:gateway:0000A019:lumi-mieu01:1",
        "extra": {
          "isSetPincode": 0,
          "fw_version": "3.5.8_147",
          "mcu_version": "0143",
          "isSubGroup": false
        },
        "orderTime": 1594794957
      },
      {
        "did": "lumi.158d000xxx",
        "uid": 1791xxx,
        "token": "",
        "name": "Yatak odası",
        "pid": 3,
        "mac": "",
        "ssid": "sozkara",
        "bssid": "FF:EC:FF:EE:FF:FF",
        "longitude": "0.00000000",
        "latitude": "0.00000000",
        "parent_id": "275955172",
        "show_mode": 0,
        "model": "lumi.sensor_magnet.v2",
        "permitLevel": 16,
        "isOnline": true,
        "spec_type": "urn:miot-spec-v2:device:magnet-sensor:0000A016:lumi-v2:1",
        "extra": {
          "isSetPincode": 0,
          "isSubGroup": false
        },
        "orderTime": 1587138824
      },
      {
        "did": "lumi.158d000xxx",
        "uid": 179xxx,
        "token": "",
        "name": "Salon Hareket Sensörü",
        "pid": 3,
        "mac": "",
        "ssid": "sozkara",
        "bssid": "FF:EC:FF:EE:FF:FF",
        "longitude": "0.00000000",
        "latitude": "0.00000000",
        "parent_id": "275955172",
        "show_mode": 0,
        "model": "lumi.sensor_motion.v2",
        "permitLevel": 16,
        "isOnline": true,
        "spec_type": "urn:miot-spec-v2:device:motion-sensor:0000A014:lumi-v2:1",
        "extra": {
          "isSetPincode": 0,
          "isSubGroup": false
        },
        "orderTime": 1587138824
      },
      {
        "did": "lumi.158d000xxx",
        "uid": 179xxx,
        "token": "",
        "name": "Switch",
        "pid": 3,
        "mac": "",
        "ssid": "sozkara 2.4 ghz",
        "bssid": "FF:EC:FF:EE:FF:FF",
        "longitude": "0.00000000",
        "latitude": "0.00000000",
        "parent_id": "275955172",
        "show_mode": 0,
        "model": "lumi.sensor_switch.v2",
        "permitLevel": 16,
        "isOnline": true,
        "extra": {
          "isSetPincode": 0,
          "isSubGroup": false
        },
        "orderTime": 1587138824
      },
      {
        "did": "lumi.158d000xxx",
        "uid": 179xxx,
        "token": "",
        "name": "Giriş Kapı",
        "pid": 3,
        "mac": "",
        "ssid": "sozkara",
        "bssid": "FF:EC:FF:EE:FF:FF",
        "longitude": "0.00000000",
        "latitude": "0.00000000",
        "parent_id": "275955172",
        "show_mode": 0,
        "model": "lumi.sensor_magnet.v2",
        "permitLevel": 16,
        "isOnline": true,
        "spec_type": "urn:miot-spec-v2:device:magnet-sensor:0000A016:lumi-v2:1",
        "extra": {
          "isSetPincode": 0,
          "isSubGroup": false
        },
        "orderTime": 1587138824
      },
      {
        "did": "lumi.158d00xxx",
        "uid": 179xxx,
        "token": "",
        "name": "Yatak odası Hareket Sensörü",
        "pid": 3,
        "mac": "",
        "ssid": "sozkara",
        "bssid": "FF:EC:FF:EE:FF:FF",
        "longitude": "0.00000000",
        "latitude": "0.00000000",
        "parent_id": "275955172",
        "show_mode": 0,
        "model": "lumi.sensor_motion.v2",
        "permitLevel": 16,
        "isOnline": true,
        "spec_type": "urn:miot-spec-v2:device:motion-sensor:0000A014:lumi-v2:1",
        "extra": {
          "isSetPincode": 0,
          "isSubGroup": false
        },
        "orderTime": 1587138824
      },
      {
        "did": "lumi.158d00xxx",
        "uid": 179xxx,
        "token": "",
        "name": "Temperature and Humidity Sensor",
        "pid": 3,
        "mac": "",
        "ssid": "sozkara",
        "bssid": "FF:EC:FF:EE:FF:FF",
        "longitude": "0.00000000",
        "latitude": "0.00000000",
        "parent_id": "275955172",
        "show_mode": 0,
        "model": "lumi.sensor_ht.v1",
        "permitLevel": 16,
        "isOnline": true,
        "spec_type": "urn:miot-spec-v2:device:temperature-humidity-sensor:0000A00A:lumi-v1:1",
        "extra": {
          "isSetPincode": 0,
          "isSubGroup": false
        },
        "orderTime": 1587139338
      }
    ],
    "next_start_did": "lumi.158d000xxxx",
    "has_more": false
  }
}

edited by @rytilahti: added triple-backtips for formatting, and masked the uid & the dids that are connected to your account.

serhatozkara avatar Jul 21 '20 20:07 serhatozkara

@serhatozkara looks greath, that contains all the information we currently need. Would be greath if you could make some simple python code to get this dict.

starkillerOG avatar Jul 24 '20 09:07 starkillerOG

@starkillerOG Hello again, I successfully signed in to Xiaomi Cloud and get the service token needed for every request to the device API's with python. Code is very crude and primitive so excuse me for that but still, this can pave way to a library. I started with http.client and proceeded with requests library to have both. I need to find a way to generate _nonce cookie values to proceed. It is done here on Openhab connector: https://github.com/openhab/openhab-addons/blob/7628135323df6f07e3c2993d7b816a16e334d849/bundles/org.openhab.binding.miio/src/main/java/org/openhab/binding/miio/internal/cloud/CloudUtil.java#L119 Also here's official implementation: https://github.com/xiaomi-passport/oauth-python-sdk/blob/81a1e2859f11d2bfcd4c1daae5138459d1a457d8/python/XMUtils.py It would be great if someone with better Python knowledge can help me on this as I don't have enough time to dedicate.

To Do: Exception and error handling To Do: Generate random device ID To Do: Use requests sessions. To Do: Generate _nonce, signed _nonce, signature To Do: cloud country server selector To Do: Domain name generator based on country selection

After this, we can finally make requests to cloud servers regarding devices. A sample request would be:

import requests

url = "https://sg.api.io.mi.com/app/v2/user/get_device_cnt"

payload = "_nonce=JgzXhBfls0oBlZQf&data=%7B%22fetch_own%22%3Atrue%2C%22fetch_share%22%3Atrue%2C%22accessKey%22%3A%22IOS00026747c5acafc2%22%7D&signature=KfGAAHAr%2Bm9ZOsMZngvGDkePg6syv2UafbDj/fG5gDE%3D"
headers = {
  'User-Agent': '	iOS-13.5.1-4.32.2-iPhone9,3--A5F96298791853B3E596085281DDB3C2ACE489C7-1791780321-054089ED3F43247A',
  'Content-Type': 'application/x-www-form-urlencoded'
}

response = requests.request("POST", url, headers=headers, data = payload)

print(response.text.encode('utf8'))

xiaomi.py.txt Best!

serhatozkara avatar Aug 01 '20 22:08 serhatozkara

when it will be possible to access the new platform via cloud for xiaomi gateways

matteos1 avatar Aug 12 '20 14:08 matteos1

@matteos1 Please doesn't spam multiple repos and issues.

syssi avatar Aug 12 '20 14:08 syssi

I've implemented a simple python module to connect to Xiaomi cloud. I'm new to python and it's very early in development. Currently you can only login and get the list of devices and their information/tokens. Feel free to use any code or tell me what you need to get the gateway working.

https://github.com/squachen/micloud

Squachen avatar Sep 01 '20 20:09 Squachen

@Squachen perfect, looks exactly like what we need. Unfortunately I cannot test it out because I am currently moving and all my equipment is in boxes... But with this it schould not be difficult anymore to get the lumi.gateway.mieu01 fully supported.

I am currently looking into getting the lumi.gateway.mgl03 working see https://github.com/rytilahti/python-miio/issues/807 That requires a very simular way of setting up the subdevices (match the zigbee_model to the type_id and then initialize the subdevice). @Oleg-I is testing this out for me so if that works I will see if I can write some code for the lumi.gateway.mieu01, but it will be buggy because I can't test it myself...

starkillerOG avatar Sep 02 '20 08:09 starkillerOG

I could use @Squachen script successfully and got the list. I could then probe my own subdevices for things like voltage. Thanks all and especially @Squachen for this big advancement.

But without event subscription, there is not much I can do with those as personally I'm looking into getting the state of door and motion sensors (and the gateway alarm but that's another problem). Any lead on that?

I can help with the code for subdevice support, but could maybe @starkillerOG help with those design question:

  • micloud should not be a dependency of python-miio, right? So systems like home assistant would use micloud and pass the JSON (or just sids + type?) to python-miio? Or is the inclusion of micloud acceptable?
  • How far should support go into home assistant given that most subdevice are useless without sensors? Would be pretty much useless to have the list of sub-devices as entities that only have the voltage, basically...?

tbarbette avatar Sep 02 '20 10:09 tbarbette

Great work @Squachen, it's great to have yet another way to obtain the tokens besides using an old version of mi home or some other tricks!

But without event subscription, there is not much I can do with those as personally I'm looking into getting the state of door and motion sensors (and the gateway alarm but that's another problem). Any lead on that?

PR #709 is aiming to allow python-miio to act as an event sink for separate devices.

  • micloud should not be a dependency of python-miio, right? So systems like home assistant would use micloud and pass the JSON (or just sids + type?) to python-miio? Or is the inclusion of micloud acceptable?

I have been contemplating on this, and I'd like to keep this library independent from any sort of cloud activities.

That being said, having a "device database" inside python-miio to allow keeping device-specific data (last used sequence id, ip address, token, model, etc.) in json/some other serialization format has been for a long time on my todo list. This store could definitely be populated by discovery, or other means, like using the micloud, or importing the data from the data stores of other implementations (openhab, javascript miio), so I'm not hardly against some sort of optional integration for this.

  • How far should support go into home assistant given that most subdevice are useless without sensors? Would be pretty much useless to have the list of sub-devices as entities that only have the voltage, basically...?

Are you sure that they don't have any other sensors (maybe battery at least)? I think the decision should be done case-by-case basis, but for some people even having the battery information can be useful to have.

rytilahti avatar Sep 02 '20 13:09 rytilahti

@tbarbette @rytilahti I think motion and door sensors etc schould wait untill PR #709 is finished before they get added to HomeAssistant. However there are many more devices like plug sockets, wall switches, light bulbs etc that can already be integrated in HomeAssistant withouth the need for events of PR #709. Moreover PR https://github.com/rytilahti/python-miio/pull/782 will open up the possiblibty to integrate all of those kind of devices in HomeAssistant.

starkillerOG avatar Sep 02 '20 15:09 starkillerOG

@rytilahti personally I would like to have the cloud credentials configurable though the options flow of HomeAssistant. Then users can chose if they want to use the cloud or not to get the device list and tokens. For the lumi.gateway.mieu01 the cloud would be the only way of getting subdevices, but for other gateways you would not have to use the cloud.

I would then preffer to have micloud as a dependency of python-miio if @rytilahti allows it. The Gateway class would then simply have optional parameters for the credentials, if those are supplied the discover_devices function of the gateway class would then use micloud to get the device list, if that fails it would fall back on the current way of getting the device list (not working for lumi.gateway.mieu01). If those cloud credentials are not supplied the discover_devices function of the gateway class would then skip micloud and go straight to the fall back which is the current way of gettting the device list.

If no credentials are given with a lumi.gateway.mieu01 an error message could be shown to allert users that the cloud credentials are the only way of getting subdevices with their model of gateway.

starkillerOG avatar Sep 02 '20 15:09 starkillerOG

Wow @Squachen perfect! You adressed most to do's in https://github.com/rytilahti/python-miio/issues/728#issuecomment-667596758 A welcome addition will be the server selector because not all people use the same country's servers, just like openhab implementation. @starkillerOG country selection should be configurable from HA integration config too, what do you think about it?

serhatozkara avatar Sep 02 '20 17:09 serhatozkara

@starkillerOG @rytilahti I'm glad you found the code useful. As I said, feel free to use it in any way you want. You could add it as your own micloud class in this project (you may remove my copyright comments) if you don't want to add it as a dependency. I made it a proper module mostly to learn how to do it. If you do want it as a dependency tho I'll maintain it and add what's needed to make it work.

@serhatozkara You can query different servers by supplying the 'country' argument: (I'll add this to the readme)

mc = MiCloud("USERNAME", "PASSWORD")
mc.login()
mc.get_devices(country="cn")

Or do you mean something else?

Squachen avatar Sep 02 '20 18:09 Squachen

@starkillerOG see my earlier comment on device database/configuration store. In the bigger picture the cloud information can also be useful for other devices besides these gateways. So to me it would make sense to have a generic support for synchronizing the available devices, tokens, and in some cases, such as for these gateways, the list of available subdevices from the cloud account, and so on.

In that sense, micloud could be used by python-miio for updating the local device database. Others ways for interacting with it would manual configuration, discovery-based or even importing from other miio implementations (openhab, miiojs).

Just an idea how this could work:

  1. We have the device store (or whatever it will be called), with information like addresses, tokens, device models, and other configuration data. This is useful for both cli and homeassistant users. The data structure could be something like this:
mybulb:
  host: 192.168.1.1
  token: 123123213
  model: some.light.model
  variables:
    sequence_id: 2

mygateway:
  host: 192.168.1.1
  token: 12341243
  model: lumi.gateway.mieu01
  variables:
    - subdevices:
      - subdevice.id
      - subdevice.something_else
  1. We have different ways to manage this store: discovery process, cloud sync using micloud, miiojs/openhab import, manually editing the file...
  2. We expose the configuration data (e.g., the list of subdevices) to Device instances over a common API, what's the best approach here needs some thinking (allow passing Configuration containing the data via constructor? Reading the configuration from the database inside Device class?).
  3. We add API to allow listing known devices, creating Device-subclassed instances based on the configuration and so on.
  4. We can add API to to allow using micloud to update the store, which could then be used by homeassistant to refresh the available devices.

@Squachen

I'm glad you found the code useful. As I said, feel free to use it in any way you want. You could add it as your own micloud class in this project (you may remove my copyright comments) if you don't want to add it as a dependency. I made it a proper module mostly to learn how to do it. If you do want it as a dependency tho I'll maintain it and add what's needed to make it work.

I really do applaud your efforts to make it more approachable to get the tokens and I appreciate your proposal for incorporating this inside python-miio, however, I want deliberately to keep this library cloud-free for various reasons. At the same time, I can see the value of having the ability to interact with the cloud, so I'm not strongly against adding an optional support using your library for fetching the token/device information.

Btw, you may want to take a look into typer or click to provide a simple cli interface. I haven't tested your library yet as I'm not actively using the official app, but my understanding is that you can also get tokens for other devices besides the gateway and a cli tool would make it more approachable for many users for the time being :-)

https://typer.tiangolo.com/tutorial/package/#add-a-script shows how to add an entrypoint using poetry (to get ready-to-run script), but similar approach works for setuptools as shown in click's documentation.

rytilahti avatar Sep 02 '20 20:09 rytilahti

I just made some code that schould allow the lumi.gateway.mieu01 to work with python_miio for subdevice support: https://github.com/starkillerOG/python-miio/tree/EU_gateway

I did no properly add micloud to the dependancies yet, so please make sure you have micloud installed. Furthermore that branch is based on the unmerged PR https://github.com/rytilahti/python-miio/pull/782 so I cannot make a PR yet because #782 first needs to be merged.

Could someone test out the code? My system is down so I can't test it myself.

You can use this test_code:

from miio import Gateway

gateway = Gateway("192.168.1.IP", "tokentokentoken", cloud_username = "USERNAME", cloud_password = "PASSWORD")

gateway.discover_devices()
devices = gateway.devices

for dev in devices:
    dev.update()
    print(dev)

starkillerOG avatar Sep 04 '20 11:09 starkillerOG

You lack a comma at line 171 of gateway/gateway.py, then I got:

WARNING:miio.gateway.gateway:Unknown subdevice discovered, could not match zigbee_model 'lumi.sensor_magnet.v2' of Xiaomi gateway with ip: 192.168.1.57
WARNING:miio.gateway.gateway:Unknown subdevice discovered, could not match zigbee_model 'lumi.sensor_magnet.v2' of Xiaomi gateway with ip: 192.168.1.57
WARNING:miio.gateway.gateway:Unknown subdevice discovered, could not match zigbee_model 'lumi.sensor_magnet.v2' of Xiaomi gateway with ip: 192.168.1.57
WARNING:miio.gateway.gateway:Unknown subdevice discovered, could not match zigbee_model 'lumi.sensor_magnet.v2' of Xiaomi gateway with ip: 192.168.1.57
WARNING:miio.gateway.gateway:Unknown subdevice discovered, could not match zigbee_model 'lumi.sensor_motion.v2' of Xiaomi gateway with ip: 192.168.1.57
WARNING:miio.gateway.gateway:Unknown subdevice discovered, could not match zigbee_model 'lumi.sensor_motion.v2' of Xiaomi gateway with ip: 192.168.1.57
WARNING:miio.gateway.gateway:Unknown subdevice discovered, could not match zigbee_model 'lumi.sensor_switch.v2' of Xiaomi gateway with ip: 192.168.1.57
Traceback (most recent call last):
  File "testm.py", line 9, in <module>
    dev.update()
AttributeError: 'str' object has no attribute 'update'

Not looked into that yet, but I guess the error is pretty much self-descriptive. But it clearly gets my devices etc, so good job! At your service to solve this, if need be.

Thanks!

tbarbette avatar Sep 04 '20 12:09 tbarbette

@tbarbette I fixed the missing comma and edited the zigbee_models of the magnet and motion sensor.

There was a small mistake in the test script I provided (missing the .values()), this schould be the correct one:

from miio import Gateway

gateway = Gateway("192.168.1.IP", "tokentokentoken", cloud_username = "USERNAME", cloud_password = "PASSWORD")

gateway.discover_devices()
devices = gateway.devices

for dev in devices.values():
    dev.update()
    print(dev)

Could you try this again?

starkillerOG avatar Sep 04 '20 12:09 starkillerOG

@tbarbette regarding your devices, is it correct that: 'lumi.sensor_magnet.v2' == model "MCCGQ01LM" 'lumi.sensor_motion.v2' == model "RTCGQ01LM"

What is the model of the 'lumi.sensor_switch.v2'? I could not figure out which one that schould be.... The ones that I know are in this file: https://github.com/starkillerOG/python-miio/blob/EU_gateway/miio/gateway/devices/switch.py

Edit: I think the 'lumi.sensor_switch.v2' is the "WXKG01LM" which is actually in this file: https://github.com/starkillerOG/python-miio/blob/EU_gateway/miio/gateway/devices/remote_switch.py

The model numbers schould be written on the back of the device itself and also in the (small) manual that comes with the device.

starkillerOG avatar Sep 04 '20 12:09 starkillerOG

<Subdevice Magnet: lumi.158d0003cfebb3, model: MCCGQ01LM, zigbee: lumi.sensor_magnet.v2, fw: -1, bat: None, vol: 3.035, props: {}>
<Subdevice Magnet: lumi.158d0003cfebf0, model: MCCGQ01LM, zigbee: lumi.sensor_magnet.v2, fw: -1, bat: None, vol: 3.005, props: {}>
<Subdevice AqaraMagnet: lumi.158d00045c80e2, model: MCCGQ11LM, zigbee: lumi.sensor_magnet.aq2, fw: -1, bat: None, vol: 2.985, props: {}>
<Subdevice Magnet: lumi.158d00052b2446, model: MCCGQ01LM, zigbee: lumi.sensor_magnet.v2, fw: -1, bat: None, vol: 3.025, props: {}>
<Subdevice Magnet: lumi.158d00052d8ddc, model: MCCGQ01LM, zigbee: lumi.sensor_magnet.v2, fw: -1, bat: None, vol: 3.015, props: {}>
<Subdevice Motion: lumi.158d000397ad53, model: RTCGQ01LM, zigbee: lumi.sensor_motion.v2, fw: -1, bat: None, vol: 3.005, props: {}>
<Subdevice Motion: lumi.158d0003d36c9c, model: RTCGQ01LM, zigbee: lumi.sensor_motion.v2, fw: -1, bat: None, vol: 3.035, props: {}>
<Subdevice AqaraMotion: lumi.158d000466783a, model: RTCGQ11LM, zigbee: lumi.sensor_motion.aq2, fw: -1, bat: None, vol: 3.005, props: {}>
<Subdevice Switch: lumi.158d0003d13c18, model: WXKG01LM, zigbee: lumi.sensor_switch.v2, fw: -1, bat: None, vol: 3.012, props: {}>

Seems good. I'm not sure about the exact model number, but it looks correct.

I just saw the cloud actually gives back the time of the last opening and closing events for magnet and last motion for motion detector. Wouldn't it be imaginable to poll the cloud like every 10 seconds? Events subscription still look like a long way to go.

tbarbette avatar Sep 04 '20 14:09 tbarbette

@tbarbette Nice, thanks for testing! Looks good to me, so this actually makes lumi.gateway.mieu01 subdevice support possible.

If you can find time I would appriciate it if you could check the model numbers on the device itself, just to be sure if it is now correct.

About the cloud polling, in principle I am not against it, but that would be even a big step further than only using the cloud to get the device list. Doing that would completly mix the micloud and python_miio libraries and realy make python_miio dependend on micloud.... I dont think that is the way @rytilahti wants to go...

Anyway the order in which things need to be done:

  1. PR https://github.com/rytilahti/python-miio/pull/782 needs to be revieuwed and merged to re-structure the gateway and its devices (otherwise other PRs get loads of merge conflicts...)
  2. We need to discuss if the approach of branch https://github.com/starkillerOG/python-miio/tree/EU_gateway is acceptable as a quick way to get the lumi.gateway.mieu01 working and later on refactor it according to @rytilahti explanation of a global device list that is not only sutable for the gateways but also for other xiaomi devices (make it more general)
  3. Based on 2) HomeAssistant needs an options flow to configure the cloud credentials such that lumi.gateway.mieu01 will work with HomeAssistant
  4. HomeAssistant integration for all the simple devices like light bulbs, plug sockets etc needs to be made (the python_miio side of things is already coverd by step 1))
  5. Then some cloud polling / event subscription needs to be looked at for the harder devices like motion sensors / door sensors / remote buttons etc.

starkillerOG avatar Sep 04 '20 14:09 starkillerOG

Ok. I'm not sure I can help for the few next steps but I'll stay around (I'll look for the model numbers). I'm still looking for a way to find if the gateway alarm is ringing if you have any idea...

tbarbette avatar Sep 04 '20 14:09 tbarbette

@rytilahti Thank you for the suggestion. I've implemented a super basic cli interface and released a new version.

Usage: micloud [OPTIONS]

Options:
  -u, --username TEXT  Your Xiaomi username.
  -c, --country TEXT   Language code of the server to query. Default: "de"
  --pretty             Pretty print json output.
  --help               Show this message and exit.

Squachen avatar Sep 04 '20 18:09 Squachen

@Squachen you're welcome, happy to help! Btw, take a look at password and prompt (https://click.palletsprojects.com/en/7.x/options/#password-prompts), that'll allow keeping the shell history clean of credentials & making the commands interactive (if one forgots to specify them).

rytilahti avatar Sep 04 '20 22:09 rytilahti

Released a new version with proper password prompt.

Squachen avatar Sep 04 '20 23:09 Squachen

Have you seen this project? https://github.com/AlexxIT/XiaomiGateway3 It has the Mi Cloud login functionality. I have a lumi.gateway.mieu01 an I was able to get the token with this custom component in Home Assistant.

vorostamas avatar Nov 14 '20 10:11 vorostamas

Hi, All of this seems promessing, and I would love to use and try this.. Any idea of if it is planned to integrate this in Home Assistant (or as a custom component) ? If there is a way to test it before release, I would love to 👍 Thanks for your answer

jonasCr avatar Dec 22 '20 21:12 jonasCr

@jonasCr basically the groundwork is there, but I have little time at the moment to work on it. First PR https://github.com/rytilahti/python-miio/pull/782 needs to be finished, then we can think of lumi.gateway.mieu01 support through the cloud.

starkillerOG avatar Dec 23 '20 11:12 starkillerOG

Hey there, is there any progress on that so far? I can help a bit if there's any help needed (can both test and write a bit of Python) as I've bought the lumi.gateway.mieu01 gateway and I cannot get it working with Home Assistant and it's no use for me without Home Assistant support. Thanks for your hard work!

serge1peshcoff avatar Jan 21 '21 08:01 serge1peshcoff

Happy new year everyone! I have been watching this since summer, but I have not really had the time to help until now. I would like to help if possible, I have some spare time next week from University after finishing my exams. I can write python code and/or test. I have the lumi.gateway.mieu01 too. :) Thanks for everything so far!

airampg avatar Jan 25 '21 20:01 airampg

I am planning on picking up this as soon as possible. I will be working on PR #782, so basically that is where any help would be appriciated.

starkillerOG avatar Jan 27 '21 16:01 starkillerOG

@serge1peshcoff, @airampg I picked up this work again, current progress is in this branch: https://github.com/starkillerOG/python-miio/tree/patch-18 I will update PR #782 once I get the code back to a working state (hopfully this weekend). But for those of you that are interested you can have a peak at patch-18 already

starkillerOG avatar Jan 29 '21 22:01 starkillerOG

Alright, I finished the PR and I think it is ready for revieuw/merge. Due to merge conflicts PR #782 was closed. The new PR is here: https://github.com/rytilahti/python-miio/pull/924

@serge1peshcoff, @airampg It would be helpfull if you could take a look at the PR and revieuw it to get it merged as soon as possible

starkillerOG avatar Jan 30 '21 20:01 starkillerOG

Alright, I finished the PR and I think it is ready for revieuw/merge. Due to merge conflicts PR #782 was closed. The new PR is here: #924

@serge1peshcoff, @airampg It would be helpfull if you could take a look at the PR and revieuw it to get it merged as soon as possible

Hey @starkillerOG Thanks a lot for your work on this!! I have downloaded miio and your patch, installed it, re-read a lot of this thread and the changelog on PR #924. I have created an object for my gateway with

from miio import gateway

hub = gateway.Gateway("192.168.0.IP", "12345678901234567890123456789012", lazy_discover=False, start_id=1000)


sid = "lumi.SidSidSidSid"
device_type = 3
subdevice_cls = lumi.sensor_magnet.v2


dev_info = gateway.SubDeviceInfo(sid, device_type, 1, 1, 3)
dev = subdevice_cls(hub, dev_info)

dev.update()
print(dev)

and I am currently getting the following traceback:

    subdevice_cls = lumi.sensor_magnet.v2
NameError: name 'lumi' is not defined

I have also tried the following just in case: print(hub.send("get_device_list")) (times out)

and gat.discover_devices() but returns:

Gateway model 'lumi.gateway.mieu01' does not (yet) support getting the device list
{}

Could you please tell me what I can test and how? I can do the tests tomorrow 😊 Thanks again!

airampg avatar Jan 31 '21 02:01 airampg

@airampg The current PR does not yet include the EU_gateway support

The following branch I just made does: https://github.com/starkillerOG/python-miio/blob/EU_gateway_2/miio/gateway/gateway.py

I did no properly add micloud to the dependancies yet, so please make sure you have micloud installed.

You can use this test_code:

from miio import Gateway

gateway = Gateway("192.168.1.IP", "tokentokentoken", cloud_username = "USERNAME", cloud_password = "PASSWORD")

gateway.discover_devices()
devices = gateway.devices

for dev in devices:
    dev.update()
    print(dev)

starkillerOG avatar Jan 31 '21 10:01 starkillerOG

@starkillerOG Thanks! I got it working, this is my output:

WARNING:miio.gateway.gateway:Unknown subdevice discovered, could not match zigbee_model 'lumi.sensor_magnet.v2' of subdevice sid 'lumi.12312311231231' from Xiaomi gateway with ip: 192.168.0.IP
WARNING:miio.gateway.gateway:Unknown subdevice discovered, could not match zigbee_model 'lumi.sensor_magnet.v2' of subdevice sid 'lumi.12312311231231' from Xiaomi gateway with ip: 192.168.0.IP
WARNING:miio.gateway.gateway:Unknown subdevice discovered, could not match zigbee_model 'lumi.sensor_magnet.v2' of subdevice sid 'lumi.12312311231231' from Xiaomi gateway with ip: 192.168.0.IP
WARNING:miio.gateway.gateway:Unknown subdevice discovered, could not match zigbee_model 'lumi.sensor_magnet.v2' of subdevice sid 'lumi.12312311231231' from Xiaomi gateway with ip: 192.168.0.IP
WARNING:miio.gateway.gateway:Unknown subdevice discovered, could not match zigbee_model 'lumi.sensor_magnet.v2' of subdevice sid 'lumi.12312311231231' from Xiaomi gateway with ip: 192.168.0.IP
WARNING:miio.gateway.gateway:Unknown subdevice discovered, could not match zigbee_model 'lumi.sensor_magnet.v2' of subdevice sid 'lumi.12312311231231' from Xiaomi gateway with ip: 192.168.0.IP
WARNING:miio.gateway.gateway:Unknown subdevice discovered, could not match zigbee_model 'lumi.sensor_motion.v2' of subdevice sid 'lumi.12312311231231' from Xiaomi gateway with ip: 192.168.0.IP
WARNING:miio.gateway.gateway:Unknown subdevice discovered, could not match zigbee_model 'lumi.sensor_motion.v2' of subdevice sid 'lumi.12312311231231' from Xiaomi gateway with ip: 192.168.0.IP
WARNING:miio.gateway.gateway:Unknown subdevice discovered, could not match zigbee_model 'lumi.sensor_motion.v2' of subdevice sid 'lumi.12312311231231' from Xiaomi gateway with ip: 192.168.0.IP
WARNING:miio.gateway.gateway:Unknown subdevice discovered, could not match zigbee_model 'lumi.sensor_motion.v2' of subdevice sid 'lumi.12312311231231' from Xiaomi gateway with ip: 192.168.0.IP
WARNING:miio.gateway.gateway:Unknown subdevice discovered, could not match zigbee_model 'lumi.sensor_motion.v2' of subdevice sid 'lumi.12312311231231' from Xiaomi gateway with ip: 192.168.0.IP
WARNING:miio.gateway.gateway:Unknown subdevice discovered, could not match zigbee_model 'lumi.sensor_motion.v2' of subdevice sid 'lumi.12312311231231' from Xiaomi gateway with ip: 192.168.0.IP
WARNING:miio.gateway.gateway:Unknown subdevice discovered, could not match zigbee_model 'lumi.sensor_switch.v2' of subdevice sid 'lumi.12312311231231' from Xiaomi gateway with ip: 192.168.0.IP
WARNING:miio.gateway.gateway:Unknown subdevice discovered, could not match zigbee_model 'lumi.sensor_switch.v2' of subdevice sid 'lumi.12312311231231' from Xiaomi gateway with ip: 192.168.0.IP
WARNING:miio.gateway.gateway:Unknown subdevice discovered, could not match zigbee_model 'lumi.sensor_switch.v2' of subdevice sid 'lumi.12312311231231' from Xiaomi gateway with ip: 192.168.0.IP
lumi.12312311231231
lumi.12312311231231
lumi.12312311231231
lumi.12312311231231
lumi.12312311231231
lumi.12312311231231
lumi.12312311231231
lumi.12312311231231
lumi.12312311231231
lumi.12312311231231
lumi.12312311231231
lumi.12312311231231
lumi.12312311231231
lumi.12312311231231
lumi.12312311231231
lumi.12312311231231
lumi.12312311231231
lumi.12312311231231

It looks like my devices are not on the subdevices.yaml, but it can detect them all! If there is some docs on how to add them there, I could try to do so myself :)

The dev.update() returned a traceback AttributeError: 'str' object has no attribute 'update'. Correct me if I am wrong, but I think that this is because devices = gateway.devices is of type dict, with the shape: 'lumi.12312311231231': <Subdevice unknown: lumi.12312311231231, model: unknown, zigbee: unknown, fw: -1, bat: None, vol: 3.005, props: {}>, and dev.update() is expecting to be called by an object of class SubDevice. I am not sure where update is going sideways for me. Thanks again!

airampg avatar Jan 31 '21 13:01 airampg

@airampg I just made a commit to branch https://github.com/starkillerOG/python-miio/blob/EU_gateway_2/miio/gateway/devices/subdevices.yaml

Could you update with that latest commit and try again?

And you are right, I made a small mistake in the script I provided to you (missing the .values()), the correct one is:

from miio import Gateway

gateway = Gateway("192.168.1.IP", "tokentokentoken", cloud_username = "USERNAME", cloud_password = "PASSWORD")

gateway.discover_devices()
devices = gateway.devices

for dev in devices.values():
    dev.update()
    print(dev)

starkillerOG avatar Jan 31 '21 14:01 starkillerOG

@starkillerOG Amazing job!!

This is the output after running with the new subdevices.yaml and devices.values():

<Subdevice Magnet: lumi.12312311231231, model: MCCGQ01LM, zigbee: lumi.sensor_magnet.v2, fw: -1, bat: None, vol: 3.005, props: {}>
<Subdevice Magnet: lumi.12312311231231, model: MCCGQ01LM, zigbee: lumi.sensor_magnet.v2, fw: -1, bat: None, vol: 2.995, props: {}>
<Subdevice Magnet: lumi.12312311231231, model: MCCGQ01LM, zigbee: lumi.sensor_magnet.v2, fw: -1, bat: None, vol: 3.005, props: {}>
<Subdevice Magnet: lumi.12312311231231, model: MCCGQ01LM, zigbee: lumi.sensor_magnet.v2, fw: -1, bat: None, vol: 2.995, props: {}>
<Subdevice Magnet: lumi.12312311231231, model: MCCGQ01LM, zigbee: lumi.sensor_magnet.v2, fw: -1, bat: None, vol: 3.005, props: {}>
<Subdevice Magnet: lumi.12312311231231, model: MCCGQ01LM, zigbee: lumi.sensor_magnet.v2, fw: -1, bat: None, vol: 3.005, props: {}>
<Subdevice Motion: lumi.12312311231231, model: RTCGQ01LM, zigbee: lumi.sensor_motion.v2, fw: -1, bat: None, vol: 3.035, props: {}>
<Subdevice Motion: lumi.12312311231231, model: RTCGQ01LM, zigbee: lumi.sensor_motion.v2, fw: -1, bat: None, vol: 3.015, props: {}>
<Subdevice Motion: lumi.12312311231231, model: RTCGQ01LM, zigbee: lumi.sensor_motion.v2, fw: -1, bat: None, vol: 3.015, props: {}>
<Subdevice Motion: lumi.12312311231231, model: RTCGQ01LM, zigbee: lumi.sensor_motion.v2, fw: -1, bat: None, vol: 3.015, props: {}>
<Subdevice Motion: lumi.12312311231231, model: RTCGQ01LM, zigbee: lumi.sensor_motion.v2, fw: -1, bat: None, vol: 3.035, props: {}>
<Subdevice Motion: lumi.12312311231231, model: RTCGQ01LM, zigbee: lumi.sensor_motion.v2, fw: -1, bat: None, vol: 3.005, props: {}>
<Subdevice Switch: lumi.12312311231231, model: WXKG01LM, zigbee: lumi.sensor_switch.v2, fw: -1, bat: None, vol: 3.012, props: {}>
<Subdevice Switch: lumi.12312311231231, model: WXKG01LM, zigbee: lumi.sensor_switch.v2, fw: -1, bat: None, vol: 3.012, props: {}>
<Subdevice Switch: lumi.12312311231231, model: WXKG01LM, zigbee: lumi.sensor_switch.v2, fw: -1, bat: None, vol: 3.022, props: {}>
<Subdevice SensorHT: lumi.12312311231231, model: WSDCGQ01LM, zigbee: lumi.sensor_ht.v1, fw: -1, bat: None, vol: 2.965, props: {'temperature': 20.49, 'humidity': 71.06}>
<Subdevice AqaraVibration: lumi.12312311231231, model: DJT11LM, zigbee: lumi.vibration.aq1, fw: -1, bat: None, vol: 2.975, props: {}>
<Subdevice CubeV2: lumi.12312311231231, model: MFKZQ01LM, zigbee: lumi.sensor_cube.aqgl01, fw: -1, bat: None, vol: 2.985, props: {}>

airampg avatar Jan 31 '21 14:01 airampg

Good news, PR https://github.com/rytilahti/python-miio/pull/924 has been merged. I am now looking into getting the EU_gateway supported. I have opend up this PR for that: https://github.com/rytilahti/python-miio/pull/935, please follow that for more information

starkillerOG avatar Feb 07 '21 22:02 starkillerOG

With the release of Python-Miio 0.5.5 everything is ready for the EU_gateway support. I just made a PR for HomeAssistant: https://github.com/home-assistant/core/pull/47955

I will be testing it in the coming days.

If someone want to already test it, that would be very helpfull

starkillerOG avatar Mar 15 '21 17:03 starkillerOG

Hey @starkillerOG

Thanks again for an amazing job!

If someone want to already test it, that would be very helpful

I can definitely help with testing, I will just need some instructions on how to add/enable this pre-release on my HA 😊

airampg avatar Mar 15 '21 19:03 airampg

you can run it as a custom component to test it. I will do some test tonight and make some improvements and then post some instructions on how to do this here.

starkillerOG avatar Mar 15 '21 20:03 starkillerOG

Alright, the PR is done. Instructions to test the code are here: https://github.com/home-assistant/core/pull/47955#issuecomment-799798564

starkillerOG avatar Mar 15 '21 22:03 starkillerOG

Thanks for the link to test it.

I have been able to install it and set it up with my cloud account.

I can see it has pulled my thermometer from the cloud and created an entity for it. (lumi.sensor_ht.v1) image

However, it does not show any of the other devices which are trigger enabled, such as buttons (lumi.sensor_switch.v2), motion sensors (lumi.sensor_motion.v2), magnetic (lumi.sensor_magnet.v2), cube (lumi.sensor_cube.aqgl01), vibration (lumi.vibration.aq1).

Could you please let me know whether this is intended behaviour or if I need to do something else?

Thank you again!

airampg avatar Mar 16 '21 00:03 airampg

@airampg thanks for testing, greath to hear it works! yes that is intended behaviour, you can see the currently suppported subdevices here: https://www.home-assistant.io/integrations/xiaomi_miio/#supported-subdevices and the recognized but not yet supported subdevices here: https://www.home-assistant.io/integrations/xiaomi_miio/#recognized-subdevices-not-yet-implemented

Note that the dev release already has PRs merged that will add support for a lot more subdevices (switches and lights) you can see that here: https://github.com/home-assistant/home-assistant.io/blob/next/source/_integrations/xiaomi_miio.markdown#supported-subdevices

starkillerOG avatar Mar 16 '21 08:03 starkillerOG

The trigger enabled devices can not yet be implemented because they don't have state attributes, they only provide trigger events and there is no way to listen for those events in python-miio yet. Support to make it possible to listen for those kinds of events is worked on in this PR: https://github.com/rytilahti/python-miio/pull/709

However that PR has been stale for quite some time. Maybe I will pick that up some time and see if I can get that working (it would have some greath advantages), however I don't know when I will have time for that

starkillerOG avatar Mar 16 '21 08:03 starkillerOG

@starkillerOG Having the Xiaomi Miio integration installed I placed the xiaomi_miio folder that is in homeassistant/components/ PR inside custom_components. I was able to insert my cloud credentials, but when I list my devices it looks like they are coming from the released Xiaomi Miio integration and not from the custom one, I assume it's wrong looking at @airampg print which shows the devices coming from xiaomi_miio and not from Xiaomi Miio 2021-03-16_10h09_33 2021-03-16_10h05_25

Can you help?

carloslindo avatar Mar 16 '21 10:03 carloslindo

@carloslindo you can try removing the gateway integration and setting it up again. Besides do you have any subdevice listed here: https://github.com/home-assistant/home-assistant.io/blob/next/source/_integrations/xiaomi_miio.markdown#supported-subdevices ?

Otherwise it will not show any aditional subdevices (because they are not yet implemented)

starkillerOG avatar Mar 16 '21 10:03 starkillerOG

@carloslindo and of course you need to select the correct "cloud server country" in the options (depends on how you setup your xiaomi miio account), you can find that in the Miio Home app under Profile --> Settings (Language & region) --> Region. Mine is "Chinese mainland" and therefore I need to select "cn" you can find more on the country servers here: https://www.openhab.org/addons/bindings/miio/#country-servers

starkillerOG avatar Mar 16 '21 10:03 starkillerOG

@starkillerOG I am using the same country code de as the token_extractor shows. I think the problem is my subdevices are lumi.sensor_motion.v2 and that falls into the list of not supported subdevices... Is there anything else that I can do to help testing?

carloslindo avatar Mar 16 '21 11:03 carloslindo

@carloslindo No not really, I think the code just works so it can be merged. The only thing you can check is if you don't see any errors in the log.

starkillerOG avatar Mar 16 '21 12:03 starkillerOG

I got this in the log :

2021-03-16 16:14:05 ERROR (SyncWorker_7) [miio.gateway.gateway] Could not find gateway with ip '192.168.1.57', mac '50:EC:50:EE:42:76', model 'lumi.gateway.mieu01' in the cloud device list response
2021-03-16 16:14:11 ERROR (SyncWorker_4) [miio.miioprotocol] Got error when receiving: timed out
2021-03-16 16:14:11 ERROR (MainThread) [custom_components.xiaomi_miio.gateway] DeviceException during setup of xiaomi gateway with host 192.168.1.57

But when I run micloud manually I do get that device which is my gateway. Also I think the "first setup" popup should start by proposing the cloud credentials, and then auto-discover the gateway and the token. So we could do everything directly in home assistant, without needing to go through the token extractor.

tbarbette avatar Mar 16 '21 15:03 tbarbette

@tbarbette If it cannot find it, the only things I can think of is that the chosen server is not the same as your gateway or the "use cloud to get connected subdevices" may be unticked. Perhaps your gateway's IP address has changed? is that the one on the Mi Home app? I definitely did not get that issue, so I am not sure of there this is going wrong for you. This is what my cloud options look like on HA: image

airampg avatar Mar 16 '21 15:03 airampg

Ticked, and I have DE too (my locale is BE). I actually re-installed the gateway from the informations given by micloud (ip and token) as that gives you the token very easily so it's the same. One thing maybe, in the micloud json, the gateway is the second device as the first one is a Xiaomi camera.

tbarbette avatar Mar 16 '21 16:03 tbarbette

@tbarbette could you try running this python code (preferably inside the virtual enviroment of HomeAssistant)?

from micloud import MiCloud

mc = MiCloud("USERNAME", "PASSWORD")
mc.login()
token = mc.get_token() # to get your cloud service token.
device_list = mc.get_devices(country="de") # get list of devices
print(device_list )

And then see if the gateway is listed in the dict

starkillerOG avatar Mar 16 '21 17:03 starkillerOG

@tbarbette the order in which the devices are listed is not importend, a for loop over the devices is made to see if the gateway can be found: https://github.com/rytilahti/python-miio/blob/5ea3157db58045260edceebb52a0f1e45f709d79/miio/gateway/gateway.py#L207-L221

starkillerOG avatar Mar 16 '21 17:03 starkillerOG

@tbarbette Note that this needs to be an exact match of the mac (case and format sensitive). So maybe the format of the mac is diffrent??? I would need the output of the python script above to compare with the error message to see what is going wrong...

starkillerOG avatar Mar 16 '21 17:03 starkillerOG

Hi, I'm trying to install it to test but no success as far. This is the steps I made:

  • Uninstall the official miio integration
  • Put your miio folder in my custom_components folder
  • restart HA
  • I'm able to add my cloud account but then nothing more happend.. :( Is there something I'm missing ?? I tried to restart HA after this but no success

I'm in spain so i put the de server

Thanks for your help

jonasCr avatar Mar 16 '21 17:03 jonasCr

Also I think the "first setup" popup should start by proposing the cloud credentials, and then auto-discover the gateway and the token. So we could do everything directly in home assistant, without needing to go through the token extractor.

I agree, but that is something for a future PR, that is a bit more complicated than you might think:

  • it may not work for users that have internet acces (cloud) blocked, so the old method schould still be supported.
  • Other devices like vacuums etc will also be discoverd in that way and they schould also be setup. However then all those things will end up in one config entry, currently it is not possible to setup multiple devices from one config_entry (all mac's and models schould be stored to be able to still setup the integration if for instance internet is down and cloud is not available at the moment HomeAssistant starts).

starkillerOG avatar Mar 16 '21 18:03 starkillerOG

@jonasCr do you see any errors in the log? Do you have one or more of the devices listed here: https://github.com/home-assistant/home-assistant.io/blob/next/source/_integrations/xiaomi_miio.markdown#supported-subdevices ? (Otherwise nothing will show up because other subdevices are not yet supported)

starkillerOG avatar Mar 16 '21 18:03 starkillerOG

Ook, that's it. Mine are in the Recognized section but not in the supported :( ... Well, I'm not going to be able to try it... But well done !! That's a big step! Thanks for your job. Let me know if more device are added

jonasCr avatar Mar 16 '21 18:03 jonasCr

@jonasCr As I see that there is quite some intrest in subdevice support for the Xiaomi Miio Gateway integration, I might see if I can pick up PR https://github.com/rytilahti/python-miio/pull/709 to get event driven (sub)devices supported.

starkillerOG avatar Mar 16 '21 18:03 starkillerOG

Yeah, I think it's because here there are selling a kit with the kit and 5 sensors (2 doors, 2 motion and 1 button) and all of them are recognized but not supported, for now. Hopefully the support is coming soon. Until that it's useless for me 😉

jonasCr avatar Mar 16 '21 19:03 jonasCr

@tbarbette could you try running this python code (preferably inside the virtual enviroment of HomeAssistant)?

from micloud import MiCloud

mc = MiCloud("USERNAME", "PASSWORD")
mc.login()
token = mc.get_token() # to get your cloud service token.
device_list = mc.get_devices(country="de") # get list of devices
print(device_list )

And then see if the gateway is listed in the dict

I get the same list than with the micloud client. Today I tried to hit "reload" and I don't get that message anymore... I only have sensors so I can't verify something else was added up. I think I did not select the right server at the first try, maybe the change of server was not saved? Anyway I guess it works :) Thanks! And yes, please support events :p

tbarbette avatar Mar 17 '21 08:03 tbarbette