jasonacox / tinytuya

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

no timeout if wrong IP #337

Open ramonetnet opened 1 year ago

ramonetnet commented 1 year ago

I have problems with the DHCP server so my Tuya device changes the IP quite often. I want to detect the "connect timeout" situation, but get a "KeyError" exception instead Any ideas ? My code, quite simple :

d = tinytuya.OutletDevice( DEVICE_ID, DEVICE_IP, DEVICE_KEY )     # connect to device and fetch state
d.set_version(3.3)
d.set_socketRetryLimit(2)                                      # set retry count limit [default 5]
d.set_socketTimeout(2)                                         # set connection timeout in seconds [default 5]
d.set_sendWait(1)                                                 # seconds to wait after sending for a response

try:
        dps = d.detect_available_dps()
except KeyError:
        print( "key error - bye" )
        sys.exit()
jasonacox commented 1 year ago

You could have tinytuya scan for the IP address each time you use it:

d = tinytuya.OutletDevice( DEVICE_ID, "Auto", DEVICE_KEY )     # connect to device and fetch state
d.set_version(3.3)
d.set_socketRetryLimit(2)                                      # set retry count limit [default 5]
d.set_socketTimeout(2)                                         # set connection timeout in seconds [default 5]
d.set_sendWait(1)                                                 # seconds to wait after sending for a response

try:
        dps = d.detect_available_dps()
except:
        print( "error - bye" )
        sys.exit()
uzlonewolf commented 1 year ago

There's no way to do that directly, but you can fake it by checking the return value:

d = tinytuya.OutletDevice( DEVICE_ID, DEVICE_IP, DEVICE_KEY )     # connect to device and fetch state
d.set_version(3.3)
d.set_socketRetryLimit(2)                                      # set retry count limit [default 5]
d.set_socketTimeout(2)                                         # set connection timeout in seconds [default 5]
d.set_sendWait(1)                                                 # seconds to wait after sending for a response

try:
        dps = d.detect_available_dps()
        if not dps:
                raise KeyError('Not Found')
except KeyError:
        print( "key error - bye" )
        sys.exit()
ramonetnet commented 1 year ago

You could have tinytuya scan for the IP address each time you use it:

d = tinytuya.OutletDevice( DEVICE_ID, "Auto", DEVICE_KEY )     # connect to device and fetch state
d.set_version(3.3)
d.set_socketRetryLimit(2)                                      # set retry count limit [default 5]
d.set_socketTimeout(2)                                         # set connection timeout in seconds [default 5]
d.set_sendWait(1)                                                 # seconds to wait after sending for a response

try:
        dps = d.detect_available_dps()
except:
        print( "error - bye" )
        sys.exit()

This is fantastic !!! Where is this feature documented ?

jasonacox commented 1 year ago

Did that work for you @ramonetnet ? Keep in mind that it can be slow (it waits for the device to emit its discovery packet), but can be helpful for devices with low DHCP lease times.

As for documentation... Oops. 😊 I'll tag this for us to add something to README.

ramonetnet commented 1 year ago

Hi, Jason - thanks for your help. It is working right now, yes I dont mind if it's slow, as I read the temperature .. once every 15 minutes. The device is (nice "device scanner" of yours) :

{
    "name": "termometre",
    "id": "bfe483b0ac18224f06dqww",
    "key": "fb9d5ba086f97ed4",
    "mac": "1c:90:ff:da:ad:42",
    "category": "wsdcg",
    "product_name": "LED WIFI T&H Sensor",
    "product_id": "o2c5btmpepi9pzf8",
    "biz_type": 18,
    "model":

"\u63d2\u7535\u6b3e\u6a21\u7ec4\u5f00\u53d1\u5e38\u4f9b\u7535\u6b3e", "sub": false, "icon": " https://images.tuyaeu.com/smart/icon/ay15427647462366edzT/1e738d42af8bebcca4f802f0074f134d.png " },

My problem is not low DHCP lease times, but router power off occuring once a week, and it loses (sometimes) the MAC to IP table.

Never mind - I got the solution I needed.

Documentation : I found a place where you mention this parameter : in this page

https://pypi.org/project/tinytuya/1.12.5/

it says ...

Classes OutletDevice(dev_id, address, local_key=None, dev_type='default') CoverDevice(dev_id, address, local_key=None, dev_type='default') BulbDevice(dev_id, address, local_key=None, dev_type='default') dev_id (str): Device ID e.g. 01234567891234567890 address (str): Device Network IP Address e.g. 10.0.1.99 or 0.0.0.0 to auto-find local_key (str, optional): The encryption key. Defaults to None. dev_type (str): Device type for payload options (see below)

:-))

Missatge de Jason Cox @.***> del dia ds., 29 d’abr. 2023 a les 4:10:

Did that work for you @ramonetnet https://github.com/ramonetnet ? Keep in mind that it can be slow (it waits for the device to emit its discovery packet), but can be helpful for devices with low DHCP lease times.

As for documentation... Oops. 😊 I'll tag this for us to add something to README.

— Reply to this email directly, view it on GitHub https://github.com/jasonacox/tinytuya/issues/337#issuecomment-1528484977, or unsubscribe https://github.com/notifications/unsubscribe-auth/AQU74ICM4MEOY436VHGYSB3XDR2A3ANCNFSM6AAAAAAXKXCNHU . You are receiving this because you were mentioned.Message ID: @.***>

jasonacox commented 1 year ago

Thanks @ramonetnet ! I just added a note to the example in the README as well. Hopefully this will help others.

https://github.com/jasonacox/tinytuya#programming-with-tinytuya

Programming with TinyTuya

After importing tinytuya, you create a device handle for the device you want to read or control. Here is an example for a Tuya smart switch or plug:

import tinytuya

# Connect to Device
d = tinytuya.OutletDevice(
    dev_id='DEVICE_ID_HERE',
    address='IP_ADDRESS_HERE',      # Or set to 'Auto' to auto-discover IP address
    local_key='LOCAL_KEY_HERE', 
    version=3.3)

# Get Status
data = d.status() 
print('set_status() result %r' % data)

# Turn On
d.turn_on()

# Turn Off
d.turn_off()
ramonetnet commented 1 year ago

Hi, Jason - the comment seems good to me

A question, just to know : is "Auto" equivalent to "0.0.0.0" ?

Have a nice day and thanks a lot for your job.

Missatge de Jason Cox @.***> del dia ds., 29 d’abr. 2023 a les 17:28:

Thanks @ramonetnet https://github.com/ramonetnet ! I just added a note to the example in the README as well. Hopefully this will help others.

https://github.com/jasonacox/tinytuya#programming-with-tinytuya Programming with TinyTuya

After importing tinytuya, you create a device handle for the device you want to read or control. Here is an example for a Tuya smart switch or plug:

import tinytuya

Connect to Deviced = tinytuya.OutletDevice(

dev_id='DEVICE_ID_HERE',
address='IP_ADDRESS_HERE',      # Or set to 'Auto' to auto-discover IP address
local_key='LOCAL_KEY_HERE',
version=3.3)

Get Statusdata = d.status() print('set_status() result %r' % data)

Turn Ond.turn_on()

Turn Offd.turn_off()

— Reply to this email directly, view it on GitHub https://github.com/jasonacox/tinytuya/issues/337#issuecomment-1528812838, or unsubscribe https://github.com/notifications/unsubscribe-auth/AQU74IHQZ63ARAOP3BLTH6LXDUXS3ANCNFSM6AAAAAAXKXCNHU . You are receiving this because you were mentioned.Message ID: @.***>

jasonacox commented 1 year ago

Yes, that works as well (and others) but "Auto" seemed the most intuitive. The code that controls it is here:

https://github.com/jasonacox/tinytuya/blob/06bf90403d7e046d54906509189466efc167dc0c/tinytuya/core.py#L784-L792

bradennapier commented 10 months ago

FWIW - if you have a dns server that allows assigning hostnames you can use that instead. Tinytuya resolves them fine from what I can tell.. at least the home assistant add on does lol.

For example I have a cree light given the hostname "kitchen.light.canopy-1.iot.arpa" which always points to the ip based on the MAC address of whatever light I have plugged into the canopy 1 socket.

Beats dealing with dhcp assignments anyway while maintaining centralized dynamic network flexibility (DHCP).

jasonacox commented 10 months ago

Thanks @bradennapier - What DNS server or router are you using that sets those iot.arpa records?

bradennapier commented 10 months ago

UniFi udm pro but in general using hostname resolution is useful over IP