jasonacox / tinytuya

Python API for Tuya WiFi smart devices using a direct local area network (LAN) connection or the cloud (TuyaCloud API).
MIT License
1.02k stars 181 forks source link

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

Closed Xilef11 closed 1 year ago

Xilef11 commented 1 year ago

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 commented 1 year ago

Found them @uzlonewolf - Thanks!

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

uzlonewolf commented 1 year ago

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

Oglaf commented 1 year ago

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

jasonacox commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

Lovely. I'll get that fixed.

Oglaf commented 1 year ago

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 commented 1 year ago

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

@uzlonewolf is looking at the scanner issues.

Xilef11 commented 1 year ago

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 commented 1 year ago

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 commented 1 year ago

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

pip install --upgrade tinytuya
Apollon77 commented 1 year ago

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

uzlonewolf commented 1 year ago

@Apollon77 All messages, both discovery and local.

Apollon77 commented 1 year ago

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

uzlonewolf commented 1 year ago

Added a "Device discovery broadcast packets" section to my Protocol Notes https://github.com/jasonacox/tinytuya/discussions/260

Apollon77 commented 1 year ago

Thank you!

uzlonewolf commented 11 months ago

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 commented 11 months ago

Thanks! Ordered.

jasonacox commented 10 months ago

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 commented 3 months ago

@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