rytilahti / python-miio

Python library & console tool for controlling Xiaomi smart appliances
https://python-miio.readthedocs.io
GNU General Public License v3.0
3.79k stars 564 forks source link

How to access zigbee peripherals (lumi.gateway.v3) #650

Open miway80 opened 4 years ago

miway80 commented 4 years ago

Hi guys,

I am starting with python, I already have token and the gateway ip but I don't know how to start my code, can somebody send me a example or explain me how can i access my gateway and see zigbee devices?

I found it, but i dont know how can i put token and ip and read zigbee goods, for example controller my Plug = 11

Thanks in advance

rytilahti commented 4 years ago

Unfortunately that part of the current gateway is not currently implemented, and it's waiting for someone to step in to do that.

If you are interested in digging in, there is some test code I used during the initial implementation in this commit: https://github.com/rytilahti/python-miio/pull/470/commits/57ff02898dc34f516705ab65c56c6524f71e6c8b

The command to access zigbee devices differs per device (get_prop_plug for the plug), which requires passing the device id in the payload. The current code does not allow doing this, so to make it work this needs to be adjusted (see #632).

If your goal is to access raw zigbee pieces, GatewayZigbee class contains some (unimplemented) methods for commands that could allow doing it. I have no clue what are the parameters and how they work (if they even work), just writing this down here in case you or someone else comes up looking and is interested in that.

Long story short, there is no way to do that currently without code changes. To get started accessing the gateway and list the devices connected to it:

from miio import Gateway

gw = Gateway("192.168.123.123", "tokentokentoken")
print(gw.devices())
miway80 commented 4 years ago

Thank you very much for answer, i am checking these posts and try to connect to my gateway at least, i add gateway.py manually and i put code in a file mi.py

from miio import Gateway

gw = Gateway("192.168.123.123", "tokentokentoken") print(gw.devices())

With this result

pi@rpi:~ $ python3 mi.py ValueError: 65 is not a valid DeviceType

During handling of the above exception, another exception occurred:

Traceback (most recent call last): File "mi.py", line 5, in print(gw.devices()) File "/home/pi/.local/lib/python3.7/site-packages/miio/gateway.py", line 108, in devices for x in range(0, len(devices_raw), 5) File "/home/pi/.local/lib/python3.7/site-packages/miio/gateway.py", line 108, in for x in range(0, len(devicesraw), 5) File "/home/pi/.local/lib/python3.7/site-packages/miio/gateway.py", line 485, in init self.type = DeviceType(type) File "/usr/lib/python3.7/enum.py", line 310, in call return cls.new(cls, value) File "/usr/lib/python3.7/enum.py", line 564, in new raise exc File "/usr/lib/python3.7/enum.py", line 548, in new result = cls.missing(value) File "/usr/lib/python3.7/enum.py", line 577, in missing raise ValueError("%r is not a valid %s" % (value, cls.name)) ValueError: 65 is not a valid DeviceType

rytilahti commented 4 years ago

See https://github.com/rytilahti/python-miio/blob/master/miio/gateway.py#L27 - that lists the known subdevices. I'll create soon a PR to make it not crash but report an error during initialization, but until that you can simply modify that enum to contain that value.

starkillerOG commented 4 years ago

@rytilahti I think this ons can also be closed since the issues discussed here are all fixed I think

rytilahti commented 4 years ago

The device type of 65 is still unknown/not implemented, so I think this can remain open?

@miway80 could you please test your script with the current master, if it is otherwise working for you? Do you happen to know which device is the one that is causing the error?

miway80 commented 4 years ago

Sorry for later answer, with the current master i get it

from miio import Gateway

gw = Gateway("192.168.123.123", "tokentokentoken") print(gw.devices())

pi@rpi:~ $ python3 mi.py Traceback (most recent call last): File "mi.py", line 4, in print(gw.devices()) TypeError: 'list' object is not callable

starkillerOG commented 4 years ago

@miway80 you schould use gw.discover_devices() to get the devices.

If you run that command and want to access the devices again you can use the gw.devices property (note that a property is not callable, there do not use brackets behind a property, that is the warning you are seeing).

miway80 commented 4 years ago

Good, thanks, with gw.discover_devices() i get many subdevices, but how can i read and modify states each subdevices? I want use it for plug and switch

Unknown subdevice type SubDeviceInfo(sid='lumi.158d0002013f4d', type_id=65, unkn own=1, unknown2=31, fw_ver=1) discovered, of Xiaomi gateway with ip: 192.168.31. 47 <Subdevice Unknown: lumi.158d0002013f4d fw: 1 bat: 60 props: {}>

With gw.devices i only get only []

starkillerOG commented 4 years ago

You need to run gw.discover_devices() and then gw.devices for the devices to show up in gw.devices. (gw.devices stores the devices that are discovered using gw.discover_devices() so you don't need to discover them again and again if you need to acces them a second time.)

The error about the Unknown subdevice is a devicetype "65" that is not yet implemented in the code because we don't know what kind of device it is. Could you look in the MiHome app under gateway-->...-->about--> hub_info, there schould be a list of all your subdevices showing the sid, model_info and name. Please find the device with sid='lumi.158d0002013f4d' and tell us what model_info is showing, and please explain what kind of device that is if you recognize the name.

starkillerOG commented 4 years ago

If a subdevice is implemented you can get info of the subdevice by executing the following code:

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)

The update() command will get the info from the device and then the properties can be vieuwd under the props: {} dict in print(dev). (to get the properties as a dict use property dev.status)

for control of specific subdevices see the implementation of that subdevice in the https://github.com/rytilahti/python-miio/blob/master/miio/gateway.py file.

from the looks of it the plug does not have control capabilty implemented yet, but I imagine that it will use very simular commands as the already implemented AqaraRelayTwoChannels, you are very welcome to implement control capability of the plug! since I do not own a plug I cannot implement it myself, but I am willing to give you directions to help you implement it.

miway80 commented 4 years ago

Thanks again, i just get info from hub_info, model: lumi.ctrl_86plug.aq1 is a wall plug as this photo https://http2.mlstatic.com/aqara-wall-outlet-zigbee-xiaomi-mi-aqara-marca-smart-wall-D_NQ_NP_750688-MLM32148824770_092019-F.jpg

I only want controller before wall plug and aqara wall one switch ( lumi.ctrl_neutral1.v1 ) https://gloimg.gbtcdn.com/soa/gb/pdm-product-pic/Electronic/2017/09/16/goods_img_big-v1/20170916200232_74480.jpg

miway80 commented 4 years ago

With this code

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)

I get

Unknown subdevice type SubDeviceInfo(sid='lumi.158d00015767a7', type_id=14, unknown=1, unknown2=0, fw_ver=4) discovered, of Xiaomi gateway with ip: 192.168.31.240 Unknown subdevice type SubDeviceInfo(sid='lumi.158d0002013f4d', type_id=65, unknown=1, unknown2=31, fw_ver=1) discovered, of Xiaomi gateway with ip: 192.168.31.240 <Subdevice Switch: lumi.158d0001f3b1b1 fw: 10 bat: 60 props: {}> <Subdevice Unknown: lumi.158d00015767a7 fw: 4 bat: 60 props: {}> <Subdevice SwitchOneChannel: lumi.158d00012e1f0c fw: 1 bat: 60 props: {}> <Subdevice SwitchOneChannel: lumi.158d0001614697 fw: 1 bat: 60 props: {}> <Subdevice SensorHT: lumi.158d0001f47015 fw: 2 bat: 60 props: {'temperature': 100.0, 'humidity': 0.0, 'pressure': 0.0}> <Subdevice Unknown: lumi.158d0002013f4d fw: 1 bat: 60 props: {}>

sid='lumi.158d00015767a7', type_id=14 == lumi.sensor_86sw1.v1 = aqara one switch wifi version sid='lumi.158d0002013f4d', type_id=65 == lumi.ctrl_86plug.aq1 = aqara wall plug

seems that SwitchOneChannel = lumi.ctrl_neutral1.v1

starkillerOG commented 4 years ago

@miway80 I just added the two device types in this PR: https://github.com/starkillerOG/python-miio/blob/patch-5/miio/gateway.py

The RemoteSwitchSingleV1 (lumi.sensor_86sw1.v1) will probably not have properties that you can get and will require this PR to be merged and fully implemented https://github.com/rytilahti/python-miio/pull/709, that will still take some time.

If you want to use the AqaraWallOutlet (lumi.ctrl_86plug.aq1), you will have to figure out what properties the device has, follow these steps in editing the gateway.py file: 1) add the devictypes to the class DeviceType(IntEnum) as is done in the mentioned PR 2) add the device to the device_type_mapping dict so the new dict becomes:

device_type_mapping = {
            DeviceType.AqaraRelayTwoChannels: AqaraRelayTwoChannels,
            DeviceType.Plug: AqaraPlug,
            DeviceType.SensorHT: SensorHT,
            DeviceType.AqaraHT: AqaraHT,
            DeviceType.AqaraMagnet: AqaraMagnet,
            DeviceType.AqaraSwitchOneChannel: AqaraSwitchOneChannel,
            DeviceType.AqaraSwitchTwoChannels: AqaraSwitchTwoChannels,
            DeviceType.AqaraWallOutlet: AqaraWallOutlet,
        }

3) add the following class at the bottom of the gateway.py file:

class AqaraWallOutlet(SubDevice):
    """Subdevice AqaraWallOutlet specific properties and methods"""

    properties = ["neutral_0", "load_power"]

    @attr.s(auto_attribs=True)
    class props:
        """Device specific properties"""

        status: str = None  # 'on' / 'off'
        load_power: int = None  # power consumption in ?unit?

    @command()
    def update(self):
        """Update all device properties"""
        values = self.get_property_exp(self.properties)
        self._props.status = values[0]
        self._props.load_power = values[1]

4) try it out, if it does not work you can also try "channel_0" as property 5) if that does not work or if you want to look if more properties are suported you will need to sniff the traffic of the MiHome app and figure out what the properties are, I succesfully sniffed traffic using BlueStack :

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.

if you also want to controll the wall outlet you will need to implement something like is done with the AqaraRelayTwoChannels class, but lets first try to see if getting the status will work.

@miway80 How experianced are you with programming?

miway80 commented 4 years ago

How experianced are you with programming? I am learning now in quarentine to program with tutorials..

Thank you very much, i just modified gateway.py and work for WallOulet, as do you said i changed neutral_0 by channel_0.

<Subdevice Switch: lumi.158d0001f3b1b1 fw: 10 bat: 60 props: {}> <Subdevice RemoteSwitchSingleV1: lumi.158d00015767a7 fw: 4 bat: 60 props: {}> <Subdevice SwitchOneChannel: lumi.158d00012e1f0c fw: 1 bat: 60 props: {}> <Subdevice SwitchOneChannel: lumi.158d0001614697 fw: 1 bat: 60 props: {}> <Subdevice SensorHT: lumi.158d0001f47015 fw: 2 bat: 60 props: {'temperature': 100.0, 'humidity': 0.0, 'pressure': 0.0}> <Subdevice AqaraWallOutlet: lumi.158d0002013f4d fw: 1 bat: 60 props: {'status': 'on', 'load_power': 587.86}>

Now the question is how can i change Status via python code? can i send any command for put Status on/off ?

Also i will try sniff trafic using BlueStack, i have some xiaomi goods, if i get sniff goods then i can add to gateway.py and share here

starkillerOG commented 4 years ago

Excelent, so the properties that worked are properties = ["channel_0", "load_power"] right? Could you look in the Mi Home app what unit the load_power is (is it 587.86 Watt)?

Are there any other properties besides status and load_power that are visable in the MiHome app?

to control the plug add this to the AqaraWallOutlet class:

    def toggle(self):
        """Toggle Aqara Wall Outlet"""
        return self.send_arg("toggle_ctrl_neutral", ["toggle"]).pop()

then you can test it by running:

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)

walloutlet = devices[5]

print(walloutlet.toggle())

if it does not work: 1) see if devices[5] is indeed the walloutlet device otherwise change the index 2) modify the parameters of the command try instead of ["toggle"]

miway80 commented 4 years ago

Excelent, so the properties that worked are properties = ["channel_0", "load_power"] right? yes, it is ok Could you look in the Mi Home app what unit the load_power is (is it 587.86 Watt)? yes, same power, 587.86

Are there any other properties besides status and load_power that are visable in the MiHome app? No, in Mihome app only put, Today, Month, Current, Turn on / Turn off, Schedule, Countdown

If only add it to gateway.py without modify mi.py i get a error, also if modify mi.py i get same error

python3 mi.py Traceback (most recent call last): File "mi.py", line 1, in from miio import Gateway File "/home/pi/.local/lib/python3.7/site-packages/miio/init.py", line 23, in from miio.gateway import Gateway File "/home/pi/.local/lib/python3.7/site-packages/miio/gateway.py", line 943 def toggle(self): ^ TabError: inconsistent use of tabs and spaces in indentation

starkillerOG commented 4 years ago

The error says it all: the indentation is wrong, apperently line 943 of the gateway.py file has a tab as indentation while the rest of the file uses spaces (or the other way around). just make sure you are consistant throughout the file. and probably also check your indentation, if everything uses the correct amount of tabs/spaces

miway80 commented 4 years ago

Sorry, i used tab and needed 2 spaces.. Now no identation error

I check again and i change ["toggle"] for this another ["channel_0", "toggle"], ["channel_0", "on"], ["channel_0", "off"],["on"],["off"] wit same result, seems that i need modify line 661 and 666

python3 mi.py <Subdevice Switch: lumi.158d0001f3b1b1 fw: 10 bat: 60 props: {}> <Subdevice RemoteSwitchSingleV1: lumi.158d00015767a7 fw: 4 bat: 60 props: {}> <Subdevice SwitchOneChannel: lumi.158d00012e1f0c fw: 1 bat: 60 props: {}> <Subdevice SwitchOneChannel: lumi.158d0001614697 fw: 1 bat: 60 props: {}> <Subdevice SensorHT: lumi.158d0001f47015 fw: 2 bat: 60 props: {'temperature': 100.0, 'humidity': 0.0, 'pressure': 0.0}> <Subdevice AqaraWallOutlet: lumi.158d0002013f4d fw: 1 bat: 60 props: {'status': 'on', 'load_power': 0.0}> Traceback (most recent call last): File "/home/pi/.local/lib/python3.7/site-packages/miio/gateway.py", line 661, in send_arg return self._gw.send(command, arguments, extra_parameters={"sid": self.sid}) TypeError: send() got an unexpected keyword argument 'extra_parameters'

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

Traceback (most recent call last): File "mi.py", line 15, in print(walloutlet.toggle()) File "/home/pi/.local/lib/python3.7/site-packages/miio/gateway.py", line 945, in toggle return self.send_arg("toggle_ctrl_neutral", ["toggle"]).pop() File "/home/pi/.local/lib/python3.7/site-packages/miio/gateway.py", line 666, in send_arg ) from ex miio.gateway.GatewayException: Got an exception while sending command 'toggle_ctrl_neutral' with arguments '['toggle']'

I just install BlueStack, but put can be not compatible with my hardware, i need a better laptop..

starkillerOG commented 4 years ago

The error above means that you still have old files of the latest release version, the master branch has more up to date files that include the "extra_parameters" capability mentioned in the error.

1) Make a backup of the gateway.py file that you have been modifing

2) Please go to the master branch of this code: https://github.com/rytilahti/python-miio and hit the green "clone or download" button. download all the files and replace all the files in your python installation of miio with the files in the miio folder that you just downloaded (except for the gateway.py file or put back your backup of the gateway.py file after you updated all files)

Then the error above schould go away.

starkillerOG commented 4 years ago

@miway80 if you finish testing the control command code fast, it might be in time for version 0.5.1 that is about to be released. I already made a PR to include the status reporting as you have tested: https://github.com/rytilahti/python-miio/pull/717

rytilahti commented 4 years ago

0.5.1 is already out, but I'm thinking about streamlining the release process to make it easier to make releases (and to shorter the cycle to wait for fixes to go out) in the future.

miway80 commented 4 years ago

Sorry for later answer, but i was working.. I did it, but i got this error

python3 mi.py Traceback (most recent call last): File "mi.py", line 1, in from miio import Gateway File "/home/pi/.local/lib/python3.7/site-packages/miio/init.py", line 2, in from importlib_metadata import version # type: ignore ModuleNotFoundError: No module named 'importlib_metadata'

Then i put # in line 2

from importlib_metadata import version # type: ignore

and got this error

python3 mi.py Traceback (most recent call last): File "mi.py", line 1, in from miio import Gateway File "/home/pi/.local/lib/python3.7/site-packages/miio/init.py", line 35, in from miio.vacuum import Vacuum, VacuumException File "/home/pi/.local/lib/python3.7/site-packages/miio/vacuum.py", line 18, in from .vacuumcontainers import ( File "/home/pi/.local/lib/python3.7/site-packages/miio/vacuumcontainers.py", line 6, in from croniter import croniter ModuleNotFoundError: No module named 'croniter'

I also update and upgrade all via sudo apt-get, strange error because i dont have vacuum

miway80 commented 4 years ago

Hi again, i tried to fix it, yesterday installed neccesary modules croniter-0.3.32.tar.gz, zipp-3.1.0.tar.gz and importlib_metadata-1.6.0.tar.gz, now only vacuum and discovery error

pi@rpi:~ $ python3 mi.py Traceback (most recent call last): File "mi.py", line 1, in from miio import Gateway File "/home/pi/.local/lib/python3.7/site-packages/miio/init.py", line 49, in from miio.discovery import Discovery File "/home/pi/.local/lib/python3.7/site-packages/miio/discovery.py", line 10, in from . import ( ImportError: cannot import name 'Vacuum' from 'miio' (/home/pi/.local/lib/python3.7/site-packages/miio/init.py)

I check miio files and have discovery.py

starkillerOG commented 4 years ago

@miway80 I do not know much about these import errors, however version 0.5.1 of python-miio has been released yesterday. So you schould now be able to simply run pip3 install --upgrade python-miio to get all the files and required modules up to date.

After you run that command you just need to reapply the changes that you made in the gateway.py file (just restore the backup of that file).

miway80 commented 4 years ago

@starkillerOG I just upgrade miio to 0.5.1. and restaure gateway.py but now i got other error

python3 mi.py <Subdevice Switch: lumi.158d0001f3b1b1 fw: 10 bat: 60 props: {}> <Subdevice RemoteSwitchSingleV1: lumi.158d00015767a7 fw: 4 bat: 60 props: {}> <Subdevice SwitchOneChannel: lumi.158d00012e1f0c fw: 1 bat: 60 props: {}> <Subdevice SwitchOneChannel: lumi.158d0001614697 fw: 1 bat: 60 props: {}> <Subdevice SensorHT: lumi.158d0001f47015 fw: 2 bat: 60 props: {'temperature': 10 0.0, 'humidity': 0.0, 'pressure': 0.0}> <Subdevice AqaraWallOutlet: lumi.158d0002013f4d fw: 1 bat: 60 props: {'status': 'on', 'load_power': 0.0}> Traceback (most recent call last): File "/home/pi/.local/lib/python3.7/site-packages/miio/gateway.py", line 661, in send_arg return self._gw.send(command, arguments, extra_parameters={"sid": self.sid}) File "/home/pi/.local/lib/python3.7/site-packages/miio/device.py", line 147, i n send command, parameters, retry_count, extra_parameters=extra_parameters File "/home/pi/.local/lib/python3.7/site-packages/miio/miioprotocol.py", line 203, in send self._handle_error(payload["error"]) File "/home/pi/.local/lib/python3.7/site-packages/miio/miioprotocol.py", line 263, in _handle_error raise DeviceError(error) miio.exceptions.DeviceError: {'code': -5005, 'message': 'params error'}

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

Traceback (most recent call last): File "mi.py", line 15, in print(walloutlet.toggle()) File "/home/pi/.local/lib/python3.7/site-packages/miio/gateway.py", line 945, in toggle return self.send_arg("toggle_ctrl_neutral", ["toggle"]).pop() File "/home/pi/.local/lib/python3.7/site-packages/miio/gateway.py", line 666, in send_arg ) from ex miio.gateway.GatewayException: Got an exception while sending command 'toggle_ct rl_neutral' with arguments '['toggle']'

starkillerOG commented 4 years ago

@miway80 This is good, basically the error tells you that you got a response from the gateway but that the parameter of the command (in this case "toggle") is invalid.

Now you just need to try and guess the command/parameter combo that will control your device.

I already posted a list of combos you can try, just play around a bit and see if some combo works.

If you cannot get it to work the only option is to sniff the traffic of the MiHome app with a program like Bluestack or something simular

miway80 commented 4 years ago

ok perfect, thank you, now i am finding a friend for leave me a new laptop, my old laptop give me problems with bluestack

I checked some paremeters return self.send_arg("toggle_ctrl_neutral", ["channel_0", "toggle"]).pop() return ok return self.send_arg("toggle_ctrl_neutral", ["channel_0", "on"]).pop() return ok but dont modify value return self.send_arg("toggle_ctrl_neutral", ["channel_0", "off"]).pop() return ok but dont modify value return self.send_arg("toggle_ctrl_neutral", ["off"]).pop() give error return self.send_arg("toggle_ctrl_neutral", ["on"]).pop() give error

starkillerOG commented 4 years ago

So self.send_arg("toggle_ctrl_neutral", ["channel_0", "toggle"]).pop() also actually toggled your wall outlet from on->off or off->on?

and self.send_arg("toggle_ctrl_neutral", ["channel_0", "on"]).pop() does nothing/does not turn it on when it is off? and self.send_arg("toggle_ctrl_neutral", ["channel_0", "off"]).pop() does nothing/does not turn it off when it is on?

miway80 commented 4 years ago

sorry i dont explain well

self.send_arg("toggle_ctrl_neutral", ["channel_0", "toggle"]).pop() also does nothing/does not turn it on when it is off, only return ok

starkillerOG commented 4 years ago

@miway80 you can try "toggle_plug" instead of "toggle_ctrl_neutral"

starkillerOG commented 4 years ago

or "set_power" with parameter "on"

miway80 commented 4 years ago

@starkillerOG toggle_plug work correctly!!

return self.send_arg("toggle_plug", ["channel_0", "toggle"]).pop() change one time on, later off return self.send_arg("toggle_plug", ["channel_0", "on"]).pop() change to on return self.send_arg("toggle_plug", ["channel_0", "off"]).pop() change to off
return self.send_arg("toggle_plug", ["off"]).pop() error return self.send_arg("toggle_plug", ["on"]).pop() error

How can i upload my gateway.py for share here?

Thank you very much

starkillerOG commented 4 years ago

@miway80 that is greath, I think we have figured out everything that is needed for the AqaraWallOutlet.

Could you check the code of PR https://github.com/rytilahti/python-miio/pull/717. I think I used all properties correctly as we discussed.

Than that PR can get merged and support will eventually be integrated in HomeAssistant.

miway80 commented 4 years ago

I just check and it is ok, there are more checked zigbee peripherals or it is the first? I will try check others with similar codes

starkillerOG commented 4 years ago

I have checked AqaraHT, @rytilahti has cheked SensorHT, and @bskaplou has implemented AqaraRelayTwoChannels. The rest still needs to be checked I think

miway80 commented 4 years ago

I have checked AqaraHT, @rytilahti has cheked SensorHT, and @bskaplou has implemented AqaraRelayTwoChannels. The rest still needs to be checked I think

Perfect, I have more Xiaomi goods, i will try do some procedure to try to connect with them and put here

miway80 commented 4 years ago

Good news! I just add SwitchOneChannel = 9 # lumi.ctrl_neutral1.v1

Need to modify . . device_type_mapping = { DeviceType.AqaraRelayTwoChannels: AqaraRelayTwoChannels, DeviceType.Plug: AqaraPlug, DeviceType.SensorHT: SensorHT, DeviceType.AqaraHT: AqaraHT, DeviceType.AqaraMagnet: AqaraMagnet, DeviceType.AqaraSwitchOneChannel: AqaraSwitchOneChannel, DeviceType.AqaraSwitchTwoChannels: AqaraSwitchTwoChannels, DeviceType.AqaraWallOutlet: AqaraWallOutlet, DeviceType.SwitchOneChannel: SwitchOneChannel, }

. .

class SwitchOneChannel(SubDevice): """Subdevice SwitchOneChannel specific properties and methods"""

properties = ["neutral_0"]

@attr.s(auto_attribs=True)
class props:
    """Device specific properties"""

    status: str = None  # 'on' / 'off'

@command()
def update(self):
    """Update all device properties"""
    values = self.get_property_exp(self.properties)
    self._props.status = values[0]

@command()
def toggle(self):
    """Toggle Switch One Channel"""
    return self.send_arg("toggle_ctrl_neutral", ["channel_0", "toggle"]).pop()

@command()
def on(self):
    """Turn on Switch One Channel"""
    return self.send_arg("toggle_ctrl_neutral", ["channel_0", "on"]).pop()

@command()
def off(self):
    """Turn off Switch One Channel"""
    return self.send_arg("toggle_ctrl_neutral", ["channel_0", "off"]).pop()
starkillerOG commented 4 years ago

@miway80 Nice, that is great! Could you make a Pull Request to include this code? I checked it and it looks good.

miway80 commented 4 years ago

I am trying make a Pull Request but i click in New and later green botton is disable, seems that i need compare with others for activate..

By other side, I tried connect others goods but seems that code have problem when gateway have many linked items, my other hub gateway have 40 items and when i tried discover devices give me a error, i tried increase value en data,addr but dont work

python3 mi.py Traceback (most recent call last): File "/home/pi/.local/lib/python3.7/site-packages/miio/miioprotocol.py", line 182, in send data, addr = s.recvfrom(1096) socket.timeout: timed out

During handling of the above exception, another exception occurred:

Traceback (most recent call last): File "mi.py", line 5, in gw.discover_devices() File "/home/pi/.local/lib/python3.7/site-packages/miio/gateway.py", line 167, in discover_devices devices_raw = self.get_prop("device_list") File "/home/pi/.local/lib/python3.7/site-packages/miio/gateway.py", line 206, in get_prop return self.send("get_device_prop", ["lumi.0", property]) File "/home/pi/.local/lib/python3.7/site-packages/miio/device.py", line 147, i n send command, parameters, retry_count, extra_parameters=extra_parameters File "/home/pi/.local/lib/python3.7/site-packages/miio/miioprotocol.py", line 226, in send extra_parameters=extra_parameters, File "/home/pi/.local/lib/python3.7/site-packages/miio/miioprotocol.py", line 150, in send self.send_handshake() File "/home/pi/.local/lib/python3.7/site-packages/miio/miioprotocol.py", line 62, in send_handshake header = m.header.value AttributeError: 'NoneType' object has no attribute 'header'

rytilahti commented 4 years ago

Looks like it's hitting the timeout, maybe rising that could help?

For contribution workflow, you should have a fork of this repository, where you work on the feature in a separate branch. After you push that modified branch to github, you will be shown a button to create a PR on github.

starkillerOG commented 4 years ago

@miway80 to start with a simple Pull Request: 1) go to the file you wish to edit, in this case: https://github.com/rytilahti/python-miio/blob/master/miio/gateway.py (make sure you are on the "master" brance wich is visible at the top left besides the file path) 2) Hit the pencile icon ("edit") on the top right of the file box 3) Make the changes that you want 4) type in a title and discribtion of the PR at the bottom 5) hit the green Propose changes button 6) A new fork will be created on your github acount and there schould apear a green button at the top to create a Pull Request to the original repositry (this reposity of rytilahti).

If you want to make more complicated changes and edit multiple files at once, check out Github Desktop https://desktop.github.com/

for even more advanced PRs you can setup a HomeAssistant devolpment enviroment on your (windows) PC to test out code and make checks: https://developers.home-assistant.io/docs/development_environment/ https://developers.home-assistant.io/docs/development_testing (but that is way overkill for the PR you want to create now) The 6 tests that I always run are (example is the HomeAssistant implementation of xiaomi miio gateway):

black homeassistant/components/xiaomi_miio/gateway.py
isort homeassistant/components/xiaomi_miio/gateway.py
flake8 homeassistant/components/xiaomi_miio
pylint homeassistant/components/xiaomi_miio
pydocstyle homeassistant/components/xiaomi_miio
pytest --cov=homeassistant/components/xiaomi_miio/ --cov-report term-missing -- tests/components/xiaomi_miio/test_*.py
miway80 commented 4 years ago

Looks like it's hitting the timeout, maybe rising that could help?

Timeout by default = 5, i check with 10 until 20 then error repeat sometimes

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

During handling of the above exception, another exception occurred:

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

During handling of the above exception, another exception occurred:

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

During handling of the above exception, another exception occurred:

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

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

Traceback (most recent call last): File "mi.py", line 5, in gw.discover_devices() File "/home/pi/.local/lib/python3.7/site-packages/miio/gateway.py", line 167, in discover_devices devices_raw = self.get_prop("device_list") File "/home/pi/.local/lib/python3.7/site-packages/miio/gateway.py", line 206, in get_prop return self.send("get_device_prop", ["lumi.0", property]) File "/home/pi/.local/lib/python3.7/site-packages/miio/device.py", line 147, in send command, parameters, retry_count, extra_parameters=extra_parameters File "/home/pi/.local/lib/python3.7/site-packages/miio/miioprotocol.py", line 226, in send extra_parameters=extra_parameters, File "/home/pi/.local/lib/python3.7/site-packages/miio/miioprotocol.py", line 226, in send extra_parameters=extra_parameters, File "/home/pi/.local/lib/python3.7/site-packages/miio/miioprotocol.py", line 226, in send extra_parameters=extra_parameters, File "/home/pi/.local/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

I also i modify data, addr = s.recvfrom(1096) to 2196, 4384, etc.. but always some error

@miway80 to start with a simple Pull Request:

  1. go to the file you wish to edit, in this case: https://github.com/rytilahti/python-miio/blob/master/miio/gateway.py (make sure you are on the "master" brance wich is visible at the top left besides the file path)
  2. Hit the pencile icon ("edit") on the top right of the file box
  3. Make the changes that you want
  4. type in a title and discribtion of the PR at the bottom
  5. hit the green Propose changes button
  6. A new fork will be created on your github acount and there schould apear a green button at the top to create a Pull Request to the original repositry (this reposity of rytilahti).

If you want to make more complicated changes and edit multiple files at once, check out Github Desktop https://desktop.github.com/

for even more advanced PRs you can setup a HomeAssistant devolpment enviroment on your (windows) PC to test out code and make checks: https://developers.home-assistant.io/docs/development_environment/ https://developers.home-assistant.io/docs/development_testing (but that is way overkill for the PR you want to create now) The 6 tests that I always run are (example is the HomeAssistant implementation of xiaomi miio gateway):

black homeassistant/components/xiaomi_miio/gateway.py
isort homeassistant/components/xiaomi_miio/gateway.py
flake8 homeassistant/components/xiaomi_miio
pylint homeassistant/components/xiaomi_miio
pydocstyle homeassistant/components/xiaomi_miio
pytest --cov=homeassistant/components/xiaomi_miio/ --cov-report term-missing -- tests/components/xiaomi_miio/test_*.py

Thank you very much, i just do it correctly, also i will check HomeAssistant devolpment later

starkillerOG commented 4 years ago

@miway80 did you try to get gateway info and see if it does respond to that request? (Than you can check if it is a problem with comunicating with the gateway or if it is specific to the discover_devices call which might be related to the large list of devices you have)

from miio import Gateway

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

print(gateway.info())

Amazing that you have 40 aqara devices! That is greath, than we can probably implement many models!

starkillerOG commented 4 years ago

@miway80 did you use the correct token for the second gateway? That probably has a diffrent token...

miway80 commented 4 years ago

print(gateway.info())

Yes i have about 50 aqara devices.. I just execute this code and receive it

lumi.gateway.v3 v1.4.1_175 (34:CE:00:77:C8:XX) @ 192.168.31.224 - token: tokentokentoken

Then can comunicate with gateway correctly, token and ip is ok, i think that problem is many devices linked

starkillerOG commented 4 years ago

And what about sniffing network trafic using for instance wireshark to see of the gateway sends something back as a response to the discover_devices call? In that wat we can see if there is a response at all that just can not be accepted by xiaomi miio due to timeout or too small buffer or something

miway80 commented 4 years ago

I am exactly on that, I have already downloaded 2 old versions of BlueStack but I cannot get mihome to work, i have Chinesse region and give me problems

starkillerOG commented 4 years ago

Because we already know the commands you won't need bluestack for this, just use python-miio and wireshark. Python-miio makes the request (schould be picked up by wireshark) and then look in wireshark for a response from the gateway

miway80 commented 4 years ago

Finally i tried in windows and many problems now with wireshark and visual basic.. but i take a other old laptop with linux mint and work correctly, windows is getting worse each time..

There any manual for get info from wireshark? there are 4 options Cisco remote Random package SSH remote UDP Listener

Tomorrow i will investigate it with more time

starkillerOG commented 4 years ago

Just open wireshark, select all interfaces and start a capture. Then type in the filter and apply the filter: ip.src==192.168.1.IP or ip.dst==192.168.1.IP with IP the ip-adress of the xiaomi gateway

Now you schould see UDP packets beeing captured when you sent stuff to the gateway and you schould also see responses from the gateway. Note that you need to communicate from the same device as wireshark is running and do not use VPN's while you are capturing.

Miio protecoll uses encryption with the token so you cant directly read the packets. 1) Stop the capture 2) click file--> Export packet dissections --> As json 3) save the file somewhere 4) install miIO Device Library using npm https://github.com/aholstenson/miio npm install -g miio 5) in command prompt type (using the path of the file of step 2 and the token of your gateway): miio protocol json-dump path-to-json-file-of-step-2 --token TokenTokenToken 6) this schould now show you the decrypted packets