jasonacox / tinytuya

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

Feature request: Option to provide device ID to the scan devices API so it can complete as soon as that device has been found. #490

Closed AdrianGarside closed 1 month ago

AdrianGarside commented 1 month ago

I'm using tinytuya in a home assistant integration to find the IP address (and protocol version) of Tuya devices enumerated initially from the cloud API but utilizing the smart life app to get them instead of needing a Tuya IOT account. The user chooses the device they want to add and then there's currently an 18s wait while I use deviceScan to try to find the local devices to try to get the IP address of the one they chose. It'd be great if I could pass a device filter in up front so the scan completes as soon as it sees that device.

jasonacox commented 1 month ago

That's a great suggestion @AdrianGarside. Can you share the code on how you are currently running the scan?

I think we could add a simple scan_id() function to https://github.com/jasonacox/tinytuya/blob/master/tinytuya/scanner.py that simply returns the IP address as soon as it detects the broadcast from that device.

AdrianGarside commented 1 month ago

It's still in progress but it's pretty basic:

https://github.com/make-all/tuya-local/pull/1881/files#diff-a0269ebba252310e431b95b4cde30017584df7088b8243db81413ab92af8331b

I'm just calling: tinytuya.deviceScan(verbose=False, byID = True)

And then looking for the device by ID in the returned dictionary. Although as I write this it occurs to me that I could be running this in the background from the moment the user starts the config flow so by the time I know which device they are adding I already have the results. I could increase the timeout if I do that too. Oh... except having the app open tends to block the discovery from succeeding and having the app open is required for the QR based authentication flow.

uzlonewolf commented 1 month ago

This is already implemented in both core and scanner.

Core: https://github.com/jasonacox/tinytuya/blob/master/tinytuya/core.py#L619

def find_device(dev_id=None, address=None):
    """Scans network for Tuya devices with either ID = dev_id or IP = address

    Parameters:
        dev_id = The specific Device ID you are looking for
        address = The IP address you are tring to find the Device ID for

    Response:
        {'ip':<ip>, 'version':<version>, 'id':<id>, 'product_id':<product_id>, 'data':<broadcast data>}
    """

result = tinytuya.find_device(dev_id='abc123')

Scanner: https://github.com/jasonacox/tinytuya/blob/master/tinytuya/scanner.py#L973

def devices(verbose=False, scantime=None, color=True, poll=True, forcescan=False, byID=False, show_timer=None, discover=True, wantips=None, wantids=None, snapshot=None, assume_yes=False, tuyadevices=[], maxdevices=0):
    """Scans your network for Tuya devices and returns dictionary of devices discovered
...
        wantids = A list of Device IDs we want.  Scan will stop early if all are found

result = tinytuya.scanner.devices( poll=False, wantids=['abc123', 'def456'] )

jasonacox commented 1 month ago

🤣 I'm blind! Thanks @uzlonewolf .... There you go @AdrianGarside - find_device() is even documented in the core header.

https://github.com/jasonacox/tinytuya/blob/62c7f13fe814cbabcd752e2201036e1b12a41742/tinytuya/core.py#L19-L28

I always wanted to create a good API doc to go with the project. I think this proves we (at least I) need it. 😊

AdrianGarside commented 1 month ago

Thanks. I did look at the docs and code but I missed that entirely (I though those were internal APIs and not exposed).

jasonacox commented 1 month ago

Well, that makes two of us... and to be fair, the main API notes in the README haven't been updated in quite some time and didn't include the great additions by @uzlonewolf that you were looking for. Hopefully this doc update will help others.

I'm still going to work on getting a better API doc... if anyone has advice on a good tool/trick to do that, let me know. :)

Thanks for opening this issue!

AdrianGarside commented 1 month ago

@jasonacox @uzlonewolf now that I have my Tuya devices finally integrated into home assistant working locally, I want to move them to my IOT vlan. That will presumably break the newly added discovery since that vlan is blocked from sending anything to my real network. I can adjust my rules to allow the broadcast ports to be allowed through. Will that be sufficient for the scanning to then find them or are there other requirements? If I have to I can workaround the lack of scanning and add the IP address manually but I'd like to make life easier for myself in the future by allowing future new tuya devices on my IOT network to be discoverable in the automated way.

I ran into a similar problem in that my WSL install that I use for my test Home Assistant instance gets a 172.xxx IP address while my real network is 192.168.0.x. It couldn't detect any of the devices either since it couldn't see the broadcasts. I had to test on my production instance which was a pain. I'm planning to see if I can solve that too but it'll be a different solution needed.

Never mind, looks like I'm out of luck - it's not just a case of allowing certain ports through since it's not direct connection attempts - I need something to repeat the Tuya broadcasts from the IOT VLan on my real network. Unifi has build it support for doing that with mDNS but for anything else like SSDP or this I'd need a device straddling both networks to repeat the broadcasts.

Got around to reinstall wireshark and it appears to be showing me that my windows PC can see broadcasts from the Tuya device - 10.10.10.111 is a new BT gateway I put onto my IOT wifi: image image

jasonacox commented 1 month ago

Thanks for the update @AdrianGarside . Have you considered dual-homing your home assistant system to allow it to hear/control the Tuya devices while giving you access to the portal? It has its own security risks, if you are looking for strict isolation but could be an option.

AdrianGarside commented 1 month ago

I really don’t want to do that. I think it’s an inevitability that iot devices will be hacked so I try to keep all I can off my main network - discovery is usually where I run into blockers for that. The new gateway is running fine on my IOT network so I wouldn’t want to take a permanent security hit just to make initial one time addition a bit easier.

Since wireshark can see the broadcasts I’ve been trying to work out why tinytuya can’t. The VM that’s hosting my home assistant on Debian is on my main network so it ought to be able to see the broadcasts too but I’m not sure of any good linux tools to let me confirm that it can, especially since it’s running without a GUI.

Maybe it’s time to bite the bullet and move that entire VM over to the untrusted network and start treating it as untrusted too. I could get all my esphome devices off my main network then too (same discovery issue with those). That could be an involved migration though.

AdrianGarside commented 1 month ago

tpcdump on the debian VM doesn't seem to be seeing the broadcasts from 10.10.10.111:

tcpdump: verbose output suppressed, use -v[v]... for full protocol decode listening on eth0, link-type EN10MB (Ethernet), snapshot length 262144 bytes 22:19:50.674960 IP 192.168.0.59.49154 > 255.255.255.255.6667: UDP, length 188 22:19:51.203399 IP 192.168.0.243.50044 > 255.255.255.255.6667: UDP, length 268 22:19:55.675267 IP 192.168.0.59.49154 > 255.255.255.255.6667: UDP, length 188 22:19:56.210967 IP 192.168.0.243.50044 > 255.255.255.255.6667: UDP, length 268

jasonacox commented 1 month ago

Understood! Thank's for sharing and the additional context. If you figure it out, let us know!

AdrianGarside commented 1 month ago

tshark (command line wireshark) for linux also doesn't show the 10.10.10.x originated broadcasts. Maybe that's a linux routing difference to Windows, maybe it's a host VM networking difference (my HA runs in Debian in a VM on a Windows 10 host PC). Might need to get tinytuya/python running on a Windows machine to see if it can see the other IOT network broadcasts.