Open marcowg opened 3 years ago
So far, I have not found anyone who has been able to make a local connection to a Tuya based sensor. It appears that these only send their data to the TuyaCloud (which is what the app uses for data) and do not respond to local traffic. What device do you have?
If you have it registered, it may still show up in the wizard:
python -m tinytuya wizard
You can try connecting to the IP to see what happens. The OutletDevice class is close to the base class.
import tinytuya
tinytuya.debug(True)
d = tinytuya.OutletDevice('DEVICE_ID_HERE', 'IP_ADDRESS_HERE', 'LOCAL_KEY_HERE')
d.set_version(3.3)
data = d.status()
I am using
JINQII Digitale Indoor Thermometer Hygrometer, draadloze WIFI Temperatuur & Vochtigheid Sensor met Smart Alert, LCD Temp Vochtigheid Monitor voor Thui Verkocht door: JINGQIIeu
the wizard gives: C:\Users\Gebruiker>python -m tinytuya wizard -nocolor TinyTuya Setup Wizard [1.2.2]
Existing settings:
API Key=xx
Secret=xx
DeviceID=xx
Region=eu
Use existing credentials (Y/n): y
Device Listing
[ { "name": "WIFI wcd led aq beneden", "id": "002616442462ab482a16", "key": "xx" }, { "name": "T1", "id": "bf4b950a700ba29e27fmhh", "key": "xx" }, { "name": "T2", "id": "bff5774aafb742deafinka", "key": "xx" } ]
Saving list to devices.json 3 registered devices saved
Poll local devices? (Y/n): y
Scanning local network for Tuya devices... 2 local devices discovered
Polling local devices... [WIFI wcd led aq beneden] - 0 - Error: No IP found [T1] - 0 - Error: No IP found [T2] - 0 - Error: No IP found
Saving device snapshot data to snapshot.json
Done. (== the Wifi WCD is connected to an application)
the test script import tinytuya
tinytuya.set_debug(True, False)
d = tinytuya.OutletDevice('DEVICE_ID_HERE', 'IP_ADDRESS_HERE', 'LOCAL_KEY_HERE') d.set_version(3.3) data = d.status()
DEBUG:status() entry (dev_type is default) DEBUG:building payload=b'{"gwId":"bff5774aafb722deafinka","devId":"bff5774aafb722deafinka","uid":"bff5774aafb722deafinka","t":"1614149841"}' DEBUG:payload generated=b'\x00\x00U\xaa\x00\x00\x00\x00\x00\x00\x00\n\x00\x00\x00\x88>o\x1f\xa1\xc8\xb5\t\xbc{\xfa\xda\xe4\xbf\x91\x9a\xdb\x0f\xbeh\x95\xbf\xd3\xda\xe6\x0bw\xaf\x93\xcbHE\xc5q\xbamN\x8e\xaf\xda9\xc8\x88N\xd6\x18#\x15\xa7\x90\xa8\xa1KH\xec+8\xcc|U\xab\xaeC\xac\xeb\xa3xdg\xfc\xa0\xbd\xd2p?uR xC\xad\x0f\xbeh\x95\xbf\xd3\xda\xe6\x0bw\xaf\x93\xcbHE\xc5\\xd1B2\x9a\x8a\x9a\xbeP\xaa\x00\x1a\xb0\x15\xae\xb3\xd0\xf1JI\x13\x88\x7f\x8f\x1c\xfc!T\x91\xc0Q\xd4/\xa0\xec$\x00\x00\xaaU' DEBUG:socket unable to connect - retry 1/5 timeout('timed out') DEBUG:socket unable to connect - retry 2/5 timeout('timed out') DEBUG:socket unable to connect - retry 3/5 timeout('timed out') DEBUG:socket unable to connect - retry 4/5 timeout('timed out') DEBUG:socket unable to connect - retry 5/5 timeout('timed out') DEBUG:ERROR Network Error: Device Unreachable - 905 - payload: null DEBUG:status received data={'Error': 'Network Error: Device Unreachable', 'Err': '905', 'Payload': None}
next test was to put the script in a while loop and power of/on the sensor. then it works, but the connection drops in about 5 sec.
{'dps': {'1': 215, '2': 60, '3': 'high'}} {'dps': {'1': 215, '2': 60, '3': 'high'}} {'dps': {'1': 215, '2': 60, '3': 'high'}} {'dps': {'1': 215, '2': 60, '3': 'high'}} {'dps': {'1': 215, '2': 60, '3': 'high'}} {'dps': {'1': 215, '2': 60, '3': 'high'}} {'dps': {'1': 215, '2': 60, '3': 'high'}} {'dps': {'1': 215, '2': 60, '3': 'high'}} {'Error': 'Network Error: Device Unreachable', 'Err': '905', 'Payload': None}
Wow! That's a great discovery. You get a response for 5s after you power it off/on? I'll need to think about that. We could try different command to see if it responds.
NOTE: you may want to consider redacting the device ID and Key from your notes.
The sensor reacts at power-on. It seems it get connected after the first 5 sec to the cloud.
Does the device use the [WiFi] device as the gateway/bridge and the [T1] and [T2] devices as temperature probes? In other words, the IP address you are using to get the data, is that for the [WiFi] device, "id": "002616442462ab482a16"?
One thought would be to see if we use that as the gateway and request information for the other IDs. We attempted that with #26 for a smart lock, with little success, but this is a sensor so it may work. Something like this:
# Tuya Command to send
command = tinytuya.DP_QUERY
GATEWAY = "002616442462ab482a16"
DEVICE = "xxx"
payload=d.generate_payload(command, data=None, gwId=GATEWAY, devId=DEVICE, uid=DEVICE)
data = d._send_receive(payload)
print('Response: %r' % data)
You could try other combinations for gwId, devId and uid and even try the different Tuya commands to see if the devices responds to anything else.
I found some of the Tuya code for MCU which might apply to your device: here with sample code that seems to indicate the DPS indexes:
/******************************************************************************
1:dp数据点序列号重新定义
**此为自动生成代码,如在开发平台有相关修改请重新下载MCU_SDK**
******************************************************************************/
//当前温度(只上报)
//备注:
#define DPID_TEMP_CURRENT 1
//湿度数值(只上报)
//备注:
#define DPID_HUMIDITY_VALUE 2
//电池电量(只上报)
//备注:
#define DPID_BATTERY_PERCENTAGE 4
/******************************************************************************
1:dp数据点序列类型对照表
**此为自动生成代码,如在开发平台有相关修改请重新下载MCU_SDK**
******************************************************************************/
DOWNLOAD_CMD_S download_cmd[] =
{
{DPID_TEMP_CURRENT, DP_TYPE_VALUE},
{DPID_HUMIDITY_VALUE, DP_TYPE_VALUE},
{DPID_BATTERY_PERCENTAGE, DP_TYPE_VALUE},
};
Which means 1 = temp(C), 2 = Humidity(%). I didn't find 3 and your example data payload didn't have 4.
{'dps': {'1': 215, '2': 60, '3': 'high'}}`
I suspect that would mean: Temp = 21.5C and Humidity = 60%. Is that reasonable?
One thought... we could see what a series of heartbeat() would produce, if anything:
import tinytuya
import time
tinytuya.set_debug(True)
d = tinytuya.OutletDevice(ID,IP,KEY)
d.set_version(3.3)
d.set_socketPersistent(True)
while(True):
data = d.heartbeat()
print('Response: %r' % data)
time.sleep(2)
both test result in 905 Network Error: Device Unreachable. my old test result in {'dps': {'1': 221, '2': 58, '3': 'high'}} Temp = 22.1C and Humidity = 58%. battery = High
If I look in the app there is a 24 hr trendline, it means the sensor is connected to the cloud. Somewhere at iot.tuya.com. can we block that in a firewall?
I also made a endless loop and values come on start up and when the temperature change 0.5 degrees.
Yes, from what I discovered from others, the Tuya sensors are designed to go to sleep to save battery life. They only become active on startup or when state change occurs. They power up, join WiFi and send update to Tuya Cloud. During that time, there is a window of opportunity for you to ping the device and potentially get a response. Keep in mind that these sensors are designed to report to the Cloud, so if you block their cloud access, results are undefined. Also, pinging the device even in sleep mode could shorten the life of the battery.
I don't have any Tuya sensors to experiment or test (I built my own with esp8266 modules) so any details or suggested code updates would be appreciated.
Long story short but a little extra info to the puzzle, I've got an s06pro which is an IR blaster here that has temp & humidity builtin they're powered by USB, I can get a status with them at any time and get back {'dps': {'101': 164, '102': 63}}, probably not super useful information but figured I'd share.
Thanks @rawrxiv - So 16.4C and 63% RH?
I would love to get the full device details. If you ran wizard you should have a tuya-raw.json
file that contains the full dump from Tuya IoT. Can you paste the s06pro portion of that? Remove any sensitive data (IP, ID, local_key, etc). The biz_type, category, product_id and product_name and status may be good data points to help build a repository of devices and types, especially for these non-outlet devices/sensors.
{
"result": [
{
"active_time": 1628634686,
"biz_type": 18,
"category": "wnykq",
"create_time": 1628634686,
"icon": "smart/icon/ay1525749833414yotNt/6b9c8b165096c8b58bb73953a95b986e.png",
"id": "",
"ip": "",
"lat": "",
"local_key": "",
"lon": "",
"model": "S06ProWB3S",
"name": "",
"online": true,
"owner_id": "",
"product_id": "y7sl2p1fgcbuh6lu",
"product_name": "Smart IR",
"status": [
{
"code": "va_temperature",
"value": 188
},
{
"code": "va_humidity",
"value": 63
}
],
"sub": false,
"time_zone": "",
"uid": "",
"update_time": 1628641897,
"uuid": ""
},
{
"active_time": 1628634205,
"biz_type": 18,
"category": "wnykq",
"create_time": 1628634205,
"icon": "smart/icon/ay1525749833414yotNt/6b9c8b165096c8b58bb73953a95b986e.png",
"id": "",
"ip": "",
"lat": "",
"local_key": "",
"lon": "",
"model": "S06ProWB3S",
"name": "",
"online": true,
"owner_id": "",
"product_id": "y7sl2p1fgcbuh6lu",
"product_name": "Smart IR",
"status": [
{
"code": "va_temperature",
"value": 191
},
{
"code": "va_humidity",
"value": 63
}
],
"sub": false,
"time_zone": "",
"uid": "",
"update_time": 1628641897,
"uuid": ""
}
],
"success": true,
"t": 1628765499128
}
There's two of these s06pros there.
Having messed around with it more, seems like it has a hard time consistently making the socket connection, If I loop it polling every second eventually it'll make a connection and looks like it'll persist it, but if say I try to poll every minute with it might miss the connection within 5 retries.
Hazarding a guess is that the successful connection may be when the device is or isn't making a connection elsewhere?
Thanks @rawrxiv ! That's very helpful.
Yes, I have seen that. Many Tuya devices are very single threaded. You could run a monitor script like this to see if it sends any updates on its own:
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)
# print(" > Send Request for Status < ")
# payload = d.generate_payload(tinytuya.DP_QUERY)
# d.send(payload)
That worked a treat for these devices, thank you for the help.
Just a thought - when these battery powered sensors wake up to send to the cloud, do they send a broadcast message on port 6666 or 6667? Could this be used to trigger a poll during the 5 second window when the device is awake (or does the broadcast contain enough info to not need the poll even)?
Hi @make-all - I don't know if all sensors emit a broadcast when they wake up, but there is a possibility that they do. The UDP broadcast message contains the IP, Device ID, productKey (sku), and protocol version. Here is an example:
{
"ip": "10.0.1.2",
"gwId": "01234567891234567890",
"active": 2,
"ability": 0,
"mode": 0,
"encrypt": true,
"productKey": "AiHXxAyyn7eAkLQY",
"version": "3.3"
}
And yes, you could set up a script to constantly monitor for that and when it comes in, poll the device. Key would be to close that connection as soon as you get it so that the device can go back to sleep to save battery (example from server.py):
import tinytuya
# devicelist is dictionary of device keys
d = tinytuya.OutletDevice(id, ip, deviceslist[id]["key"])
d.set_version(float(version))
status = d.status()
d.close()
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.