Code Monkey home page Code Monkey logo

tinytuya's Introduction

TinyTuya

License PyPI version Build Test Contrib Test PyPI - Python Version PyPI Downloads

Python module to interface with Tuya WiFi smart devices

Description

This python module controls and reads state of Tuya compatible WiFi Smart Devices (Plugs, Switches, Lights, Window Covers, etc.) using the local area network (LAN) or the cloud (TuyaCloud API). This is a compatible replacement for the pytuya PyPI module and currently supports Tuya Protocols 3.1, 3.2, 3.3, 3.4 and 3.5.

Tuya devices are designed to communicate with the TuyaCloud but most also expose a local area network API. This allows us to directly control the devices without using the cloud. This python module provides a way to poll status and issue commands to these devices.

TinyTuya can also connect to the Tuya Cloud to poll status and issue commands to Tuya devices.

TinyTuya Diagram

# Example Usage of TinyTuya
import tinytuya

d = tinytuya.OutletDevice('DEVICE_ID_HERE', 'IP_ADDRESS_HERE', 'LOCAL_KEY_HERE')
d.set_version(3.3)
data = d.status() 
print('Device status: %r' % data)

NOTE: Devices need to be activated by Smart Life App.

TinyTuya Installation

# Install TinyTuya
python -m pip install tinytuya

Pip will attempt to install cryptography, requests and colorama if not already installed.

Tuya Device Preparation

Controlling and monitoring Tuya devices on your network requires the following:

  • Address - Network address (IPv4) of the device e.g. 10.0.1.100
  • Device ID - Unique identifier for the Tuya device
  • Version - Tuya protocol version used (3.1, 3.2, 3.3, 3.4 or 3.5)
  • Local_Key - Security key needed to access the Tuya device. See Setup Wizard to get these keys.

Network Scanner

TinyTuya has a built in network scanner that can be used to find Tuya Devices on your local network. It will show Address, Device ID and Version for each device. Your LAN and firewall will need to allow UDP (6666, 6667 and 7000) and TCP (6668) traffic.

python -m tinytuya scan

Setup Wizard - Getting Local Keys

TinyTuya has a built-in setup Wizard that uses the Tuya IoT Cloud Platform to generate a JSON list (devices.json) of all your registered devices, including secret Local_Key and Name of your devices. Follow the steps below:

  1. PAIR - Download the Smart Life App or Tuya Smart App, available for iPhone or Android. Set up your SmartLife account and pair all of your Tuya devices (this is important as you cannot access a device that has not been paired).

  2. SCAN (Optional) - Run the TinyTuya scan to get a list of Tuya devices on your network. It will show device Address, Device ID and Version number (3.x):

    python -m tinytuya scan

    NOTE: You will need to use one of the displayed Device IDs for step 4.

  3. TUYA ACCOUNT - Set up a Tuya Account (see PDF Instructions):

    • NOTE: Tuya often changes their portal and services. Please open an issue with screenshots if we need to update these instructions.
    • Create a Tuya Developer account on iot.tuya.com. When it asks for the "Account Type", select "Skip this step..." (see screenshot).
    • Click on "Cloud" icon -> "Create Cloud Project"
      1. Pick the correct Data Center "Region" for your location (check HERE to find your Region). This will be used by TinyTuya Wizard (screenshot).
      2. Skip the configuration wizard but remember the Authorization Key: API ID and Secret for below (screenshot).
    • Click on "Cloud" icon -> Select your project -> Devices -> Link Tuya App Account (see screenshot)
    • Click Add App Account (screenshot) and it will pop-up a "Link Tuya App Account" dialog, chose "Automatic" and "Read Only Status" (it will still alow commands). Click OK and it will display a QR code. Scan the QR code with the Smart Life app on your Phone (see step 1 above) by going to the "Me" tab in the Smart Life app and clicking on the QR code button [..] in the upper right hand corner of the app. When you scan the QR code, it will link all of the devices registered in your Smart Life app into your Tuya IoT project. If the QR code will not scan then make sure to disable any browser theming plug-ins (such as Dark Reader) and try again.
    • NO DEVICES? If no devices show up after scanning the QR code, you will need to select a different data center and edit your project (or create a new one) until you see your paired devices from the Smart Life App show up. (screenshot). The data center may not be the most logical. As an example, some in the UK have reported needing to select "Central Europe" instead of "Western Europe".
    • SERVICE API: Under "Service API" ensure these APIs are listed: IoT Core and Authorization. To be sure, click subscribe again on every service. Very important: disable popup blockers otherwise subscribing won't work without providing any indication of a failure. Make sure you authorize your Project to use those APIs:
      • Click "Service API" tab
      • Click "Go to Authorize" button
      • Select the API Groups from the dropdown and click Subscribe (screenshot)
  4. WIZARD - Run Setup Wizard:

    • From your Linux/Mac/Win PC run the TinyTuya Setup Wizard to fetch the Local_Keys for all of your registered devices:
      python -m tinytuya wizard   # use -nocolor for non-ANSI-color terminals
    • The Wizard will prompt you for the API ID key, API Secret, API Region (cn, us, us-e, eu, eu-w, or in) from your Tuya IoT project as set in Step 3 above.
      • To find those again, go to iot.tuya.com, choose your project and click Overview
        • API Key: Access ID/Client ID
        • API Secret: Access Secret/Client Secret
    • It will also ask for a sample Device ID. You can have the wizard scan for one (enter scan), use one from step 2 above or in the Device List on your Tuya IoT project.
    • The Wizard will poll the Tuya IoT Cloud Platform and print a JSON list of all your registered devices with the "name", "id" and "key" of your registered device(s). The "key"s in this list are the Devices' Local_Key you will use to access your device.
    • In addition to displaying the list of devices, Wizard will create a local file devices.json that TinyTuya will use to provide additional details for scan results from tinytuya.deviceScan() or when running python -m tinytuya scan. The wizard also creates a local file tuya-raw.json that contains the entire payload from Tuya Cloud.
    • The Wizard will ask if you want to poll all the devices. If you do, it will display the status of all devices on record and create a snapshot.json file with these results. Make sure your LAN and firewall permit UDP (6666, 6667 and 7000) and TCP (6668) traffic.

Notes:

  • If you ever reset or re-pair your smart devices, the Local_Key will be reset and you will need to repeat the steps above.
  • The TinyTuya Wizard was inspired by the TuyAPI CLI which is an alternative way to fetch the Local_Keys: npm i @tuyapi/cli -g and run tuya-cli wizard

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()

TinyTuya Module Classes and Functions

Global Functions
    devices = deviceScan()             # Returns dictionary of devices found on local network
    scan()                             # Interactive scan of local network
    wizard()                           # Interactive setup wizard
    set_debug(toggle, color)           # Activate verbose debugging output

Classes
    OutletDevice(args...)
    CoverDevice(args...)
    BulbDevice(args...)
      Where args:
        dev_id (str): Device ID e.g. 01234567891234567890
        address (str): Device Network IP Address e.g. 10.0.1.99 or "Auto" to auto-find
        local_key (str): The encryption key
        dev_type (str): Device type for payload options (see below)
        connection_timeout = 5 (int): Timeout in seconds
        version = 3.1 (float): Tuya Protocol (e.g. 3.1, 3.2, 3.3, 3.4, 3.5)
        persist = False (bool): Keep TCP link open
        cid = None (str): Optional sub device id
        node_id = None (str): Alias for cid
        parent = None (object): Gateway device object this is a child of
        connection_retry_limit = 5 (int)
        connection_retry_delay = 5 (int)

    Cloud(apiRegion, apiKey, apiSecret, apiDeviceID, new_sign_algorithm)


Functions:

  Configuration Settings: 

    set_version(version)               # Set device version 3.1 [default] or 3.3 (all new devices)
    set_socketPersistent(False/True)   # Keep connect open with device: False [default] or True
    set_socketNODELAY(False/True)      # Add cooldown period for slow Tuya devices: False or True [default]
    set_socketRetryLimit(integer)      # Set retry count limit [default 5]
    set_socketTimeout(s)               # Set connection timeout in seconds [default 5]
    set_dpsUsed(dpsUsed)               # Set data points (DPs) to expect (rarely needed)
    set_retry(retry=True)              # Force retry if response payload is truncated
    set_sendWait(num_secs)             # Seconds to wait after sending for a response
    set_bulb_type(type):               # For BulbDevice, set type to A, B or C

  Device Commands:

    status()                           # Fetch status of device (json payload)
    subdev_query(nowait)               # query sub-device list and online status (only for gateway devices)
    detect_available_dps()             # Return list of DPS available from device
    set_status(on, switch=1, nowait)   # Control status of the device to 'on' or 'off' (bool)
                                       # nowait (default False) True to send without waiting for response
    set_value(index, value, nowait)    # Send and set value of any DPS/index on device.
    set_multiple_values(index_value_dict, nowait)
                                       # Set multiple values with a single request
				       # Note: Some devices do not like this!
    heartbeat(nowait)                  # Send heartbeat to device
    updatedps(index=[1], nowait)       # Send updatedps command to device to refresh DPS values
    turn_on(switch=1, nowait)          # Turn on device / switch #
    turn_off(switch=1, nowait)         # Turn off device
    set_timer(num_secs, nowait)        # Set timer for num_secs on devices (if supported)
    generate_payload(command, data)    # Generate TuyaMessage payload for command with data
    send(payload)                      # Send payload to device (do not wait for response)
    receive()                          # Receive payload from device

    OutletDevice:
        set_dimmer(percentage):
        
    CoverDevice:
        open_cover(switch=1):  
        close_cover(switch=1):
        stop_cover(switch=1):

    BulbDevice
        set_colour(r, g, b, nowait):
        set_hsv(h, s, v, nowait):
        set_white(brightness, colourtemp, nowait):
        set_white_percentage(brightness=100, colourtemp=0, nowait):
        set_brightness(brightness, nowait):
        set_brightness_percentage(brightness=100, nowait):
        set_colourtemp(colourtemp, nowait):
        set_colourtemp_percentage(colourtemp=100, nowait):
        set_scene(scene, nowait):             # 1=nature, 3=rave, 4=rainbow
        set_mode(mode='white', nowait):       # white, colour, scene, music
        result = brightness():
        result = colourtemp():
        (r, g, b) = colour_rgb():
        (h,s,v) = colour_hsv():
        result = state():
    
    Cloud
        setregion(apiRegion)
	cloudrequest(url, action=[POST if post else GET], post={}, query={})
        getdevices(verbose=False)
        getstatus(deviceid)
        getfunctions(deviceid)
        getproperties(deviceid)
        getdps(deviceid)
        sendcommand(deviceid, commands [, uri])
	getconnectstatus(deviceid)
	getdevicelog(deviceid, start=[now - 1 day], end=[now], evtype="1,2,3,4,5,6,7,8,9,10", size=0, max_fetches=50, start_row_key=None, params={})

TinyTuya Error Codes

Starting with v1.2.0 TinyTuya functions will return error details in the JSON data responses instead of raising exceptions. The format for this response:

{ "Error":"Invalid JSON Payload", "Err":"900", "Payload":"{Tuya Message}" }

The "Err" number will be one of these:

  • 900 (ERR_JSON) - Invalid JSON Response from Device
  • 901 (ERR_CONNECT) - Network Error: Unable to Connect
  • 902 (ERR_TIMEOUT) - Timeout Waiting for Device
  • 903 (ERR_RANGE) - Specified Value Out of Range
  • 904 (ERR_PAYLOAD) - Unexpected Payload from Device
  • 905 (ERR_OFFLINE) - Network Error: Device Unreachable
  • 906 (ERR_STATE) - Device in Unknown State
  • 907 (ERR_FUNCTION) - Function Not Supported by Device
  • 908 (ERR_DEVTYPE) - Device22 Detected: Retry Command
  • 909 (ERR_CLOUDKEY) - Missing Tuya Cloud Key and Secret
  • 910 (ERR_CLOUDRESP) - Invalid JSON Response from Cloud
  • 911 (ERR_CLOUDTOKEN) - Unable to Get Cloud Token
  • 912 (ERR_PARAMS) - Missing Function Parameters
  • 913 (ERR_CLOUD) - Error Response from Tuya Cloud
  • 914 (ERR_KEY_OR_VER) - Check device key or version

Example Usage

See the sample python script test.py for an OutletDevice example or look in the examples directory for other scripts.

import tinytuya

"""
OUTLET Device
"""
d = tinytuya.OutletDevice('DEVICE_ID_HERE', 'IP_ADDRESS_HERE', 'LOCAL_KEY_HERE')
d.set_version(3.3)
data = d.status()  

# Show status and state of first controlled switch on device
print('Dictionary %r' % data)
print('State (bool, true is ON) %r' % data['dps']['1'])  

# Toggle switch state
switch_state = data['dps']['1']
data = d.set_status(not switch_state)  # This requires a valid key
if data:
    print('set_status() result %r' % data)

# On a switch that has 4 controllable ports, turn the fourth OFF (1 is the first)
data = d.set_status(False, 4)
if data:
    print('set_status() result %r' % data)
    print('set_status() extra %r' % data[20:-8])

"""
RGB Bulb Device
"""
import time

d = tinytuya.BulbDevice('DEVICE_ID_HERE', 'IP_ADDRESS_HERE', 'LOCAL_KEY_HERE')
d.set_version(3.3)  # IMPORTANT to set this regardless of version
d.set_socketPersistent(True)  # Optional: Keep socket open for multiple commands
data = d.status()

# Show status of first controlled switch on device
print('Dictionary %r' % data)

# Set to RED Color - set_colour(r, g, b):
d.set_colour(255,0,0)  

# Cycle through the Rainbow
rainbow = {"red": [255, 0, 0], "orange": [255, 127, 0], "yellow": [255, 200, 0],
          "green": [0, 255, 0], "blue": [0, 0, 255], "indigo": [46, 43, 95],
          "violet": [139, 0, 255]}
for color in rainbow:
    [r, g, b] = rainbow[color]
    d.set_colour(r, g, b, nowait=True)  # nowait = Go fast don't wait for response
    time.sleep(0.25)

# Brightness: Type A devices range = 25-255 and Type B = 10-1000
d.set_brightness(1000)

# Set to White - set_white(brightness, colourtemp):
#    colourtemp: Type A devices range = 0-255 and Type B = 0-1000
d.set_white(1000,10)

# Set Bulb to Scene Mode
d.set_mode('scene')

# Scene Example: Set Color Rotation Scene
d.set_value(25, '07464602000003e803e800000000464602007803e803e80000000046460200f003e803e800000000464602003d03e803e80000000046460200ae03e803e800000000464602011303e803e800000000')

Example Device Monitor

You can set up a persistent connection to a device and then monitor the state changes with a continual loop. This is helpful for troubleshooting and discovering DPS values.

import tinytuya

d = tinytuya.OutletDevice('DEVICEID', 'DEVICEIP', 'DEVICEKEY')
d.set_version(3.3)
d.set_socketPersistent(True)

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)    

Tuya Cloud Access

You can poll and manage Tuya devices using the Cloud class and functions.

CAUTION: The free Tuya IoT Developer (Trial) account allows a very limited number of Cloud API calls. Be aware of the restrictions before enabling any automation that makes frequent calls.

import tinytuya

# Connect to Tuya Cloud
# c = tinytuya.Cloud()  # uses tinytuya.json 
c = tinytuya.Cloud(
        apiRegion="us", 
        apiKey="xxxxxxxxxxxxxxxxxxxx", 
        apiSecret="xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", 
        apiDeviceID="xxxxxxxxxxxxxxxxxxID")

# Display list of devices
devices = c.getdevices()
print("Device List: %r" % devices)

# Select a Device ID to Test
id = "xxxxxxxxxxxxxxxxxxID"

# Display Properties of Device
result = c.getproperties(id)
print("Properties of device:\n", result)

# Display Status of Device
result = c.getstatus(id)
print("Status of device:\n", result)

# Send Command - Turn on switch
commands = {
    "commands": [
        {"code": "switch_1", "value": True},
        {"code": "countdown_1", "value": 0},
    ]
}
print("Sending command...")
result = c.sendcommand(id,commands)
print("Results\n:", result)

Up to one week of device logs can also be pulled from the Cloud. By default getdevicelog() will pull 1 day of logs or 5000 log entries, whichever comes first. The returned timestamps are unixtime*1000, and event_id 7 (data report) will probably be the most useful.

import tinytuya
import json

c = tinytuya.Cloud()
#r = c.getdevicelog( '00112233445566778899', start=-1, end=0, size=0, max_fetches=50 )
#r = c.getdevicelog( '00112233445566778899', start=1669990000, end=1669990300, size=20 )
r = c.getdevicelog( '00112233445566778899' )
print( json.dumps(r, indent=2) )

Encryption Notes

Tuya devices use AES encryption which is not available in the Python standard library. PyCA/cryptography is recommended and installed by default. Other options include PyCryptodome , PyCrypto and pyaes.

  • Deprecation notice for pyaes: The pyaes library works for Tuya Protocol <= 3.4 but will not work for 3.5 devices. This is because pyaes does not support GCM which is required for v3.5 devices.

Command Line

python -m tinytuya <command> [<max_time>] [-debug] [-nocolor] [-force [192.168.0.0/24 192.168.1.0/24 ...]] [-h]

  wizard         Launch Setup Wizard to get Tuya Local KEYs.
  scan           Scan local network for Tuya devices.
  devices        Scan all devices listed in devices.json file.
  snapshot       Scan devices listed in snapshot.json file.
  json           Scan devices listed in snapshot.json file [JSON].
  <max_time>     Maximum time to find Tuya devices [Default=18]
  -nocolor       Disable color text output.
  -force         Force network scan of device IP addresses based on format:
                 [net1/mask1 net2/mask2 ...] Auto-detects if none provided.
  -no-broadcasts Ignore broadcast packets when force scanning.
  -debug         Activate debug mode.
  -h             Show usage.

Scan Tool

The function tinytuya.scan() will listen to your local network (UDP 6666 and 6667) and identify Tuya devices broadcasting their Address, Device ID, Product ID and Version and will print that and their stats to stdout. This can help you get a list of compatible devices on your network. The tinytuya.deviceScan() function returns all found devices and their stats (via dictionary result).

You can run the scanner from the command line using these interactive commands:

# Listen for Tuya Devices and match to devices.json if available
python -m tinytuya scan

# The above creates a snapshot.json file with IP addresses for devices
# You can use this command to get a rapid poll of status of all devices
python -m tinytuya snapshot

# The sames thing as above but with a non-interactive JSON response
python -m tinytuya json

# List all register devices discovered from Wizard and poll them
python -m tinytuya devices

By default, the scan functions will retry 15 times to find new devices. If you are not seeing all your devices, you can increase max_retries by passing an optional arguments (eg. 50 retries):

# command line
python -m tinytuya scan 50
# invoke verbose interactive scan
tinytuya.scan(50)

# return payload of devices
devices = tinytuya.deviceScan(false, 50)

Troubleshooting

  • Tuya devices only allow one TCP connection at a time. Make sure you close the TuyaSmart or SmartLife app before using TinyTuya to connect.
  • Some devices ship with older firmware that may not work with TinyTuya. If you're experiencing issues, please try updating the device's firmware in the official app.
  • The LOCAL KEY for Tuya devices will change every time a device is removed and re-added to the TuyaSmart app. If you're getting decrypt errors, try getting the key again as it might have changed.
  • Devices running protocol version 3.1 (e.g. below Firmware 1.0.5) do not require a device Local_Key to read the status. All devices will require a device Local_Key to control the device.
  • Some devices with 22 character IDs will require additional setting to poll correctly. TinyTuya will attempt to detect and accomodate for this, but it can be specified directly:
    a = tinytuya.OutletDevice('here_is_my_key', '192.168.x.x', 'secret_key_here', 'device22')
    a.set_version(3.3)
    a.set_dpsUsed({"1": None})  # This needs to be a datapoint available on the device
    data =  a.status()
    print(data)
  • Windows 10 Users - TinyTuya wizard and scan interactive tools use ANSI color. This will work correctly in PowerShell but will show cryptic escape codes when run in Windows CMD. You can fix this by using the -nocolor option on tinytuya, or by changing the Windows CMD console registry to process ANSI escape codes by doing something like this:
    reg add HKEY_CURRENT_USER\Console /v VirtualTerminalLevel /t REG_DWORD /d 0x00000001 /f
    

User Contributed Device Modules

In addition to the built-in OutletDevice, BulbDevice and CoverDevice device support, the community is encourage to submit additional device modules which are available here: Contrib Library:

# Example usage of community contributed device modules
from tinytuya import Contrib

thermo = Contrib.ThermostatDevice( 'abcdefghijklmnop123456', '172.28.321.475', '1234567890123abc' )

Tuya Data Points - DPS Table

The Tuya devices send back data points (DPS) also called device function points, in a json string. The DPS attributes define the state of the device. Each key in the DPS dictionary refers to key value pair, the key is the DP ID and its value is the dpValue. You can refer to the Tuya developer platform for definition of function points for the products.

The following table represents several of the standard Tuya DPS values and their properties. It represents data compiled from Tuya documentation and self-discovery. Devices may vary. Feedback or additional data would would be appreciated. Please submit a Issue or Pull Request if you have additional data that would be helpful for others.

To find Tuya DPS for devices not listed below, you can discover the DPS values using the Tuya IoT platform. See this help here: Find your Data Point.

DPS Read and Set Example:

# Read Value of DPS 25
data = d.status()  
print("Value of DPS 25 is ", data['dps']['25'])

# Set Value of DPS 25
d.set_value(25, '010e0d0000000000000003e803e8')

Version 3.1 Devices

Version 3.1 (and some 3.3) - Plug or Switch Type

DP ID Function Point Type Range Units
1 Switch bool True/False
2 Countdown? integer 0-86400 s
4 Current integer 0-30000 mA
5 Power integer 0-50000 W
6 Voltage integer 0-5000 V

Version 3.1 - Light Type (RGB)

DP ID Function Point Type Range Units
1 Switch bool True/False
2 Mode enum white,colour,scene,music
3 Bright integer 10-1000*
4 Color Temp integer 0-1000*
5 Color hexstring r:0-255,g:0-255,b:0-255,h:0-360,s:0-255,v:0-255 rgb+hsv

Version 3.3 Devices

Version 3.3 - Plug, Switch, Power Strip Type

DP ID Function Point Type Range Units
1 Switch 1 bool True/False
2 Switch 2 bool True/False
3 Switch 3 bool True/False
4 Switch 4 bool True/False
5 Switch 5 bool True/False
6 Switch 6 bool True/False
7 Switch 7/usb bool True/False
9 Countdown 1 integer 0-86400 s
10 Countdown 2 integer 0-86400 s
11 Countdown 3 integer 0-86400 s
12 Countdown 4 integer 0-86400 s
13 Countdown 5 integer 0-86400 s
14 Countdown 6 integer 0-86400 s
15 Countdown 7 integer 0-86400 s
17 Add Electricity integer 0-50000 kwh
18 Current integer 0-30000 mA
19 Power integer 0-50000 W
20 Voltage integer 0-5000 V
21 Test Bit integer 0-5 n/a
22 Voltage coeff. integer 0-1000000
23 Current coeff. integer 0-1000000
24 Power coeff. integer 0-1000000
25 Electricity coeff. integer 0-1000000
26 Fault fault ov_cr
38 Power-on state setting enum off, on, memory
39 Overcharge Switch bool True/False
40 Indicator status setting enum none, on, relay, pos
41 Child Lock bool True/False
42 UNKNOWN
43 UNKNOWN
44 UNKNOWN

Note: Some 3.3 energy management plugs use the DPS values of the 3.1 plug above.

Version 3.3 - Dimmer Switch

DP ID Function Point Type Range Units
1 Switch bool True/False
2 Brightness integer 10-1000*
3 Minimum of Brightness integer 10-1000*
4 Type of light source1 enum LED,incandescent,halogen
5 Mode enum white

Version 3.3 - Light Type (RGB)

DP ID Function Point Type Range Units
20 Switch bool True/False
21 Mode enum white,colour,scene,music
22 Bright integer 10-1000*
23 Color Temp integer 0-1000
24 Color hexstring h:0-360,s:0-1000,v:0-1000 hsv
25 Scene string n/a
26 Left time integer 0-86400 s
27 Music string n/a
28 Debugger string n/a
29 Debug string n/a
30 Rhythms n/a n/a
31 Go To Sleep n/a n/a
32 Wake Up n/a n/a
33 Power Off Memory n/a n/a
34 Do not Disturb n/a n/a
41 Remote Control Switch n/a n/a
209 Cycle Timing n/a n/a
210 Vaction Timing n/a n/a

Version 3.3 - Automated Curtain Type

DP ID Function Point Type Range Units
1 Curtain Switch 1 enum open, stop, close, continue
2 Percent control 1 integer 0-100 %
3 Accurate Calibration 1 enum start, end
4 Curtain Switch 2 enum open, stop, close, continue
5 Percent control 2 integer 0-100
6 Accurate Calibration 2 enum start, end
8 Motor Steer 1 enum forward, back
9 Motor steer 2 enum forward, back
10 Quick Calibration 1 integer 1-180 s
11 Quick Calibration 2 integer 1-180 s
12 Motor Mode 1 enum strong_power, dry_contact
13 Motor Mode 2 enum strong_power, dry_contact
14 Light mode enum relay, pos, none

Version 3.3 - Fan Switch Type

DP ID Function Point Type Range Units
1 Fan switch bool True/False n/a
2 Fan countdown integer 0-86400 s
3 Fan speed enum level_1, level_2, level_3, level_4, level_5
4 Fan speed integer 1-100 %
5 Fan light switch bool True/False
6 Brightness integer integer 10-1000
7 Fan light countdown integer 0-86400
8 Minimum brightness integer 10-1000
9 Maximum brightness integer 10-1000
10 Mode enum white
11 Power-on state setting enum off, on, memory
12 Indicator status setting enum none, relay, pos
13 Backlight switch bool True/False

Version 3.3 - Universal IR Controller with optional Temp/Humidity

DP ID Function Point Type Range Units
101 Current Temperature integer 0-600 10x Celsius
102 Current Humidity integer 0-100 %
201 IR Commands (set only) JSON* n/a n/a
# The IR Commands JSON has the following format:
command = {
    "control": "send_ir",
    "head": "",
    "key1": "[[TO_BE_REPLACED]]",
    "type": 0,
    "delay": 300,
}
# Sending the IR command:
payload = d.generate_payload(tinytuya.CONTROL, {"201": json.dumps(command)})
d.send(payload)

The key1 attribute is a base64 string that contains the IR signal. You can extract it using this procedure:

  1. Register a new IR device on Tuya Smart / Smart Life app (if not registered already) and map, setup or import your buttons.
  2. Tap multiple times on the button you wish to control.
  3. Go to Tuya IoT Platform and select your app under Cloud > Development section.
  4. Go to to the Device tab and select "Debug Device" on the parent device. Browse Device Logs section and retrieve the key1 attribute that matches your tapping timestamp from step 2 above. Use that key1 attribute in the payload example above.

You need to repeat these steps for each button (cloud logging is not always sequential).

Version 3.3 - Sensor Type

Important Note: Battery-powered Tuya sensors are usually designed to stay in sleep mode until a state change (eg.open or close alert). This means you will not be able to poll these devices except in the brief moment they awake, connect to the WiFi and send their state update payload the the Tuya Cloud. Keep in mind that if you manage to poll the device enough to keep it awake, you will likely quickly drain the battery.

DP ID Function Point Type Range Units
1 Door Sensor bool True/False
2 Battery level state enum low, middle, high
3 Battery level integer 0-100 %
4 Temper alarm bool True/False
5 Flooding Detection State enum alarm, normal
6 Luminance detection state enum low, middle, high, strong
7 Current Luminance integer 0-100 %
8 Current Temperature integer 400-2000
9 Current Humidity integer 0-100 %
10 Shake State enum normal, vibration, drop, tilt
11 Pressure State enum alarm, normal
12 PIR state enum pir, none
13 Smoke Detection State enum alarm, normal
14 Smoke value integer 0-1000
15 Alarm Volume enum low, middle, high, mute
16 Alarm Ringtone enum 1, 2, 3, 4, 5
17 Alarm Time integer 0-60 s
18 Auto-Detect bool True/False
19 Auto-Detect Result enum checking, check_success, check_failure, others
20 Preheat bool True/False
21 Fault Alarm fault fault, serious_fault, sensor_fault, probe_fault, power_fault Barrier
22 Lifecycle bool True/False
23 Alarm Switch bool True/False
24 Silence bool True/False
25 Gas Detection State enum alarm, normal
26 Detected Gas integer 0-1000
27 CH4 Detection State enum alarm, normal
28 CH4 value integer 0-1000
29 Alarm state enum alarm_sound, alarm_light, alarm_sound_light, normal
30 VOC Detection State enum alarm, normal
31 VOC value integer 0-999
32 PM2.5 state enum alarm, normal
33 PM2.5 value integer 0-999
34 CO state enum alarm, normal
35 CO value integer 0-1000
36 CO2 Detection State enum alarm, normal
37 CO2 value integer 0-1000
38 Formaldehyde Detection State enum alarm, normal
39 CH2O value integer 0-1000
40 Master mode enum disarmed, arm, home, sos
41 Air quality index enum level_1, level_2, level_3, level_4, level_5, level_6

NOTE (*) - The range can vary depending on the device. As an example, for dimmers, it may be 10-1000 or 25-255.

Version 3.3 - WiFi Air Quality Detector PM2.5/Formaldehyde/VOC/CO2/Temperature/Humidity

DP ID Function Point Type Range Units
2 PM2.5 value integer 0 - 999 ug/m3
18 Current Temperature integer 0 - 850 หšC (multiplied by 10)
19 Current Humidity integer 0 - 1000 % (multiplied by 10)
20 CH2O (Formaldehyde) value integer 0 - 1000 ppm
21 VOC (Volatile organic compound) value integer 0 - 2000 ppm
22 CO2 value integer 350 - 2000 ppm

Example device: https://www.aliexpress.com/item/1005005034880204.html

Version 3.3 - Robot Mower Type

DP ID Function Point Type Range Units
6 Battery integer 0-100 %
101 Machine Status enum
  • STANDBY MOWING
  • CHARGING
  • EMERGENCY
  • LOCKED
  • PAUSED
  • PARK
  • CHARGING_WITH_TASK_SUSPEND
  • FIXED_MOWING
102 Machine error integer 0, ?
103 Machine warning enum
  • MOWER_LEAN
  • MOWER_EMERGENCY
  • MOWER_UI_LOCKED
    104 Rain mode boolean True/False
    105 Work time interger 1-99 hours
    106 Machine password byte str ?
    107 Clear machine appointment boolean True/False
    108 Query machine reservation boolean True/False
    109 Query partition parameters boolean True/False
    110 Report machine reservation byte str
    111 Error log byte str
    112 Work log byte str
    113 Partition parameters byte str
    114 Work mode enum AutoMode/??

    Reference pymoebot for further definition.

    Version 3.3 - 24v Thermostat (i.e. PCT513-TY)

    DP ID Function Point Type Range Units
    2 System Mode enum [ 'auto' 'cool' 'heat' 'off' others? ]
    16 Center of Setpoint, High-Resolution ยฐC integer 500-3200 ยฐC x 100 in steps of 50
    17 Center of Setpoint, ยฐF integer 20-102 ยฐF
    18* Cooling Setpoint, Low-Resolution ยฐF integer 20-102 ยฐF
    19* Cooling Setpoint, Low-Resolution ยฐC integer 500-3200 ยฐC
    20* Heating Setpoint, Low-Resolution ยฐF integer 20-102 ยฐF
    23 Display Units enum [ 'f' 'c' ]
    24 Current Temperature, High-Resolution ยฐC integer 500-3200 ยฐC x 100 in steps of 50
    26* Heating Setpoint, Low-Resolution ยฐC integer 5-32 ยฐC
    27* Temperature Correction integer -10 - +10
    29 Current Temperature, ยฐF integer 20-102 ยฐF
    34 Current Humidity integer 0-100 %
    45 Fault Flags bitmask [ e1 e2 e3 ]
    107 System Type integer-as-string ? ?
    108* Cooling Setpoint, High-Resolution ยฐC integer 500-3200 ยฐC x 100 in steps of 50
    109* Heating Setpoint, High-Resolution ยฐC integer 500-3200 ยฐC x 100 in steps of 50
    110* Cooling Setpoint, ยฐF integer 20-102 ยฐF
    111* Heating Setpoint, ยฐF integer 20-102 ยฐF
    115 Fan Mode enum [ 'auto' 'cycle' 'on' ]
    116 "at home/away from home" integer-as-string ? ?
    118 Schedule Data base64 binary blob
    119 Schedule Enabled bool True/False
    120 Hold/Schedule enum [ 'permhold' 'temphold' 'followschedule' ]
    121 Vacation Data base64 binary blob
    122 Sensor Data, list 1 base64 binary blob
    123 Minimum Fan Run Time integer 0-55 minutes per hour
    125 Sensor Data, list 2 base64 binary blob
    126 Sensor Data, list 3 base64 binary blob
    127 Sensor Data, list 4 base64 binary blob
    128 Sensor Data, list 5 base64 binary blob
    129 System State enum [ 'fanon' 'coolfanon' 'alloff' others? ]
    130 Weather Forcast ? ? ?

    NOTE (*) - Depending on the firmware, either 18/19/20/26/27 or 108/109/110/111/x are used, not both

    A user contributed module is available for this device in the Contrib library:

    from tinytuya import Contrib
    
    thermo = Contrib.ThermostatDevice( 'abcdefghijklmnop123456', '172.28.321.475', '1234567890123abc' )

    For info on the Sensor Data lists, see #139

    Tuya References

    Credits

    • TuyAPI https://github.com/codetheweb/tuyapi by codetheweb and blackrozes. Protocol reverse engineering from jepsonrob and clach04.
    • PyTuya https://github.com/clach04/python-tuya by clach04. The origin of this python module (now abandoned). Thanks to nijave for pycryptodome support and testing, Exilit for unittests and docstrings, mike-gracia for improved Python version support, samuscherer for RGB Bulb support, magneticflux for improved Python version support, sean6541 for initial PyPi package and Home Assistant support https://github.com/sean6541/tuya-homeassistant, ziirish - for resolving a dependency problem related to version numbers at install time
    • https://github.com/rospogrigio/localtuya-homeassistant by rospogrigio. Updated pytuya to support devices with Device IDs of 22 characters
    • Thanks to @uzlonewolf, our top contributor and resident wizard, for expanding the Outlet/Cover/Bulb/Cloud modules into separate files, introducing Contrib structure for user generated device modules, making enhancements to TuyaMessage logic for multi-payload messages, rewriting the scanner and adding Tuya Protocol 3.2, 3.4 & 3.5 support to TinyTuya!
    • Finally, thanks to the entire TinyTuya community for the great engagement, contributions and encouragement! See RELEASE notes for the ever growing journal of improvements and the incredible list of talent making this project possible.

    Related Projects

    TinyTuya Powered Projects

    Please feel free to submit a PR or open an issue to add your project.

    tinytuya's People

    Contributors

    bikerglen avatar clusterm avatar cowboy3d avatar cy1110 avatar elfman03 avatar elockman avatar eykamp avatar fajarmnrozaki avatar felix-pi avatar fr3dz10 avatar gstein avatar jasonacox avatar knrdl avatar mafrosis avatar mschlenstedt avatar nyok92 avatar osomdev avatar pawel-szopinski avatar paxy avatar pkasprzyk avatar poil avatar rustic-monkey avatar syrooo avatar teejo75 avatar theonlywayup avatar unit-404 avatar uzlonewolf avatar valentindusollier avatar whytey avatar xgustavoh avatar

    Stargazers

     avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

    Watchers

     avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

    tinytuya's Issues

    Yeeuu K1 Smart Lock Box

    Hi,
    I'm trying to use tinytuya to check status and open a Smart Lock Box (https://www.yeeuu.com/products/yeeuu-k1-smart-lock-box ) connected to Wifi via a Bluetooth Bridge (https://www.yeeuu.com/products/yeeuu-h1-gateway ). I have imported both of them via tuya.com and see both in devices.json
    { "name": "YEEUU K1 Smart Lock Box", "id": "id-made-of-22-chars", "key": "mykey" }, { "name": "YEEUU H1 WiFi Bridge", "id": "id-made-of-22-chars", "key": "same key as above" },

    so I have tried using the suggestion to handle 22-chars-id's:
    `import tinytuya

    DEVICEID = "the id of the K1"
    DEVICEIP = "the IP"
    DEVICEKEY = "mykey"
    DEVICEVERS = "3.3"

    a = tinytuya.CoverDevice(DEVICEID, DEVICEIP, DEVICEKEY, 'device22')
    a.set_version(3.3)
    a.set_dpsUsed({"1": None}) # This needs to be a datapoint available on the device
    data = a.status()
    print(data)`

    but when I run this I get a timeout

    python3 k1test.py Exceeded tinytuya retry limit (5) Traceback (most recent call last): File "/usr/local/lib/python3.7/dist-packages/tinytuya/__init__.py", line 353, in _send_receive data = self.socket.recv(1024) # try again socket.timeout: timed out Traceback (most recent call last): File "k1test.py", line 11, in <module> data = a.status() File "/usr/local/lib/python3.7/dist-packages/tinytuya/__init__.py", line 556, in status data = self._send_receive(payload) File "/usr/local/lib/python3.7/dist-packages/tinytuya/__init__.py", line 353, in _send_receive data = self.socket.recv(1024) # try again socket.timeout: timed out

    Any clue of what I am doing wrong? I also haven't tried "open_cover(switch=1):" yet because I am physically far away in VPN...

    Thanks!
    R

    tinytuya requests time out

    When running tinytuya the smartbulb is found and its status is displayed. But when running the wizard or trying to change the status of the light, there is no response. The light works fine with the tuya app and with Alexa.

    Help would be much appreciated as I am running out of ideas myself :)

    scan not showing device ID

    py -m tinytuya scan -nocolor

    TinyTuya (Tuya device scanner) [1.1.3]

    Scanning on UDP ports 6666 and 6667 for devices (15 retries)...

    • Unexpected payload=%r
      b"\xd0\x97fgo3i\xeb\x10\xb5\xe9\xf12\xfd\x80*\xc1w\xcf=\x9e\xc5\xe6\x8dD\xed'\xad\xe5\xe7U0\xde\x19\xf6\x08\xc0\xf6\x16&\xb1\xf8w\x87'\x97\xc
      ao\x1a{\xcbu\xef[\xb8\xeb3\n\xd3D\xdd\x0b\x10h\xdb\x19\xaf\x80#H\xb8\x03B\x1e@\xba\n{|x\xfa@g\xfbZs\x89\xaf\xbe\xaf\x88\n\x12\xd3\xbbl\x9f9`\x
      8aV\xbc\x82\x10\x8d\xd9\x84\xa5\xbf\xdc\x87\xe3ZtL95'>\xa5*ez\xcc\xeeOT\xa4\xa1,\xcaMo\xba\xcc\x17l\xe6\xa4\x01T\xedr2b\x7f,=\x9cGDX^G\x1bj/\x
      c4y\xca"
      Device Found [Unknown payload]: 192.168.1.3
      ID = , Product ID = , Version =
      No Stats - Device Key required to poll for status
    • Unexpected payload=%r
      b"\xd0\x97fgo3i\xeb\x10\xb5\xe9\xf12\xfd\x80*\xc1w\xcf=\x9e\xc5\xe6\x8dD\xed'\xad\xe5\xe7U0\xde\x19\xf6\x08\xc0\xf6\x16&\xb1\xf8w\x87'\x97\xc
      ao\x1a{\xcbu\xef[\xb8\xeb3\n\xd3D\xdd\x0b\x10h\xdb\x19\xaf\x80#H\xb8\x03B\x1e@\xba\n{|x\xfa@g\xfbZs\x89\xaf\xbe\xaf\x88\n\x12\xd3\xbbl\x9f9`\x
      8aV\xbc\x82\x10\x8d\xd9\x84\xa5\xbf\xdc\x87\xe3ZtL95'>\xa5*ez\xcc\xeeOT\xa4\xa1,\xcaMo\xba\xcc\x17l\xe6\xa4\x01T\xedr2b\x7f,=\x9cGDX^G\x1bj/\x
      c4y\xca"
    • Unexpected payload=%r
      b"\xd0\x97fgo3i\xeb\x10\xb5\xe9\xf12\xfd\x80*\xc1w\xcf=\x9e\xc5\xe6\x8dD\xed'\xad\xe5\xe7U0\xde\x19\xf6\x08\xc0\xf6\x16&\xb1\xf8w\x87'\x97\xc
      ao\x1a{\xcbu\xef[\xb8\xeb3\n\xd3D\xdd\x0b\x10h\xdb\x19\xaf\x80#H\xb8\x03B\x1e@\xba\n{|x\xfa@g\xfbZs\x89\xaf\xbe\xaf\x88\n\x12\xd3\xbbl\x9f9`\x
      8aV\xbc\x82\x10\x8d\xd9\x84\xa5\xbf\xdc\x87\xe3ZtL95'>\xa5*ez\xcc\xeeOT\xa4\xa1,\xcaMo\xba\xcc\x17l\xe6\xa4\x01T\xedr2b\x7f,=\x9cGDX^G\x1bj/\x
      c4y\xca"
    • Unexpected payload=%r
      b"\xd0\x97fgo3i\xeb\x10\xb5\xe9\xf12\xfd\x80*\xc1w\xcf=\x9e\xc5\xe6\x8dD\xed'\xad\xe5\xe7U0\xde\x19\xf6\x08\xc0\xf6\x16&\xb1\xf8w\x87'\x97\xc
      ao\x1a{\xcbu\xef[\xb8\xeb3\n\xd3D\xdd\x0b\x10h\xdb\x19\xaf\x80#H\xb8\x03B\x1e@\xba\n{|x\xfa@g\xfbZs\x89\xaf\xbe\xaf\x88\n\x12\xd3\xbbl\x9f9`\x
      8aV\xbc\x82\x10\x8d\xd9\x84\xa5\xbf\xdc\x87\xe3ZtL95'>\xa5*ez\xcc\xeeOT\xa4\xa1,\xcaMo\xba\xcc\x17l\xe6\xa4\x01T\xedr2b\x7f,=\x9cGDX^G\x1bj/\x
      c4y\xca"

    Scan Complete! Found 1 devices.

    On scanning i am not getting device details like version, device id
    These are beca thermostat sensor it was working fine before, Now it is not showing anything
    Please help

    Network Error: Device Unreachable

    I get device unreachable error when I have two interface connected, eth0 and wlan0 with ip address of 192.168.1.108 and 192.168.1.10 respectively. Any reason causing this happening?

    Smart Energy meter

    Hello,
    I have 2 smart energy meter, the first one has a firmware version 1.0.2 and the second is in 1.1.17.
    The first one is working fine and I can get the current and power with tinytuya.

    The second one return with tinytuya
    import tinytuya

    PLUGID = 'nzexeqam9qulajbf'
    PLUGIP = '192.168.0.94'
    PLUGKEY = 'XXXXXXX'
    PLUGVERS = '3.3'

    d = tinytuya.OutletDevice(PLUGID, PLUGIP, PLUGKEY)
    d.set_version(3.3)
    data = d.status()
    print('set_status() result %r' % data)

    set_status() result {'dps': {'1': 133, '10': 0, '16': True, '18': '111111111111'}}

    Field '1' correspond to the total energy consumption but I can not see the real time power or the current consumption.

    It seems to be linked to a newer firmware. Do you plan a new upgrade to this firmware?

    Python ERROR when trying to run 'wizzard'

    When I type the command: 'python3 -m tinytua wizard' I can enter the: 'api Key, apiSecret, apiRegion, apiDeviceID'. But then running the command an error shows up after like 2sec:

    Traceback (most recent call last):
    File "/usr/lib/python3.8/runpy.py", line 194, in _run_module_as_main
    return _run_code(code, main_globals, None,
    File "/usr/lib/python3.8/runpy.py", line 87, in _run_code
    exec(code, run_globals)
    File "/usr/local/lib/python3.8/dist-packages/tinytuya/main.py", line 48, in
    tinytuya.wizard(color)
    File "/usr/local/lib/python3.8/dist-packages/tinytuya/init.py", line 1548, in wizard
    uid = response_dict['result']['uid']
    KeyError: 'result'

    Tested platforms: mac osx high Sierra 10.13.6 and linux(pop os! 2020)
    Also I have 3 tuya devices(Breaker) and they are connected using the Tuya Smart app.

    Multiple DPS

    Hi,

    I was wondering how to set multiple DPS in one request? F.e. i want to turn on a dimmer and set the dimming value in the same request. The devices support the following format i got from Googling around:

    {multiple: true,data: {'1': true,'2': 50}}

    Any thoughts?

    Thanks!!

    Another JSONDecodeError

    Hi
    I have similar problem with a bulb. tinytuya on RPi Zero. Python 3.7.3
    3 equal bulbs. 2 of them I can read just fine.

    TinyTuya (Tuya device scanner) [1.1.3]
    
    Scanning on UDP ports 6666 and 6667 for devices (15 retries)...
    
    3.1 Device Found [Valid payload]: 192.168.0.115
        ID = 37800275840d8e54d1d2, Product ID = keyneruwsdethu7u, Version = 3.1
        Status: {'1': False, '9': 0, '18': 0, '19': 0, '20': 2344, '21': 1, '22': 748, '23': 32838, '24': 22222, '25': 935}
    3.3 Device Found [Valid payload]: 192.168.0.109
        ID = 8052770184f3ebeec5b1, Product ID = keyj979nf3q3theh, Version = 3.3
        No Stats - Device Key required to poll for status
    3.3 Device Found [Valid payload]: 192.168.0.189
        ID = 01147546600194dd1765, Product ID = keyjcr45yfptp7h7, Version = 3.3
        No Stats - Device Key required to poll for status
    3.3 Device Found [Valid payload]: 192.168.0.161
        ID = 80527701ecfabc47dfac, Product ID = keyj979nf3q3theh, Version = 3.3
        No Stats - Device Key required to poll for status
    3.3 Device Found [Valid payload]: 192.168.0.138
        ID = 8052770184f3ebf633b5, Product ID = keyj979nf3q3theh, Version = 3.3
        No Stats - Device Key required to poll for status
                        
    Scan Complete!  Found 5 devices.
    
    Traceback (most recent call last):
      File "main.py", line 255, in <module>
        get_tuya_data_test('80527701ecfabc47dfac', '192.168.0.161', '6af642384da9f2d1')
      File "/root/tee/tee/data.py", line 262, in get_tuya_data_test
        d.set_version(3.3)
      File "/usr/local/lib/python3.7/dist-packages/tinytuya/__init__.py", line 891, in set_version
        status = self.status()
      File "/usr/local/lib/python3.7/dist-packages/tinytuya/__init__.py", line 589, in status
        result = json.loads(result)
      File "/usr/lib/python3.7/json/__init__.py", line 348, in loads
        return _default_decoder.decode(s)
      File "/usr/lib/python3.7/json/decoder.py", line 337, in decode
        obj, end = self.raw_decode(s, idx=_w(s, 0).end())
      File "/usr/lib/python3.7/json/decoder.py", line 355, in raw_decode
        raise JSONDecodeError("Expecting value", s, err.value) from None
    json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
    
    def get_tuya_data_test(tuya_id, ip_addr, tuya_key):
        
            d = tinytuya.BulbDevice(tuya_id, ip_addr, tuya_key)
            d.set_version(3.3)
            data = d.status()
            print(data)
    

    Originally posted by @burgas1 in #4 (comment)

    Cause of unreachable devices while scanning

    I have about 20 dimmable tuya lights on a 2.4 Ghz network. I am attempting to control these using the localtuya project and Home Assistant, but I wanted to start here as I think I can determine my problem within tinytuya alone.

    A couple observations:

    • All 20 of my lights are controllable using the Tuya app via Tuya cloud as the manufacturer intended
    • Immediately after configuring my lights in the Tuya app, they all appeared successfully when running python3 -m tinytuya scan
    • When I configure and begin communicating with the lights using localtuya and hass.io, most of the lights respond. These lights no longer appear when running python3 -m tinytuya scan
    • A handful of lights never respond via localtuya running on a hass.io machine, and these lights do respond when running python3 -m tinytuya scan

    So there seems to be something mutually exclusive where lights controlled by localtuya can't be reached by tinytuya, and lights that can be reached by tintuya cannot be controlled by localtuya. All devices can be controlled from tuya cloud.

    Note that I am putting all my devices on a common 2.4ghz network that I am connected to from my macbook, etc. when running scans. I can see all the devices assigned to respective static IPs on the network.

    Any ideas?

    This happened while trying to scan my network from Raspbian on a Pi 4

    Scanning local network for Tuya devices...
    Traceback (most recent call last):
    File "/usr/lib/python3.7/runpy.py", line 193, in _run_module_as_main
    "main", mod_spec)
    File "/usr/lib/python3.7/runpy.py", line 85, in _run_code
    exec(code, run_globals)
    File "/home/shane/.local/lib/python3.7/site-packages/tinytuya/main.py", line 48, in
    tinytuya.wizard(color)
    File "/home/shane/.local/lib/python3.7/site-packages/tinytuya/init.py", line 1479, in wizard
    devices = deviceScan(False, 20)
    File "/home/shane/.local/lib/python3.7/site-packages/tinytuya/init.py", line 1139, in deviceScan
    client.bind(("", UDPPORT))
    OSError: [Errno 98] Address already in use

    colourtemp_percentage works the same way as white_percentage

    The command set_colourtemp_percentage works the exact same way as set_white_percentage.
    It seems to revert to the white color instead of adjusting the temp of the current color.
    Is this intended?

    I noticed this while i did some testing with my program "tuyactl" that is based on your library

    Do you have an example with set_colour(r,g,b) ?

    THanks for a very useful package !

    I'm able to turn on/off on my Tuya enabled lights and able to set their brightness, but I'm not able to get the set_colour(r,g,b) to work properly. set_colour(r,g,b) seems to hang no matter what values I put in for r,g,b. I can't find an example of being usedโ€ฆ So perhaps I'm doing it wrong. It looks OK from the source codeโ€ฆ Any suggestions?

    John Cohn
    [email protected]

    thanks again !

    here's my code

    import tinytuya
    import random
    
    candles = {}
    candles[0] = tinytuya.BulbDevice('868515018caab5ef1554', '192.168.1.26', '03ca98398a11c78a')
    candles[1] = tinytuya.BulbDevice('86851501e09806ac519d', '192.168.1.27', '970cdd010944cf8b')
    candles[2] = tinytuya.BulbDevice('868515018caab5e57b07', '192.168.1.28', '5aa724e67b0b4bd9')
    candles[3] = tinytuya.BulbDevice('868515018caab5ef1d2b', '192.168.1.29', '129668119d3e840c')
    candles[4] = tinytuya.BulbDevice('868515018caab5e48e96', '192.168.1.30', '431b646c91ffca5c')
    candles[5] = tinytuya.BulbDevice('868515018caab5ef529e', '192.168.1.31', 'daf67a675bf9287d')
    candles[6] = tinytuya.BulbDevice('eb14adb45f8dfeb872fk5x', '192.168.1.25', '2f239ce262516e4b')
    candles[7] = tinytuya.BulbDevice('ebe1eb6797591db8eslal', '192.168.1.24', 'eefb1deb6155f9f6')
    candles[8] = tinytuya.BulbDevice('eb044207ff02162f1f248g', '192.168.1.4', '44b9d8edcf92ca3e')
    for i in range (9):
        candles[i].set_version(3.3)
    
    for i in range (9):
        candles[i].set_value('20',True) # turn on each light                                                                                                                             
        z = random.randint(10, 1000) # choose a random brightness                                                                                                                        
        candles[i].set_value('22',z) # set brighntess (this works)                                                                                                                       
    ## if uncommented, the next line hangss                                                                                                                                              
    #    candles[i].set_colour(100,100,100) # attempt to set a colour .. (this does NOT work.. iit hangs  forever))                                                                      
        data = candles[i].status()  # NOTE this does NOT require a valid key vor version 3.1                                                                                             
        print(data)
    
    
    
    
    

    Energy Monitor, Measurement Refresh

    Hi,

    Looping through, getting energy monitor readings from a switch (outlet). => it can take a minute (or more) for the reading to update ... but if I "trigger" it from SmartLife, it updates immediately. Does some sort of refresh / trigger need to be sent, to get the reading to update (or is it cached somehow?)?

    Thanks!

    New To Python, Tuya & TinyTuya, tips to start & operate Garage Door control

    I hate to ask as a real newbie to this but not sure where to start. I can program VBA so not a complete idiot.
    Have Garage door set up fine on Tuya, works fine, Alexa etc.
    Would like a script to operate from PC. Windows 10.
    Have installed Python, py V 3.93, has the built in PIP installer.
    TinyTuya seemed to installed OK
    python -m tinytuya - runs OK but says 0 devices found
    I have no idea what to do with sudo apt-get install python-crypto python-pip # for RPi, Linux
    from py command prompt, above gives syntax error, with or without the # bit
    Could you just point me in the right direction.
    Many thanks I/A

    status() Shutting Off Power on v3.1 Device

    OK, I thought I was crazy before (in fairness, I likely was ๐Ÿ˜†), but now seeing it a second time. Let me explain ...

    1. Had an earlier Tuya switch, it was v3.1 - and it seemed like when I did a status() query, it was (sometimes?) shutting the switch off. Wasn't 100% sure, but got Tuya to push a firmware upgrade ... it went to v3.3, and the issue went away. Case closed ... I thought, but then ...
    2. Bought another switch, it's on v3.1 - and Tuya says there is no firmware update for this one. It does the same ... shuts off (often / always - to be confirmed yet) when I run a status() command.

    So, time to figure out why? Is there a defined format for messages in and out? I can try to capture the traffic, and we can decipher then (i.e. tcpdump and/or Wireshark).

    Thanks!

    Strange data on dp 18 for wattmeter

    Hello, I'm completely new in smart home devices but i'm running very fast and set multiple devices that runs ok.
    Maybe i've lost something during this fast way but i cannot read data from my new wattmeter . I can read from other plugs but i would like to use a din mount device.
    this is what comes out from the status:
    {'dps': {'1': 1277, '10': 0, '16': True, '18': '111111111111'}}
    1277 is the total power consumption (12.77Kwh)
    16: true is the switch on or off
    the main info that i needed was the current, active power, and voltage (that are readable on smartlife app) but does not appear here. there is only that 18: 1111111111
    Have you got any suggestion.
    the device is https://www.amazon.it/gp/product/B07TJS27D6/ref=ppx_yo_dt_b_asin_title_o02_s00?ie=UTF8&psc=1
    All the other i can see on italian amazon seem to be the same product with different label.... have you got any way to make it work or a suggestion on an alternative device working with tinytuya?
    Thank you

    Exception when status() receives 28byte payload

    I got a local key via the wizard, construct an OutletDevice, and invoke status(). Sometimes it works but often it crashes with an exception (below).

    I believe there's a bug in the following line. The device is sending me a 28 byte response. This line should test "len(data) <= 28" to catch the 28-byte case, and try again. But it's not catching the 28 byte response, and so isn't retrying. Once I changed this line in the tinytuya library to be "<= 28" rather than "< 28", then my invocations of status() all started working reliably.

                    # Some devices fail to send full payload in first response
                    # Note - some devices respond with len = 28 for error response
                    if self.retry and len(data) < 28:  
                        time.sleep(0.1)
                        data = self.socket.recv(1024)  # try again
    

    Here is the debug trace from when I invoked status(). (the line numbers are marginally off because I deleted a few python2-compatible lines from my copy of tinytuya.py so it would pass clean in MyPy).

    DEBUG:tinytuya:status() entry (dev_type is default)
    DEBUG:tinytuya:json_payload=b'{"gwId":"10871285d8bfc016260e","devId":"10871285d8bfc016260e","uid":"10871285d8bfc016260e","t":"1610307603"}'
    DEBUG:tinytuya:status received data=b'\x00\x00U\xaa\x00\x00\x00\x00\x00\x00\x00\x07\x00\x00\x00\x0c\x00\x00\x00\x00x\x93p\x91\x00\x00\xaaU'
    DEBUG:tinytuya:result=b''
    [2021-01-10 11:40:03.156686] Table lamps: exception - TypeError('ord() expected a character, but string of length 0 found')
    Traceback (most recent call last):
      File "./lights.py", line 92, in set_dimmer_loop
        status = device.status()
      File "/Users/ljw/code/bell/tinytuya.py", line 484, in status
        result = cipher.decrypt(result, False)
      File "/Users/ljw/code/bell/tinytuya.py", line 162, in decrypt
        return self._unpad(raw).decode('utf-8')
      File "/Users/ljw/code/bell/tinytuya.py", line 177, in _unpad
        return s[:-ord(s[len(s)-1:])]
    TypeError: ord() expected a character, but string of length 0 found
    

    TreatLife Product

    Hello Jason!
    I am working on TreatLife switches and LED lights and have some details, along with some code I have been fiddling with for a couple of weeks to familiarize my just over a year old Python with your Module.

    Now in your examples you have bulb.py and this is using ""class BulbDevice(Device):"" I see you have two types A and B for different DPS.
    Now both the switch and lights work on the ""class OutletDevice(Device):"" for TreatLife and I can cycle both using the modified send_raw_dps_''_.py below.
    ##bulb.py does print its tasks with no actions when I pounded out line 34 else: and 35 d.set_version(3.1) to get it to run as BulbDevice. Now when I use OutletDevice it fails when calling d.set_white() with an attributeError as this type probably needs to be added as type C?

    Next is my snapshot.json and the switches have a "devId" and the name for my one and only switch that is "name": "Office Outside Lights". This should make it easier to get them separated as I am writing separate control polyglot Node Servers one for lighting and the other switches/dimmers.
    The lights do not have "devId" in their json listing between the "dps".

    Now I am trying to build a modified wizard to bring in the DEVICEID, IP, KEY and the snapshot.py is a fantastic start I see you just added!
    So I will create the json, parse the data for the control of each switch and of course the token with requests.

    Have one running as a Universal Devices Node Server and it is cycling a switch with manual inputs for its DEVICE key id & ip upon a token refresh every 20 minutes, but it is not working at all for actual control, lol.

    I hope you do not mind my long winded message and hope to ask you some more questions along my weary path. I am 60 so it is kind of old dog with new tricks to keep my brain young. Sometime I get stuck on the simplest fundamentals mostly string formatting, lol! So for me to Len or separate out all of the switches from a json, then grab the data for DEVICE, then create another class to push that to for control, takes some brain twisting!
    What's that advertisement for jellyfish brain enhancers, Previgen? lol!

    Highest Regards and Thank You for Your TIME!

    Code Examples,

    send_raw_dps_light_treatlife.py
    Light Bulb

    import tinytuya
    import time
    import os
    import random
    
    DEVICEID = "BLAAAA"  
    DEVICEIP = "BLAAAA" 
    DEVICEKEY = "BLAAAA"   
    DEVICEVERS = "us" ##This works? instead of 3.3 which they all are
    
    # Check for environmental variables and always use those if available
    DEVICEID = os.getenv("DEVICEID", DEVICEID)
    DEVICEIP = os.getenv("DEVICEIP", DEVICEIP)
    DEVICEKEY = os.getenv("DEVICEKEY", DEVICEKEY)
    DEVICEVERS = os.getenv("DEVICEVERS", DEVICEVERS)
    
    print("TinyTuya - Smart Bulb RGB Test [%s]\n" % tinytuya.__version__)
    print('TESTING: Device %s at %s with key %s version %s' %
          (DEVICEID, DEVICEIP, DEVICEKEY, DEVICEVERS))
    
    
    # Connect to the device - replace with real values
    d=tinytuya.OutletDevice(DEVICEID, DEVICEIP, DEVICEKEY)
    d.set_version(3.3)
    # Show status of device
    data = d.status()
    
    
    # Generate the payload to send - add all the DPS values you want to change here
    payload1=d.generate_payload(tinytuya.CONTROL, {'20': False, '22': 100, '23': 10,})
    #time.sleep(1)
    print('\nCurrent Status of Bulb: %r' % data)
    time.sleep(2)
    payload2=d.generate_payload(tinytuya.CONTROL, {'20': True, '22': 100, '23': 10,})
    #time.sleep(1)
    print('\nCurrent Status of Bulb: %r' % data)
    #time.sleep(2)
    payload3=d.generate_payload(tinytuya.CONTROL, {'20': True, '22': 1000, '23': 236,})
    #time.sleep(1)
    print('\nCurrent Status of Bulb: %r' % data)
    # Send the payload to the device
    
    d._send_receive(payload1)
    time.sleep(2)
    d._send_receive(payload2)
    time.sleep(2)
    d._send_receive(payload3)
    #print('\nCurrent Status of Bulb: %r' % data)`
    

    send_raw_dps_switch_treatlife.py
    Switch

    import tinytuya
    import time
    import os
    import random
    
    DEVICEID = "BLAAAA"
    DEVICEIP = "192.168.1.137"
    DEVICEKEY = "BLAAAA"
    DEVICEVERS = "us" ##This works? instead of 3.3 which they all are
    
    # Check for environmental variables and always use those if available
    DEVICEID = os.getenv("DEVICEID", DEVICEID)
    DEVICEIP = os.getenv("DEVICEIP", DEVICEIP)
    DEVICEKEY = os.getenv("DEVICEKEY", DEVICEKEY)
    DEVICEVERS = os.getenv("DEVICEVERS", DEVICEVERS)
    
    print("TinyTuya - Smart Bulb RGB Test [%s]\n" % tinytuya.__version__)
    print('TESTING: Device %s at %s with key %s version %s' %
          (DEVICEID, DEVICEIP, DEVICEKEY, DEVICEVERS))
    
    
    # Connect to the device - replace with real values
    d=tinytuya.OutletDevice(DEVICEID, DEVICEIP, DEVICEKEY)
    d.set_version(3.3)
    
    # Generate the payload to send - add all the DPS values you want to change here
    #if data != [0]
    #payload=d.generate_payload(tinytuya.CONTROL, {'1': False, '2': 50})
    #time.sleep(2)
    #payload=d.generate_payload(tinytuya.CONTROL, {'1': True, '2': 50})
    #time.sleep(2)
    
    payload1=d.generate_payload(tinytuya.CONTROL, {'1': False, '2': 50})
    payload2=d.generate_payload(tinytuya.CONTROL, {'1': True, '2': 50})
    
    # Send the payload to the device
    
    d._send_receive(payload1)
    time.sleep(2)
    d._send_receive(payload2)
    
    # Get the status of the device
    #response = requests.request("GET", url, headers=headers, data=payload)
    
    #print(str(d._send_receive(payload)))
    
    #Command for 
    # Show status of device
    data = d.status()
    print('\nCurrent Status of Bulb: %r' % data)
    
    

    Here is my snapshot.json

    {
        "timestamp": 1613548219.2819111,
        "devices": [
            {
                "name": "Under Cabinets",
                "ip": "192.168.1.158",
                "ver": "3.3",
                "id": "BLAAAAAAAAAAAAA",
                "key": "BLAAAAAAAAAAA",
                "dps": {
                    "dps": {
                        "20": false,
                        "21": "scene",
                        "24": "007d007903e8",
                        "25": "05464601000003e803e800000000464601007803e803e80000000046460100f003e803e800000000464601003d03e803e80000000046460100ae03e803e800000000464601011303e803e800000000",
                        "26": 0
                    }
                }
            },
            {
                "name": "Office Outside Lights",
                "ip": "192.168.1.137",
                "ver": "3.3",
                "id": "BLAAAAAAAAAA",
                "key": "BLAAAAAAAA",
                "dps": {
                    "devId": "BLAAAAAAAAAA",
                    "dps": {
                        "1": true,
                        "9": 0
                    }
                }
            },
            {
                "name": "Garage",
                "ip": "192.168.1.138",
                "ver": "3.3",
                "id": "BLAAAAAAAAAA",
                "key": "BLAAAAAAAAAA",
                "dps": {
                    "dps": {
                        "20": true,
                        "21": "colour",
                        "22": 1000,
                        "23": 767,
                        "24": "00ac02c501f0",
                        "25": "000e0d0000000000000000c803e8",
                        "26": 0
                    }
                }
            },
            {
                "name": "Office Light",
                "ip": "192.168.1.139",
                "ver": "3.3",
                "id": "BLAAAAAAAAAA",
                "key": "BLAAAAAAAAAA",
                "dps": {
                    "dps": {
                        "20": true,
                        "21": "white",
                        "22": 1000,
                        "23": 236,
                        "24": "00d60000026c",
                        "25": "000e0d0000000000000000c803e8",
                        "26": 0
                    }
                }
            }
        ]
    }
    

    Lastly Postman Function list for the lights.

    {
        "result": {
            "category": "dj",
            "functions": [
                {
                    "code": "switch_led",
                    "desc": "switch led",
                    "name": "switch led",
                    "type": "Boolean",
                    "values": "{}"
                },
                {
                    "code": "work_mode",
                    "desc": "work mode",
                    "name": "work mode",
                    "type": "Enum",
                    "values": "{\"range\":[\"white\",\"colour\",\"scene\",\"music\",\"scene_1\",\"scene_2\",\"scene_3\",\"scene_4\"]}"
                },
                {
                    "code": "bright_value_v2",
                    "desc": "bright value v2",
                    "name": "bright value v2",
                    "type": "Integer",
                    "values": "{\"min\":10,\"scale\":0,\"unit\":\"\",\"max\":1000,\"step\":1}"
                },
                {
                    "code": "temp_value_v2",
                    "desc": "temp value v2",
                    "name": "temp value v2",
                    "type": "Integer",
                    "values": "{\"min\":0,\"scale\":0,\"unit\":\"\",\"max\":1000,\"step\":1}"
                },
                {
                    "code": "colour_data_v2",
                    "desc": "colour data v2",
                    "name": "colour data v2",
                    "type": "Json",
                    "values": "{}"
                },
                {
                    "code": "scene_data_v2",
                    "desc": "scene data v2",
                    "name": "scene data v2",
                    "type": "Json",
                    "values": "{}"
                },
                {
                    "code": "music_data",
                    "desc": "music data",
                    "name": "music data",
                    "type": "Json",
                    "values": "{}"
                },
                {
                    "code": "control_data",
                    "desc": "control data",
                    "name": "control data",
                    "type": "Json",
                    "values": "{}"
                },
                {
                    "code": "countdown_1",
                    "desc": "countdown 1",
                    "name": "countdown 1",
                    "type": "Integer",
                    "values": "{\"unit\":\"\",\"min\":0,\"max\":86400,\"scale\":0,\"step\":1}"
                },
                {
                    "code": "bright_value",
                    "desc": "bright value",
                    "name": "bright value",
                    "type": "Integer",
                    "values": "{\"min\":25,\"scale\":0,\"unit\":\"\",\"max\":255,\"step\":1}"
                },
                {
                    "code": "temp_value",
                    "desc": "temp value",
                    "name": "temp value",
                    "type": "Integer",
                    "values": "{\"min\":0,\"scale\":0,\"unit\":\"\",\"max\":255,\"step\":1}"
                },
                {
                    "code": "flash_scene_1",
                    "desc": "flash scene 1",
                    "name": "flash scene 1",
                    "type": "Json",
                    "values": "{\"h\":{\"min\":1,\"scale\":0,\"unit\":\"\",\"max\":360,\"step\":1},\"s\":{\"min\":1,\"scale\":0,\"unit\":\"\",\"max\":255,\"step\":1},\"v\":{\"min\":1,\"scale\":0,\"unit\":\"\",\"max\":255,\"step\":1}}"
                },
                {
                    "code": "flash_scene_2",
                    "desc": "flash scene 2",
                    "name": "flash scene 2",
                    "type": "Json",
                    "values": "{\"h\":{\"min\":1,\"scale\":0,\"unit\":\"\",\"max\":360,\"step\":1},\"s\":{\"min\":1,\"scale\":0,\"unit\":\"\",\"max\":255,\"step\":1},\"v\":{\"min\":1,\"scale\":0,\"unit\":\"\",\"max\":255,\"step\":1}}"
                },
                {
                    "code": "flash_scene_3",
                    "desc": "flash scene 3",
                    "name": "flash scene 3",
                    "type": "Json",
                    "values": "{\"h\":{\"min\":1,\"scale\":0,\"unit\":\"\",\"max\":360,\"step\":1},\"s\":{\"min\":1,\"scale\":0,\"unit\":\"\",\"max\":255,\"step\":1},\"v\":{\"min\":1,\"scale\":0,\"unit\":\"\",\"max\":255,\"step\":1}}"
                },
                {
                    "code": "flash_scene_4",
                    "desc": "flash scene 4",
                    "name": "flash scene 4",
                    "type": "Json",
                    "values": "{\"h\":{\"min\":1,\"scale\":0,\"unit\":\"\",\"max\":360,\"step\":1},\"s\":{\"min\":1,\"scale\":0,\"unit\":\"\",\"max\":255,\"step\":1},\"v\":{\"min\":1,\"scale\":0,\"unit\":\"\",\"max\":255,\"step\":1}}"
                },
                {
                    "code": "scene_select",
                    "desc": "scene select",
                    "name": "scene select",
                    "type": "Enum",
                    "values": "{\"range\":[\"1\",\"2\",\"3\",\"4\",\"5\"]}"
                },
                {
                    "code": "read_time",
                    "desc": "read time",
                    "name": "read time",
                    "type": "Integer",
                    "values": "{\"unit\":\"minute\",\"min\":1,\"max\":60,\"scale\":0,\"step\":1}"
                },
                {
                    "code": "rest_time",
                    "desc": "rest time",
                    "name": "rest time",
                    "type": "Integer",
                    "values": "{\"unit\":\"minute\",\"min\":1,\"max\":60,\"scale\":0,\"step\":1}"
                },
                {
                    "code": "switch_health_read",
                    "desc": "switch health read",
                    "name": "switch health read",
                    "type": "Boolean",
                    "values": "{}"
                },
                {
                    "code": "colour_data",
                    "desc": "colour data",
                    "name": "colour data",
                    "type": "Json",
                    "values": "{}"
                },
                {
                    "code": "scene_data",
                    "desc": "scene data",
                    "name": "scene data",
                    "type": "Json",
                    "values": "{}"
                },
                {
                    "code": "rhythm_mode",
                    "desc": "rhythm mode",
                    "name": "rhythm mode",
                    "type": "Raw",
                    "values": "{\"maxlen\":255}"
                },
                {
                    "code": "wakeup_mode",
                    "desc": "wakeup mode",
                    "name": "wakeup mode",
                    "type": "Raw",
                    "values": "{\"maxlen\":255}"
                },
                {
                    "code": "power_memory",
                    "desc": "power memory",
                    "name": "power memory",
                    "type": "Raw",
                    "values": "{\"maxlen\":255}"
                },
                {
                    "code": "debug_data",
                    "desc": "debug data",
                    "name": "debug data",
                    "type": "String",
                    "values": "{\"maxlen\":255}"
                },
                {
                    "code": "sleep_mode",
                    "desc": "sleep mode",
                    "name": "sleep mode",
                    "type": "Raw",
                    "values": "{\"maxlen\":255}"
                }
            ]
        },
        "success": true,
        "t": 1613549900843
    }
    

    No data after Wizard

    Hello all,
    I get this error after wizard. I'm on Debian 10 in VM. Can you help me please ?

    root@debian:/home/franck# python3 -m tinytuya wizard TinyTuya Setup Wizard [1.2.1]

    Existing settings:
    API Key=xxx
    Secret=xxx
    DeviceID=xxx
    Region=eu

    Use existing credentials (Y/n): Y
    Traceback (most recent call last):
    File "/usr/lib/python3.7/runpy.py", line 193, in _run_module_as_main
    "main", mod_spec)
    File "/usr/lib/python3.7/runpy.py", line 85, in _run_code
    exec(code, run_globals)
    File "/usr/local/lib/python3.7/dist-packages/tinytuya/main.py", line 48, in
    tinytuya.wizard(color)
    File "/usr/local/lib/python3.7/dist-packages/tinytuya/init.py", line 1789, in wizard
    uid = response_dict['result']['uid']
    KeyError: 'result'
    root@debian:/home/franck#

    Missing New Authorization instruction for the project in Setup Wizard step

    Hello,

    I was getting KeyError: 'result' errors when running the wizard after following the instruction to subscribe in API Products:

    IMPORTANT Under "Cloud" -> select your project -> "API Management" -> "API Products" that the following API groups have status "Subscribed": Smart Home Devices Management, Authorization and Smart Home Family Management (see screenshot here)

    After authorizing each API Product above to my project as described in https://github.com/codetheweb/tuyapi/blob/master/docs/SETUP.md#linking-a-tuya-device-with-smart-link like below

    Click into the Product and click Subscribe
    Select the free tier and Buy Now
    Click back to the API Products page and select the API again
    Click to the Projects tab
    Click **New Authorization
    Select your Project from the dropdown and click OK
    

    I am able to complete the wizard successfully (note: I did not have to subscribe to Smart Home Data Service
    Smart Home Scene Linkage as mentioned in the tuyapi documentation).

    Unable to pull dps

    Hi, I'm new to IoT programming so please forgive me for stupid mistakes.
    I've bought a no-brand smart bulb (this) and I'm trying to use it with this library but I get the error " Unexpected error for 192.168.1.193: Unable to poll " whenever I use the tinytuya scanner and even the example script provided crash as soon as it neet to set the version with error: " if 'dps' in status:
    TypeError: argument of type 'NoneType' is not iterable ".
    does anyone have an idea on how to fix this?
    Thanks!

    Different / Varied Failure Cases

    Hi,

    Really liking tinytuya - appreciate it! But I admit, seeing some odd results here. I think that's my specialty though ... ๐Ÿคฃ.

    I am polling my devices on a regular basis, using them for power monitoring (of some switches providing energy monitoring capability). But ... relatively often (i.e. 10+ times a day), they cause my code to "yell", for a few different reasons. So attaching my code below, as well as some of the error messages. And a few thoughts,

    1. I was going to add code to check for the recently added Error status ... but nothing is there in the case of passing results? Thinking there should always be a return status? Just to avoid try ... catch loops (they just seem nasty, LOL!)
    2. I seem to be seeing different outcomes and failures, some of them not caught (reported) by the Error status. Or am I missing it?

    My code, called inside the loop, with except to let me know what kinds of failure I am seeing,

            try:
                device = tinytuya.OutletDevice(currdevice['id'], currdevice['hostname'], currdevice['key'])
                device.set_version(currdevice['ver'])
                device.set_socketPersistent(True)
                device.updatedps()
                currData = device.status()
                if currdevice['ver'] == 3.1:
                    time.sleep(0.5)
                dps = currData["dps"]
                # Check for power data - DP 19 on some 3.1/3.3 devices
                W = A = V = 0
                if "19" in dps.keys():
                    W = float(dps['19']) / 10.0
                    A = float(dps['18']) / 1000.0
                    V = float(dps['20']) / 10.0
                # Check for power data - DP 5 for some 3.1 devices
                elif "5" in dps.keys():
                    W = float(dps["5"]) / 10.0
                    A = float(dps["4"]) / 1000.0
                    V = float(dps["6"]) / 10.0
                # Return power measurement results
                return {'Current': A, 'Power': W, 'Voltage': V}
            except OSError:
                print("[OSError] Error reading Tuya power meter, ", currdevice['hostname'])
                return None
            except ValueError:
                print("[ValueError] Error reading Tuya power meter, ", currdevice['hostname'])
                return None
            except KeyError:
                print("[KeyError] Error reading Tuya power meter, ", currdevice['hostname'])
                print("[KeyError] Data, ", currData)
                return None
            except TypeError:
                print("[TypeError] Error reading Tuya power meter, ", currdevice['hostname'])
                print("[TypeError] Data, ", currData)
                return None
    

    And, some of the exceptions (some normal / caught, others not,

    [KeyError] Error reading Tuya power meter,  emFrontSwitch [KeyError] Data,  {'Error': 'Network Error: Unable to Connect', 'Err': '901', 'Payload': None}
    [TypeError] Error reading Tuya power meter,  emRussell [TypeError] Data,  None
    [KeyError] Error reading Tuya power meter,  emWinServer [KeyError] Data,  {'dps': {'18': 530, '19': 642}, 't': 1617010003}
    [KeyError] Error reading Tuya power meter,  emRussell [KeyError] Data,  {'Error': 'Network Error: Device Unreachable', 'Err': '905', 'Payload': None}
    

    And this one, when using the data (somehow wrong data type?),

    influxdb.exceptions.InfluxDBClientError: 400: {"error":"partial write: field type conflict: input field \"value\" on measurement \"Current\" is type integer, already exists as type float dropped=3"}
    

    Thanks!

    Event listener

    Hi all,

    I was Tuya dimming units that can also can be switched by a physical switch. I would like to receive an update through the socket connected to the device to know when that happens, so i can sync my Dashboard (Openhab). Anyone any success in getting this to
    work?
    I think i could add a listener to the socket on the device object directly, but it seems like a hack to me: what happens when the the socket closes and a new one is made? I assume the socket listener is gone then as well. Also, i may read data which is the response to a command instead of a physical switch...

    Any thoughts?

    thanks! Michiel

    Scan failed when color=False

    TinyTuya (Tuya device scanner) [1.2.7]

    Scanning on UDP ports 6666 and 6667 for devices (10 retries)...

    Traceback (most recent call last):
    File "run.py", line 45, in
    tinytuya.scan(max_retries, color)
    File "d:\Downloads\TinyTuya\libs\tinytuya_init_.py", line 1629, in scan
    d = deviceScan(True, maxretry, color)
    File "d:\Downloads\TinyTuya\libs\tinytuya_init_.py", line 1792, in deviceScan
    normal, version, dim, productKey, note, subbold, ip, cyan, gwId, red, dkey, yellow, version))
    UnboundLocalError: local variable 'cyan' referenced before assignment

    Nedis Zigbee Gateway can't connect using tinytuya

    Hello, I'm working on a project where I would like to read temperature/humidity from a sensor connected through a Nedis Zigbee Gateway. I am not able to connect the gateway. I this possible with tinytuya?

    I would be very thankful if someone could take a look or at least tell me if it's supported.

    Simply running it on my PC using Python 3.8.5

    python -m tinytuya

    TinyTuya (Tuya device scanner) [1.1.4]
    
    Scanning on UDP ports 6666 and 6667 for devices (15 retries)...
    
    3.3 Device Found [Valid payload]: 192.168.8.XXX
        ID = XXXXXX, Product ID = XXXXX, Version = 3.3
        No Stats - Device Key required to poll for status
    
    Scan Complete!  Found 1 devices.
    

    Here is a snapshot created by the wizard

    Poll local devices? (Y/n): Y
    
    Scanning local network for Tuya devices...
        1 local devices discovered
    
    Polling local devices...
        [Temperature and humidity sensor] - 0 - Error: No IP found
        [Zigbee Smart Gateway] - 192.168.8.XXX - No Response
    
    >> Saving device snapshot data to snapshot.json
    
    Done.
    
    {
        "timestamp": 1612792884.4107103,
        "devices": [
            {
                "name": "Temperature and humidity sensor",
                "ip": 0,
                "ver": 0,
                "id": "XXXX",
                "key": "XXXX"
            },
            {
                "name": "Zigbee Smart Gateway",
                "ip": "192.168.8.XXX",
                "ver": "3.3",
                "id": "XXXX",
                "key": "XXXX"
            }
        ]
    }

    Checking the SmartLife app I was able to find another IP-adress for the Gateway (5.240.XXX.XX) which I am able to ping at least.
    Pinging 192.168.8.XXX does not work.

    Tested the following code on the two different IP-addresses

    import tinytuya
    
    if __name__ == "__main__":
        d = tinytuya.OutletDevice('DEVICE_ID', 'IP_ADRESS', 'DEVICE_SECRET')
        d.set_version(3.3)
        data = d.status()  
        print(data)

    192.168.8.XXX

    Traceback (most recent call last):
      File ".\main.py", line 6, in <module>
        data = d.status()
      File "C:\Users\Krille\git\temper\venv\lib\site-packages\tinytuya\__init__.py", line 580, in status
        data = self._send_receive(payload)
      File "C:\Users\Krille\git\temper\venv\lib\site-packages\tinytuya\__init__.py", line 364, in _send_receive
        self._get_socket(False)
      File "C:\Users\Krille\git\temper\venv\lib\site-packages\tinytuya\__init__.py", line 350, in _get_socket
        self.socket.connect((self.address, self.port))
    socket.timeout: timed out
    (venv) PS C:\Users\Krille\git\temper> 
    

    5.240.XXX.XX

    Traceback (most recent call last):
      File ".\main.py", line 6, in <module>
        data = d.status()
      File "C:\Users\Krille\git\temper\venv\lib\site-packages\tinytuya\__init__.py", line 613, in status
        result = json.loads(result)
      File "c:\users\krille\appdata\local\programs\python\python38-32\lib\json\__init__.py", line 357, in loads
        return _default_decoder.decode(s)
      File "c:\users\krille\appdata\local\programs\python\python38-32\lib\json\decoder.py", line 337, in decode
        obj, end = self.raw_decode(s, idx=_w(s, 0).end())
      File "c:\users\krille\appdata\local\programs\python\python38-32\lib\json\decoder.py", line 355, in raw_decode
        raise JSONDecodeError("Expecting value", s, err.value) from None
    json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
    

    Tried the following as well:

    import tinytuya
    
    if __name__ == "__main__":
        d = tinytuya.OutletDevice('DEVICE_ID', 'IP_ADRESS', 'DEVICE_SECRET', 'device22')
        d.set_version(3.3)
        d.set_dpsUsed({"1": None})
        data = d.status()  
        print(data)
    Traceback (most recent call last):
      File ".\main.py", line 7, in <module>
        data = d.status()
      File "C:\Users\Krille\git\temper\venv\lib\site-packages\tinytuya\__init__.py", line 580, in status
        data = self._send_receive(payload)
      File "C:\Users\Krille\git\temper\venv\lib\site-packages\tinytuya\__init__.py", line 374, in _send_receive
        data = self.socket.recv(1024)  # try again
    socket.timeout: timed out
    ```
    

    JSONDecodeError

    Good evening Mr. Cox,

    I came across this issue when testing devices on v3.3:
    image

    I am testing on a Windows10 x64-19041; Python 3.8; PyCharm.

    Any insight would be greatly appreciated.
    I am new to the developing scene. Please, pardon my ignorance.

    d.status() not working

    The outlet is correctly turning on and off, but d.status() is raising a JSONDecodeError

    Traceback (most recent call last): File "C:/Users/theco/Desktop/AA.py", line 11, in <module> data= d.status() File "C:\Users\theco\AppData\Local\Programs\Python\Python39\lib\site-packages\tinytuya\__init__.py", line 502, in status result = json.loads(result) File "C:\Users\theco\AppData\Local\Programs\Python\Python39\lib\json\__init__.py", line 346, in loads return _default_decoder.decode(s) File "C:\Users\theco\AppData\Local\Programs\Python\Python39\lib\json\decoder.py", line 337, in decode obj, end = self.raw_decode(s, idx=_w(s, 0).end()) File "C:\Users\theco\AppData\Local\Programs\Python\Python39\lib\json\decoder.py", line 355, in raw_decode raise JSONDecodeError("Expecting value", s, err.value) from None json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

    Any help on this?

    Registering a Cloud Project on iot.tuya.com is not free anymore

    Hi, I was following the instructions to Get the Tuya Device LOCAL_KEY found on https://pypi.org/project/tinytuya/, but it seems that it is not longer supported as a free service.
    From the developer framework https://iot.tuya.com/cloud/, if I click on Cloud => Projects => Try It Free, I get the message that I need a personal authentication or enterprise authentication. It is not clear what is a personal authentication, whereas an enterprise authentication seems reserverd to big companies. And after all, the Free Trial is just for three months.
    I asked for support in chat, the answer was that API usage is not for device users, but only for companies.
    Does it means that the use of TinyTuya is precluded to single developers?

    Fast color changing

    Hi, I came across a certain problem.

    I am trying to make my BulbDevice change color every 0.2 second. The desired effect is blinking light.
    Unfortunately, while program is running, bulb starts blinking in a desired way, but after a few blinkings it starts pulsating and then stars blinking again. I change color from (255, 0, 255) to (0, 0, 0) and by "pulsating" I mean that bulb only darkens a little and comes back to (255, 0, 255). I am wondering now, if it results from bulb limitations or it is something wrong with my code.

    My code:

    import tinytuya
    import time
    import random
    
    d = tinytuya.BulbDevice('x', 'x', 'x, 'device22')
    d.set_dpsUsed({"1": None})
    d.set_version(3.3) 
    d.set_socketPersistent(True)
    d.set_socketNODELAY(False)
    
    for i in range(100):
        d.set_colour(255, 0, 255)
        time.sleep(0.2)
        d.set_colour(0, 0, 0)
        time.sleep(0.2)
    

    Sombody Help me with my code

    I have managed to make two simple scripts to turn a light on and off.
    I would like to know, how i can make the script a bit more interactive & check status of power before flipping it to the other state. I cannot seem to make it show power status bol of 1 or 0 but using the smart life app it displays the status just fine so my bulbs are capable of providing that data.

    So to clarify I have got two 432mhz switches that my rpi is listening to. i would like to assign them to the power flip flop i was asking about.

    At the moment it works using a bash script. It monitors the exec binary that prints a "signal received" msg. and that in turn triggers my two independent simple py scripts

    So how do i add it all into one python script that can also control a group of lights.

    I hope this is possible to someone with greater knowledge than me.
    Thank you in advance if you decide to help.

    Wrong path in setup.py

    1.0.0 points to the wrong location of README.md.

    + /usr/bin/python3 setup.py build '--executable=/usr/bin/python3 -s'
    Traceback (most recent call last):
      File "setup.py", line 5, in <module>
        with open("tinytuya/README.md", "r") as fh:
    FileNotFoundError: [Errno 2] No such file or directory: 'tinytuya/README.md'

    This was fixed with 24fcf56

    Set Scene Not Doing Anything

    I have been trying to get my bulb to use one of the scenes but nothing appears to happen on my bulb when I run the code. Are my bulbs just not compatible?

    import tinytuya
    
    d = tinytuya.BulbDevice('XXXX', 'XXXX', 'XXXX')
    d.set_version(3.3)
    data = d.status()
    
    d.set_mode('scene')
    d.set_scene(3)
    

    Error when using 'wizzard'

    After typing the: api key, secret, deviceId and region.
    tiny python gives some python error:
    Traceback (most recent call last): File "/usr/local/Cellar/[email protected]/3.9.1_6/Frameworks/Python.framework/Versions/3.9/lib/python3.9/runpy.py", line 197, in _run_module_as_main return _run_code(code, main_globals, None, File "/usr/local/Cellar/[email protected]/3.9.1_6/Frameworks/Python.framework/Versions/3.9/lib/python3.9/runpy.py", line 87, in _run_code exec(code, run_globals) File "/usr/local/lib/python3.9/site-packages/tinytuya/__main__.py", line 48, in <module> tinytuya.wizard(color) File "/usr/local/lib/python3.9/site-packages/tinytuya/__init__.py", line 1548, in wizard uid = response_dict['result']['uid'] KeyError: 'result'

    Sensor devices

    How can I connect a TEmp/Hum sensor fron tuya ?. It works in my app but cant fint it in tinytuya.
    Is there a class for Sensor Devices such as Temp/Hum sensors?

    I found the block descriptor Version 3.3 - Sensor Type.

    Can't get .status() from switch

    Hi,

    i can get the status from my 10 lamps, but when I try to get a status from a switch, i get the following error. This is my code:

    a = tinytuya.OutletDevice('here_is_my_key', '192.168.178.46', 'secret_key_here')
    a.set_version(3.3)
    data =  a.status()
    print(data)
    
    

    And this error occurs:

    Traceback (most recent call last):
      File "tuya.py", line 89, in <module>
        data =  a.status()
      File "/home/pi/tinytuya/tinytuya/__init__.py", line 405, in status
        result = json.loads(result)
      File "/usr/lib/python3.7/json/__init__.py", line 348, in loads
        return _default_decoder.decode(s)
      File "/usr/lib/python3.7/json/decoder.py", line 337, in decode
        obj, end = self.raw_decode(s, idx=_w(s, 0).end())
      File "/usr/lib/python3.7/json/decoder.py", line 355, in raw_decode
        raise JSONDecodeError("Expecting value", s, err.value) from None
    json.decoder.JSONDecodeError: Expecting value: line 1 column 1 (char 0)
    

    Empty Payload Response

    Hi,
    I'm using an Energizer bulb I realized was talking to the Tuya servers. It works from the Tuya app, but Tuya demands that I use their beta IoT solutions app, and when I try to control it locally I get the following error.

    DEBUG:raw unpacked message = TuyaMessage(seqno=1, cmd=10, retcode=1, payload=b"\x96\xa2\x8d\x9dB\xf1\xcc\xae\xe6{K\xc9'\xe8\x19\x11\xab\xbf\x8dL\x91v\x13\xa9!\xd2\xdck\x89\xc1\x96n", crc=2352078917) DEBUG:decode payload=b"\x96\xa2\x8d\x9dB\xf1\xcc\xae\xe6{K\xc9'\xe8\x19\x11\xab\xbf\x8dL\x91v\x13\xa9!\xd2\xdck\x89\xc1\x96n" DEBUG:decrypting=b"\x96\xa2\x8d\x9dB\xf1\xcc\xae\xe6{K\xc9'\xe8\x19\x11\xab\xbf\x8dL\x91v\x13\xa9!\xd2\xdck\x89\xc1\x96n" DEBUG:decrypted 3.3 payload='' DEBUG:decoded results='' DEBUG:ERROR Invalid JSON Response from Device - 900 - payload: "" DEBUG:status() received data={'Error': 'Invalid JSON Response from Device', 'Err': '900', 'Payload': ''}

    This is after requesting a status. It is worth noting I cannot poll locally.

    [WinError 10054]

    Sometimes this error appears, probably because a connection hasnt been closed before connecting to it again. How would I make sure that a connection to a device is closed?

    Can't control/get state of single socket WiFi power plugs

    Controlling a 4-socket WiFi power strip works fine...

    Though when using those Marmitek Power SE single socket WiFi Plugs, no state can be read nor can the switch be set to on or off....tested with version 3.1 and 3.3 protocol....

    The devices.json file was created correctly with the keys for the WiFi plugs as the keys can be used in Home Assistants LocalTuya add on without any problems...

    In Home Assistant I can control single socket and 4 socket power plugs...here I can only control the 4 socket power stips...

    With the dps example I don't get any output...so no error message...

    With the test script:

    TinyTuya (Tuya Interface) [1.2.3]

    TESTING: Device 8626xxxxxxxxxxxxx at 10.0.100.49 with key xxxxxxxxxxxxxxxx version 3.3

    READING TEST: Response {'Error': 'Network Error: Unable to Connect', 'Err': '901', 'Payload': None}

    READING TEST: Response {'Error': 'Network Error: Unable to Connect', 'Err': '901', 'Payload': None}

    READING TEST: Response {'Error': 'Network Error: Unable to Connect', 'Err': '901', 'Payload': None}
    TIMEOUT: No response from plug 8626xxxxxxxxxxxxx [10.0.100.49] after 2 attempts.

    And yes..the device is there (o;

    Starting Nmap 7.70 ( https://nmap.org ) at 2021-03-06 10:26 CET
    Nmap scan report for 10.0.100.49
    Host is up (0.0032s latency).
    Not shown: 999 closed ports
    PORT STATE SERVICE
    6668/tcp open irc

    Nmap done: 1 IP address (1 host up) scanned in 7.37 seconds

    Error 901 , very new to python.

    Ok so when I tried the test file for an RGB bulb it would only change the color right after i turned the light off and then on again.After that it would not work until i turned it off and then on again.I am using a rasberry pi 4.

    How to get power status of light bulb, Py noob

    Hello I would like to know how make a script that checks status of lights before switching strate.
    Looking at how the code is made it should be possible but i cannot figure it out as i'm still learning python
    DPS_2_STATE = does not end at 24 in this file

    my output from print('\nCurrent Status of Bulb: %r' % data) is Current Status of Bulb: {'dps': {'20': True, '21': 'white', '22': 1000, '23': 1000, '24': '000003e803e8', '25': '000e0d0000000000000000c80000', '26': 0}}
    Is that why I cant see the power state ?

    Cover Control time

    Hi, After log time I finaly found this great py....

    I have bought the Loratap blinds cover

    https://nl.aliexpress.com/item/33052311020.html?spm=a2g0o.productlist.0.0.1fce6edfWhEofY&algo_pvid=4a8c0398-bc03-4c6a-8910-49a94bf9925e&algo_expid=4a8c0398-bc03-4c6a-8910-49a94bf9925e-0&btsid=0b0a050116172030867828749e1023&ws_ab_test=searchweb0_0,searchweb201602_,searchweb201603_

    And when i pull the status I get

    Dictionary {u'dps': {u'1': u'stop', u'3': 15, u'2': u'forward'}}

    I made 3 scripts... open/stop/close
    e.g.
    import tinytuya

    d = tinytuya.CoverDevice('#####', '######', '#######')
    d.set_version(3.3)
    data = d.status()
    #print(data)

    d.open_cover(switch=1)

    Show status of first controlled switch on device

    #print('Dictionary %r' % data)
    print('State %r' % data['dps']['1'])
    print('State %r' % data['dps']['2'])
    print('State %r' % data['dps']['3'])

    Now comes the parts I want to controll the u3: 15
    This the time that the cover(shutter) rolls....
    I did allot of commands but i don't get the right one..

    let's say I want to get to 21 value.....
    please help..
    thanks

    Remco aka mupsje

    default22 device

    Well one of my device is in

    Problem :

    I am tryinig get_status and its always return None.

    
    DEBUG:building payload=b'{"gwId":"bf89e15533aa8988cd4avu","devId":"bf89e15533aa8988cd4avu","uid":"bf89e15533aa8988cd4avu","t":"1623820243"}'
    DEBUG:payload generated=b"\x00\x00U\xaa\x00\x00\x00\x00\x00\x00\x00\n\x00\x00\x00\x88j\xff\xbf\xbd\xcb1y\x00\x1d=\x0f\x92\x02\x8d>\x142\x10\x8b\xffW\xa4\xfa\x13'\x04\xeb\xf2\x1a 1\x1f\x18\x93\xdah\x89\xf4\xa2\x13\xb5ku\xd3{\x19-\x91\xd5o\xdd\xb2\xcbl\xf4\xea\xc7\x98\x11\x9eFa\xe2\xec\xff\xbc]\xdc\xca\x05C\x90\xb7\x87\t\xa0e\xa2\xed\x802\x10\x8b\xffW\xa4\xfa\x13'\x04\xeb\xf2\x1a 1\x1f@AI\x9a;\x88n\xe9 \x92D\x84\xf8\xec\xd8\xc5\x9a/\x8c\nI\x9a@\xa6\xf0C\xaf\xac\xd2\xd3\xa5\x8f\xf9\x91\xe3\x08\x00\x00\xaaU"
    DEBUG:received data=b'\x00\x00U\xaa\x00\x00\x00\x00\x00\x00\x00\n\x00\x00\x00,\x00\x00\x00\x01\x02:jyw\ta\xb85\xe7\xd3\x82\x1d\x9b\xb1\xd2\xc1==\xc9\xa4\xf2\xfb\xcb\xbf\xf8\x88OyC\x97\xe7$\xb3g\xd5\x00\x00\xaaU'
    DEBUG:raw unpacked message = TuyaMessage(seqno=0, cmd=10, retcode=1, payload=b'\x02:jyw\ta\xb85\xe7\xd3\x82\x1d\x9b\xb1\xd2\xc1==\xc9\xa4\xf2\xfb\xcb\xbf\xf8\x88OyC\x97\xe7', crc=615737301)
    DEBUG:decode payload=b'\x02:jyw\ta\xb85\xe7\xd3\x82\x1d\x9b\xb1\xd2\xc1==\xc9\xa4\xf2\xfb\xcb\xbf\xf8\x88OyC\x97\xe7'
    DEBUG:decrypting=b'\x02:jyw\ta\xb85\xe7\xd3\x82\x1d\x9b\xb1\xd2\xc1==\xc9\xa4\xf2\xfb\xcb\xbf\xf8\x88OyC\x97\xe7'
    DEBUG:decrypted 3.3 payload='json obj data unvalid'
    DEBUG:'data unvalid' error detected: switching to dev_type 'device22'
    DEBUG:Re-send b"\x00\x00U\xaa\x00\x00\x00\x00\x00\x00\x00\n\x00\x00\x00\x88j\xff\xbf\xbd\xcb1y\x00\x1d=\x0f\x92\x02\x8d>\x142\x10\x8b\xffW\xa4\xfa\x13'\x04\xeb\xf2\x1a 1\x1f\x18\x93\xdah\x89\xf4\xa2\x13\xb5ku\xd3{\x19-\x91\xd5o\xdd\xb2\xcbl\xf4\xea\xc7\x98\x11\x9eFa\xe2\xec\xff\xbc]\xdc\xca\x05C\x90\xb7\x87\t\xa0e\xa2\xed\x802\x10\x8b\xffW\xa4\xfa\x13'\x04\xeb\xf2\x1a 1\x1f@AI\x9a;\x88n\xe9 \x92D\x84\xf8\xec\xd8\xc5\x9a/\x8c\nI\x9a@\xa6\xf0C\xaf\xac\xd2\xd3\xa5\x8f\xf9\x91\xe3\x08\x00\x00\xaaU" due to device type change (default -> device22)
    DEBUG:received data=b'\x00\x00U\xaa\x00\x00\x00\x00\x00\x00\x00\n\x00\x00\x00,\x00\x00\x00\x01\x02:jyw\ta\xb85\xe7\xd3\x82\x1d\x9b\xb1\xd2\xc1==\xc9\xa4\xf2\xfb\xcb\xbf\xf8\x88OyC\x97\xe7$\xb3g\xd5\x00\x00\xaaU'
    DEBUG:raw unpacked message = TuyaMessage(seqno=0, cmd=10, retcode=1, payload=b'\x02:jyw\ta\xb85\xe7\xd3\x82\x1d\x9b\xb1\xd2\xc1==\xc9\xa4\xf2\xfb\xcb\xbf\xf8\x88OyC\x97\xe7', crc=615737301)
    DEBUG:decode payload=b'\x02:jyw\ta\xb85\xe7\xd3\x82\x1d\x9b\xb1\xd2\xc1==\xc9\xa4\xf2\xfb\xcb\xbf\xf8\x88OyC\x97\xe7'
    DEBUG:removing 3.3=b'\xd2\xc1==\xc9\xa4\xf2\xfb\xcb\xbf\xf8\x88OyC\x97\xe7'
    DEBUG:decrypting=b'\xd2\xc1==\xc9\xa4\xf2\xfb\xcb\xbf\xf8\x88OyC\x97\xe7'
    DEBUG:incomplete payload=b'\xd2\xc1==\xc9\xa4\xf2\xfb\xcb\xbf\xf8\x88OyC\x97\xe7'
    DEBUG:status received data=None
    

    But if we call get status again - its normal return data. So re-send data is not working.
    I think need some timeout ?

    DEBUG:status() entry (dev_type is device22)
    DEBUG:building payload=b'{"devId":"bf89e15533aa8988cd4avu","uid":"bf89e15533aa8988cd4avu","t":"1623820269","dps":{"1":null}}'
    DEBUG:payload generated=b"\x00\x00U\xaa\x00\x00\x00\x02\x00\x00\x00\r\x00\x00\x00\x873.3\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x001G\x967\x8eS\x89\xba\xab\x96\x97\x10.\xe1\x94\xbc\xd5o\xdd\xb2\xcbl\xf4\xea\xc7\x98\x11\x9eFa\xe2\xec\xff\xbc]\xdc\xca\x05C\x90\xb7\x87\t\xa0e\xa2\xed\x802\x10\x8b\xffW\xa4\xfa\x13'\x04\xeb\xf2\x1a 1\x1f\xde\xb7\x99W\xf18\xa2\xaf1V\x87\xf1\xa1\xcb\xc4}\xa2\x85dS\xea\xa03\tr\xff\xfc-T\xc7\x97(\xe7\x8e\xee\x95\xf08\xc1\x13i\x9af\x87l#\x0e\xe5G@NC\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\x00\x00N\x00\x00\x00\x01\x91e4K\x02\x17o\x1c\x81N\xac\xa0\x91\x98\xd4\xed\x95\xd2;\xa2\xfe\xffP\xd4X\xa9k@b\xb1\xf3r\xef\xc7\xf2O3\x18e\xb4\xf6\xe7\x03f\x90}\xb1nrIQV\x00\x00\xaaU'
    DEBUG:raw unpacked message = TuyaMessage(seqno=0, cmd=8, retcode=0, payload=b'3.3\x00\x00\x00\x00\x00\x00\x00N\x00\x00\x00\x01\x91e4K\x02\x17o\x1c\x81N\xac\xa0\x91\x98\xd4\xed\x95\xd2;\xa2\xfe\xffP\xd4X\xa9k@b\xb1\xf3r\xef\xc7\xf2O3\x18e\xb4\xf6\xe7\x03f\x90}\xb1n', crc=1917407574)
    DEBUG:decode payload=b'3.3\x00\x00\x00\x00\x00\x00\x00N\x00\x00\x00\x01\x91e4K\x02\x17o\x1c\x81N\xac\xa0\x91\x98\xd4\xed\x95\xd2;\xa2\xfe\xffP\xd4X\xa9k@b\xb1\xf3r\xef\xc7\xf2O3\x18e\xb4\xf6\xe7\x03f\x90}\xb1n'
    DEBUG:removing 3.3=b'\x91e4K\x02\x17o\x1c\x81N\xac\xa0\x91\x98\xd4\xed\x95\xd2;\xa2\xfe\xffP\xd4X\xa9k@b\xb1\xf3r\xef\xc7\xf2O3\x18e\xb4\xf6\xe7\x03f\x90}\xb1n'
    DEBUG:decrypting=b'\x91e4K\x02\x17o\x1c\x81N\xac\xa0\x91\x98\xd4\xed\x95\xd2;\xa2\xfe\xffP\xd4X\xa9k@b\xb1\xf3r\xef\xc7\xf2O3\x18e\xb4\xf6\xe7\x03f\x90}\xb1n'
    DEBUG:decrypted 3.3 payload='{"dps":{"1":true},"t":1623820269}'
    DEBUG:decoded results='{"dps":{"1":true},"t":1623820269}'
    DEBUG:status received data={'dps': {'1': True}, 't': 1623820269}
    

    Timeout errors while toggling device state

    I'm sure there's something I'm doing wrong here, but every time I try to set the state of my OutletDevice I get timeout errors. I checked this with the example test.py too. I followed all the instructions for getting the device key and checked through them multiple times, and watched the linked video as well. I can get the device state fine, I just can't set it, which is what leads me to believe it's something to do with the device key. Any help or explanation as to what is happening here would be much appreciated.

    Thank you

    Recommend Projects

    • React photo React

      A declarative, efficient, and flexible JavaScript library for building user interfaces.

    • Vue.js photo Vue.js

      ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

    • Typescript photo Typescript

      TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

    • TensorFlow photo TensorFlow

      An Open Source Machine Learning Framework for Everyone

    • Django photo Django

      The Web framework for perfectionists with deadlines.

    • D3 photo D3

      Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

    Recommend Topics

    • javascript

      JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

    • web

      Some thing interesting about web. New door for the world.

    • server

      A server is a program made to process requests and deliver data to clients.

    • Machine learning

      Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

    • Game

      Some thing interesting about game, make everyone happy.

    Recommend Org

    • Facebook photo Facebook

      We are working to build community through open source technology. NB: members must have two-factor auth.

    • Microsoft photo Microsoft

      Open source projects and samples from Microsoft.

    • Google photo Google

      Google โค๏ธ Open Source for everyone.

    • D3 photo D3

      Data-Driven Documents codes.