Skip to content

custom device _system

Marco Sillano edited this page Mar 21, 2022 · 96 revisions

SW custom device: _system

With version 2.0 the '_system' device has undergone refactoring and now is a device, in a separate flow. The goal of this SW-only custom device is to group some useful extra functionalities. Here an overview of the _system features, for details see the standard documentation.

_laststart

This _system property (and the related start_DEAMON node) is SET only one time, some seconds after a node-red restart. Used to do some delayed startup operations on custom devices or to check the devices' status.

_proxy

_This system property implements the message exchange between tuyaDAEMON instances on lan. It uses the REST interface to connect a remote tuyaDAEMON server. A map of the URLs for the existing tuyaDAMON instances is in CORE, in config 'global' node, named 'remotemap'. _name returns the user-friendly name of this tuyaDAEMON instance.

The user doesn't use directly this property, enough to extend the tuyaDAEMON standard messages so:

       {
          "remote": "ANDROID",
          "device": "switch module #1",
          "property": "switch",
          "value": "OFF"
       }

tuyastatus

The global.tuyastatus variable is the storage of all last values got from devices, structured in device.property.value, plus some pseudoDP (_t, _connected). The tuyastatus is automatically updated any GET and SET. Some _system functions allow more control over it.

  • _tuyastatus(std_cmd) Alternative and indirect access to the global.tuyastatus structure, regardless of dp capabilities. We can get:

    • the device list (if std_cmd is empty {})
    • the SCHEMA for a device, if std_cmd.property is undefined
    • to GET the last value of a property if std_cmd.value is undefined
    • an unconditioned SET (take care: potentially dangerous) if the std_cmd is full.
  • _doSCHEMA(device) Uses native SCHEMA (if available) or does a SCHEMA simulation for any device (real, virtual, fake) sending ALL GETs available (from alldevices definitions), and updating tuyastatus. Returns a list of all DPs tested.

  • _doUPDATE(NULL|real|virtual|fake) For all devices connected, does a 'doSCHEMA' command. That can fully update tuyastatus, e.g. after a startup. Returns a list of devices. This can be a good check for 'alldevices' definitions: it must run without 'warning messages.

_exec

Runs a system command and returns its output.

DB functions

Any used DB can be controlled via _system, for DB maintenance and DB data access:

  • _sqlDBlocal(SQL) allows to send a sql-string to a DB and get the answer
    • more _sqlDBxxxx properties can be user-defined for all DB used. See core.

Timer functions

The timer functions are build around the 'node-red-contrib-jsontimer'. This implementation allows to define a temporized start for any task (local or remote tuyaDAEMON standard command) using a standard command or a share. The timer itself is simple: it has only one function, to send a stored message at a specific time. The time can be defined in three ways: timeout (in ms), time (as 22:13:36.010), and datetime (unixtimestamp).

The timer doesn't offer any kind of repetitions. But it can handle many timers, identified by an 'id'.

  • _timerON ((id,) timeout:xx|time:yy|datetime:zz, alarmPayload:{<std_cmd>|<share>}) sets a new timer.
    • alarmPayload can be a standard command (more simple) or a share (more powerful).
    • id is mandatory only if you use _timerOFF else id is auto.
  • _timerOFF(id) deletes an existing timer selected by id, mandatory.
  • _timerList() gets the list of all active timers.

A timer can be used also inside a standard share, to have a delay effect on a task triggered by an event, see _system._beep_loop implementation in global.alldevices.

Use of _timerON: this command sets a timer to send a TRIGGER5000 to Tuya-cloud, 100 seconds later.

    {
          "device": "_system",
          "property": "_timerON",
          "value": {
               "timeout": 100000,        // or time|datetime
               "alarmPayload": {         // the delayed command                
                      "device": "_system",
                      "property": "_doTrigger",
                      "value": 5000
               }
         }
   }

_trgPing

(obsolete, since 2.2.0 moved to core_TRIGGER)

benchmark

Benchmarks can be done by repeatedly running a task in free-run and counting the number of runs performed by tuyaDAEMON in a given time.

Some _system properties simplify the benchmarks:

  • _zeroTask: the fastest SW only task, does nothing, and it is without any logging (no debug pad, no DB).
  • _zeroLog: like _zeroTask, but with logging (debug pad and DB).
  • _benchmark: to SET/GET the tested task (default _zeroTask) and the benchmark duration (default 10000 ms).
  • _doBenchmark: SET: trigger to execute a benchmark.

To do a benchmark, choose the task (device and property), then:

  1. To retrigger in free-run the chosen task, add to global.alldevice.&lt;device&gr;.&lt;&lt;property&gr; the share:
                    "share": [{
                            "action": [{
                                    "device": "_system",
                                    "property": "_benchmark_step"
                                }]}]

note: the _benchmark_step does is retrigger action only inside a running benchmark, so this share can be permanent (see global.alldevices._system._zeroTask and global.alldevices._system._zeroTask), or you can delete it after the benchmark.

  1. Use the _benchmark property to SET the task:
                  "payload":{
                            "device": "_system",
                            "property": "_benchmark",
                            "value" {
                                    "device":"_system",              // the chosen task GET _system._zeroTask
                                    "property":"_zeroTask",
                                    "value": if_required,            // GET/SET
                                    "timeout": 20000                 // optional, default 10000 ms
                                }}
  1. Use _doBenchmark (SET: trigger) to start the benchmark.

In my test server (i7-4777, 3.40 GHz, Win 10) I get 15300/20s for _zeroTask, 11700/20s for _zeroLog, and a good 480/20s for a GET from the tuya_bridge real device. Nevertheless, I have set very conservative limits: 1000/10s for output (and SW tasks), and 30/10s for real devices.

note on _zeroLog SET _zeroLog(value) returns the value encoded (see alldevicesnote[8]) using the default or _zeroLog.type rules: this allows to do tests changing the _zeroLog.type in alldevices.

note Also _doUPDATE, with all trace enabled, is a good stress test: if you get any warning, fine-tune global.alldevices, if you miss any message on debug pad, reduce limits

User interface

Some _system features are about the UI:

  • _toDebug(string|obj) The string|obj is printed on the debug pad by a debug node. To share results and info between tuyaDAEMON servers.
  • _toWarn(string|obj) The string|obj is printed on the debug pad by a node.warn() call. To share alarms between tuyaDAEMON servers.
  • **_play(WAV|string) ** Play a sound (WAV) or does text-to-speech function (browser dependent: set language on interface)
  • **_beep **
    Plays the short beep stored in globals.beep64 as WAV code64.
  • **_beep_loop(count, interval) ** Example of tuyaDAEMON-chain : repeats 'beep' count times, with an interval in ms.

security and recovery

A group of properties is present to help the user to build robust and fault-tolerant applications. This is one strong motivation for the tuyaDAEMON project.

Random or malicious events can cause serious problems. Here some accident scenarios:

  1. _DBase and DB_ALARM node control the MySQL connections (note: this is placed in the CORE flow).
  2. loss of remote connection: tuya-cloud is out. Also the user control from remote. Only tuyaDAEMON works. _LANnet (and the related LAN_ALARM node) are triggered by this event.
  3. local WiFi down: all devices are offline. Only the cabled LAN and devices (a siren?) can works. _WiFinet, WiFi_ALARM and _WiFiunconnected (a list of unconnected devices, includes 'disabled' devices) can handle this event.
  4. AC power off: blackout or external action? Only the UPS devices are available. Good to provide for the WiFi router, one tuyaDEAMON server, the siren, also the IP cams... _ACpower, AC_ALARM and _ACunconnected are triggered by this event.

It is now common for apartment thieves to interrupt the AC power and to use a jammer to disrupt communications. If you build your own security alarm think carefully to choose a good solution.

helper functions

These are some low-level properties that offer access to CORE functions via messages. This way allows meta-Programmation and can be useful for applications that use REST or for remote control:

  1. _doTrigger(number) Offers an alternative way to send TRIGGERs to tuya-cloud. Useful used in 'share' structures (see timer example).
  2. _toLowIN(toDev, dev-msg) The dev-msg is sent directly to the tuya-smart-device node, selected by toDev (see 'core.low_level_IN' node). To test new device functions.
  3. _toFastIN(std_msg) The standard message is sent to the 'core.fast_cmds' node to be executed.
  4. _toStdCmd(std_msg) The standard message is sent to the 'core.std_cmd' node to be executed.
  5. _toShare(share) The share structure is sent to the 'core.share_IN' node to be processed.
  6. _toLogging(out_msg) The out_msg (see 'core.logging' node) is processed like any device event.

This _system v 2.0 is now a collection of heterogeneous and basic utilities. It can be extended to meet the user's application needs. Better, it can be split into many SW-only devices, by application fields, to become specialized user's "libraries".

Clone this wiki locally