jasonacox / tinytuya

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

Unable to control Universal IR Device #225

Closed anar4732 closed 1 year ago

anar4732 commented 1 year ago

Hi. just bought a Smart IR Remote Control Hub unable to control it with tinytuya

I can control the device with Tuya App. the led on the device blinks when sending any button with the app. But there is no response from the device nor the led blinks when trying to control it with tinytuya

python -m tinytuya scan

TinyTuya (Tuya device scanner) [1.8.0]

[Loaded devices.json - 3 devices]

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

Smart IR   Product ID = keyf9fsmuufeywsr  [Valid payload]:
    Address = 192.168.0.184,  Device ID = 35217541c45bbef5a1f1, Local Key = e363f4ddda******,  Version = 3.3, MAC = c4:5b:**:**:**:**
    Status: {'1': 'send_ir'}

Scan Complete!  Found 1 devices.

>> Saving device snapshot data to snapshot.json

My Code:

import tinytuya
from tinytuya import Contrib

tinytuya.set_debug(toggle=True, color=False)

ir = Contrib.IRRemoteControlDevice("35217541c45bbef5a1f1")

ir.send_button("IyOvEToCZQI5AkoCOgJNAjYCTwI4AlACNQJMAjkCTQI2ApsGSwKZBkkClwZMAp8GLALLBhgC0wYRAtMGEwLRBhMCbgIdAmkCGwLKBhsCagIaAsoGGgJzAhACbwIWAnICFAJvAh0CxgYdAmoCFwLMBhoCcAIUAtAGFALRBhQC0QYUAtAGFQKXnBgjCAkXAiDL")
# Nothing happenes, no light on IR device.
"""
DEBUG:TinyTuya [1.8.0]

DEBUG:loaded=devices.json [3 devices]
DEBUG:Device '35217541c45bbef5a1f1' found in devices.json
DEBUG:Listening for device 35217541c45bbef5a1f1 on the network
DEBUG:find() received broadcast from '192.168.0.184': {'ip': '192.168.0.184', 'gwId': '35217541c45bbef5a1f1', 'active': 2, 'ability': 0, 'mode': 0, 'encrypt': True, 'productKey': 'keyf9fsmuufeywsr', 'version': '3.3'}
DEBUG:find() is returning: {'ip': '192.168.0.184', 'version': '3.3', 'id': '35217541c45bbef5a1f1', 'product_id': 'keyf9fsmuufeywsr', 'data': {'ip': '192.168.0.184', 'gwId': '35217541c45bbef5a1f1', 'active': 2, 'ability': 0, 'mode': 0, 'encrypt': True, 'productKey': 'keyf9fsmuufeywsr', 'version': '3.3'}}
DEBUG:Sending IR Button: 1IyOvEToCZQI5AkoCOgJNAjYCTwI4AlACNQJMAjkCTQI2ApsGSwKZBkkClwZMAp8GLALLBhgC0wYRAtMGEwLRBhMCbgIdAmkCGwLKBhsCagIaAsoGGgJzAhACbwIWAnICFAJvAh0CxgYdAmoCFwLMBhoCcAIUAtAGFALRBhQC0QYUAtAGFQKXnBgjCAkXAiDL
DEBUG:Pulses and gaps (microseconds): p8995 g4527 p570 g613 p569 g586 p570 g589 p566 g591 p568 g592 p565 g588 p569 g589 p566 g1691 p587 g1689 p585 g1687 p588 g1695 p556 g1739 p536 g1747 p529 g1747 p531 g1745 p531 g622 p541 g617 p539 g1738 p539 g618 p538 g1738 p538 g627 p528 g623 p534 g626 p532 g623 p541 g1734 p541 g618 p535 g1740 p538 g624 p532 g1744 p532 g1745 p532 g1745 p532 g1744 p533 g40087 p8984 g2312 p535 g52000
DEBUG:building command 7 payload=b'{"devId":"35217541c45bbef5a1f1","uid":"35217541c45bbef5a1f1","t":"1669663589","dps":{"201":"{\\"control\\":\\"send_ir\\",\\"key1\\":\\"1IyOvEToCZQI5AkoCOgJNAjYCTwI4AlACNQJMAjkCTQI2ApsGSwKZBkkClwZMAp8GLALLBhgC0wYRAtMGEwLRBhMCbgIdAmkCGwLKBhsCagIaAsoGGgJzAhACbwIWAnICFAJvAh0CxgYdAmoCFwLMBhoCcAIUAtAGFALRBhQC0QYUAtAGFQKXnBgjCAkXAiDL\\",\\"type\\":0}"}}'
DEBUG:sending payload
DEBUG:payload encrypted=b'000055aa000000010000000700000177332e330000000000000000000000008286c18de89ac00b7ddfb5d573b9d4fca92603bab7c419c3f95a4c2c092a7657a99f76692b7aebd8fbcc7ee14d8db5fe7d592a36396dd0f232d55044095a6cd409b3c064c928b641c7ee260c44f9d738092c0026982bc755b836371ca69615975992bc30ee5d3b16c1c84f479378786abf7ea14f247ec18cf96bc3ff97b6ac7d634eb1e6e7378acc4083156562a982f35427bc934b17d782908d21959690c93c26500b9be3a535f25187bddd89b8ebaffd5efc8cc530383b1d2f503b3bfcad05bd9e65e6b23d0ebdf5a0ba48a4935dc4b64b4ffb72f1162d785a25b2ff18e765bcd8d6d1970eab08673bf71495a515387e6ab544a457588755801bae904a721612be37298018a58f792a687784c9d0f6fe1294a1bfd2e1a562f05388fa25cb31b2e994426b4477906183f9a9b08f38b7065c364e14e964ba76fcb0a849037b663dae1cc3e160cd05ec05f52bd93fbd130a24d1dbcf811b12f82b0d209f294705879859bf0000aa55'
"""

ir.receive_button(5)
# Doesn't detect the button.
"""
DEBUG:Receiving button
DEBUG:building command 7 payload=b'{"devId":"35217541c45bbef5a1f1","uid":"35217541c45bbef5a1f1","t":"1669664119","dps":{"201":"{\\"control\\":\\"study_exit\\"}"}}'
DEBUG:sending payload
DEBUG:payload encrypted=b'000055aa000000020000000700000097332e330000000000000000000000008286c18de89ac00b7ddfb5d573b9d4fca92603bab7c419c3f95a4c2c092a7657a99f76692b7aebd8fbcc7ee14d8db5fe7d592a36396dd0f232d55044095a6cd477089ae18f65a19697953ea7c4b6cd3f092c0026982bc755b836371ca6961597690bacb94b08137fb62ae91bd9d3e7e2c4b344921ec4e3057f1ddbf29d32cf6457e94ae50000aa55'
DEBUG:building command 7 payload=b'{"devId":"35217541c45bbef5a1f1","uid":"35217541c45bbef5a1f1","t":"1669664119","dps":{"201":"{\\"control\\":\\"study\\"}"}}'
DEBUG:sending payload
DEBUG:payload encrypted=b'000055aa000000030000000700000097332e330000000000000000000000008286c18de89ac00b7ddfb5d573b9d4fca92603bab7c419c3f95a4c2c092a7657a99f76692b7aebd8fbcc7ee14d8db5fe7d592a36396dd0f232d55044095a6cd477089ae18f65a19697953ea7c4b6cd3f092c0026982bc755b836371ca6961597690bacb94b08137fb62ae91bd9d3e7e2c7be09cf6b0a43f19843a54721b58fdefc7b5c2d0000aa55'
DEBUG:Waiting for button...
DEBUG:received data=b'000055aa00000003000000070000000c00000000c5591c5f0000aa55'
DEBUG:received null payload (TuyaMessage(seqno=3, cmd=7, retcode=0, payload=b'', crc=3310951519, crc_good=True)), fetch new one - retry 0 / 5
DEBUG:Timeout
DEBUG:building command 7 payload=b'{"devId":"35217541c45bbef5a1f1","uid":"35217541c45bbef5a1f1","t":"1669664124","dps":{"201":"{\\"control\\":\\"study_exit\\"}"}}'
DEBUG:sending payload
DEBUG:payload encrypted=b'000055aa000000040000000700000097332e330000000000000000000000008286c18de89ac00b7ddfb5d573b9d4fca92603bab7c419c3f95a4c2c092a7657a99f76692b7aebd8fbcc7ee14d8db5fe7d592a36396dd0f232d55044095a6cd4598289ebdc0b573ed82cb8f74625ee46092c0026982bc755b836371ca6961597690bacb94b08137fb62ae91bd9d3e7e2c4b344921ec4e3057f1ddbf29d32cf64cbf51ce30000aa55'
"""
anar4732 commented 1 year ago

@ClusterM since you added this support, can you help with this?

uzlonewolf commented 1 year ago

This might be one of the new devices mentioned in #74.

After sending a command with the app, what do the device debug logs show? What DPS are they using? These can be found in the Tuya developer portal (instructions for getting them can be found at https://www.zigbee2mqtt.io/advanced/support-new-devices/03_find_tuya_data_points.html#_7-find-your-devices )

anar4732 commented 1 year ago

Hi @uzlonewolf those are shown after sending a command with the app. image The IDs are 1.2.3 and so on. image

uzlonewolf commented 1 year ago

Thanks for that. What happens if you run:

import tinytuya

tinytuya.set_debug(toggle=True, color=False)

ir = tinytuya.Device("35217541c45bbef5a1f1", version=3.3, persist=True)

ir.set_value(3, "1IyOvEToCZQI5AkoCOgJNAjYCTwI4AlACNQJMAjkCTQI2ApsGSwKZBkkClwZMAp8GLALLBhgC0wYRAtMGEwLRBhMCbgIdAmkCGwLKBhsCagIaAsoGGgJzAhACbwIWAnICFAJvAh0CxgYdAmoCFwLMBhoCcAIUAtAGFALRBhQC0QYUAtAGFQKXnBgjCAkXAiDL")
ir.set_value(1, "send_ir")
anar4732 commented 1 year ago

@uzlonewolf

DEBUG:TinyTuya [1.8.0]

DEBUG:loaded=devices.json [3 devices]
DEBUG:Device '35217541c45bbef5a1f1' found in devices.json
DEBUG:Listening for device 35217541c45bbef5a1f1 on the network
DEBUG:find() received broadcast from '192.168.0.184': {'ip': '192.168.0.184', 'gwId': '35217541c45bbef5a1f1', 'active': 2, 'ability': 0, 'mode': 0, 'encrypt': True, 'productKey': 'keyf9fsmuufeywsr', 'version': '3.3'}
DEBUG:find() is returning: {'ip': '192.168.0.184', 'version': '3.3', 'id': '35217541c45bbef5a1f1', 'product_id': 'keyf9fsmuufeywsr', 'data': {'ip': '192.168.0.184', 'gwId': '35217541c45bbef5a1f1', 'active': 2, 'ability': 0, 'mode': 0, 'encrypt': True, 'productKey': 'keyf9fsmuufeywsr', 'version': '3.3'}}
DEBUG:building command 7 payload=b'{"devId":"35217541c45bbef5a1f1","uid":"35217541c45bbef5a1f1","t":"1669736185","dps":{"3":"1IyOvEToCZQI5AkoCOgJNAjYCTwI4AlACNQJMAjkCTQI2ApsGSwKZBkkClwZMAp8GLALLBhgC0wYRAtMGEwLRBhMCbgIdAmkCGwLKBhsCagIaAsoGGgJzAhACbwIWAnICFAJvAh0CxgYdAmoCFwLMBhoCcAIUAtAGFALRBhQC0QYUAtAGFQKXnBgjCAkXAiDL"}}'
DEBUG:sending payload
DEBUG:payload encrypted=b'000055aa000000010000000700000137332e330000000000000000000000008286c18de89ac00b7ddfb5d573b9d4fca92603bab7c419c3f95a4c2c092a7657a99f76692b7aebd8fbcc7ee14d8db5fe7d592a36396dd0f232d55044095a6cd40d6666b9c826beff76f702c408ff3dd3a5a7509ae3a27a13ab6bc77f7057e1e9b62c7f71b0090cea22b31587653bef9eddeb99dacfe97878f8136485446f8ebc9601141f149897d82fb45cfe97a777cdfb00a634a31e767a4d0fa281240f2628d1b345dcc7596d3d530385e718f36c9de5c484bba8980b8ff0be902dcc0add5dc011a25fc3ce18a3a5ad443b250b73dc0e5d3d9779c3c1ae61620a229091e27d8bc4e381daa7bf9cf9c3233695e30f77a3505564761d68f09c223dba1f7a102e83fcb10338f4abccd0cad74622c854a55ba7c8c7cf20543240d590372add73ee041bb7ee0000aa55'
DEBUG:received data=b'000055aa00000001000000070000000c00000000a505a9140000aa55'
DEBUG:received null payload (TuyaMessage(seqno=1, cmd=7, retcode=0, payload=b'', crc=2768611604, crc_good=True)), fetch new one - retry 0 / 5
DEBUG:building command 7 payload=b'{"devId":"35217541c45bbef5a1f1","uid":"35217541c45bbef5a1f1","t":"1669736191","dps":{"1":"send_ir"}}'
DEBUG:sending payload
DEBUG:payload encrypted=b'000055aa000000020000000700000087332e330000000000000000000000008286c18de89ac00b7ddfb5d573b9d4fca92603bab7c419c3f95a4c2c092a7657a99f76692b7aebd8fbcc7ee14d8db5fe7d592a36396dd0f232d55044095a6cd4065c583fcb201547f7cd65a36f9fadbe9d025a7eed0ae1af7b0e87c3cf63d9d53b421278a9a6f7978c8215514ac2bbaa9cf1a6840000aa55'
DEBUG:received data=b'000055aa00000002000000070000000c0000000018cfc5da0000aa55'
DEBUG:received null payload (TuyaMessage(seqno=2, cmd=7, retcode=0, payload=b'', crc=416269786, crc_good=True)), fetch new one - retry 0 / 5
DEBUG:received data=b'000055aa00000000000000080000006b00000000332e330000000000000010000000018286c18de89ac00b7ddfb5d573b9d4fca92603bab7c419c3f95a4c2c092a7657371ba5a0c5f80659b4f31e1677365d21dba163e77c54df4e162e83701fb7c894ab97ec30a23a66a4410c95ef576987c7c13fded40000aa55'
DEBUG:received message=TuyaMessage(seqno=0, cmd=8, retcode=0, payload=b'3.3\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x01\x82\x86\xc1\x8d\xe8\x9a\xc0\x0b}\xdf\xb5\xd5s\xb9\xd4\xfc\xa9&\x03\xba\xb7\xc4\x19\xc3\xf9ZL,\t*vW7\x1b\xa5\xa0\xc5\xf8\x06Y\xb4\xf3\x1e\x16w6]!\xdb\xa1c\xe7|T\xdfN\x16.\x83p\x1f\xb7\xc8\x94\xab\x97\xec0\xa2:f\xa4A\x0c\x95\xefWi\x87\xc7', crc=3242188500, crc_good=True)
DEBUG:raw unpacked message = TuyaMessage(seqno=0, cmd=8, retcode=0, payload=b'3.3\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x01\x82\x86\xc1\x8d\xe8\x9a\xc0\x0b}\xdf\xb5\xd5s\xb9\xd4\xfc\xa9&\x03\xba\xb7\xc4\x19\xc3\xf9ZL,\t*vW7\x1b\xa5\xa0\xc5\xf8\x06Y\xb4\xf3\x1e\x16w6]!\xdb\xa1c\xe7|T\xdfN\x16.\x83p\x1f\xb7\xc8\x94\xab\x97\xec0\xa2:f\xa4A\x0c\x95\xefWi\x87\xc7', crc=3242188500, crc_good=True)
DEBUG:decode payload=b'3.3\x00\x00\x00\x00\x00\x00\x00\x10\x00\x00\x00\x01\x82\x86\xc1\x8d\xe8\x9a\xc0\x0b}\xdf\xb5\xd5s\xb9\xd4\xfc\xa9&\x03\xba\xb7\xc4\x19\xc3\xf9ZL,\t*vW7\x1b\xa5\xa0\xc5\xf8\x06Y\xb4\xf3\x1e\x16w6]!\xdb\xa1c\xe7|T\xdfN\x16.\x83p\x1f\xb7\xc8\x94\xab\x97\xec0\xa2:f\xa4A\x0c\x95\xefWi\x87\xc7'
DEBUG:removing 3.x=b'\x82\x86\xc1\x8d\xe8\x9a\xc0\x0b}\xdf\xb5\xd5s\xb9\xd4\xfc\xa9&\x03\xba\xb7\xc4\x19\xc3\xf9ZL,\t*vW7\x1b\xa5\xa0\xc5\xf8\x06Y\xb4\xf3\x1e\x16w6]!\xdb\xa1c\xe7|T\xdfN\x16.\x83p\x1f\xb7\xc8\x94\xab\x97\xec0\xa2:f\xa4A\x0c\x95\xefWi\x87\xc7'
DEBUG:decrypting=b'\x82\x86\xc1\x8d\xe8\x9a\xc0\x0b}\xdf\xb5\xd5s\xb9\xd4\xfc\xa9&\x03\xba\xb7\xc4\x19\xc3\xf9ZL,\t*vW7\x1b\xa5\xa0\xc5\xf8\x06Y\xb4\xf3\x1e\x16w6]!\xdb\xa1c\xe7|T\xdfN\x16.\x83p\x1f\xb7\xc8\x94\xab\x97\xec0\xa2:f\xa4A\x0c\x95\xefWi\x87\xc7'
DEBUG:decrypted 3.x payload='{"devId":"35217541c45bbef5a1f1","dps":{"1":"send_ir"},"t":1669736191}'
DEBUG:payload type = <class 'str'>
DEBUG:decoded results='{"devId":"35217541c45bbef5a1f1","dps":{"1":"send_ir"},"t":1669736191}'
uzlonewolf commented 1 year ago

Did that work? If not, how about:

import tinytuya

tinytuya.set_debug(toggle=True, color=False)

ir = tinytuya.Device("35217541c45bbef5a1f1", version=3.3, persist=True)

ir.set_value(4, "01%^002001FE50AF@&%*@(")
ir.set_value(3, "020ed8000000000008001600160042015600ac05f3005807b8")
ir.set_value(1, "send_ir")
anar4732 commented 1 year ago

Did that work? If not, how about:

import tinytuya

tinytuya.set_debug(toggle=True, color=False)

ir = tinytuya.Device("35217541c45bbef5a1f1", version=3.3, persist=True)

ir.set_value(4, "01%^002001FE50AF@&%*@(")
ir.set_value(3, "020ed8000000000008001600160042015600ac05f3005807b8")
ir.set_value(1, "send_ir")

nothing happening on the device. (no led blink too) 😟

uzlonewolf commented 1 year ago

Can you post the IDs for "Send Delay" and "Code library label"?

Better yet, can you post all of them? If you bring up the developer console before clicking on the "Device Logs" tab then the very first "list" should list all of them. Screenshot from 2022-11-29 08-42-27 cropped

anar4732 commented 1 year ago

@uzlonewolf here. image

uzlonewolf commented 1 year ago

Thanks for that. Try these:

import tinytuya

tinytuya.set_debug(toggle=True, color=False)

ir = tinytuya.Device("35217541c45bbef5a1f1", version=3.3, persist=True)

ir.set_value(4, "01%^002001FE50AF@&%*@(")
ir.set_value(3, "020ed8000000000008001600160042015600ac05f3005807b8")
ir.set_value(13, 0)
ir.set_value(10, 300)
ir.set_value(1, "send_ir")

or

import tinytuya

tinytuya.set_debug(toggle=True, color=False)

ir = tinytuya.Device("35217541c45bbef5a1f1", version=3.3, persist=True)

ir.set_value(4, "01%^002001FE50AF@&%*@(")
ir.set_value(3, "020ed8000000000008001600160042015600ac05f3005807b8")
ir.set_value(13, 0)
ir.set_value(10, 300)
ir.set_value(1, "send")

If neither of those work then it's going to have to wait until I have one to poke at, hopefully late tomorrow.

anar4732 commented 1 year ago

still not work 😟

anar4732 commented 1 year ago

is there a way to sniff the packages the app sends?

uzlonewolf commented 1 year ago

Yes, however it's not exactly easy unless you've done it before. You basically need to keep your phone connected to the WiFi but block all internet access (both cellular and via WiFi), sniff the WiFi packets to the device, and then decrypt them with the local key. It's not too bad if you have an environment set up to do it, but the first time will take a while to get everything set up.

Amazon says mine will be delivered later today, so expect a patch later tonight.

uzlonewolf commented 1 year ago

Well that was a lot harder than it should have been. Turns out, unlike pretty much every other device I have, IR blasters cannot be used in offline-local mode, so I was not able to sniff the traffic. They also do not send async status reports when another device tells it to transmit IR. So, I ended up taking mine to bits and plugging into the exposed headers to capture debug information in an attempt to glean something useful. (As a side note, it turns out these things use a ESP8266 chip, so Tasmota is an option if you want to go that route.) At first the logs didn't look too useful, just notes about updating DPS 1, 3, and 4:

[N]ir_lib.c:878 mode:1
[N]ir_lib.c:616 remain size:21400
[N]ir_lib.c:625 3:010ed800000000000700150040015a005600ad06580e74
[N]ir_lib.c:642 ir code type:0
[N]ir_lib.c:681 4:01$^002010E728D7@&$%@*
[N]ir_lib.c:439 getFre=38000
[N]ir_lib.c:529 start send.......
[N]ir_lib.c:583 send finish!
[N]ir_lib.c:725 remain size:23176
[N]ir_lib.c:886 MODE_IRSEND END......

But then I noticed that "remain size" line. That sure looks like a buffer for the DPS JSON, but why is it so large? Unless...

import tinytuya

tinytuya.set_debug(toggle=True, color=False)

ir = tinytuya.Device("35217541c45bbef5a1f1", version=3.3, persist=True)
payload = ir.generate_payload(tinytuya.CONTROL, {"1": "send_ir", "3":"020ed8000000000008001600160042015600ac05f3005807b8", "4":"01%^002001FE50AF@&%*@(", "10":3000, "13":0})
print( ir._send_receive(payload, getresponse=True) )

Bingo! It transmits! Quite obvious in hindsight actually. Raw sequences are similar:

import tinytuya

ir = tinytuya.Device("35217541c45bbef5a1f1", version=3.3, persist=True)
payload = ir.generate_payload(tinytuya.CONTROL, {"1": "study_key", "7":"liGiETMCqQYwAqcGOQKhBjYCSgIsAkwCNgJGAi8CTQIyAkoCLwKmBjYCowYyAqsGLwJlAhsCZQIQAmYCFQJsAg8CaAIRAmsCEQLIBhICzQYQAmYCEQJqAhECbAIQAmoCFwJmAhACxwYUAmcCEwJrAhECxgYTAskGEALHBhMCxgYSAsgGFwIgyw=="})
print( ir._send_receive(payload, getresponse=True) )

Hopefully I can get a patch submitted tomorrow.