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.01k stars 177 forks source link

Strange behavior with color for bulbs #123

Closed MandolinMicke closed 2 years ago

MandolinMicke commented 2 years ago

Hi, thanks for the package, nice and easy to use. I have experienced some strange behavior that would be nice to sort out.

Short description: Started with this a couple of weeks ago, and got everything to work as I wanted, tried it out today again and got a very strange behavior.

A very simple script

import tinytuya
tinytuya.set_debug(True)

d = tinytuya.BulbDevice(XXX,XXX,XXX)
d.set_version(3.3)
print(d.set_mode('colour'))
print(d.set_colour(200,100,0))

From this I get something like this:


DEBUG:TinyTuya [1.3.1]

DEBUG:status() entry (dev_type is default)
DEBUG:building payload=b'{"gwId":"bf45bfbdd34094a418tcd4","devId":"bf45bfbdd34094a418tcd4","uid":"bf45bfbdd34094a418tcd4","t":"1648912784"}'
DEBUG:payload generated=b'\x00\x00U\xaa\x00\x00\x00\x00\x00\x00\x00\n\x00\x00\x00\x88\x02\n[\x91\xca\xcb0QY4a\xf8\x01\xf4\xc4\x1cY\xd0\xd1\x08\xa4\x01\xbdF\x07\xcd\xff\xcb\xc2Z]\xb1\x00!\x1c\x08\x8c\xfd\x05\xc7\xd7\xb2\xdfG\xb4\xe3&n\\\x8c\x91\x7f\xe3\xa1\xa0A\x8e9*\x81\xa2d\x13\x95\xed\xbe3\xfc\x0cedo\xb7n\x9a\x1c\xeb\xe2\xaf\xe9Y\xd0\xd1\x08\xa4\x01\xbdF\x07\xcd\xff\xcb\xc2Z]\xb1Y\xd7\xa4\xd4\x8e\x93-o\xac%\r\x06h\xd6\x80%\xe6\x88\xd6\xe3\xdc\xaf\xacN\xa1\xf2\xeb\xedF\t\x15\xfe\xb9\xc4\x96&\x00\x00\xaaU'
DEBUG:received data=b'\x00\x00U\xaa\x00\x00\x00\x00\x00\x00\x00\n\x00\x00\x00,\x00\x00\x00\x00\xc3]\n\xb9\x8e\xd7\xd7\xbd?v\xc874\t\x85}I\x0b\x83)d\xf7\x06\xb9\x99\xc3c\xcb\xf1\x15?\xebS\x8f\xb0w\x00\x00\xaaU'
DEBUG:raw unpacked message = TuyaMessage(seqno=0, cmd=10, retcode=0, payload=b'\xc3]\n\xb9\x8e\xd7\xd7\xbd?v\xc874\t\x85}I\x0b\x83)d\xf7\x06\xb9\x99\xc3c\xcb\xf1\x15?\xeb', crc=1401925751)
DEBUG:decode payload=b'\xc3]\n\xb9\x8e\xd7\xd7\xbd?v\xc874\t\x85}I\x0b\x83)d\xf7\x06\xb9\x99\xc3c\xcb\xf1\x15?\xeb'
DEBUG:decrypting=b'\xc3]\n\xb9\x8e\xd7\xd7\xbd?v\xc874\t\x85}I\x0b\x83)d\xf7\x06\xb9\x99\xc3c\xcb\xf1\x15?\xeb'
DEBUG:decrypted 3.3 payload='{"dps":{"21":"colour"}}'
DEBUG:payload type = <class 'str'>
DEBUG:decoded results='{"dps":{"21":"colour"}}'
DEBUG:status() received data={'dps': {'21': 'colour'}}
DEBUG:bulb type set to B
DEBUG:building payload=b'{"devId":"bf45bfbdd34094a418tcd4","uid":"bf45bfbdd34094a418tcd4","t":"1648912784","dps":{"21":"colour"}}'
DEBUG:payload generated=b'\x00\x00U\xaa\x00\x00\x00\x01\x00\x00\x00\x07\x00\x00\x00\x873.3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd4!C\x85\xdc\xb1\xb6do\x01\xcd\xb5\xaeR\x1d\x8a\\\x8c\x91\x7f\xe3\xa1\xa0A\x8e9*\x81\xa2d\x13\x95\xed\xbe3\xfc\x0cedo\xb7n\x9a\x1c\xeb\xe2\xaf\xe9Y\xd0\xd1\x08\xa4\x01\xbdF\x07\xcd\xff\xcb\xc2Z]\xb1Y\xd7\xa4\xd4\x8e\x93-o\xac%\r\x06h\xd6\x80%\x9d\x9e\xfd`*E$M*:\xd5\xa9\xfc\xe5\xe6Ow\xad\xb6\x9b\x05\x8b\x8a2\x0b\xf8\xd1]U\xb1%\xd2\xc3\x0b\x0c\xcb\x00\x00\xaaU'
DEBUG:received data=b'\x00\x00U\xaa\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00K\x00\x00\x00\x003.3\x00\x00\x00\x00\x00\x00y7\x00\x00\x00\x01\xc3]\n\xb9\x8e\xd7\xd7\xbd?v\xc874\t\x85}\x1b\xf0\xb6\x92v\xd0Y\x8a\x0bz\x92\xe7M\x98#.h\x8b\x97\x01Ui\x93{q\xd3Hn\r\xa1,\xa0.\xee\xa4\xcb\x00\x00\xaaU'
DEBUG:raw unpacked message = TuyaMessage(seqno=0, cmd=8, retcode=0, payload=b'3.3\x00\x00\x00\x00\x00\x00y7\x00\x00\x00\x01\xc3]\n\xb9\x8e\xd7\xd7\xbd?v\xc874\t\x85}\x1b\xf0\xb6\x92v\xd0Y\x8a\x0bz\x92\xe7M\x98#.h\x8b\x97\x01Ui\x93{q\xd3Hn\r\xa1,\xa0', crc=787391691)
DEBUG:decode payload=b'3.3\x00\x00\x00\x00\x00\x00y7\x00\x00\x00\x01\xc3]\n\xb9\x8e\xd7\xd7\xbd?v\xc874\t\x85}\x1b\xf0\xb6\x92v\xd0Y\x8a\x0bz\x92\xe7M\x98#.h\x8b\x97\x01Ui\x93{q\xd3Hn\r\xa1,\xa0'
DEBUG:removing 3.3=b'\xc3]\n\xb9\x8e\xd7\xd7\xbd?v\xc874\t\x85}\x1b\xf0\xb6\x92v\xd0Y\x8a\x0bz\x92\xe7M\x98#.h\x8b\x97\x01Ui\x93{q\xd3Hn\r\xa1,\xa0'
DEBUG:decrypting=b'\xc3]\n\xb9\x8e\xd7\xd7\xbd?v\xc874\t\x85}\x1b\xf0\xb6\x92v\xd0Y\x8a\x0bz\x92\xe7M\x98#.h\x8b\x97\x01Ui\x93{q\xd3Hn\r\xa1,\xa0'
DEBUG:decrypted 3.3 payload='{"dps":{"21":"colour"},"type":"query","t":1348}'
DEBUG:payload type = <class 'str'>
DEBUG:decoded results='{"dps":{"21":"colour"},"type":"query","t":1348}'
{'dps': {'21': 'colour'}, 'type': 'query', 't': 1348}
DEBUG:ERROR Function Not Supported by Device - 907 - payload: "set_colour: Device does not support color."
{'Error': 'Function Not Supported by Device', 'Err': '907', 'Payload': 'set_colour: Device does not support color.'}

However it is a RGB bulb and (it has been working before)

What makes it even stranger is that if I start the "Smart Life" app and change the color of the bulb, then it works as it should?

DEBUG:TinyTuya [1.3.1]

DEBUG:status() entry (dev_type is default)
DEBUG:building payload=b'{"gwId":"bf45bfbdd34094a418tcd4","devId":"bf45bfbdd34094a418tcd4","uid":"bf45bfbdd34094a418tcd4","t":"1648913076"}'
DEBUG:payload generated=b'\x00\x00U\xaa\x00\x00\x00\x00\x00\x00\x00\n\x00\x00\x00\x88\x02\n[\x91\xca\xcb0QY4a\xf8\x01\xf4\xc4\x1cY\xd0\xd1\x08\xa4\x01\xbdF\x07\xcd\xff\xcb\xc2Z]\xb1\x00!\x1c\x08\x8c\xfd\x05\xc7\xd7\xb2\xdfG\xb4\xe3&n\\\x8c\x91\x7f\xe3\xa1\xa0A\x8e9*\x81\xa2d\x13\x95\xed\xbe3\xfc\x0cedo\xb7n\x9a\x1c\xeb\xe2\xaf\xe9Y\xd0\xd1\x08\xa4\x01\xbdF\x07\xcd\xff\xcb\xc2Z]\xb15M\x0eO\x96i\xf9\x8b\x07I\xc3\x08:o,\xce\xe6\x88\xd6\xe3\xdc\xaf\xacN\xa1\xf2\xeb\xedF\t\x15\xfe\xcc\xb5\x15\xe4\x00\x00\xaaU'
DEBUG:received data=b"\x00\x00U\xaa\x00\x00\x00\x00\x00\x00\x00\n\x00\x00\x00<\x00\x00\x00\x00\xc3]\n\xb9\x8e\xd7\xd7\xbd?v\xc874\t\x85}\xc5\xd5\x04\xfb\\\xb4\xfa\x08^0w$@\xda\xe0G\x90r\xa4\xa0H\xfe\x1e\xc2\xdb\xf7\x1eyQ'\x8b\xadFo\xd9<\x00\x00\xaaU"
DEBUG:raw unpacked message = TuyaMessage(seqno=0, cmd=10, retcode=0, payload=b"\xc3]\n\xb9\x8e\xd7\xd7\xbd?v\xc874\t\x85}\xc5\xd5\x04\xfb\\\xb4\xfa\x08^0w$@\xda\xe0G\x90r\xa4\xa0H\xfe\x1e\xc2\xdb\xf7\x1eyQ'\x8b\xad", crc=1181735228)
DEBUG:decode payload=b"\xc3]\n\xb9\x8e\xd7\xd7\xbd?v\xc874\t\x85}\xc5\xd5\x04\xfb\\\xb4\xfa\x08^0w$@\xda\xe0G\x90r\xa4\xa0H\xfe\x1e\xc2\xdb\xf7\x1eyQ'\x8b\xad"
DEBUG:decrypting=b"\xc3]\n\xb9\x8e\xd7\xd7\xbd?v\xc874\t\x85}\xc5\xd5\x04\xfb\\\xb4\xfa\x08^0w$@\xda\xe0G\x90r\xa4\xa0H\xfe\x1e\xc2\xdb\xf7\x1eyQ'\x8b\xad"
DEBUG:decrypted 3.3 payload='{"dps":{"21":"colour","24":"015203e803e8"}}'
DEBUG:payload type = <class 'str'>
DEBUG:decoded results='{"dps":{"21":"colour","24":"015203e803e8"}}'
DEBUG:status() received data={'dps': {'21': 'colour', '24': '015203e803e8'}}
DEBUG:bulb type set to B
DEBUG:building payload=b'{"devId":"bf45bfbdd34094a418tcd4","uid":"bf45bfbdd34094a418tcd4","t":"1648913076","dps":{"21":"colour"}}'
DEBUG:payload generated=b'\x00\x00U\xaa\x00\x00\x00\x01\x00\x00\x00\x07\x00\x00\x00\x873.3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd4!C\x85\xdc\xb1\xb6do\x01\xcd\xb5\xaeR\x1d\x8a\\\x8c\x91\x7f\xe3\xa1\xa0A\x8e9*\x81\xa2d\x13\x95\xed\xbe3\xfc\x0cedo\xb7n\x9a\x1c\xeb\xe2\xaf\xe9Y\xd0\xd1\x08\xa4\x01\xbdF\x07\xcd\xff\xcb\xc2Z]\xb15M\x0eO\x96i\xf9\x8b\x07I\xc3\x08:o,\xce\x9d\x9e\xfd`*E$M*:\xd5\xa9\xfc\xe5\xe6Ow\xad\xb6\x9b\x05\x8b\x8a2\x0b\xf8\xd1]U\xb1%\xd2\xb9i5\xc0\x00\x00\xaaU'
DEBUG:received data=b'\x00\x00U\xaa\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00K\x00\x00\x00\x003.3\x00\x00\x00\x00\x00\x00y;\x00\x00\x00\x01\xc3]\n\xb9\x8e\xd7\xd7\xbd?v\xc874\t\x85}\x1b\xf0\xb6\x92v\xd0Y\x8a\x0bz\x92\xe7M\x98#.\xb3\xd8\x03\xcd\xeb\x02X\xf0O\xfc\xbbn\xe2lR\xe9}gVN\x00\x00\xaaU'
DEBUG:raw unpacked message = TuyaMessage(seqno=0, cmd=8, retcode=0, payload=b'3.3\x00\x00\x00\x00\x00\x00y;\x00\x00\x00\x01\xc3]\n\xb9\x8e\xd7\xd7\xbd?v\xc874\t\x85}\x1b\xf0\xb6\x92v\xd0Y\x8a\x0bz\x92\xe7M\x98#.\xb3\xd8\x03\xcd\xeb\x02X\xf0O\xfc\xbbn\xe2lR\xe9', crc=2103924302)
DEBUG:decode payload=b'3.3\x00\x00\x00\x00\x00\x00y;\x00\x00\x00\x01\xc3]\n\xb9\x8e\xd7\xd7\xbd?v\xc874\t\x85}\x1b\xf0\xb6\x92v\xd0Y\x8a\x0bz\x92\xe7M\x98#.\xb3\xd8\x03\xcd\xeb\x02X\xf0O\xfc\xbbn\xe2lR\xe9'
DEBUG:removing 3.3=b'\xc3]\n\xb9\x8e\xd7\xd7\xbd?v\xc874\t\x85}\x1b\xf0\xb6\x92v\xd0Y\x8a\x0bz\x92\xe7M\x98#.\xb3\xd8\x03\xcd\xeb\x02X\xf0O\xfc\xbbn\xe2lR\xe9'
DEBUG:decrypting=b'\xc3]\n\xb9\x8e\xd7\xd7\xbd?v\xc874\t\x85}\x1b\xf0\xb6\x92v\xd0Y\x8a\x0bz\x92\xe7M\x98#.\xb3\xd8\x03\xcd\xeb\x02X\xf0O\xfc\xbbn\xe2lR\xe9'
DEBUG:decrypted 3.3 payload='{"dps":{"21":"colour"},"type":"query","t":1640}'
DEBUG:payload type = <class 'str'>
DEBUG:decoded results='{"dps":{"21":"colour"},"type":"query","t":1640}'
{'dps': {'21': 'colour'}, 'type': 'query', 't': 1640}
DEBUG:building payload=b'{"devId":"bf45bfbdd34094a418tcd4","uid":"bf45bfbdd34094a418tcd4","t":"1648913077","dps":{"21":"colour","24":"001e03e80310"}}'
DEBUG:payload generated=b'\x00\x00U\xaa\x00\x00\x00\x02\x00\x00\x00\x07\x00\x00\x00\x973.3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xd4!C\x85\xdc\xb1\xb6do\x01\xcd\xb5\xaeR\x1d\x8a\\\x8c\x91\x7f\xe3\xa1\xa0A\x8e9*\x81\xa2d\x13\x95\xed\xbe3\xfc\x0cedo\xb7n\x9a\x1c\xeb\xe2\xaf\xe9Y\xd0\xd1\x08\xa4\x01\xbdF\x07\xcd\xff\xcb\xc2Z]\xb1\xfa\xe6!\xfe\x8e\xec\xa7\x11$/^|\xddU\x00U\x9d\x9e\xfd`*E$M*:\xd5\xa9\xfc\xe5\xe6O\naK\x81q\xaf\xf0\x08\xb7v1=\x00\x93\xd2^z\xbd\xa6y\x16\x8d5\x13\x8a9c\xe0\xdc\x9f-\x8a5\x17f\xf7\x00\x00\xaaU'
DEBUG:received data=b'\x00\x00U\xaa\x00\x00\x00\x00\x00\x00\x00\x08\x00\x00\x00K\x00\x00\x00\x003.3\x00\x00\x00\x00\x00\x00y=\x00\x00\x00\x01\xc3]\n\xb9\x8e\xd7\xd7\xbd?v\xc874\t\x85}r\xe3\xa86m\xeb\xbcp\x9afC\x1c\x91\xd6\xda&=\xfd&\xbcY\xcb<\xe5\x01f\x94\xdc\xd1P\x0b\xcdZ,\x18\x08\x00\x00\xaaU'
DEBUG:raw unpacked message = TuyaMessage(seqno=0, cmd=8, retcode=0, payload=b'3.3\x00\x00\x00\x00\x00\x00y=\x00\x00\x00\x01\xc3]\n\xb9\x8e\xd7\xd7\xbd?v\xc874\t\x85}r\xe3\xa86m\xeb\xbcp\x9afC\x1c\x91\xd6\xda&=\xfd&\xbcY\xcb<\xe5\x01f\x94\xdc\xd1P\x0b\xcd', crc=1512839176)
DEBUG:decode payload=b'3.3\x00\x00\x00\x00\x00\x00y=\x00\x00\x00\x01\xc3]\n\xb9\x8e\xd7\xd7\xbd?v\xc874\t\x85}r\xe3\xa86m\xeb\xbcp\x9afC\x1c\x91\xd6\xda&=\xfd&\xbcY\xcb<\xe5\x01f\x94\xdc\xd1P\x0b\xcd'
DEBUG:removing 3.3=b'\xc3]\n\xb9\x8e\xd7\xd7\xbd?v\xc874\t\x85}r\xe3\xa86m\xeb\xbcp\x9afC\x1c\x91\xd6\xda&=\xfd&\xbcY\xcb<\xe5\x01f\x94\xdc\xd1P\x0b\xcd'
DEBUG:decrypting=b'\xc3]\n\xb9\x8e\xd7\xd7\xbd?v\xc874\t\x85}r\xe3\xa86m\xeb\xbcp\x9afC\x1c\x91\xd6\xda&=\xfd&\xbcY\xcb<\xe5\x01f\x94\xdc\xd1P\x0b\xcd'
DEBUG:decrypted 3.3 payload='{"dps":{"21":"colour"},"t":1641}'
DEBUG:payload type = <class 'str'>
DEBUG:decoded results='{"dps":{"21":"colour"},"t":1641}'
{'dps': {'21': 'colour'}, 't': 1641}

Any idea why or how this is happening? (want to avoid this in the future)

Note: similar behavior was experienced with scene and brightness aswell.

jasonacox commented 2 years ago

Hi @MandolinMicke ! Thanks for this note. The way TinyTuya detects color capability is by looking for the DPS key for colour value (DPS 24 for a Bulb type B like you have) when set_version() is called. If you notice above, for the two different sessions your bulb is sending back a different status:

# First session - doesn't work
DEBUG:status() received data={'dps': {'21': 'colour'}}

# Second session - works
DEBUG:status() received data={'dps': {'21': 'colour', '24': '015203e803e8'}}

DPS key 21 is for mode and it shows 'colour' indicating the mode the bulb is in at the moment, so I know that seems confusing, but key 24 is the actual value for the color it should be displaying. TinyTuya logic is designed to look for that since the value for 21 can be other values (e.g. 'white', 'scene', 'music').

I don't know why your Smartbulb is not consistently sending the 24 key. I haven't seen that before. In any case, that is causing the logic in TinyTuya to assume that color cannot be set on the device . The good news is that there is a workaround. You can FORCE it to think the bulb has color capability by doing something like this:

import tinytuya
tinytuya.set_debug(True)

d = tinytuya.BulbDevice(XXX,XXX,XXX)
d.set_version(3.3)
d.has_colour = True           # Force color mode capability
#d.has_brightness = True      # Force brightness capability
#d.has_colourtemp = True      # Force color temp capability

d.set_socketPersistent(True)  # Helps when you make multiple calls to the bulb

print(d.set_mode('colour'))
print(d.set_colour(200,100,0))

As you can see, you can also force brightness and colourtemp capabilities. You mention issues with scene as well. Can you elaborate on that one? There isn't any logic in TinyTuya to detect scene capability but perhaps it is something else?

MandolinMicke commented 2 years ago

well, i had issues with scene, but it might be my fault aswell.. (cant really try again since i can't replicate the issue on demand). But thanks for the tip about the force options! Will add that to my code :)