-
Notifications
You must be signed in to change notification settings - Fork 4
55. Howto: add a new device since v. 2.2.4
Since version 2.2.4 Tuya_DAEMON introduces access to Tuya OpenAPI, which changes the way new devices and 'mirror devices' are managed. This article explores the new possibilities, using a 'smoke alarm device', WiFi battery powered, as an example.
- The goal is always to identify, document, and make accessible via TuyaDEAMON all the functions of a new device.
- The study of a new Tuya device and the design phase of a 'mirror' device are both greatly facilitated by the use of core_OPENAPI and the 'Tuya IoT Development Platform'.
- Mirror devices are Tuya devices that are not supported MQTT by the tuya-smart-device node. However, they are still accessible through core_TRIGGER and core_OPENAPI, TuyaDAEMON optional extensions.
-
core_OPENAPI
allows you to access Tuya Cloud directly, but to do so, you must add the device to thereal
section ofglobal.alldevices
. This is also for 'mirror' devices using core_OPENAPI, no longer in the 'fake' section.
note: This document is focused on TuyaDAEMON, but addresses general features of Tuya Cloud: so this information may also be useful in other contexts. In particular, I developed a standalone node-red flow for testing with OpenAPI without TuyaDAEMON.
- TuyaDAEMON is installed and configured with the
core_OPENAPI
and (for 'mirror' devices)core_TRIGGER
extensions. - Optionally, you can install and configure the tuyadaemon.toolkit for additional features.
- Alternative without TuyaDAEMON: install nr_Tuya_OpenAPI_2.0 on node-red.
- The new device is present in the 'SmartLife' app and is working correctly.
- You can access the Tuya IoT Platform and see the new device listed in the 'Cloud/Open Project/Device' section ( or in the 'Debug Devices' dropdown list). Here is a good guide.
note: The following steps replace 5..8 Steps in 50. Howto: add a new device to tuyaDAEMON when core_OPENAPI is available.
-
Find the deviceID of the new device
- in SmartLife,
device info
- using
Tuya IoT Platform
- using
tuyapi-cli wizard
- The last best and fastest solution is to use TuyaUIweb modified to display the
id
andkey
of each device in the tooltips.
- in SmartLife,
-
Create this simple flow (e.g. in 'mirror_devices' flow), with two nodes: an
input
node and alink out
node (tocore.std_cmds
), to call some Tuya APIs for testing.
- API 'Query Device Details'
Set in the input
node a msg.payload
like this (JSON), to call this API:
{
"device": "_openapi",
"property": "_callAPI",
"value": {
"method": "GET",
"APIurl": "/v2.0/cloud/thing/<your_deviceID>",
"body": ""
}
}
On the debug pad you must have: RESULT: "[RX: openapi/_callAPI", object]", and, opening it:
payload: {
success: true
result: {
active_time: 1692989353
category: "kg" // manufacturer defined
create_time: 1613403089
custom_name: "tuya_bridge" // in SmartLife
icon: "smart/device_icon/eu1580902146346G23Gy/bf8c4fd0c03067079cplb1461381627983590.png"
id: "1234567xx" // same as in the call, required by tuya-smart-device (Device Virtual ID)
local_key: "12345kk" // required by tuya-smart-device (Device key)
ip: "12.23.34.45" // your public network IP address
is_online: true
product_id: "123456pp" // Tuya unique label for each independent product.
model: "1CH" // manufacturer defined
name: "1CH 2" // (brand) + (product) + (module model), manufacturer defined
product_name: "1CH" // manufacturer defined
sub: false // is subdevice?
lat: "41.9"
lon: "12.4"
time_zone: "+02:00"
update_time: 1693051814
uuid: "987654321" // Tuya internal use
}}
- Alternative: use the flow 'Get Device Details V2.0'
Copy and paste the data in a notepad, you can need it later.
- API 'Send Properties'
Set in the input
node a msg.payload like this (JSON), to call the API:
{
"device": "_openapi",
"property": "_callAPI",
"value": {
"method": "GET",
"APIurl": "/v2.0/cloud/thing/<your_deviceID>/shadow/properties",
"body": ""
}
}
On the debug pad you must have: RESULT: "[RX: openapi/_callAPI", object]", and, opening it:
payload: {
success: true
result: {
properties: array[8] // This device is with 8 DPs (codes)
0: {
code: "switch_1" // used by Tuya APIs
custom_name: "Free"
dp_id: 1 // used by TuyaDAEMON
time: 1702399814901
value: true // actual DP's value
}
1: object
2: object
...more...
}}
- Alternative: Use the flow 'GET device SCHEMA V2.0'.
Expand all, then copy and paste the data into a notepad.
Now we group all information about DPs in a table: DP
, and code
are from the API result; standard
, status
(sta), instruction
(ins), and values
are from 'Tuya IoT Platform'; condition
(con) and action
(act) from 'SmartLife' Automation definition pages.
DP | code | standard | sta | ins | con | act | values | notes&behavior |
---|---|---|---|---|---|---|---|---|
1 | smoke_sensor_state | smoke_sensor_status | yes | - | yes | - | 1..2 ? => "Smoke alarm", "normal" | code <> standard, More codes? |
2 | smoke_sensor_value | smoke_sensor_value | yes | - | yes | - | 0.0..10.0 [ppm] | pushed only on "Smoke alarm" change |
11 | fault | -- | - | - | - | - | 0..? | err code? |
14 | battery_state | battery_state | yes | - | yes | - | "low", "middle", "high" | by Tuya Cloud, never by device |
15 | battery_percentage | battery_percentage | yes | - | yes | - | 0..100 [%] | pushed on any alarm state change |
16 | muffling | muffling | yes | yes | yes | yes | true/false | SET only during alarm, returns to false at alarm end. Also HW |
101 | test | -- | - | - | - | - | true/false | 'Test alarm', only HW |
The minimal global.alldevices
- in CORE_devices
flow, *Global CORE config
node - update is (if you like, you can start to use tuyadaemon_toolkit
to do that), in 'real' section:
{
"id": "<your_deviceID>",
"name": "smoke detector", // user name, used by TuyaDAEMON interfaces, any
"dps": [
{
"dp": 1,
"capability": "TRG",
"name": "smoke_sensor_state" // user name, used by TuyaDAEMON interfaces, here is the `code`
},
{
"dp": 2,
"capability": "TRG",
"typefield": "BYTESMALLFLOAT", // to make the value human-readable
"name": "smoke_sensor_value"
},
{
"dp": 11,
"capability": "TRG",
"name": "fault"
},
{
"dp": 14,
"capability": "TRG",
"name": "battery_state"
},
{
"dp": 15,
"capability": "TRG",
"name": "battery_percentage"
},
{
"dp": 16,
"capability": "TRG",
"name": "muffling"
},
{
"dp": 101,
"capability": "TRG",
"name": "test"
}
]
},
The "capability": "TRG"
is used here, since this mirror device does not have the smart-tuya-device
node. The
"BYTESMALLFLOAT" decode function divides by ten the value: see CORE_devices
flow, *ENCODE/DECODE user library
node.
Now you are enabled to use core_OPENAPI
pseudoDP (_APIstatus
, and _APIinstruction
):
You must set the following command in the test input
node, equivalent to GET SCHEMA:
{
"device": "smoke detector",
"property": "_APIstatus",
"value": "any"
}
and all DPs will be updated (in global.tuyastatus
) with the returned values.
Or you can do the following command, equivalent to SET (also MULTIPLE):
{
"device": "smoke detector",
"property": "_APIinstruction",
"value": {
"properties": {
"test": true
}
}
}
In the 'Tuya device log' this is reported as:
2023-12-15 10:22:21 | Publish | 手动测试报警 (Manual test alarm) | on | unknown
but without any visible effect on the device: i.e. SET 'test' is not available via Tuya API 'send_properties'.
The definition and value of all DPs are not enough to use the device with confidence. Further investigations are necessary to identify behavior and quirks in DP
use. The tools available are:
- SmartLife commands on the user interface and in automation, and the resulting effects.
- The tuya log (max one week) in 'Tuya IoT Platform' - 'debug device', which shows all messages to/from a device.
- Test sequences of actions can be performed with the device directly, with SmartLife, or using TuyaDEAMON, checking the results in the device's log and status.
Tuya_DAEMON 'smoke detector' behavior
This is the information I found for the "smoke detector" device and its DPs (codes
), also summarized in the 'notes & behavior' column:
- The alarm sound can be triggered by 2 different causes:
- 'Test': only starts with the HW button; the alarm lasts 5 seconds
- 'Smoke': starts at the ON-level (9.0 ppm?) and ends at the OFF-level (1.0 ppm?)
- The code 'smoke_sensor_state'(RO) is 1 only for a 'Smoke alarm', 2 for normal
- The code 'test' (RO) is true only for a 'Test alarm'.
- The code 'fault' (RO) is 0 (code for no error?) (? untested).
- The code 'smoke_sensor_value' is pushed by the device at any smoke alarm state change.
- The code 'battery_percentage' is pushed by the device at any alarm state change (so 'test' can be used to GET the battery status).
- I found differences between values of
battery_percentage
at the start (e.g. 93%) and the end (79%) of an alarm. (note. 0% = low battery value, e.g. 7.0 V, 100% = hight battery value, e.g. 9.7 V, defined in FW by producer). - The code 'battery_state' is NEVER pushed by the device; maybe it is calculated by Tuya Cloud at any read.
- The code 'muffling' (silence) is writable by
_APIinstruction
only if the alarm is ON and auto returns to false at the alarm end.
general criteria
- The general objective is a minimal but complete implementation: all the functionality of a device must be reachable ASAP, with a minimum of custom code.
- The use of 'Tuya IoT Platform' is only cognitive, without changing anything: the default for Smartlife is the standard instruction set mode, and this will not be modified.
- In the case of mirror devices, keep in mind the advantages and limitations of the available tools:
- The use of
core_TRIGGER
+Tuya smart scenes
(automation) can cover the majority of cases:- available only for
DPs
present in the 'condition' or the 'action' columns - signal a device event, not numerical (condition
value = xx
) - signal a numerical event (condition
value > | = | < xx
) - start an action or SET a value (action
value = xx
), using a automation.
- available only for
- The use of
core_OPENAPI
must be very limited, only in truly necessary cases, to keep your dependence on Tuya Cloud low:- it is executed by tuya_DAEMON, in polling mode: therefore you cannot use it as a signal for asynchronous device events.
- it is essential for GETting numerical codes.
- it is useful when a code is in 'status' (i.e. it is readable), but it is NOT in SmartLife 'automation' 'conditions' (TRIGGER not available).
- it is useful when a code is in 'instruction' (i.e. it is writable), but it is NOT in SmartLife 'tap-to-run' 'actions' (TRIGGER not available).
- The use of
note: it is clear that OpenAPI
cannot, on its own, satisfy all needs, lacking a simple event-driven mechanism.
Tuya_DAEMON 'smoke detector' design
Considering the limits highlighted in the DP and the behavior of the device, the minimum functionalities for tuya_DAEMON are:
- we use native DPs (1..101) as 'base properties', updated via API or via 'trigger'.
These Tuya_triggers are generated by automation fired when some conditions are met. As a result, the 'native DPs' are updated ASAP by the device, in an event-driven strategy.
DPtrigger | name | condition | logging | more actions |
---|---|---|---|---|
30030 | TRGalarmON | 'smoke status' = 'smoke alarm' | DP_1 => 1 | - |
30100 | TRGalarmOFF | 'smoke status' = 'smoke alarm release' | - | API SCHEMA updates status |
30170 | TRGbattLOW | 'battery state' = 'low' | DP_14 => 'low' | - |
notes:
- _'TRGalarmOFF' uses 'APIstatus' to refresh all
native DPs
on the occasion of an alarmOFF event. - Only the 'TRGbattLOW' trigger is useful to update the 'battery state' ASAP, i.e. after a 'test alarm' (after a 'smoke alarm' the refresh is done by 'TRGalarmOFF')
- In the 'online' property (see API 'Query Device Details') of this device I always find 'true', even if I have disconnected the battery for more than 48 hours! The msg 'online' is sent by the device at startup and never reset. I would say, as a first solution, to always define 'connected' as true also in TuyaDAEMON.
- Since this device is always online, it is appropriate for the startup to use the 'API SCHEMA updates status' to initialize the data in the
tuyastatus
.
- solution: In the 'trigge_devices' flow, the incoming trigger produces only a message for the 'smoke alarm.DPtrigger' properties. The 'base properties' logging and 'more actions' are then implemented via share (more verbose, but puts all logic in the
global.alldevices
structure under strict user control)- solution In the 'trigge_devices' flow, the incoming trigger generates, using a custom node-red flow, the 'base properties' logging and 'more actions' required; the 'DPtriggers' are not required (more simple, the logic is wired in the 'mirror_devices' flow, preferred).
These Tuya_triggers are generated by Tuya_DAEMON to fire an 'automation' in Tuya Cloud or to do some more action. Implemented as 'SKIP' extra DPs, are accessible by the user as SET.
DP | name | trigger | automation | action | more |
---|---|---|---|---|---|
_silenceTRG | silence | 50050 | SMOKE50050 | silence = ON | trigger=0 |
_statsTRG (optional) | status | - | - | - | API SCHEMA updates status |
notes:
- In the log, the code
muffling
is calledSilence
and exposes 2 values:OFF
|Open Mute
. - The capability to do an 'API SCHEMA updates status' under user control is useful, e.g. after a manual 'Test', to refresh the 'battery state'. Since this feature is always available using the
_APIstatus
pseudoDP, a dedicated DP (_statsTRG
) is optional.
solution: standard: the Trigger or the required action is implemented via share (no alternatives: '_silenceTRG' DP and
share
are mandatory).
This implementation of the "smoke detector" mirror device is minimal: the device exports only a SET for
_silenceTRG
and no GETs: the data is updated in thetuyastatus
structure automatically and ASAP. For the APPs, nothing changes: the updates of all the DPs are disseminated via MQTT, while all data can be read via REST.
If for some reason you wanted to implement GET() for all DPs (I don't see the reason, but you never know) it's simple: you need a subflow that is a replacement fortuya-smart-device
node, but that reads the values fromglobal.tuyastatus
(see as a model the 'interface' node in the CORE flow).
Now for TRIGGERs, GETs are implemented as solution 2, and for SETs, solution 1.
Some fragments about the "smoke detector" mirror device:
a) Automation required in Tuya Cloud (you use SmartLife to build them):
SMOKE30030: If "smoke":alarm:on, Then "tuya_bridge":countdown_1:30030
SMOKE30100: If "smoke":alarm:off, Then "tuya_bridge":countdown_1:30100
SMOKE30170: If "smoke":battery:low, Then "tuya_bridge":countdown_1:30170
SMOKE50050: If "tuya_bridge":countdown_1 = 50050, Then "tuya_bridge":countdown_1:0 + "smoke":silence:ON
b) Share added in global.alldevices
, 'smoke detector': to call the SMOKE50050 automation via TRIGGER:
{
"dp": "_silenceTRG",
"capability": "SKIP",
"share": [
{
"action": [
{
"device": "tuya_bridge",
"property": "_trigger",
"value": "50050"
}
]
}
]
}
c) This is the implementation of a "smoke detector" mirror device in the 'mirror_devices' flow. This implementation is quite simple: there is only one function node, tuyastatus startup for mirror_smoke
, but it is stereotyped, always similar to itself. The others are nodes or subflows with parameters to set.
The three triggers, coming from the device, are selected by a selector, and then 3 sub-flows prepare the data for logging or to launch an API request. ACKs are handled automatically by core_TRIGGER.
The trigger to the device is generated directly by a share
.
Now we can implement the various parts and test the device.
The tests in the mirror_devices
flow simulate the trigger reception or send a SET silence ON
. Expected results (in the debug pad):
-
test Alarm ON
[ "RX: smoke detector/smoke_senso…", "1" ] // the updated value in DP 1
[ "RX: tuya_bridge/_trigger", 0 ] // ACK from TuyaDEAMON, clears the trigger
-
test Alarm OFF
[ "TX SET: device smoke detector/…", "any" ] // the request _APIstatus
[ "RX: tuya_bridge/_trigger", 0 ] // ACK from TuyaDEAMON, , clears the trigger
[ "RX: openapi/_APIstatus", object ] // _APIstatus response as an object, plus:
[ "RX: smoke detector/smoke_senso…", "2" ] // the updated value in DP 1
[ "RX: smoke detector/smoke_senso…", 0.2 ] // the updated value in DP 2
[ "RX: smoke detector/fault", 0 ] // the updated value in DP 11
... more ...
-
test Battery Low
[ "RX: smoke detector/battery_sta…", "low" ] // The updated value in DP 14
[ "RX: tuya_bridge/_trigger", 0 ] // ACK from TuyaDEAMON, clears the trigger
-
set_silence ON
[ "RX: smoke detector/_silenceTRG", "ON" ] // Local response to SET
[ "RX: tuya_bridge/_trigger", 50050 ] // Trigger sent to Tuya
[ "RX: tuya_bridge/_trigger", 0 ] // ACK from Tuya Cloud, verifying automation execution
note:
- This is the full echo on the debug pad. Users can hide unnecessary messages.
- If you use
tuyadaemon.toolkit
, don't forget to update the database and produce the updated 'datasheet' for your devices. If you also usetuyadaemon.thing
, use it to quickly create the required 'shares' and to keepglobal.alldevices
up to date.
The use of 'core_OPENAPI' is optional, but, as can be seen in the example reported here, it brings substantial benefits both in the analysis and in the implementation of devices for Tuya_DAEMON. The strategy used is conservative, with limited access to Tuya Cloud, but this completes the range of tools available to Tuya_DAEMON users.
It is interesting to compare this version of the 'smoke detector' device with the previous version, without the use of 'core_OPENAPI'.