jasonacox / tinytuya

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

Potentially a new bug. #447

Open Electrik-rich546456 opened 5 months ago

Electrik-rich546456 commented 5 months ago

Hi @jasonacox hows it going ? I wonder if there is a way to limit the amount of retries tinytuya.Cloud() has? I believe its 3 by default and wondering if i can make it 1 try instead? Let me explain what is happening, I don't have any errors when this happens it's just sometime very occasionally when i trigger the cloud turn off action it just sits there trying for a very long time before succeeding in actually turning off the specific light. I have 2 wireless kinetic switches (very cool no batteries needed) and the BASE is wired up to my rpi. When the switch is pressed the rpi detects the activity. I have a service i created on the pi that runs the Light_switch.py inside that it imports another file i made called room_controller.py and that is where your code is for turning various lights on and off by calling light_off(name of device) so my question is when i have the strange time issue can i have the room_controller.py only try the light once. If it fails call for service to restart Light_switch with debug of tuya set to true. that means next time it happens i get to potentially catch the error.

The only other option is i start with debug flag on all the time however that shows so much info even when everything is fine is there a way to hide the debug messages away in a file. So when the error happens i can just look at the last few entries ? What do you think ?

uzlonewolf commented 5 months ago

The .Cloud() functions do not retry failed requests except for a single retry after getting a 'token invalid' (auth token expired) response. The requests library is used for the actual HTTP calls, and any hanging or connect retries would be internal to that library; I'm not sure what its defaults are.

Electrik-rich546456 commented 5 months ago

I found this and i'm not sure how i would set that up do i put the commands in your cloud.py files or can i put it in my script even if my script only calls on the cloud switching from importing it.

This will not only change the max_retries but also enable a backoff strategy which makes requests to all http:// addresses sleep for a period of time before retrying (to a total of 5 times):


import requests

from requests.adapters import HTTPAdapter, Retry

s = requests.Session()

retries = Retry(total=5,
                backoff_factor=0.1,
                status_forcelist=[ 500, 502, 503, 504 ])

s.mount('http://', HTTPAdapter(max_retries=retries))

s.get('http://httpstat.us/500')

As per documentation for Retry: if the backoff_factor is 0.1, then sleep() will sleep for [0.05s, 0.1s, 0.2s, 0.4s, ...] between retries. It will also force a retry if the status code returned is 500, 502, 503 or 504.

Various other options to Retry allow for more granular control:

total – Total number of retries to allow. connect – How many connection-related errors to retry on. read – How many times to retry on read errors. redirect – How many redirects to perform. method_whitelist – Set of uppercased HTTP method verbs that we should retry on. status_forcelist – A set of HTTP status codes that we should force a retry on. backoff_factor – A backoff factor to apply between attempts. raise_on_redirect – Whether, if the number of redirects is exhausted, to raise a MaxRetryError, or to return a response with a response code in the 3xx range. raise_on_status – Similar meaning to raise_on_redirect: whether we should raise an exception, or return a response, if status falls in status_forcelist range and retries have been exhausted.

Electrik-rich546456 commented 5 months ago

how do i make the tinytuya.set_debug(True) output go into a log file instead of output on the console ?

jasonacox commented 5 months ago

I would try something like this...

import logging
import tinytuya

# Configure logging
logging.basicConfig(filename='tinytuya.log', level=logging.DEBUG)

# Create a logger
logger = logging.getLogger('tinytuya')

# Replace the default logger in tinytuya with the configured logger
tinytuya.set_logger(logger)