jasonacox / tinytuya

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

Can't connect to device AllPetSolutions Pet Feeder F1-C/TA (T21) #293

Open hijamie32 opened 1 year ago

hijamie32 commented 1 year ago

Hi,

I am trying to setup my device to use with Home Assistant but was having issues so decided to try tinytuya.

I am also having issues with this for this particular device (Other devices work fine in both).

I have enabled DP instruction and can now control the feeder with all function on Tuya IOT Platform.

However when I try to even get device information with TinyTuya via the wizard I get:

[PetFeeder ] Error: No IP found

I have also noticed that when viewing the device via Tuya it has a different Device_ID compared to when accessing locally via TinyTuya scan where it seems to be broadcasting the UUID as the Device_ID instead.

Output from Scan:

Unknown v3.3 Device Product ID = e800gjvtrn6kjpuv [Valid Broadcast]: Address = 192.168.1.25 Device ID = d**b9928 (len:16) Local Key = Version = 3.3 Type = default, MAC = No Stats for 192.168.1.25: DEVICE KEY required to poll for status

Output from Wizard:

{ "name": "PetFeeder", "id": "b**daa27a8fcs7", "key": "**34eb98", "mac": "::::51:5e", "category": "sp", "product_name": "PetFeeder", "product_id": "e800gjvtrn6kjpuv", "biz_type": 0, "model": "T21", "sub": false, "icon": "https://images.tuyaeu.com/smart/icon/ay1539074879262GYXmu/3c2ac7d0730f7dba50c478f3850c09a0.jpg", "uuid": "d ** b9928" },

Do you have any idea what I can do next to try and debug further?

Many Thanks for any help you can give.

Here is a link to the device in question.

https://www.allpetsolutions.co.uk/smart-pet-feeder-with-wifi-camera/

uzlonewolf commented 1 year ago

Hmmm, that's interesting. What happens if you edit devices.json with a text editor and replace the "id" value with the uuid and re-run the scanner?

jasonacox commented 1 year ago

You can also try a short python script:

import tinytuya

d = tinytuya.OutletDevice(
      dev_id="********** b9928",
      address="192.168.1.25",
      local_key="**********34eb98",
      version=3.3)

print(d)

print(" > Fetch Status < ")
data = d.status()
print(data)
hijamie32 commented 1 year ago

Hmmm, that's interesting. What happens if you edit devices.json with a text editor and replace the "id" value with the uuid and re-run the scanner?

Hi Thanks for your message.

I had tried editing that before posting but if it is any use here is the output of the scan:

PetFeeder Product ID = e800gjvtrn6kjpuv [Valid Broadcast]: Address = 192.168.1.25 Device ID = ** b9928 (len:16) Local Key = **34eb98 Version = 3.3 Type = default, MAC = 44:01:bb:71:51:5e Polling 192.168.1.25 Failed: No response

Cheers

hijamie32 commented 1 year ago

You can also try a short python script:

import tinytuya

d = tinytuya.OutletDevice(
      dev_id="********** b9928",
      address="192.168.1.25",
      local_key="**********34eb98",
      version=3.3)

print(d)

print(" > Fetch Status < ")
data = d.status()
print(data)

Hi,

Just tried your script and the response was just:

 > Fetch Status < 
None

Thanks

jasonacox commented 1 year ago

Can you turn on debug mode?

import tinytuya

tinytuya.set_debug(True)

d = tinytuya.OutletDevice(
      dev_id="********** b9928",
      address="192.168.1.25",
      local_key="**********34eb98",
      version=3.3)

print(d)

print(" > Fetch Status < ")
data = d.status()
print(data)

Try with uuid and id values if you can.

uzlonewolf commented 1 year ago

This reminds me a lot of #190. If they're similar devices then this should work:

import tinytuya

tinytuya.set_debug(True)

d = tinytuya.OutletDevice(
      dev_id="********** b9928",
      address="192.168.1.25",
      local_key="**********34eb98",
      dev_type = "device22",
      version=3.3)

d.add_dps_to_request(101)

data = d.status()
print('Device status: %r' % data)
hijamie32 commented 1 year ago
import tinytuya

tinytuya.set_debug(True)

d = tinytuya.OutletDevice(
      dev_id="********** b9928",
      address="192.168.1.25",
      local_key="**********34eb98",
      version=3.3)

print(d)

print(" > Fetch Status < ")
data = d.status()
print(data)

This is one:

OutletDevice( '** b9928', address='192.168.1.25', local_key='**34eb98', dev_type='default', connection_timeout=5, version=3.3, persist=False, cid=None, parent=None, children={} )

Fetch Status < DEBUG:status() entry (dev_type is default) DEBUG:building command 10 payload=b'{"gwId":"** b9928","devId":"** b9928","uid":"** b9928","t":"1678034636"}' DEBUG:sending payload DEBUG:payload encrypted=b'000055aa000000010000000a00000078f9312c816bf5da49e75ecad70c2b0c4ba7060984c4ee8cf6dfd3cddea6c1177575c72b9cf53c1c6f745dd1d31db462edd6ba511f8bb627a452c642184975b7740b54b6abb1d721f0f0bb47bf0913700390181f7cc91e0d9c8ccb27e83ee7e4d532f7990249ad94827d4b3268a906fb65e7c0f2630000aa55' DEBUG:received data=b'000055aa000000010000000a0000002c00000001e9aaf7e71e2024a8f669b85d30f856a15468048367f5dbf67160d7433626c636163b3fef0000aa55' DEBUG:received message=TuyaMessage(seqno=1, cmd=10, retcode=1, payload=b'\xe9\xaa\xf7\xe7\x1e $\xa8\xf6i\xb8]0\xf8V\xa1Th\x04\x83g\xf5\xdb\xf6q\xd7C6&\xc66', crc=372981743, crc_good=True, prefix=21930, iv=None) DEBUG:raw unpacked message = TuyaMessage(seqno=1, cmd=10, retcode=1, payload=b'\xe9\xaa\xf7\xe7\x1e $\xa8\xf6i\xb8]0\xf8V\xa1Th\x04\x83g\xf5\xdb\xf6q\xd7C6&\xc66', crc=372981743, crc_good=True, prefix=21930, iv=None) DEBUG:decode payload=b'\xe9\xaa\xf7\xe7\x1e $\xa8\xf6i\xb8]0\xf8V\xa1Th\x04\x83g\xf5\xdb\xf6q\xd7C6&\xc66' DEBUG:decrypting=b'\xe9\xaa\xf7\xe7\x1e $\xa8\xf6i\xb8]0\xf8V\xa1Th\x04\x83g\xf5\xdb\xf6q\xd7C6&\xc66' DEBUG:decrypted 3.x payload='json obj data unvalid' DEBUG:payload type = <class 'str'> DEBUG:'data unvalid' error detected: switching to dev_type 'device22' DEBUG:_decode_payload() failed! DEBUG:Device22 detected and updated (default -> device22) - Update payload and try again DEBUG:ERROR Device22 Detected: Retry Command - 908 - payload: null DEBUG:status() received data={'Error': 'Device22 Detected: Retry Command', 'Err': '908', 'Payload': None} DEBUG:status() rebuilding payload for device22 DEBUG:building command 10 payload=b'{"devId":"** b9928","uid":"** b9928","t":"1678034636","dps":{"1":null}}' DEBUG:sending payload DEBUG:payload encrypted=b'000055aa000000020000000d00000077332e3300000000000000000000000054949d8d3ca8480cc85b1407d20944ed97fd0af5d2a610060cb846bc060854cab0696467babab124d72a4ade41bd9fa6b605dd86a20088f891a19b02abcac7193a69831be4a86507004121a362e2774e85d204bdb342e8bb994c6ff7fbf3c95b45b966550000aa55' DEBUG:received data=b'000055aa000000020000000d0000000c000000008de14f440000aa55' DEBUG:received null payload (TuyaMessage(seqno=2, cmd=13, retcode=0, payload=b'', crc=2380353348, crc_good=True, prefix=21930, iv=None)), fetch new one - retry 0 / 5 None


And the another:

OutletDevice( 'b**daa27a8fcs7', address='192.168.1.25', local_key='**34eb98', dev_type='default', connection_timeout=5, version=3.3, persist=False, cid=None, parent=None, children={} )

Fetch Status < DEBUG:status() entry (dev_type is default) DEBUG:building command 10 payload=b'{"gwId":"b**daa27a8fcs7","devId":"b**daa27a8fcs7","uid":"b**daa27a8fcs7","t":"1678034752"}' DEBUG:sending payload DEBUG:payload encrypted=b'000055aa000000010000000a0000008816712c44b33ee2023b189227ffd1fc0ed6db93e05e3e81abe04a36bc64a1658073a3c2475e7daf7560fa8feeaf8d763a3662830a5b548354d2c1f4dd719bb5b4278a79634b03e6e10f74e2ca96dc337dd6db93e05e3e81abe04a36bc64a16580fe562adcd814de12dc9503c6830e4738a6f026b45407dab787a02b10446e09fb693823540000aa55' DEBUG:received data=b'000055aa000000010000000a0000002c00000001e9aaf7e71e2024a8f669b85d30f856a15468048367f5dbf67160d7433626c636163b3fef0000aa55' DEBUG:received message=TuyaMessage(seqno=1, cmd=10, retcode=1, payload=b'\xe9\xaa\xf7\xe7\x1e $\xa8\xf6i\xb8]0\xf8V\xa1Th\x04\x83g\xf5\xdb\xf6q\xd7C6&\xc66', crc=372981743, crc_good=True, prefix=21930, iv=None) DEBUG:raw unpacked message = TuyaMessage(seqno=1, cmd=10, retcode=1, payload=b'\xe9\xaa\xf7\xe7\x1e $\xa8\xf6i\xb8]0\xf8V\xa1Th\x04\x83g\xf5\xdb\xf6q\xd7C6&\xc66', crc=372981743, crc_good=True, prefix=21930, iv=None) DEBUG:decode payload=b'\xe9\xaa\xf7\xe7\x1e $\xa8\xf6i\xb8]0\xf8V\xa1Th\x04\x83g\xf5\xdb\xf6q\xd7C6&\xc66' DEBUG:decrypting=b'\xe9\xaa\xf7\xe7\x1e $\xa8\xf6i\xb8]0\xf8V\xa1Th\x04\x83g\xf5\xdb\xf6q\xd7C6&\xc66' DEBUG:decrypted 3.x payload='json obj data unvalid' DEBUG:payload type = <class 'str'> DEBUG:'data unvalid' error detected: switching to dev_type 'device22' DEBUG:_decode_payload() failed! DEBUG:Device22 detected and updated (default -> device22) - Update payload and try again DEBUG:ERROR Device22 Detected: Retry Command - 908 - payload: null DEBUG:status() received data={'Error': 'Device22 Detected: Retry Command', 'Err': '908', 'Payload': None} DEBUG:status() rebuilding payload for device22 DEBUG:building command 10 payload=b'{"devId":"b**daa27a8fcs7","uid":"b**daa27a8fcs7","t":"1678034752","dps":{"1":null}}' DEBUG:sending payload DEBUG:payload encrypted=b'000055aa000000020000000d00000087332e330000000000000000000000002d3a05a8ce43ba1c67c258e2413558083662830a5b548354d2c1f4dd719bb5b4278a79634b03e6e10f74e2ca96dc337dd6db93e05e3e81abe04a36bc64a16580fe562adcd814de12dc9503c6830e4738c618d480901b6a817ab3bdd822153152448c904e0992ca1574c747cb26e83b076899cd260000aa55' DEBUG:received data=b'000055aa000000020000000d0000000c000000008de14f440000aa55' DEBUG:received null payload (TuyaMessage(seqno=2, cmd=13, retcode=0, payload=b'', crc=2380353348, crc_good=True, prefix=21930, iv=None)), fetch new one - retry 0 / 5 None

Thank you

hijamie32 commented 1 year ago

This reminds me a lot of #190. If they're similar devices then this should work:

import tinytuya

tinytuya.set_debug(True)

d = tinytuya.OutletDevice(
      dev_id="********** b9928",
      address="192.168.1.25",
      local_key="**********34eb98",
      dev_type = "device22",
      version=3.3)

d.add_dps_to_request(101)

data = d.status()
print('Device status: %r' % data)

This is the output:

Jamie@Jamies-MBP Downloads % python3 34.py -nocolor
DEBUG:TinyTuya [1.10.3]

DEBUG:status() entry (dev_type is device22)
DEBUG:building command 10 payload=b'{"devId":"********** b9928","uid":"********** b9928","t":"1678035135","dps":{"101":null}}'
DEBUG:sending payload
DEBUG:payload encrypted=b'000055aa000000010000000d00000077332e3300000000000000000000000054949d8d3ca8480cc85b1407d20944ed97fd0af5d2a610060cb846bc060854cab0696467babab124d72a4ade41bd9fa6b605dd86a20088f891a19b02abcac71998175137fa4bd817b3afef949f0d72a3f32456d0769769a0b7588f1fea4a7eb1ba0632860000aa55'
DEBUG:received data=b'000055aa000000010000000d0000000c00000000302b238a0000aa55'
DEBUG:received null payload (TuyaMessage(seqno=1, cmd=13, retcode=0, payload=b'', crc=808133514, crc_good=True, prefix=21930, iv=None)), fetch new one - retry 0 / 5
DEBUG:status() received data=None
Device status: None

The other:


DEBUG:TinyTuya [1.10.3]

DEBUG:status() entry (dev_type is device22)
DEBUG:building command 10 payload=b'{"devId":"b**********daa27a8fcs7","uid":"b**********daa27a8fcs7","t":"1678035291","dps":{"101":null}}'
DEBUG:sending payload
DEBUG:payload encrypted=b'000055aa000000010000000d00000087332e330000000000000000000000002d3a05a8ce43ba1c67c258e2413558083662830a5b548354d2c1f4dd719bb5b4278a79634b03e6e10f74e2ca96dc337dd6db93e05e3e81abe04a36bc64a165802e66d59de0e76ffaec0e2db54b9f1e7b62d6ff5365809514210e99017b90be6137eb6ffd82b48f2a2c81a79074835eaa27d165fd0000aa55'
DEBUG:received data=b'000055aa000000010000000d0000000c00000000302b238a0000aa55'
DEBUG:received null payload (TuyaMessage(seqno=1, cmd=13, retcode=0, payload=b'', crc=808133514, crc_good=True, prefix=21930, iv=None)), fetch new one - retry 0 / 5
DEBUG:received data=b'000055aa00000000000000080000004b00000000332e33000000000000d96b00000001f223cc731a57c9db80af6cd8246606c235334241a53a562fab042c6471dfe67e5a4d9bb1f73b205ea8ea260b931e4111714e595d0000aa55'
DEBUG:received message=TuyaMessage(seqno=0, cmd=8, retcode=0, payload=b'3.3\x00\x00\x00\x00\x00\x00\xd9k\x00\x00\x00\x01\xf2#\xccs\x1aW\xc9\xdb\x80\xafl\xd8$f\x06\xc253BA\xa5:V/\xab\x04,dq\xdf\xe6~ZM\x9b\xb1\xf7; ^\xa8\xea&\x0b\x93\x1eA\x11', crc=1900960093, crc_good=True, prefix=21930, iv=None)
DEBUG:raw unpacked message = TuyaMessage(seqno=0, cmd=8, retcode=0, payload=b'3.3\x00\x00\x00\x00\x00\x00\xd9k\x00\x00\x00\x01\xf2#\xccs\x1aW\xc9\xdb\x80\xafl\xd8$f\x06\xc253BA\xa5:V/\xab\x04,dq\xdf\xe6~ZM\x9b\xb1\xf7; ^\xa8\xea&\x0b\x93\x1eA\x11', crc=1900960093, crc_good=True, prefix=21930, iv=None)
DEBUG:decode payload=b'3.3\x00\x00\x00\x00\x00\x00\xd9k\x00\x00\x00\x01\xf2#\xccs\x1aW\xc9\xdb\x80\xafl\xd8$f\x06\xc253BA\xa5:V/\xab\x04,dq\xdf\xe6~ZM\x9b\xb1\xf7; ^\xa8\xea&\x0b\x93\x1eA\x11'
DEBUG:removing 3.x=b'\xf2#\xccs\x1aW\xc9\xdb\x80\xafl\xd8$f\x06\xc253BA\xa5:V/\xab\x04,dq\xdf\xe6~ZM\x9b\xb1\xf7; ^\xa8\xea&\x0b\x93\x1eA\x11'
DEBUG:decrypting=b'\xf2#\xccs\x1aW\xc9\xdb\x80\xafl\xd8$f\x06\xc253BA\xa5:V/\xab\x04,dq\xdf\xe6~ZM\x9b\xb1\xf7; ^\xa8\xea&\x0b\x93\x1eA\x11'
DEBUG:decrypted 3.x payload='{"dps":{"101":false},"t":1678035291}'
DEBUG:payload type = <class 'str'>
DEBUG:decoded results='{"dps":{"101":false},"t":1678035291}'
DEBUG:status() received data={'dps': {'101': False}, 't': 1678035291}
Device status: {'dps': {'101': False}, 't': 1678035291}

That looks more promising!!?

Thank you both again

uzlonewolf commented 1 year ago

That looks more promising!!?

Yep, that's it. So, to summarize the quirks of this device:

  1. In broadcasts packets it sends the UUID instead of the Device ID, but when talking to it you must use the Device ID.
  2. Status requests need a d.add_dps_to_request(N) or d.set_dpsUsed(...) with a valid DP set before the request or they will not return anything.
  3. You can only retrieve the current device state one DP at a time (you will need to call d.set_dpsUsed(...) and then d.status() for every DP).

This is going to be a fun one to implement...

hijamie32 commented 1 year ago

Thanks making some progress :)

I Just ran the following script:

import tinytuya

d = tinytuya.OutletDevice(
      dev_id="***,
      address="192.168.1.25",
      local_key="***",
      dev_type = "device22",
      version=3.3)
d.add_dps_to_request(209)

print(" > Send Request for Status < ")
payload = d.generate_payload(tinytuya.DP_QUERY)
d.send(payload)

print(" > Begin Monitor Loop <")
while(True):
    # See if any data is available
    data = d.receive()
    print('Received Payload: %r' % data)

    # Send keyalive heartbeat
    print(" > Send Heartbeat Ping < ")
    payload = d.generate_payload(tinytuya.HEART_BEAT)
    d.send(payload)

    # NOTE If you are not seeing updates, you can force them - uncomment:
    # print(" > Send Request for Status < ")
    # payload = d.generate_payload(tinytuya.DP_QUERY)
    # d.send(payload)

    # NOTE Some smart plugs require an UPDATEDPS command to update power data
    # print(" > Send DPS Update Request < ")
    # payload = d.generate_payload(tinytuya.UPDATEDPS)
    # d.send(payload)    

And interestingly after sending a command via Tuya app for manual feed I got this response:

 > Send Heartbeat Ping < 
Received Payload: {'dps': {'210': 1}, 't': 1678036668}
 > Send Heartbeat Ping < 
Received Payload: {'dps': {'206': 18945}, 't': 1678036668}

I am surprised it picked them up as I only specified 209?

uzlonewolf commented 1 year ago

Yes, it will pick up async updates if you listen for them, you don't need to specify the DPs in that case. If you want to do this then I recommend setting persist=True after the version=3.3 so you don't miss any, otherwise it will close and reopen the connection after every update.