Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Unable to discover Xiaomi Philips LED Bulb #106

Closed
mals opened this issue Oct 29, 2017 · 17 comments
Closed

Unable to discover Xiaomi Philips LED Bulb #106

mals opened this issue Oct 29, 2017 · 17 comments

Comments

@mals
Copy link

mals commented Oct 29, 2017

I'm unable to connect to my Xiaomi Philips LED bulb using home-assistant 0.56.2 with python-miio 0.3.0. I'm running into the following error:

2017-10-29 17:16:11 INFO (MainThread) [homeassistant.components.light.xiaomi_miio] Initializing with host 192.168.4.14 (token ddd6b...) 2017-10-29 17:16:16 ERROR (MainThread) [miio.device] Unable to discover a device at address 192.168.4.14

I've tried to use python-miio directly to connect to the device and I'm getting the following error:

from miio import *
a = Device('192.168.4.14', 'ddd...')
a.info()
Unable to discover a device at address 192.168.4.14
Traceback (most recent call last):
File "", line 1, in
File "/usr/local/lib/python3.5/dist-packages/miio/device.py", line 231, in info
return DeviceInfo(self.send("miIO.info", []))
File "/usr/local/lib/python3.5/dist-packages/miio/device.py", line 165, in send
self.do_discover()
File "/usr/local/lib/python3.5/dist-packages/miio/device.py", line 118, in do_discover
raise DeviceException("Unable to discover the device %s" % self.ip)
miio.device.DeviceException: Unable to discover the device 192.168.4.14

Please let me know if I can provide any further information. Thanks!

@rytilahti
Copy link
Owner

It means the device is not answering to the handshake, which could be caused by your network setup among other things, so there is no simple solution for this.

@mals
Copy link
Author

mals commented Nov 2, 2017

For some reason the Xiaomi Philips LED Ball (firmware 1.3.0__0032) doesn't respond to the initial helo request. I have a Xiaomi vacuum on the same subnet which does respond.

I've used some prototype code (from https://notes.jmsinfor.com/blog/post/admin/Xiaomi-Hub) to simply send the helo packet and wait for a response.

Xiaomi Philips LED Ball:

./test1.py 
UDP target IP: 192.168.4.15
UDP target port: 54321
message:
        b'21310020ffffffffffffffffffffffffffffffffffffffffffffffffffffffff'

Vacuum:

./test1.py 
UDP target IP: 192.168.4.30
UDP target port: 54321
message:
         b'21310020ffffffffffffffffffffffffffffffffffffffffffffffffffffffff'
received message:
         b'213100200000000003dae61a59fb3396ffffffffffffffffffffffffffffffff'
token: b'3396'

Is anyone running into a similar issue?

@mals
Copy link
Author

mals commented Nov 5, 2017

I believe the protocol has changed in the latest firmware. It seems that the bulb only responds to the host sending the packet on UDP 8053 during the discover process.

I modified device.py to bind to port 8053 during the discover process and I was able to get the bulb to respond:

diff --git a/miio/device.py b/miio/device.py
index eaf1adf..f5d7e3f 100644
--- a/miio/device.py
+++ b/miio/device.py
@@ -137,6 +137,7 @@ class Device:
         s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
         s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
         s.settimeout(timeout)
+        s.bind(("0.0.0.0", 8053))
         s.sendto(helobytes, (addr, 54321))
         while True:
             try:

However, I'm now running into some errors. Here is the output from miceil:

INFO:miio.ceil_cli:Debug mode active
DEBUG:miio.ceil_cli:Connecting to 192.168.4.103 with token b...e590d4
DEBUG:miio.protocol:Unable to decrypt, returning raw bytes.
DEBUG:miio.device:Got a response: Container: 
    data = Container: 
        value =  (total 0)
        length = 0
        data =  (total 0)
        offset2 = 32
        offset1 = 32
    header = Container: 
        value = Container: 
            length = 32
            unknown = 4294967295
            devtype = 65535
            serial = 65535
            ts = 2038-01-19 03:14:07
        length = 16
        data = !1\x00 \xff\xff\xff\xff\xff\xff\xff\xff\x7f\xff\xff\xff (total 16)
        offset2 = 16
        offset1 = 0
    checksum = \x00\x00\x00\x00\x03\x9e\x1c'0\x97\xff?O\x04\x10@ (total 16)
DEBUG:miio.device:Discovered 65535 65535 with ts: 2038-01-19 03:14:07, token: b'00000000039e1c273097ff3f4f041040'
DEBUG:miio.device:192.168.4.103:54321 >>: {'method': 'get_prop', 'id': 3, 'params': ['power', 'bright', 'cct', 'snm', 'dv', 'bl', 'ac']}
ERROR:miio.device:Got error when receiving: timed out

@mals
Copy link
Author

mals commented Nov 5, 2017

I believe I resolved the timeout error by binding to port 8053 during the send command in device.py

diff --git a/miio/device.py b/miio/device.py
index eaf1adf..642e96c 100644
--- a/miio/device.py
+++ b/miio/device.py
@@ -137,6 +137,7 @@ class Device:
         s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
         s.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
         s.settimeout(timeout)
+        s.bind(("0.0.0.0", 8053))
         s.sendto(helobytes, (addr, 54321))
         while True:
             try:
@@ -188,6 +189,7 @@ class Device:
                           self._timeout, Message.parse(m, ctx))
 
         s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+        s.bind(("0.0.0.0", 8053))
         s.settimeout(self._timeout)
 
         try:

Now, I'm running into the following error:

INFO:miio.ceil_cli:Debug mode active
DEBUG:miio.ceil_cli:Connecting to 192.168.4.103 with token b047fd319d7bc9c7e57d1bd297e590d4
DEBUG:miio.protocol:Unable to decrypt, returning raw bytes.
DEBUG:miio.device:Got a response: Container: 
    data = Container: 
        data =  (total 0)
        length = 0
        offset1 = 32
        offset2 = 32
        value =  (total 0)
    header = Container: 
        data = !1\x00 \xff\xff\xff\xff\xff\xff\xff\xff\x80\x00\x00\x04 (total 16)
        length = 16
        offset1 = 0
        offset2 = 16
        value = Container: 
            length = 32
            unknown = 4294967295
            devtype = 65535
            serial = 65535
            ts = 2038-01-19 03:14:12
    checksum = \x00\x00\x00\x00\x03\x9e\x1c'0\x97\xff?O\x04\x10@ (total 16)
DEBUG:miio.device:Discovered 65535 65535 with ts: 2038-01-19 03:14:12, token: b'00000000039e1c273097ff3f4f041040'
DEBUG:miio.device:192.168.4.103:54321 >>: {'method': 'get_prop', 'params': ['power', 'bright', 'cct', 'snm', 'dv', 'bl', 'ac'], 'id': 3}
DEBUG:miio.protocol:Unable to decrypt, returning raw bytes.
Traceback (most recent call last):
  File "/usr/local/bin/miceil", line 11, in <module>
    sys.exit(cli())
  File "/usr/local/lib/python3.5/dist-packages/click/core.py", line 722, in __call__
    return self.main(*args, **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/click/core.py", line 697, in main
    rv = self.invoke(ctx)
  File "/usr/local/lib/python3.5/dist-packages/click/core.py", line 1043, in invoke
    return Command.invoke(self, ctx)
  File "/usr/local/lib/python3.5/dist-packages/click/core.py", line 895, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/usr/local/lib/python3.5/dist-packages/click/core.py", line 535, in invoke
    return callback(*args, **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/click/decorators.py", line 17, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/miio/ceil_cli.py", line 82, in cli
    ctx.invoke(status)
  File "/usr/local/lib/python3.5/dist-packages/click/core.py", line 535, in invoke
    return callback(*args, **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/click/decorators.py", line 64, in new_func
    return ctx.invoke(f, obj, *args[1:], **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/click/core.py", line 535, in invoke
    return callback(*args, **kwargs)
  File "/usr/local/lib/python3.5/dist-packages/miio/ceil_cli.py", line 95, in status
    res = dev.status()
  File "/usr/local/lib/python3.5/dist-packages/miio/ceil.py", line 72, in status
    properties
  File "/usr/local/lib/python3.5/dist-packages/miio/device.py", line 208, in send
    self.__id = m.data.value["id"]
TypeError: byte indices must be integers or slices, not str

@syssi
Copy link
Collaborator

syssi commented Nov 5, 2017

Why did you pick port 8053?

@mals
Copy link
Author

mals commented Nov 5, 2017

I was capturing packets between the bulb and Xiaomi's servers and the bulb was sending data to 8053 so I gave it a shot and it worked.

@syssi
Copy link
Collaborator

syssi commented Nov 5, 2017

Could you try some more ports? I assume we cannot use your fix because a single static port would prevent the execution of two parallel miio calls. The port can be only bound once.

@rytilahti
Copy link
Owner

DEBUG:miio.protocol:Unable to decrypt, returning raw bytes.
that is the real warning here, that case should only happen for the initial handshake. Maybe they have changed the communication protocol / encryption routines for these devices?

You could try to change the exception handler in https://github.com/rytilahti/python-miio/blob/master/miio/protocol.py#L139 to print out the exception:

except Exception as ex:
    _LOGGER.debug("unable to decrypt: %s", ex)

to see what exception is being thrown out.

@mals
Copy link
Author

mals commented Nov 6, 2017

@syssi - It seems as though the bulb always initiates a connection to Xiaomi's servers on 8053. I'll write a script to see if it ends up responding on other ports.

@rytilahti: The exception is invalid padding bytes

DEBUG:miio.device:Discovered 65535 65535 with ts: 2038-01-19 03:14:09, token: b'00000000039e1c273097ff3f4f041040'
DEBUG:miio.device:192.168.4.103:54321 >>: {'params': ['power', 'bright', 'cct', 'snm', 'dv', 'bl', 'ac'], 'method': 'get_prop', 'id': 3}
DEBUG:miio.protocol:unable to decrypt: Invalid padding bytes.

@syssi
Copy link
Collaborator

syssi commented Nov 26, 2017

Can you tell me the firmware version of your light bulb? Please try to use the mihome app for a firmware update. I'm unable to reproduce your behavior. This is my firmware version: 1.3.0_0032.

@mals
Copy link
Author

mals commented Nov 28, 2017

That's interesting. My bulbs are on firmware 1.3.0_0032 as well. I'm unsure why mine are not working. The only thing I can think of is that I have them on a separate vlan with my other IOT devices including yeelight bulbs and mi vacuum, which are working. Any ideas?

@syssi
Copy link
Collaborator

syssi commented Nov 28, 2017

Has your bulb internet access? Could you setup a small and standard WiFi network (AP + Bulb + miio host) for testing?

@marcelrv
Copy link

marcelrv commented Nov 28, 2017 via email

@mals
Copy link
Author

mals commented Nov 28, 2017

@marcelrv Thanks a lot for that info! I managed to get the bulb working by NAT'ing traffic to the bulb from my VLAN which has my homeassistant server. You may want to give that a go to see if it works for you.

@mals
Copy link
Author

mals commented Nov 28, 2017

@syssi and @rytilahti - Thanks a lot for your help with this as well! I believe the bulb was responding when I sent a packet from UDP 8053 because it thought it was talking to Xiaomi's servers, which would not be on the same network. However, it seems the protocol which Xiaomi's servers use is different from the LAN protocol.

@syssi
Copy link
Collaborator

syssi commented Dec 1, 2017

Is the issue solved and can we close the issue?

@mals
Copy link
Author

mals commented Dec 1, 2017 via email

@syssi syssi closed this as completed Dec 2, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants