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

Tuya Protocol 3.5 - Globe lightbulb - Unexpected payload in scan & can't control #247

Closed
Xilef11 opened this issue Jan 5, 2023 · 70 comments · Fixed by #261
Closed

Tuya Protocol 3.5 - Globe lightbulb - Unexpected payload in scan & can't control #247

Xilef11 opened this issue Jan 5, 2023 · 70 comments · Fixed by #261
Labels
tuya_device Support for specific Tuya Devices

Comments

@Xilef11
Copy link

Xilef11 commented Jan 5, 2023

Hi,
I have an RGB lightbulb that I'm trying to control, and although the wizard managed to pull the device information and local key from the cloud, I can't control the device. The scan finds it, but gets an "unexpected payload":

python -m tinytuya scan -nocolor

TinyTuya (Tuya device scanner) [1.9.1]

[Loaded devices.json - 1 devices]

Scanning on UDP ports 6666 and 6667 for devices (16 retries)...

*  Unexpected payload=%r
 b'\x13@\x8d(H\x7f`\xe3\xb9Muf<\x97Ej\xaf)@\xd4\xe0\xdf\x19\xfa\x04,\xa6Bm\xceK\x0f;fuE j\x01\x129S\n\xb6\xb0"\xeb\xc7\xf9mn\xa0\x15\xd2T\xa8f\x93\x85\x94\xa5pEi\xd0\xeeY\x1100\'\xfao\x946\x07\xeb\x99\xe8\x17]\x1e\xdc\x87\xa20\xf4\t\x8d\xd4\xc5$\xd9\r\x94\xea6\xcc\x0c\x8c\xfb\x9b\xce /A\xa0\xfb\xb9gn\xcb\x04\x0e\xd4Hb\xb6t\xb1\xbe\xbeO\x18w\xdb\xbf\xad\xf0\xe90>r\xa4\xa1\x1a\xdf\xd1O$f\x10\xa6\xf9gt\x07\x01\x82\xa9\xd4\x87\x8f\xbb\xc6u\xeb\'\xbe\xbbv6\xe0\xc6\xae\xf6\xa4\\\xe9}\x1e\xa359B\x15\xb3W\xeb\x14\x11=q;\x96\xac\xcc8\xd3ZF\x19m\xb7\xf6"\x17\x9bA\xfe=\x97\xdbL\n\xcdt\x1d\xe3\x95T>I\x94\xfa\xa7p\xb1\x87x\x97\xb7\xbb\x81\xfe\xd9gH\xf2\x0e\x86B\xd1'
Unknown v Device   Product ID =   [Unknown payload]:
    Address = 192.168.2.46,  Device ID = , Local Key = ,  Version = , MAC =
    No Stats for 192.168.2.46: DEVICE KEY required to poll for status
*  Unexpected payload=%r
 b'\x13@\x8d(H\x7f`\xe3\xb9Muf<\x97Ej\xaf)@\xd4\xe0\xdf\x19\xfa\x04,\xa6Bm\xceK\x0f;fuE j\x01\x129S\n\xb6\xb0"\xeb\xc7\xf9mn\xa0\x15\xd2T\xa8f\x93\x85\x94\xa5pEi\xd0\xeeY\x1100\'\xfao\x946\x07\xeb\x99\xe8\x17]\x1e\xdc\x87\xa20\xf4\t\x8d\xd4\xc5$\xd9\r\x94\xea6\xcc\x0c\x8c\xfb\x9b\xce /A\xa0\xfb\xb9gn\xcb\x04\x0e\xd4Hb\xb6t\xb1\xbe\xbeO\x18w\xdb\xbf\xad\xf0\xe90>r\xa4\xa1\x1a\xdf\xd1O$f\x10\xa6\xf9gt\x07\x01\x82\xa9\xd4\x87\x8f\xbb\xc6u\xeb\'\xbe\xbbv6\xe0\xc6\xae\xf6\xa4\\\xe9}\x1e\xa359B\x15\xb3W\xeb\x14\x11=q;\x96\xac\xcc8\xd3ZF\x19m\xb7\xf6"\x17\x9bA\xfe=\x97\xdbL\n\xcdt\x1d\xe3\x95T>I\x94\xfa\xa7p\xb1\x87x\x97\xb7\xbb\x81\xfe\xd9gH\xf2\x0e\x86B\xd1'
*  Unexpected payload=%r
 b'\xbb\xcfh+@\x0b\xe6t\x0c\x83H\'\xb1-\xdc\xb9D\xc2\xc7\x08\x8a\x13\xaf]\x8b4\xda\x17\x847\xdfn\xb7\x81v\xcf\xf2\';\x10\x1f\x1bA;(#\xca3r\x83U\xdeh\xa6\xfe>\xd2"YH\xaf\xf0\'\x9aV}\x08uIs\xdf\xd0\x12\x826\xae\x1e%){+{ijJk\x18\x9e\xfb\xdetp\xe3V2\xa1\x1f\x02\xef@\xee\x05\xc2\xddy\xb4\x88oF\x97\xc2\x04\x1aW<rJ $\x89.y\x0b\x89\x86\x81\xd6\x08i\xc0\x0b\xf7\xa3~\xd1\x98%\x11\xb9\xe7\xc0\xb7\x9c+\x16\xc0\xf7\xb9\xe1\xc3\xb0\x89d\xd2\xb2\x0b\x19\xa5\xd6s\x01\x0e,/v~=iVe\tv\xa4 A0\xf5\x02\xf1\xae$\x18\xfc\x91\xaf\xc9?\xf74\x19z\xe9\x0e)\x02\xc1\xa2?5\xf1\xf02\x17N\xf6\xa1\xf3\x87\x81t\x0e\xa3(\x9d\xbf\x17\xa8jrE\x06\x1d\x92\xf0\xa8n\xd6\xa5\xf2\x82P\xa6;'
*  Unexpected payload=%r
 b'\xbb\xcfh+@\x0b\xe6t\x0c\x83H\'\xb1-\xdc\xb9D\xc2\xc7\x08\x8a\x13\xaf]\x8b4\xda\x17\x847\xdfn\xb7\x81v\xcf\xf2\';\x10\x1f\x1bA;(#\xca3r\x83U\xdeh\xa6\xfe>\xd2"YH\xaf\xf0\'\x9aV}\x08uIs\xdf\xd0\x12\x826\xae\x1e%){+{ijJk\x18\x9e\xfb\xdetp\xe3V2\xa1\x1f\x02\xef@\xee\x05\xc2\xddy\xb4\x88oF\x97\xc2\x04\x1aW<rJ $\x89.y\x0b\x89\x86\x81\xd6\x08i\xc0\x0b\xf7\xa3~\xd1\x98%\x11\xb9\xe7\xc0\xb7\x9c+\x16\xc0\xf7\xb9\xe1\xc3\xb0\x89d\xd2\xb2\x0b\x19\xa5\xd6s\x01\x0e,/v~=iVe\tv\xa4 A0\xf5\x02\xf1\xae$\x18\xfc\x91\xaf\xc9?\xf74\x19z\xe9\x0e)\x02\xc1\xa2?5\xf1\xf02\x17N\xf6\xa1\xf3\x87\x81t\x0e\xa3(\x9d\xbf\x17\xa8jrE\x06\x1d\x92\xf0\xa8n\xd6\xa5\xf2\x82P\xa6;'
*  Unexpected payload=%r
 b'RU8\xd9\t&\xec\xee]\xces6*:0\x02\xab\xe3\xfe\xa1\xf5\xf7a7\xde\xdc\xac\xb87\xa0\xc3\xe4\xc2\xfc\xff\xab.u\xeb\x93\x8bx\xc4>\xee\xafX%p\xb8\xa2\xd6L\x058M\xea\xb25\xdbs\x82\x0c\xad\xab\xfc\xa1`\xb3N7\xabM\xf4\xe9\x89D%So\xc0\x1fpG\xfc\xd5\xef\x1f\xabd\xda\xa0h\xbf\xf0cE\xdc)G\x87o\xe4\xc6=te\x1d\x0e:9\xf0\x0c\xb5\xf3\xb4\xc8\xcd\x81^zOU\xf9J\xd8\x9b\xb78\xe5\x92\x10Y\x93\xd30\xe2\xe6\xfe\xa6\xb3\t2\x84\xa8\xc9\x1b\xf3\xb8y\xeb\xdf\xa1*\xb6\xea\xf0\xcd\xebH\xac\xa1\xfa\xaa\x0e\x91\xa2\x1cD\x0eg\x81t\x0c\xf0Z\x8c\x8836"\xa1\xa4\xf1y+Y~Ot(\xee\x1eqF \xd4GsZ\xc2*\xa3}\x19\x15D.\xad\x19\xeb9\xfd\x9e\x9f>e\x80\xdd\xaf\xd44\xf4.\xc4\xf3\xd4\xd8+\xeb>!\xbc'
*  Unexpected payload=%r
 b'RU8\xd9\t&\xec\xee]\xces6*:0\x02\xab\xe3\xfe\xa1\xf5\xf7a7\xde\xdc\xac\xb87\xa0\xc3\xe4\xc2\xfc\xff\xab.u\xeb\x93\x8bx\xc4>\xee\xafX%p\xb8\xa2\xd6L\x058M\xea\xb25\xdbs\x82\x0c\xad\xab\xfc\xa1`\xb3N7\xabM\xf4\xe9\x89D%So\xc0\x1fpG\xfc\xd5\xef\x1f\xabd\xda\xa0h\xbf\xf0cE\xdc)G\x87o\xe4\xc6=te\x1d\x0e:9\xf0\x0c\xb5\xf3\xb4\xc8\xcd\x81^zOU\xf9J\xd8\x9b\xb78\xe5\x92\x10Y\x93\xd30\xe2\xe6\xfe\xa6\xb3\t2\x84\xa8\xc9\x1b\xf3\xb8y\xeb\xdf\xa1*\xb6\xea\xf0\xcd\xebH\xac\xa1\xfa\xaa\x0e\x91\xa2\x1cD\x0eg\x81t\x0c\xf0Z\x8c\x8836"\xa1\xa4\xf1y+Y~Ot(\xee\x1eqF \xd4GsZ\xc2*\xa3}\x19\x15D.\xad\x19\xeb9\xfd\x9e\x9f>e\x80\xdd\xaf\xd44\xf4.\xc4\xf3\xd4\xd8+\xeb>!\xbc'
*  Unexpected payload=%r
 b'\x99\xee\xe8L\xea\xb1\xf1\x83\xb2\xd5\xa8\xc0\xa9\x02/\xe5\x0b-\t\xaa]\x99\x8cy\x009\x0cp\x8eyd\xdeb\x97\x94\x94\xc6\x99r\xaa\x8a\xdcfM\xce\xa3\x8cB^\xbf\x92\xa0y_\xd5\xa1CT\xa9\x87\xd9\xbb#%\xcb\xbe%\x02\r\xa15\xad\xaaV\r\xfb\x17\xfd\xda,O\x03N8\x9c\x9a%\xd7\xc8\xd6\xaf\x02\x91\xb9\xc7\xf0\x81\x9c\xf0=\x08\xd3\xc3\\\xa1\x1a%\xb8\x82\xa3\xda\xa0\x03\x9d\x15y\x08\x7f\xc4\xb8h\xdc5\x18\xd0\xa6/\x03\xc1\xae\xe9P\x9e\x98\xfaT&(1\xf1\xe1oj$K\x88-\x89\xde\x1c>\xf1\x080\x82\x8d\x15\xad\xdad"\x8ds\xdd\x18\xa5\xb5rku\x07\xcf\xc6\xb5\xc0\x0e\xffp\xfa\xe0B\x00s\x13\xbc\xe3\xe61(\xe6\xa3\x84a{?\x1b\'\xc6\xa9\x8a\xce~\xbd\xc0\xd4\r\\\xcb];\t\x80$\xcf\xd6\xa3\xb0\xa3\x8eO\xf1I\x9c\xb6\x0b\xc3Q\xbc\xdekR\x18\x00'
*  Unexpected payload=%r
 b'\x99\xee\xe8L\xea\xb1\xf1\x83\xb2\xd5\xa8\xc0\xa9\x02/\xe5\x0b-\t\xaa]\x99\x8cy\x009\x0cp\x8eyd\xdeb\x97\x94\x94\xc6\x99r\xaa\x8a\xdcfM\xce\xa3\x8cB^\xbf\x92\xa0y_\xd5\xa1CT\xa9\x87\xd9\xbb#%\xcb\xbe%\x02\r\xa15\xad\xaaV\r\xfb\x17\xfd\xda,O\x03N8\x9c\x9a%\xd7\xc8\xd6\xaf\x02\x91\xb9\xc7\xf0\x81\x9c\xf0=\x08\xd3\xc3\\\xa1\x1a%\xb8\x82\xa3\xda\xa0\x03\x9d\x15y\x08\x7f\xc4\xb8h\xdc5\x18\xd0\xa6/\x03\xc1\xae\xe9P\x9e\x98\xfaT&(1\xf1\xe1oj$K\x88-\x89\xde\x1c>\xf1\x080\x82\x8d\x15\xad\xdad"\x8ds\xdd\x18\xa5\xb5rku\x07\xcf\xc6\xb5\xc0\x0e\xffp\xfa\xe0B\x00s\x13\xbc\xe3\xe61(\xe6\xa3\x84a{?\x1b\'\xc6\xa9\x8a\xce~\xbd\xc0\xd4\r\\\xcb];\t\x80$\xcf\xd6\xa3\xb0\xa3\x8eO\xf1I\x9c\xb6\x0b\xc3Q\xbc\xdekR\x18\x00'
*  Unexpected payload=%r
 b'Df\xa6L\xa4\xfc\xa4\x18\xb5\xceJ\x8dN`.j\x8c\xaf\x90)4\xfa\r\xach%p\x7f\x1e9h\xc2\xd62kP\xb9\xa7\xc1\x01\x83\xde\n\xdf\xca\xd0|\x19\xcfZ~\xc4\xb3\xd9x-M\xa2qk\xa5\x9evz3\xa5\xa2/%\x06\xf4\x8c\xe4\x86a\x9f\xc0^.Y\xabf\xd2\xc0\xce\xadF&T\x1c\x01.\x831\x11\xf07\xcb\x95M\x83cX\xba4%L^\xb1\x96\x13\x0c"\xb1;\xcc/\x93R\xbeX3t8\x16\xc6v*\x1a\xfe9\xfe0<=\xfc\x80\x12\x9e%B\xae\x1a\xcci\xfb\xf57\xe3\x04\xa3\x1b\xe9\xbc@aB\xfd{d\xf5[l{h\xe3\xd5n|j\x8c\x82*\xfe\xa2O.\xf3w(\x86%wg\x9b\x83c*\xe4J\x8as\xd8}\xa48\xc4\xb4Id\xad\x9a\xf7\x08P\x07!\xbc\x8c\xd2\xf6\xcd\xb8\xd3j\xe3?\xa7O\xe2\x86%\xac\xfc;|\xa7\xa3)\x83n\xf1\xcb'

Scan Complete!  Found 1 devices.

>> Saving device snapshot data to snapshot.json

When trying to send commands, I get {'Error': 'Timeout Waiting for Device', 'Err': '902', 'Payload': 'Check device key or version'}. I tried all protocol versions and the "device22" device type, to no avail. Enabling debug mode only reveals a "timeout in _send_receive()" and no reply from the bulb. Control using tinytuya.Cloud works perfectly. I can ping the bulb's IP with no problem.

I checked the datapoint codes on the website and they seem to match the "version 3.3 - light type (RGB)" table in the README. However, trying to set these values through code doesn't work.

Any ideas?
Thanks!

@jasonacox
Copy link
Owner

Hi @Xilef11 - I may be reading this wrong since you mention sending commands (via python script), but in the example you pasted I see this...

Address = 192.168.2.46, Device ID = , Local Key = , Version = , MAC =
DEVICE KEY required to poll for status

Did you remove the Device ID from the output or was that actually blank? In any case, it is reporting that you are missing the local key. The 3.3 devices require a valid local key. If you run wizard, it will create a devices.json file that will have the local key. Run the scan again in that same directory and TinyTuya will use that local key to poll the devices.

If that is not the issue, try to power cycle the device completely. I know that sounds odd, but I have seen it myself. Also, keep in mind that the local key will change if you every re-pair the device with the SmartLife app (e.g. factory reset).

@Xilef11
Copy link
Author

Xilef11 commented Jan 5, 2023

No, that's the output from the scan, all blank. devices.json was created correctly, so either it's not using the file or it can't match it to the device. I'd guess the latter since there's a [loaded devices.json - 1 devices] message at the start of the scan.
devices.json (key is present in the file):

[
    {
        "name": "36819",
        "id": "ebf310edb88d15f0edyr5i",
        "key": "XXXXXXXXXXXXXXXX",
        "mac": "38:1f:8d:36:d2:03",
        "category": "dj",
        "product_name": "",
        "product_id": "qlbfchuhqdbmeheo",
        "biz_type": 0,
        "model": "Litech",
        "sub": false,
        "icon": "https://images.tuyaus.com/smart/icon/ay1514166115504M4mB5/059dcd620d85996a42b54c681a6b5ba9.png",
        "uuid": "60b308e46e1b5871"
    }
]

@uzlonewolf
Copy link
Collaborator

uzlonewolf commented Jan 5, 2023

Edit: if anyone's just looking for an overview of the v3.5 protocol, check out #260 (comment)


That's really odd. Can you post the output from:

import socket

clients = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
clients.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
clients.bind(("", 6667))
clients.settimeout(7)

for i in range( 8 ):
    data, addr = clients.recvfrom(4048)
    print( addr, '=', data )

@Xilef11
Copy link
Author

Xilef11 commented Jan 5, 2023

Here it is, looks like the same block repeated 8 times

('192.168.2.46', 57749) = b'\x00\x00f\x99\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13\x00\x00\x00\xef\xe6_\xba\xd0\x9a\x1eL\xcc\'F\x0ce\xe6\xb0AX\x94\x8c}\xc9\xd3\xdf\xf1[\x87U\x16a\xdc\xa6)O\x7f\x027v\x0e\x84\n\x9c12G\x14\n\x19\x13\x85\xd8\x9b_+\xb9&*7%\x8e\xe9b\xba\x90"\xb1Z\xb5\x9f\xaa\xcc\xdc\xad\xa2\x9a\x8f\xfbz=65G\x1c\xabZN\xc9E\x81\'\x90\xaa~KN\x8b\x13k\xccr\x13\x199\x8f\x92\xf5\x10\xf8\xb4\xeb\xe9\xa83\x80\xe0R\xc9\xe7\xde\x90\xd7\x90\x08\x11\xdc\xa0\x93\xc9@\xb40uf\xce\x82|\x94\x93\x8b\xe91_\x96\xdf3\xc2\x94\xc4\x05o\xc4\xafN1o!\x12^\xcb\x85\xa0\xce\xfd\xb8\xafG-D\xdb\xd8Xy\x87\xc2\xc0\xd8\x11\xcc\x05\xf3"s7\xac\x88\x8d\xec\x88\xf0jg.\xba\x01`\xde\xb3v\x9a\x03g\xa2X\x00\x01\xc2\xd0"\xc1A[\x1e\x0fu;&\x17\xf02\\\x9a\xf4^\x84t\x94\x01O\x9b\x148\xd7\xf7\xaeks\x82,\xff`\xad\x00\x00\x99f'

('192.168.2.46', 57749) = b'\x00\x00f\x99\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13\x00\x00\x00\xef\\\x86\xc0v$y]\x96\xdd#Y)\x02\xa2"\\\xc2\xe0\xcf\xcd}\x89\xd4@\xcd\xcc6\xc7\xc1S\\\xe1\xdc,\xef\xfcu\x13\xae\x02\xff\xe0\xc6\xfa\xd7r"Y\x953\x1a\xc0\x10\xdc\x9cZe\x08\x1e\x97\xc8\xb1\xe7\x89j\xb6\xb56\x10u\x0e\xcd\xfdf\xf9\xcbA\xcf\x04\xff9\xa02\xe3\xe9\xc0\xe2V=\xc8\x17\xa8"\xaa[\xee\x84\x8aN\xf9\xd5\xcb:\xf4|\x0b\xcdT\x04\x03\x03\x82^\xd1\x1b\x7f\xb57\xaa,\x05{O\x04\x86\xd8\x0e\x8a0\x9e\xd6/\xd2\x0cE\xe9\x97\xfa\x92t\xfa\xa1}\x80\x9f\x01\x98\xf3\x07\xa9\xeb\xce\xb1 !`w\x92\x06\x14\xffT^\xe8\x19>~\xf4\x0b\x0f\x0c\xb6,\x11\xb9\x05^\xdc@\x97a\xfdOa\xb7\x9d\xd0M\xb4P\xdb+\xe3\x87\x9b\xd8d\xb0=\xa4\xb2Z\x04\xc2s\xa4_v\x9d#\x7f \xc1\x99\x97\xadF6\xf8U\x8aT\x1b\xac\xa2\x85\xf7\xb9 \x8d\xb4M\x02\xe2\xd7\x94\xd7\xa97\x00\x00\x99f'

('192.168.2.46', 57749) = b'\x00\x00f\x99\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13\x00\x00\x00\xef\\\x86\xc0v$y]\x96\xdd#Y)\x02\xa2"\\\xc2\xe0\xcf\xcd}\x89\xd4@\xcd\xcc6\xc7\xc1S\\\xe1\xdc,\xef\xfcu\x13\xae\x02\xff\xe0\xc6\xfa\xd7r"Y\x953\x1a\xc0\x10\xdc\x9cZe\x08\x1e\x97\xc8\xb1\xe7\x89j\xb6\xb56\x10u\x0e\xcd\xfdf\xf9\xcbA\xcf\x04\xff9\xa02\xe3\xe9\xc0\xe2V=\xc8\x17\xa8"\xaa[\xee\x84\x8aN\xf9\xd5\xcb:\xf4|\x0b\xcdT\x04\x03\x03\x82^\xd1\x1b\x7f\xb57\xaa,\x05{O\x04\x86\xd8\x0e\x8a0\x9e\xd6/\xd2\x0cE\xe9\x97\xfa\x92t\xfa\xa1}\x80\x9f\x01\x98\xf3\x07\xa9\xeb\xce\xb1 !`w\x92\x06\x14\xffT^\xe8\x19>~\xf4\x0b\x0f\x0c\xb6,\x11\xb9\x05^\xdc@\x97a\xfdOa\xb7\x9d\xd0M\xb4P\xdb+\xe3\x87\x9b\xd8d\xb0=\xa4\xb2Z\x04\xc2s\xa4_v\x9d#\x7f \xc1\x99\x97\xadF6\xf8U\x8aT\x1b\xac\xa2\x85\xf7\xb9 \x8d\xb4M\x02\xe2\xd7\x94\xd7\xa97\x00\x00\x99f'

('192.168.2.46', 57749) = b'\x00\x00f\x99\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13\x00\x00\x00\xef\x9c+\xd2\x1ax\xaa\xee\xf8\xf4\xf9\xee\xe9h3\xf1-\xa4\xda\xf2\xb9\xf5v\xf5\x99\xf7aH\xa4\xf8\xab\xc3\xfa>d\x7fq\x0f\xfa\x1e\xf8\x85\xe3\xa8\xe9\'~[\r\xf6*e\n\xee\x02\x06JMA\xfe\xc70\xa8{\xdd\xdc\xaaeIn\xf7t\xbc\x90\x1d\xb0\xfd(q?J\xfe\x90v+\xc0\xd1MW6,h\x19\xfe\x0b\xd7\xcc\x98\xec}L\xce7\n\xfa\x15\xe8Th\xccd\x84jX`\t~*\x80\x97?NL\xdb\xb0\xd3\xc8@-\xed;\xfb\xcdk\xcd\xa9\xa5\xb2s\x806\x1a\x9dlfM\x04\x062\xfbR\xc0\xab\xe5b~\x87\xe7\xd2\xb7\x87\xf5\x0e\xc0X\x1d\xf3:B\xe4\xa9\x8e\x03\x9e|\xbb\xf1\x02\xa1\x03U;\xab\x91\x03\xa3\x86_U_N\xa4\xc6\xb8]\xe9Ca*\x12d\x14\xb6\xec\xbd\xb9\x88\x1e\xd0r\xdb\x1e\x95\xbc\x13\xa8",\xb3&\xb9H\xa3\xd1\xdfgA\x1a\xe6\xd5\x04o\xe8\xc4\x86j\xab\xdb\xa7T\x00\x00\x99f'

('192.168.2.46', 57749) = b'\x00\x00f\x99\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13\x00\x00\x00\xef\x9c+\xd2\x1ax\xaa\xee\xf8\xf4\xf9\xee\xe9h3\xf1-\xa4\xda\xf2\xb9\xf5v\xf5\x99\xf7aH\xa4\xf8\xab\xc3\xfa>d\x7fq\x0f\xfa\x1e\xf8\x85\xe3\xa8\xe9\'~[\r\xf6*e\n\xee\x02\x06JMA\xfe\xc70\xa8{\xdd\xdc\xaaeIn\xf7t\xbc\x90\x1d\xb0\xfd(q?J\xfe\x90v+\xc0\xd1MW6,h\x19\xfe\x0b\xd7\xcc\x98\xec}L\xce7\n\xfa\x15\xe8Th\xccd\x84jX`\t~*\x80\x97?NL\xdb\xb0\xd3\xc8@-\xed;\xfb\xcdk\xcd\xa9\xa5\xb2s\x806\x1a\x9dlfM\x04\x062\xfbR\xc0\xab\xe5b~\x87\xe7\xd2\xb7\x87\xf5\x0e\xc0X\x1d\xf3:B\xe4\xa9\x8e\x03\x9e|\xbb\xf1\x02\xa1\x03U;\xab\x91\x03\xa3\x86_U_N\xa4\xc6\xb8]\xe9Ca*\x12d\x14\xb6\xec\xbd\xb9\x88\x1e\xd0r\xdb\x1e\x95\xbc\x13\xa8",\xb3&\xb9H\xa3\xd1\xdfgA\x1a\xe6\xd5\x04o\xe8\xc4\x86j\xab\xdb\xa7T\x00\x00\x99f'

('192.168.2.46', 57749) = b'\x00\x00f\x99\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13\x00\x00\x00\xef\xc0\x81\x89#\x8cr\xab\xdf\xaf\x80\xadH\xef\xd43\xa7\xcf\x1eTM\xd7[\r\xb5,\x176+\x1bV\x94w\xdb\x1fz\t5\x04\xa2\xaa\x93\xefPo_\xfd\xddY\xa9\xb0M\xbf\xc1\xee~0\xcc\n~\xe1\xfb\xc2\xef\xf6\x93\xa0\x8d\xb0,\xcc\xa0\t\xfe\t\xec\x93f\x9e\x12\x8a\xfa\'\x9f\xe6\x82\xb0}\xfb-\x19\xb2\x9b\x89\xd3-C\xb3\xd2\xd1,\x06Xr\x86\xa2\t\x8e*\xaa\x8b\x93\xe1J\xfd\xb1\t\x04\x89m\xa1\x8e\x8c+\xfd\xbf\x13C\x1fT\x96ky\x16\xb8\x10\x86s\x82""c^\\lC\xbe7\xb6\x0c\xd7\x9d\xf6n\xc0\xe1\xbc=h\xd7*\x91\xf1\x1b6!K\x17\r\xf0\x10\xf3X[m7\x99\xe8\x14\x92r\xaf\xc9M\x9a\xa7 WU\xf5\x91\x88\x89\xed\x9f,{:B\x93\n\xdf\xe6\x86 bP\xe0\x13:]\xb7<\xe7\xe0r jf\xccz)\xb0\x0c\xc0\xee\x15\x88\xeew5;\xf3\xac\x16\xda\xf7\x16\xb2\x9b\x00\x00\x99f'

('192.168.2.46', 57749) = b'\x00\x00f\x99\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13\x00\x00\x00\xef\xc0\x81\x89#\x8cr\xab\xdf\xaf\x80\xadH\xef\xd43\xa7\xcf\x1eTM\xd7[\r\xb5,\x176+\x1bV\x94w\xdb\x1fz\t5\x04\xa2\xaa\x93\xefPo_\xfd\xddY\xa9\xb0M\xbf\xc1\xee~0\xcc\n~\xe1\xfb\xc2\xef\xf6\x93\xa0\x8d\xb0,\xcc\xa0\t\xfe\t\xec\x93f\x9e\x12\x8a\xfa\'\x9f\xe6\x82\xb0}\xfb-\x19\xb2\x9b\x89\xd3-C\xb3\xd2\xd1,\x06Xr\x86\xa2\t\x8e*\xaa\x8b\x93\xe1J\xfd\xb1\t\x04\x89m\xa1\x8e\x8c+\xfd\xbf\x13C\x1fT\x96ky\x16\xb8\x10\x86s\x82""c^\\lC\xbe7\xb6\x0c\xd7\x9d\xf6n\xc0\xe1\xbc=h\xd7*\x91\xf1\x1b6!K\x17\r\xf0\x10\xf3X[m7\x99\xe8\x14\x92r\xaf\xc9M\x9a\xa7 WU\xf5\x91\x88\x89\xed\x9f,{:B\x93\n\xdf\xe6\x86 bP\xe0\x13:]\xb7<\xe7\xe0r jf\xccz)\xb0\x0c\xc0\xee\x15\x88\xeew5;\xf3\xac\x16\xda\xf7\x16\xb2\x9b\x00\x00\x99f'

('192.168.2.46', 57749) = b'\x00\x00f\x99\x00\x00\x00\x00\x00\x00\x00\x00\x00\x13\x00\x00\x00\xefdJ\xa0\xf3\xc8:\xb7\xa7\xa7\x81\x0f$\xad\x04\x9d\x13\x00\x88\xe2x\x15\xc6\x88\x8b\x9b`\x98\xd6Hc^\xc6IKt\xe5\xb9\xf06\xba6\xc37\xf9\xdf\x8a\xed\xbd\xd7Y\xe3\xbaoR\xed\x92z\xbf\x98x\xea\xeag\xbd\xe2\xd0\xa2A6\xde}Y\xc8\xb1.Q\x03\x98\xef\xfd\x96#\xc7\x91\xcb\'\xc0\xfb\xb1\xaa\xa7\xf4\x1dV\x08Hpb\xdc\xf8\xa1\x11\xdbX`\xd1\x08\xbeD\xe8L^d\xc4\xd00\xc7\xe2u\xe1\xa6A,N\x1a\x86l(\x8c\x8e\x7f\xe2\x14\x12\x17%Ngnt\xd3\xdca\t#G\x103\xac\xcd\xa6\x80\xb1\x03t\xed>\xc71\x17R\x9b\xa2\xb6\xd3J,\x1f\xd3R\xa6mP"v!\xa2\x10\x91\x84^\xa7\xc9\xdb\x84:\x86\x19C\xd1\x1e\x8eT0\x15\xc16\x002\xc4y\x1a\xcc\xb64{:/?\x0fkEn\x11Z]\xa2D\xeb\x00\xe2X\xe8\x99\xfejU\xdd\xf1\x08\xd5;$.\x80o\x0c \xa3\x00\x00\x99f'

I also tried a scan in debug mode, which adds the following line after the "unexpected payload=%r..." : DEBUG:Invalid UDP Packet: {'ip': '192.168.2.46'}

@uzlonewolf
Copy link
Collaborator

uzlonewolf commented Jan 5, 2023

b'\x00\x00\x66\x99'

o.O Well that's a new one, looks like it may be a new protocol (or at least a new encryption key). This is going to take some reverse engineering...

@Xilef11
Copy link
Author

Xilef11 commented Jan 5, 2023

I see... Anything I can do to help?

@uzlonewolf
Copy link
Collaborator

uzlonewolf commented Jan 5, 2023

Do you have a link to the lightbulb you bought? We're probably going to need to buy one and dump the firmware. If it's similar to one of the existing versions we might be able to figure it out with just packet captures if you're able to get them (it's not trivial to set up if you've never done it before), but if it has substantial changes then that probably won't help.

@Xilef11
Copy link
Author

Xilef11 commented Jan 5, 2023

It's this product from costco, model number on the bulb is 36819 but I can't find it on the globe website.

I should be able to get you a packet capture no problem. Is there any specific part that you need?

@uzlonewolf
Copy link
Collaborator

I basically need all the packets the phone app sends and receives to/from the bulb while in offline local-only mode, as well as the local key (you can generate a new local key if you want by removing and re-adding the bulb).

I have some similar ones coming from Amazon tomorrow, no idea if they're the same or if the ones you have are Costco exclusives. I'm hoping the different part numbers are just due to the different packaging (4-pack vs 2-pack vs single).

@Xilef11
Copy link
Author

Xilef11 commented Jan 6, 2023

Getting the capture in offline mode was a bit trickier than I expected, but I think I managed to get something. Here's what I did:

  1. set up computer as AP with wireshark capturing
  2. connect the phone and lightbulb to said network
  3. play with lightbulb setting in the app to confirm that messages to/from the cloud are captured
  4. pull the localkey from the cloud using the wizard
  5. kill the internet connection (this happens around packet 2014 in the capture)
  6. confirm no internet access
  7. keep changing settings in the app.

Interestingly, I didn't find a direct connection between the lightbulb and the phone when the internet was offline. Just UDP broadcasts and RTPS packets. Hope I did it right.
Do you have an email where I can send the capture and localkey? It doesn't look like there's any personal data that got in but I'd rather be safe.

@uzlonewolf
Copy link
Collaborator

uzlonewolf commented Jan 6, 2023

Sure

@uzlonewolf
Copy link
Collaborator

Well that's odd. In that packet capture there's only a normal v3.3 device with the usual 000055aa header, it should work with TinyTuya as-is. The phone does appear to be broadcasting 00006699 packets on port 7000 though. I also do not see any local-offline communication, not sure if your computer's not seeing it as it's WiFi-to-WiFi or what.

@Xilef11
Copy link
Author

Xilef11 commented Jan 6, 2023

The scan is capture is from a second bulb in the same box, I just checked and this one is picked up by tinytuya scan and it works fine. The model number on the bulb is the same and they are identical in the app. strange.

If the local/offline communication is p2p and doesn't go through the "router" I won't be able to capture it with my setup. I found an older capture of the non-working bulb which also had the 000055aa UDP broadcasts, but now it's at 00006699 (port 66667) for some reason.

Edit: So the non-cooperating one says its firmware is version 1.5.10 while the working one is 1.2.16. Both say they are "up to date"

@jasonacox jasonacox added the tuya_device Support for specific Tuya Devices label Jan 7, 2023
@uzlonewolf
Copy link
Collaborator

Well my bulbs came in today. The "tunable white" ones showed up with the name "34204 - V4" and firmware version 2.9.6 and use protocol v3.3. The RGB ones showed up with the name "34207" and firmware version 1.3.21 and use protocol v3.4.

@Xilef11 I would like to purchase the 00006699 bulbs you have if you don't mind selling them.

@uzlonewolf
Copy link
Collaborator

uzlonewolf commented Jan 12, 2023

I ended up picking up some single-pack 34212 RGB+white bulbs, and they're both version 2.9.6. I think this company's nuts for having a completely different part for a 2-pack vs single vs 4-pack, but whatever.

I managed to decode the 6699 broadcast messages, though I won't be able to verify sending commands without a packet capture.

from Crypto.Cipher import AES
from hashlib import md5,sha256
import socket

clients = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
clients.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1)
clients.bind(("", 6667))
clients.settimeout(7)

amode = AES.MODE_GCM
key = md5( b'yGAdlopoPVldABfn' ).digest()

for i in range( 8 ):
    data, addr = clients.recvfrom(4048)

    header = data[:18]
    iv = data[18:30]
    payload = data[30:-4]

    print( addr, '=', payload )

    decrypted = AES.new(key, amode, nonce=iv).decrypt( payload )

    print( decrypted )
    print('')

Once decrypted these new devices are reporting protocol v3.5.

@Xilef11
Copy link
Author

Xilef11 commented Jan 12, 2023

Apologies for the delay. Unfortunately I won't be able to sell you the device, but the above code does give some legible information:

('192.168.2.46', 55125) = b'\x9b\xe6\x05\xf5\xf5r\xbe\xfb\x14/\x07\xca]\xe1_K\x88\x92\xad-J\xe4\xfa[Z\xc4>a\x94\x8a\xa5\x9f\xb6\xa8\xee\x94\xa8\xed\xe8P_\x8d\x85\xa1\xbf\xedN\x15\xe4\x1a|\xe5\xdbB1\x00\x0c\xa7\x89\tx\xb7u\xf8\xda\x11\x19i\xec\xcc,K\xf8\xd9\xf3\x8f=\xb45l\x19\xbd\xe2\xf0p\x9c*\xc7\xf1\xdf6v\xc6\xab\xf5\x8f\xea\x84\xceK\x7f\xd5\x03\x84\xad\x1dI/`U\xf3S\xa1\x85\nd[_\xa3TJ\x8d\xfe\xc4\xb4\x90gA\xb4\x8e\xb8.4\xc5\'"\xa2p\xcfQ\xeb\xca\xe5{B\xd1\xa5\xc3\n\x0c\xd3h\xa3\x8c\xee\xd2\xc5\xa16\x94BH\x07\xdf\xeb\x8b N\x04\x94\x80n\x05\xaet\xfb\xd8\xca\x08\xaad\x90\xf2A9x\x1d\x8e\x8e\xa0\xee-/\xc7\x97Q\xcd\xd3\x80\xb7\x0c\xc2\x87\xdb%,MX\xb2\x8aA\x9f\x00o\xa4\xc9\xd5XyX\x00v\x1d\xa1\x00\xdf\xe5'
b'\x00\x00\x00\x00{"ip":"192.168.2.46","gwId":"ebf310edb88d15f0edyr5i","uuid":"60b308e46e1b5871","active":2,"ablilty":0,"encrypt":true,"productKey":"key8u54q9dtru5jw","version":"3.5","token":true,"wf_cfg":true,"clientLink":3})\t\xf8W\x86\t\x8c\x057\xa8U\xb1r\xb6:\x9d'

@uzlonewolf
Copy link
Collaborator

It's fine, no worries.

At this point there's not much I can do without either a firmware dump or a packet capture of a local-offline transaction. I have the gateway from #248 coming, but it's been out for a few years now and I'm doubtful it'll arrive with the correct firmware version.

You can try running this while changing something in the app, but it probably won't work:

import socket
import time

ip = '192.168.2.46'

for i in range( 3 ):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.settimeout( 5 )
    sock.connect( (ip, 6668) )
    print( 'connected!' )
    stime = time.time()
    sock.settimeout( 300 )
    while True:
        try:
            rtime = time.time()
            data = sock.recv( 4096 )
        except:
            print( 'connection closed after ', (time.time() - stime) )
            break
        print( 'data:', data, 'in', (time.time() - rtime) )
        if not data:
            break
    sock.close()
    sock = None

@Xilef11
Copy link
Author

Xilef11 commented Jan 12, 2023

Yeah, it just prints empty data:

connected!
data: b'' in 31.303014278411865
connected!
connection closed after  1.3680005073547363
connected!
data: b'' in 30.56010413169861

@Oglaf
Copy link

Oglaf commented Jan 13, 2023

I recently bought a smart light imported and rebranded from a brazilian company with the same issue.
Datasheet in portuguese, but I believe the numbers are understandable.

Unfortunately as soon as I connected to Smart Life it's firmware got updated to version 1.5.10
image

Although the firmware number is lower than my other smart lights (2.9.16), on Smart Life I noticed this one has more features:
image

Even on device list, it has a quick access toolbar unlike the others:
image

My devices.json:

{
        "name": "EWS 410",
        "id": "eb68e355da1be4ae69ok5o",
        "key": "6434389541e96704",
        "mac": "38:1f:8d:4f:66:f6",
        "category": "dj",
        "product_name": "EWS 410",
        "product_id": "tgfkxkkbcwbz1pmo",
        "biz_type": 18,
        "model": "EWS 410",
        "sub": false,
        "icon": "https://images.tuyaus.com/smart/icon/ay1553088530507BVYGE/16522947904d7f64da11e.png",
        "uuid": "8b05ecd80b3d2553"
    }

The error messages from TinyTuya are exactly the same and wireshark results are probably similar.

@uzlonewolf
Copy link
Collaborator

uzlonewolf commented Jan 14, 2023

Can @Xilef11 or @Oglaf run this and let me know if it reports anything? Make sure to fill in your IP and local key.

import socket
import time
import struct
from hashlib import md5,sha256
from Crypto.Cipher import AES

ip = '192.168..'
key = b'YOUR LOCAL KEY'


for i in range( 2 ):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.settimeout( 5 )
    sock.connect( (ip, 6668) )
    print( 'connected!' )
    stime = time.time()
    local_nonce = b'0123456789abcdef' # not-so-random random key
    local_iv = local_nonce[:12]       # not-so-random random iv

    pkt = struct.pack( ">IHIII", 0x6699, 0, 1, 3, len(local_nonce)+len(local_iv)+16 )

    c = AES.new(key, AES.MODE_GCM, nonce=local_iv)
    c.update( pkt[4:] )
    encrypted, tag = c.encrypt_and_digest( local_nonce )

    pkt += local_iv + encrypted + tag + struct.pack( ">I", 0x9966 )

    #print( pkt )
    #print( pkt.hex() )

    sock.sendall( pkt )

    try:
        data = sock.recv( 4096 )
    except:
        data = None

    print( 'data:', data, 'in', (time.time() - stime) )

    sock.close()
    sock = None

@Oglaf
Copy link

Oglaf commented Jan 14, 2023

Nop, nothing... I confirmed the code works with my other lightbulbs .

Results:

connected!
data: None in 5.004519939422607
connected!
data: None in 5.019267559051514

@uzlonewolf
Copy link
Collaborator

🤦 It would help if I get the format right. Replace struct.pack( ">IBIII" with struct.pack( ">IHIII". Or just wait a few hours and I'll hopefully have a PR in.

@Xilef11
Copy link
Author

Xilef11 commented Jan 14, 2023

That actually works! I think. At least there's some data, not sure if it's meaningful

connected!
data: b"\x00\x00f\x99\x00\x00\x00\x00\xe9~\x00\x00\x00\x04\x00\x00\x00Pk\xac\x89\xac#1T\x90\xbfy\xdb\xd6q^\x1e\xc5\xe7\x852k\x04\x11\x9fv\n\xdc\x97:d&|'q\x10\x9c\x1e\x08\xfa\xd00\x8b\xd8\x83Y\xe0k\xcfg\xe0\xe8\xc6\r\x06\x87\xf6nr\x10X\t\xb87\xb8\x08V\xf3\xd4\xad\x97\x14\xe6!\xaa\xfb\x0e)\x1e(\xa1.\x00\x00\x99f" in 0.020395755767822266
connected!
data: b'\x00\x00f\x99\x00\x00\x00\x00M\x10\x00\x00\x00\x04\x00\x00\x00PM-\x0b\xa5<\xe7p\xe0\xcc\x81\xa6d\xcf\xc5\xd5\xf2\xb1\x14\x91)\x8b\x93\xdf\xe2\x8a\x04p\xb4/p\nAJ\x96e\xff\xd0k\x0e\xf6Q\x9c\x0e3\x96}\xaa\x97\xd2{\xff\xd7\x93?\xca\xfb\x9f\xd6Qqh\x8b/\x80\xdbLvi\xf1@"Uj\xfeS\xd5\xfa\x16]\xf1\x00\x00\x99f' in 0.03944563865661621

@uzlonewolf
Copy link
Collaborator

Great, that's exactly what I need! I'm almost done adding these encryption routines and should have a PR for people to test in a bit.

@Oglaf
Copy link

Oglaf commented Jan 14, 2023

FYI, got positive results:

connected!
data: b'\x00\x00f\x99\x00\x00\x00\x00\\\xd3\x00\x00\x00\x04\x00\x00\x00P\x0c\x1c\xef\xea\xccm\xe9\x16e\xd0z\\X\xc6\xf6\xfc\xe4;R\xf4\xdf\x0fI\x88\x8e\xd64\xa7\x11b\xa2\x1b"\xaeBL\xd3[n\x17n\x96/\xceX\xa1\x1d\xbe%\x11\x1fu\xf7\xecB,ytr*\xf55y\xf9R\x82/\xc8\xd57\x89!h\x95\xb7\x86\x9c\x80\xf2b\x00\x00\x99f' in 0.05198383331298828
connected!
data: b'\x00\x00f\x99\x00\x00\x00\x00\xa9B\x00\x00\x00\x04\x00\x00\x00P\x80\x1fJ\xc1~\xce\xf7\xb8\x14a\xa6\x95Wi\xc9\xc1\\\x9f/"\x16\xfd\x12-\xde\x85v\xfd\x8b\x96\xb1\xc7\x97\x84\xc8\xff<\xff\x7f\xacv6&\x8bM\xb4\xf9\x0f\xfd\xb9\'\xa7\xdf/5\xcc\x88Q\xcf\x91\xa6\xbc\xa1\x1f\x94\xbe\xe3\xee6! \\\'\xe3\xa7\x8f\xd0\x86$Z\x00\x00\x99f' in 0.11254739761352539

Thank you for your help @uzlonewolf !

@uzlonewolf
Copy link
Collaborator

uzlonewolf commented Jan 14, 2023

Can everyone checkout #256 (aka https://github.com/uzlonewolf/tinytuya/tree/pv35 ) and let me know if it works?

@jasonacox
Copy link
Owner

Thank you @Xilef11 ! Good news on the status() results! That means there is still a bug in scanner.py. Can you also try this?

python3 -m tinytuya scan
python3 -m tinytuya snapshot

I'm more interested in the snapshot output to see if it reads the 3.5 device there.

@Xilef11
Copy link
Author

Xilef11 commented Jan 16, 2023

scan:

TinyTuya (Tuya device scanner) [1.10.0]

[Loaded devices.json - 3 devices]

Scanning on UDP ports 6666 and 6667 and 7000 for devices for 18 seconds...

36819   Product ID = key8u54q9dtru5jw  [Valid Broadcast]:
    Address = 192.168.2.46   Device ID = ebf310edb88d15f0edyr5i (len:22)  Local Key = 0afcd6c2451d2f3e  Version = 3.5  Type = default, MAC = 38:1f:8d:36:d2:03
    Polling 192.168.2.46 Failed: No response
Scan completed in 18.0373 seconds

Scan Complete!  Found 1 devices.
Broadcasted: 1
Versions: 3.5: 1

>> Saving device snapshot data to snapshot.json

snapshot:

TinyTuya (Tuya device scanner) [1.10.0]

Loaded snapshot.json - 1 devices:

Name                      ID                       IP                 Key               Version

36819                     ebf310edb88d15f0edyr5i   192.168.2.46       0afcd6c2451d2f3e  3.5

Poll local devices? (Y/n):

Polling 1 local devices from last snapshot...
Traceback (most recent call last):
  File "d:\users\felix\appdata\local\miniconda3\lib\runpy.py", line 193, in _run_module_as_main
    "__main__", mod_spec)
  File "d:\users\felix\appdata\local\miniconda3\lib\runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "D:\Users\Felix\Desktop\tuya\tinytuya\tinytuya\__main__.py", line 86, in <module>
    scanner.snapshot(color=color)
  File "D:\Users\Felix\Desktop\tuya\tinytuya\tinytuya\scanner.py", line 1687, in snapshot
    result = devices(verbose=False, scantime=0, color=color, poll=True, byID=True, discover=False, snapshot=by_ip)
  File "D:\Users\Felix\Desktop\tuya\tinytuya\tinytuya\scanner.py", line 1295, in devices
    rd, _, _ = select.select( read_socks, [], [], 0 )
OSError: [WinError 10022] Un argument non valide a été fourni

"invalid argument" from Windows when polling from the snapshot.

@uzlonewolf
Copy link
Collaborator

@jasonacox Looks like there are 3 places in the scanner with == 3.4 that need to be changed to >= 3.4

jasonacox added a commit that referenced this issue Jan 16, 2023
@jasonacox
Copy link
Owner

Found them @uzlonewolf - Thanks!

@Xilef11 can you pull the latest and try the scan again?

@uzlonewolf
Copy link
Collaborator

I'm also working on the snapshot issue, hopefully I'll have a PR for that one soon

@Oglaf
Copy link

Oglaf commented Jan 16, 2023

@jasonacox and @uzlonewolf do you guys still needs me to send any log?

@jasonacox
Copy link
Owner

Thanks for all your help!

@Oglaf just for additional testing, can you do the same as @Xilef11 - pull latest and:

python3 -m tinytuya scan
import tinytuya

d = tinytuya.OutletDevice('DEVICEID', 'DEVICEIP', 'DEVICEKEY')
d.set_version(3.5)
d.set_socketPersistent(True)
print(d.status())

@Xilef11
Copy link
Author

Xilef11 commented Jan 16, 2023

new error! here's the scan

TinyTuya (Tuya device scanner) [1.10.0]

[Loaded devices.json - 3 devices]

Scanning on UDP ports 6666 and 6667 and 7000 for devices for 18 seconds...

v3.4 device session key step 2 decrypt failed, payload=b'569b3a545e68181c\x0c3\xc8\xcd\xbf\xc1\xc6_\xcf,\x12\x15G\xb3\xa8)N\x806 \xa1\xa0\x88^vea\x97?\xac\xde(' (len:48) l-key:b'0afcd6c2451d2f3e' l-nonce:b'0123456789abcdef'
Traceback (most recent call last):
  File "D:\Users\Felix\Desktop\tuya\tinytuya\tinytuya\scanner.py", line 298, in v34_negotiate_sess_key_step_2
    payload = cipher.decrypt(payload, False, decode_text=False)
  File "D:\Users\Felix\Desktop\tuya\tinytuya\tinytuya\core.py", line 285, in decrypt
    raw = self._unpad(raw, verify_padding)
  File "D:\Users\Felix\Desktop\tuya\tinytuya\tinytuya\core.py", line 308, in _unpad
    raise ValueError("invalid padding length byte")
ValueError: invalid padding length byte
odata: b'\x00\x00f\x99\x00\x00\x00\x00[(\x00\x00\x00\x04\x00\x00\x00P\x14\xd1{\xec\xc9S\x83\xcd\xb7\xcc\x93\xab\x1ak\xacl7\x0e\xfb<\x05\x93\x95\xa9\xc9\xe6nr,=z\xc1\xabNX\xd8\xf9hwIjbidO\xdc\x7f\x0eh\xb8\xd8\xc4(\xeb6\xf4h\x96\x1d\xd04\r3\x1d&%M\xe8?w\x1d\x7f}\xf9?\xdd\xb7\xb1wh\x00\x00\x99f'
v3.4 device session key step 2 decrypt failed, payload=b'f6e33fba598625ef\x0c3\xc8\xcd\xbf\xc1\xc6_\xcf,\x12\x15G\xb3\xa8)N\x806 \xa1\xa0\x88^vea\x97?\xac\xde(' (len:48) l-key:b'0afcd6c2451d2f3e' l-nonce:b'0123456789abcdef'
Traceback (most recent call last):
  File "D:\Users\Felix\Desktop\tuya\tinytuya\tinytuya\scanner.py", line 298, in v34_negotiate_sess_key_step_2
    payload = cipher.decrypt(payload, False, decode_text=False)
  File "D:\Users\Felix\Desktop\tuya\tinytuya\tinytuya\core.py", line 285, in decrypt
    raw = self._unpad(raw, verify_padding)
  File "D:\Users\Felix\Desktop\tuya\tinytuya\tinytuya\core.py", line 308, in _unpad
    raise ValueError("invalid padding length byte")
ValueError: invalid padding length byte
odata: b'\x00\x00f\x99\x00\x00\x00\x00\x0f\x8f\x00\x00\x00\x04\x00\x00\x00P\x83_e\x80O\x9a\x95\xfe\xd5-\xe1F,\\\x89\xba^\xd5\xaa\x19\x87\xd3]\x7f\xe1l*d\xb81\xa4\xa1\x7f\xad\xcc\x7f\xed\x91B\x1b\x90\x18\n\xc6=\xa6\x9bOPq\xcc\xfe\xb4u\x18R\x87\xb2\xa8\x80\xc5\xc4O\xdf\x82\x16\x15\xcf\xa7\xe8@\xd4Y\xbc\x113\xc4uV\xa3\x00\x00\x99f'
v3.4 device session key step 2 decrypt failed, payload=b'15b1d643b3914627\x0c3\xc8\xcd\xbf\xc1\xc6_\xcf,\x12\x15G\xb3\xa8)N\x806 \xa1\xa0\x88^vea\x97?\xac\xde(' (len:48) l-key:b'0afcd6c2451d2f3e' l-nonce:b'0123456789abcdef'
Traceback (most recent call last):
  File "D:\Users\Felix\Desktop\tuya\tinytuya\tinytuya\scanner.py", line 298, in v34_negotiate_sess_key_step_2
    payload = cipher.decrypt(payload, False, decode_text=False)
  File "D:\Users\Felix\Desktop\tuya\tinytuya\tinytuya\core.py", line 285, in decrypt
    raw = self._unpad(raw, verify_padding)
  File "D:\Users\Felix\Desktop\tuya\tinytuya\tinytuya\core.py", line 308, in _unpad
    raise ValueError("invalid padding length byte")
ValueError: invalid padding length byte
odata: b'\x00\x00f\x99\x00\x00\x00\x00;\x8c\x00\x00\x00\x04\x00\x00\x00P\xe3\x1f\x80g$]\xd7\x1e\xd2\x87U\xb2\xfd\x93|pB1%\xd9\t{\xedB\xa9j\xf2(\x1c\xa2{\xd7o 8T\xb7\xec\x94(\x1e?Y?n\xd3\x01\xdc\xae\xc5\x00C\x13h1\xf0f)6\x877\x05\xe5\xd2\x02\xb1\xb5\x01\xb1/*\xb2\x9e\x83\xf8\x00\x16g\xb8H\x00\x00\x99f'
36819   Product ID = key8u54q9dtru5jw  [Valid Broadcast]:
    Address = 192.168.2.46   Device ID = ebf310edb88d15f0edyr5i (len:22)  Local Key = 0afcd6c2451d2f3e  Version = 3.5  Type = default, MAC = 38:1f:8d:36:d2:03
    Polling 192.168.2.46 Failed: v3.4 device session key step 2 decrypt failed, payload=b'15b1d643b3914627\x0c3\xc8\xcd\xbf\xc1\xc6_\xcf,\x12\x15G\xb3\xa8)N\x806 \xa1\xa0\x88^vea\x97?\xac\xde(' (len:48) l-key:b'0afcd6c2451d2f3e' l-nonce:b'0123456789abcdef'
Scan completed in 18.0958 seconds

Scan Complete!  Found 1 devices.
Broadcasted: 1
Versions: 3.5: 1

python -m tinytuya snapshot returns the same "invalid argument" error as before
debug scan:

DEBUG:loaded=devices.json [3 devices]

TinyTuya (Tuya device scanner) [1.10.0]

[Loaded devices.json - 3 devices]

Scanning on UDP ports 6666 and 6667 and 7000 for devices for 18 seconds...

DEBUG:Listening for Tuya devices on UDP 6666 and 6667 and 7000
DEBUG:Received valid UDP packet: {'ip': '192.168.2.46', 'gwId': 'ebf310edb88d15f0edyr5i', 'uuid': '60b308e46e1b5871', 'active': 2, 'ablilty': 0, 'encrypt': True, 'productKey': 'key8u54q9dtru5jw', 'version': '3.5', 'token': True, 'wf_cfg': True, 'clientLink': 3}
DEBUG:final payload: b'0123456789abcdef'
DEBUG:payload encrypted=b'00006699000000000001000000030000002c30313233343536373839616291dcba3ea388100b9931b38a4fd0a7a2a8d102cf5ade930670dab0afa5994c0200009966'
DEBUG:decrypting=b'136ffc5da9d1cc22\x0c3\xc8\xcd\xbf\xc1\xc6_\xcf,\x12\x15G\xb3\xa8)N\x806 \xa1\xa0\x88^vea\x97?\xac\xde('
WARNING:v3.4 device session key step 2 decrypt failed, payload=b'136ffc5da9d1cc22\x0c3\xc8\xcd\xbf\xc1\xc6_\xcf,\x12\x15G\xb3\xa8)N\x806 \xa1\xa0\x88^vea\x97?\xac\xde(' (len:48) l-key:b'0afcd6c2451d2f3e' l-nonce:b'0123456789abcdef'
Traceback (most recent call last):
  File "D:\Users\Felix\Desktop\tuya\tinytuya\tinytuya\scanner.py", line 298, in v34_negotiate_sess_key_step_2
    payload = cipher.decrypt(payload, False, decode_text=False)
  File "D:\Users\Felix\Desktop\tuya\tinytuya\tinytuya\core.py", line 285, in decrypt
    raw = self._unpad(raw, verify_padding)
  File "D:\Users\Felix\Desktop\tuya\tinytuya\tinytuya\core.py", line 308, in _unpad
    raise ValueError("invalid padding length byte")
ValueError: invalid padding length byte
odata: b'\x00\x00f\x99\x00\x00\x00\x00\xde\x07\x00\x00\x00\x04\x00\x00\x00P\x86b\xcf\x81\xa9.\xd8d\x11\'F\x9a\x7f\xa0\xf7\x8e\xbf\x84O\'\xd0\x95\xa2m<\xc0\x00:\xe7\x17\xe6\x9d\xeb\xe1\xfc\xa34\'\xb8\xfc\xa5r]U}"\xfc\x1a\xe7<pVfU\x12#\xd0\xc2Ln\xd3d\xa9KRY\xfd\x7f\x82x%\x95\x15b\xfb\xb8\x11\x80\xaa\xa3\x00\x00\x99f'
DEBUG:final payload: b'0123456789abcdef'
DEBUG:payload encrypted=b'00006699000000000001000000030000002c30313233343536373839616291dcba3ea388100b9931b38a4fd0a7a2a8d102cf5ade930670dab0afa5994c0200009966'
DEBUG:decrypting=b'740f7c3406c92e01\x0c3\xc8\xcd\xbf\xc1\xc6_\xcf,\x12\x15G\xb3\xa8)N\x806 \xa1\xa0\x88^vea\x97?\xac\xde('
WARNING:v3.4 device session key step 2 decrypt failed, payload=b'740f7c3406c92e01\x0c3\xc8\xcd\xbf\xc1\xc6_\xcf,\x12\x15G\xb3\xa8)N\x806 \xa1\xa0\x88^vea\x97?\xac\xde(' (len:48) l-key:b'0afcd6c2451d2f3e' l-nonce:b'0123456789abcdef'
Traceback (most recent call last):
  File "D:\Users\Felix\Desktop\tuya\tinytuya\tinytuya\scanner.py", line 298, in v34_negotiate_sess_key_step_2
    payload = cipher.decrypt(payload, False, decode_text=False)
  File "D:\Users\Felix\Desktop\tuya\tinytuya\tinytuya\core.py", line 285, in decrypt
    raw = self._unpad(raw, verify_padding)
  File "D:\Users\Felix\Desktop\tuya\tinytuya\tinytuya\core.py", line 308, in _unpad
    raise ValueError("invalid padding length byte")
ValueError: invalid padding length byte
odata: b'\x00\x00f\x99\x00\x00\x00\x00\xd08\x00\x00\x00\x04\x00\x00\x00P\x1e\x0fs\xb0\x9c\xb7LXwOJ\xcbK\xb3,\xea\xf0\xc9\xb5\x97\xd8\xba\xc9G\xac\'\x07\x1e\x98\x94\xcf?\x886\xaf"am(\xf0\x9e\n\xac\xaa\x15\xc1u2N\xc5a6\xdc\x98?\n\x91o{\x075\xb0\x98\x03\xf1\x16\'\xa2\xb5\x18^A\xa8s\x1e\x01\xef:\x19t\x00\x00\x99f'
DEBUG:final payload: b'0123456789abcdef'
DEBUG:payload encrypted=b'00006699000000000001000000030000002c30313233343536373839616291dcba3ea388100b9931b38a4fd0a7a2a8d102cf5ade930670dab0afa5994c0200009966'
DEBUG:decrypting=b'9faadc2bc9259875\x0c3\xc8\xcd\xbf\xc1\xc6_\xcf,\x12\x15G\xb3\xa8)N\x806 \xa1\xa0\x88^vea\x97?\xac\xde('
WARNING:v3.4 device session key step 2 decrypt failed, payload=b'9faadc2bc9259875\x0c3\xc8\xcd\xbf\xc1\xc6_\xcf,\x12\x15G\xb3\xa8)N\x806 \xa1\xa0\x88^vea\x97?\xac\xde(' (len:48) l-key:b'0afcd6c2451d2f3e' l-nonce:b'0123456789abcdef'
Traceback (most recent call last):
  File "D:\Users\Felix\Desktop\tuya\tinytuya\tinytuya\scanner.py", line 298, in v34_negotiate_sess_key_step_2
    payload = cipher.decrypt(payload, False, decode_text=False)
  File "D:\Users\Felix\Desktop\tuya\tinytuya\tinytuya\core.py", line 285, in decrypt
    raw = self._unpad(raw, verify_padding)
  File "D:\Users\Felix\Desktop\tuya\tinytuya\tinytuya\core.py", line 308, in _unpad
    raise ValueError("invalid padding length byte")
ValueError: invalid padding length byte
odata: b"\x00\x00f\x99\x00\x00\x00\x000\x86\x00\x00\x00\x04\x00\x00\x00P\x8eF\xc8R\xa5f\xd7\xbd\xdf8\xed+#\x7f\xb5N\xbc2\x86\xd5l\xc2RKeMM\xcb\xc1^\xbfF!\x9f\x19%\xa0\xa0B\x89\xefI\xc6\xcf\xa3\xa3i\xc4d\xa4ssD@\xf2\x83\xea?\x1c\xbe\xa6\xbc\x17}kg\x8f>\xd7\xe0E\x97l\xfc\x11\xedu'\x8f\xb1\x00\x00\x99f"
36819   Product ID = key8u54q9dtru5jw  [Valid Broadcast]:
    Address = 192.168.2.46   Device ID = ebf310edb88d15f0edyr5i (len:22)  Local Key = 0afcd6c2451d2f3e  Version = 3.5  Type = default, MAC = 38:1f:8d:36:d2:03
    Polling 192.168.2.46 Failed: v3.4 device session key step 2 decrypt failed, payload=b'9faadc2bc9259875\x0c3\xc8\xcd\xbf\xc1\xc6_\xcf,\x12\x15G\xb3\xa8)N\x806 \xa1\xa0\x88^vea\x97?\xac\xde(' (len:48) l-key:b'0afcd6c2451d2f3e' l-nonce:b'0123456789abcdef'
DEBUG:Received valid UDP packet: {'ip': '192.168.2.46', 'gwId': 'ebf310edb88d15f0edyr5i', 'uuid': '60b308e46e1b5871', 'active': 2, 'ablilty': 0, 'encrypt': True, 'productKey': 'key8u54q9dtru5jw', 'version': '3.5', 'token': True, 'wf_cfg': True, 'clientLink': 3}
DEBUG:Received valid UDP packet: {'ip': '192.168.2.46', 'gwId': 'ebf310edb88d15f0edyr5i', 'uuid': '60b308e46e1b5871', 'active': 2, 'ablilty': 0, 'encrypt': True, 'productKey': 'key8u54q9dtru5jw', 'version': '3.5', 'token': True, 'wf_cfg': True, 'clientLink': 3}
DEBUG:Received valid UDP packet: {'ip': '192.168.2.46', 'gwId': 'ebf310edb88d15f0edyr5i', 'uuid': '60b308e46e1b5871', 'active': 2, 'ablilty': 0, 'encrypt': True, 'productKey': 'key8u54q9dtru5jw', 'version': '3.5', 'token': True, 'wf_cfg': True, 'clientLink': 3}
Scan completed in 18.0862 seconds

Scan Complete!  Found 1 devices.
Broadcasted: 1
Versions: 3.5: 1

>> Saving device snapshot data to snapshot.json

DEBUG:Scan complete with 1 devices found

This is on commit 19e2cbe5de2c7443d621de67072d81d33106df49

@uzlonewolf
Copy link
Collaborator

Lovely. I'll get that fixed.

@Oglaf
Copy link

Oglaf commented Jan 16, 2023

Scan results:

TinyTuya (Tuya device scanner) [1.10.0]

[Loaded devices.json - 9 devices]

Scanning on UDP ports 6666 and 6667 and 7000 for devices for 18 seconds...

Smart Plug WiFi  2   Product ID = keydnqmh87c8ajv4  [Valid Broadcast]:
    Address = 192.168.1.207   Device ID = eb597c0e524d178a80caat (len:22)  Local Key = bdf5b78fccf86c7b  Version = 3.3  Type = default, MAC = d8:1f:12:d2:55:d1
    Status: {'1': True, '9': 0, '17': 37, '18': 578, '19': 705, '20': 1269, '21': 1, '22': 617, '23': 31090, '24': 17649, '25': 1180, '26': 0}
Smart Lâmpada WiFi 2   Product ID = keytg5kq8gvkv9dh  [Valid Broadcast]:
    Address = 192.168.1.204   Device ID = ebd1b02d382049733dnq0u (len:22)  Local Key = c383f271346743c0  Version = 3.3  Type = default, MAC = d8:1f:12:c9:54:66
    Status: {'20': False, '21': 'white', '22': 126, '23': 0, '24': '0159023b0006', '25': '010e0d0000000000000003e801f4', '26': 0, '34': False}
Smart Plug   Product ID = keym9qkuywghyrvs  [Valid Broadcast]:
    Address = 192.168.1.201   Device ID = eb06b9ad96cc645217ruup (len:22)  Local Key = 5cd62b469b6d961e  Version = 3.3  Type = default, MAC = 7c:f6:66:86:bf:06
    Status: {'1': False, '9': 0, '17': 13, '18': 0, '19': 0, '20': 1266, '21': 1, '22': 564, '23': 29000, '24': 15795, '25': 2640, '26': 0, '38': 'memory', '41': '', '42': '', '46': True}
Smart Lâmpada WiFi   Product ID = keytg5kq8gvkv9dh  [Valid Broadcast]:
    Address = 192.168.1.203   Device ID = eb3dcc68131b35ae344alc (len:22)  Local Key = d9bb19e75b0aa051  Version = 3.3  Type = default, MAC = d8:1f:12:c9:54:c4
    Status: {'20': False, '21': 'white', '22': 18, '23': 0, '24': '003c03e802d9', '25': '000e0d0000000000000000c80000', '26': 0, '34': False}
Smart Plug WiFi   Product ID = keydnqmh87c8ajv4  [Valid Broadcast]:
    Address = 192.168.1.206   Device ID = eb099f68fc98defbd6vqcs (len:22)  Local Key = dfd4cb0ca6a36d8a  Version = 3.3  Type = default, MAC = d8:1f:12:d2:57:71
    Status: {'1': False, '9': 0, '17': 2, '18': 0, '19': 0, '20': 1266, '21': 1, '22': 625, '23': 31468, '24': 18126, '25': 1148, '26': 0}
Pet feeder   Product ID = 5xierbs16mkdnkpk  [Valid Broadcast]:
    Address = 192.168.1.200   Device ID = eb629cf13d51f2d0d5gv7t (len:22)  Local Key = 99af400dccb3a41b  Version = 3.3  Type = default, MAC = 7c:f6:66:22:b7:b0
    Status: {'4': 'standby', '14': 0, '15': 1}
v3.4 device session key step 2 decrypt failed, payload=b'a9953944c20833fc\xa2jN\xbf?\x07H\xc3\x1f37\xe4\x97\xc2\xae\x07\x8d\x92\xe1\x9a\xb4N\x95\x89\xd5h\x84\xf5\xfc~\xe1\x9c' (len:48) l-key:b'6434389541e96704' l-nonce:b'0123456789abcdef'
Traceback (most recent call last):
  File "C:\Users\chris\OneDrive\Documents\GitHub\tinytuya3.5\tinytuya\scanner.py", line 298, in v34_negotiate_sess_key_step_2
    payload = cipher.decrypt(payload, False, decode_text=False)
  File "C:\Users\chris\OneDrive\Documents\GitHub\tinytuya3.5\tinytuya\core.py", line 285, in decrypt
    raw = self._unpad(raw, verify_padding)
  File "C:\Users\chris\OneDrive\Documents\GitHub\tinytuya3.5\tinytuya\core.py", line 308, in _unpad
    raise ValueError("invalid padding length byte")
ValueError: invalid padding length byte
odata: b'\x00\x00f\x99\x00\x00\x00\x00\x85\xc5\x00\x00\x00\x04\x00\x00\x00PT\x0f1"\'\xe5dP\xae\xa6\xd4\xdf\x9cxu\xb2\xb7\xbe\x13L\xd4\r\xe43\xe7t\xa1\xa2\xfd\x80\xcf\xd1\x1a>\xfd\xceJ\xb4\xfc\xdb\xf1L2I\x079\xf85\xf9V{3\xd0\x1f<yW\x89\xb6\xc8?\xd5\xdf\r\xb1[\x18Chy\xbf\xc4\xbe#\xcf\xcdf\xde\xde\xc9\x00\x00\x99f'
v3.4 device session key step 2 decrypt failed, payload=b'4fd1d9044e0f1f7f\xa2jN\xbf?\x07H\xc3\x1f37\xe4\x97\xc2\xae\x07\x8d\x92\xe1\x9a\xb4N\x95\x89\xd5h\x84\xf5\xfc~\xe1\x9c' (len:48) l-key:b'6434389541e96704' l-nonce:b'0123456789abcdef'
Traceback (most recent call last):
  File "C:\Users\chris\OneDrive\Documents\GitHub\tinytuya3.5\tinytuya\scanner.py", line 298, in v34_negotiate_sess_key_step_2
    payload = cipher.decrypt(payload, False, decode_text=False)
  File "C:\Users\chris\OneDrive\Documents\GitHub\tinytuya3.5\tinytuya\core.py", line 285, in decrypt
    raw = self._unpad(raw, verify_padding)
  File "C:\Users\chris\OneDrive\Documents\GitHub\tinytuya3.5\tinytuya\core.py", line 308, in _unpad
    raise ValueError("invalid padding length byte")
ValueError: invalid padding length byte
odata: b"\x00\x00f\x99\x00\x00\x00\x00\xdf\x9f\x00\x00\x00\x04\x00\x00\x00PT\xba;FlD\x7f9}\n\x87\xa7\x9b'!\x82Z\x7f\x16G\x94\xa9/17S,\xbb\x8bgAG\xdcl\xdcP\xc5\xe2\xe2\xbc\xff\\_\xa4\x12LA\x9b\xaep\x947!\x8c-\xb1\xd3\xd8\x85\x9bv3\xbe:\x99\x11VG\xe6|\xd5\xa5\xa4\x82\x00\x90\x17\x11\xf3g\x00\x00\x99f"
v3.4 device session key step 2 decrypt failed, payload=b'c3c37fa71b1cc252\xa2jN\xbf?\x07H\xc3\x1f37\xe4\x97\xc2\xae\x07\x8d\x92\xe1\x9a\xb4N\x95\x89\xd5h\x84\xf5\xfc~\xe1\x9c' (len:48) l-key:b'6434389541e96704' l-nonce:b'0123456789abcdef'
Traceback (most recent call last):
  File "C:\Users\chris\OneDrive\Documents\GitHub\tinytuya3.5\tinytuya\scanner.py", line 298, in v34_negotiate_sess_key_step_2
    payload = cipher.decrypt(payload, False, decode_text=False)
  File "C:\Users\chris\OneDrive\Documents\GitHub\tinytuya3.5\tinytuya\core.py", line 285, in decrypt
    raw = self._unpad(raw, verify_padding)
  File "C:\Users\chris\OneDrive\Documents\GitHub\tinytuya3.5\tinytuya\core.py", line 308, in _unpad
    raise ValueError("invalid padding length byte")
ValueError: invalid padding length byte
odata: b'\x00\x00f\x99\x00\x00\x00\x00\xb9\x1c\x00\x00\x00\x04\x00\x00\x00P"\x1b\xdb6\x11\xb3\xd3\nY\xac)\xe2\xaf\xc8]{\xcc;\x14S\x00\xb2M\xba\xe6\x94\xb8\xff\xc1\xea*\xb3\x11\x92\x97\xc8\xba\xf8\xcb\xe6\xb94~\xe1\xa3h5\xf4O9k\x0eU\xa8-\x7f@\x05\xc4\x1e-4/A\x98d\x8d;5\xe2\xe0N4\xce#\xec\xe8\xad?4\x00\x00\x99f'
EWS 410   Product ID = key8u54q9dtru5jw  [Valid Broadcast]:
    Address = 192.168.1.205   Device ID = eb68e355da1be4ae69ok5o (len:22)  Local Key = 6434389541e96704  Version = 3.5  Type = default, MAC = 38:1f:8d:4f:66:f6
    Polling 192.168.1.205 Failed: v3.4 device session key step 2 decrypt failed, payload=b'c3c37fa71b1cc252\xa2jN\xbf?\x07H\xc3\x1f37\xe4\x97\xc2\xae\x07\x8d\x92\xe1\x9a\xb4N\x95\x89\xd5h\x84\xf5\xfc~\xe1\x9c' (len:48) l-key:b'6434389541e96704' l-nonce:b'0123456789abcdef'
Scan completed in 18.0443 seconds

Scan Complete!  Found 7 devices.
Broadcasted: 7
Versions: 3.3: 6, 3.5: 1

Snapshot:

TinyTuya (Tuya device scanner) [1.10.0]

Loaded snapshot.json - 9 devices:

Name                      ID                       IP                 Key               Version

Cleaner Robot             eb1f0804f3145f2189grsj   Error: No IP found 25b2c81f286581e7  0    
EWS 410                   eb68e355da1be4ae69ok5o   192.168.1.205      6434389541e96704  3.5
Pet feeder                eb629cf13d51f2d0d5gv7t   192.168.1.200      99af400dccb3a41b  3.3
Smart Lâmpada WiFi        eb3dcc68131b35ae344alc   192.168.1.203      d9bb19e75b0aa051  3.3
Smart Lâmpada WiFi 2      ebd1b02d382049733dnq0u   192.168.1.204      c383f271346743c0  3.3
Smart Plug                eb06b9ad96cc645217ruup   192.168.1.201      5cd62b469b6d961e  3.3
Smart Plug WiFi           eb099f68fc98defbd6vqcs   192.168.1.206      dfd4cb0ca6a36d8a  3.3
Smart Plug WiFi  2        eb597c0e524d178a80caat   192.168.1.207      bdf5b78fccf86c7b  3.3
Temperature Sensor        ebf3e7c38a62e56ab4a8jf   Error: No IP found 4c5186b1731b332a  0

Poll local devices? (Y/n): y

Polling 9 local devices from last snapshot...
Traceback (most recent call last):
  File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.10_3.10.2544.0_x64__qbz5n2kfra8p0\lib\runpy.py", line 196, in _run_module_as_main
    return _run_code(code, main_globals, None,
  File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.10_3.10.2544.0_x64__qbz5n2kfra8p0\lib\runpy.py", line 86, in _run_code
    exec(code, run_globals)
  File "C:\Users\chris\OneDrive\Documents\GitHub\tinytuya3.5\tinytuya\__main__.py", line 86, in <module>
    scanner.snapshot(color=color)
  File "C:\Users\chris\OneDrive\Documents\GitHub\tinytuya3.5\tinytuya\scanner.py", line 1687, in snapshot
    result = devices(verbose=False, scantime=0, color=color, poll=True, byID=True, discover=False, snapshot=by_ip)
  File "C:\Users\chris\OneDrive\Documents\GitHub\tinytuya3.5\tinytuya\scanner.py", line 1295, in devices
    rd, _, _ = select.select( read_socks, [], [], 0 )
OSError: [WinError 10022] An invalid argument was supplied

Script:

import tinytuya

d = tinytuya.OutletDevice('eb68e355da1be4ae69ok5o', '192.168.1.205', '6434389541e96704')
d.set_version(3.5)
d.set_socketPersistent(True)
print(d.status())

Result:
{'dps': {'20': True, '21': 'white', '22': 946, '23': 3, '24': '014a03e803a9', '25': '04464602007803e803e800000000464602007803e8000a00000000', '26': 0, '34': False}}

Edit: Corrected status result.

@jasonacox
Copy link
Owner

Thanks @Oglaf - That's great news on the status() success! 🎉 Thanks for your help.

@uzlonewolf is looking at the scanner issues.

@Xilef11
Copy link
Author

Xilef11 commented Jan 17, 2023

Well that PR does give correct output on python -m tinytuya scan and snapshot. Control also seems to work (using BulbDevice.set_colourtemp and BulbDevice.set_brightness

@jasonacox
Copy link
Owner

That's great news! Thanks for helping test. The changes from @uzlonewolf have been merged into the main repo.

A huge thanks to @uzlonewolf ! 🙇 You are brilliant!

Please report any other issues. I'll continue my standard battery of test (even though I don't have a 3.5 device) and if all goes well, will be releasing tinytuya v1.10.0 to PyPI later tonight.

@jasonacox
Copy link
Owner

New release published https://pypi.org/project/tinytuya/1.10.0/

pip install --upgrade tinytuya

@Apollon77
Copy link

@uzlonewolf I also stumbled over that. One question: Is just the "discovery" message is in the new format or also all local messages?

@uzlonewolf
Copy link
Collaborator

@Apollon77 All messages, both discovery and local.

@Apollon77
Copy link

Thank you ... yeeaaayyy ... more work :-) ... They should concentrate on Matter (like me) and not to invent new tuya protocols ;-)

@uzlonewolf
Copy link
Collaborator

Added a "Device discovery broadcast packets" section to my Protocol Notes #260

@Apollon77
Copy link

Thank you!

@uzlonewolf
Copy link
Collaborator

If anyone wants v3.5 devices, the bulbs I got from https://www.ebay.com/itm/395006526624 came with v3.5 (firmware is reporting V1.5.21).

@jasonacox
Copy link
Owner

Thanks! Ordered.

@jasonacox
Copy link
Owner

Got this today. You are right, finally have my first legit v3.5 device. 😂

SmartBulb Product ID = key8u54q9dtru5jw [Valid Broadcast]:
Address = 10.0.1.94 Device ID = ************************** (len:22) Local Key = ************ Version = 3.5 Type = default, MAC = 18:de:50:e7:12:64
Status: {'20': False, '21': 'white', '22': 596, '23': 0, '24': '00d603e803e8', '25': '000e0d0000000000000000c80000', '26': 0, '34': False}

@nospam2k
Copy link

nospam2k commented Aug 1, 2024

@uzlonewolf Can you please provide a simple decrypt packet test for 3.5 as you did for this request. I'm wanting to try and update tuyapi for 3.5. I have the request working but I can't get the decrypt to work. Thanks!

Can @Xilef11 or @Oglaf run this and let me know if it reports anything? Make sure to fill in your IP and local key.

import socket
import time
import struct
from hashlib import md5,sha256
from Crypto.Cipher import AES

ip = '192.168..'
key = b'YOUR LOCAL KEY'


for i in range( 2 ):
    sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
    sock.settimeout( 5 )
    sock.connect( (ip, 6668) )
    print( 'connected!' )
    stime = time.time()
    local_nonce = b'0123456789abcdef' # not-so-random random key
    local_iv = local_nonce[:12]       # not-so-random random iv

    pkt = struct.pack( ">IHIII", 0x6699, 0, 1, 3, len(local_nonce)+len(local_iv)+16 )

    c = AES.new(key, AES.MODE_GCM, nonce=local_iv)
    c.update( pkt[4:] )
    encrypted, tag = c.encrypt_and_digest( local_nonce )

    pkt += local_iv + encrypted + tag + struct.pack( ">I", 0x9966 )

    #print( pkt )
    #print( pkt.hex() )

    sock.sendall( pkt )

    try:
        data = sock.recv( 4096 )
    except:
        data = None

    print( 'data:', data, 'in', (time.time() - stime) )

    sock.close()
    sock = None

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

Successfully merging a pull request may close this issue.

6 participants