Logic manager
Contents
Logic manager is a software programmable logic controller, which allows to cope with typical automation tasks.
Functionality
Rules
A rule is a way to react to item state events, either for a particular item or for an item mask.
If an event matches condition and the previous state was out-of-condition range, the rule executes lmacro handler, a local or remote.
The handler receives additional keyword arguments:
Name |
Content |
|---|---|
source |
Event source (state + OID) |
Chillout
If a rule has chill-out time set and an event matches the rule condition, further events are ignored until chill-out time is over.
If a rule receives match-event during the chill-out time, the handler is executed right after the chill-out is over. source argument contains the last event received during the chill-out.
Cycles
A cycle is a high-performance loop-executor for a lmacro, a local or remote. The service provides cycles up to 1000Hz (interval 0.001 sec = 1ms), nevertheless cycle frequencies are usually limited to lmacro execution time (e.g. Python macros controller has the fastest execution time near 3ms for local actions).
In case of errors, an error-handler lmacro is called if defined, which gets the following args:
Error |
Arg 1 |
Arg 2 |
|---|---|---|
Cycle timeout |
cycle |
timeout |
Handler error |
lmacro |
result error as-is |
Handler timeout |
lmacro |
timeout |
Handler exec error |
exec |
BUS error code (i16) |
Cycles can be started automatically or manually, via BUS calls. E.g. to start a cycle with Python Logic Macros, use rpc_call method.
Jobs
A job is a low-performance loop or scheduled executor for a lmacro, a local or remote.
Jobs provide the same functionality as the system cron, except the smallest execution time unit is a second, plus optionally year(s) can be set.
Note
Job schedulers use local time, which may cause certain commands to be repeated/skipped if the system time goes backward/forward, when corrected or during dayling saving switches.
Parsers
Parsers allow Logic Manager to watch item values which contain structured data, extract selected fields using JSON paths and update other items with extracted values.
This is useful when a device or another service publishes a single complex payload, but automation rules should work with individual values such as voltage, RSSI, counters or nested sensor readings.
Each parser group contains source items and one or more mappings. A mapping defines the JSON path to read from the source value and the target item which receives the extracted value.
Parser groups can work in two modes:
event-driven, when source item state changes are processed as they arrive;
periodic, when source item values are re-read with a configured interval.
Both modes can be enabled together.
The source item status is copied to every parsed target item.
JSON path support covers the most typical cases:
top-level fields, e.g.
$.Vccnested fields, e.g.
$.Wifi.RSSIarray elements, e.g.
$.readings[0].v
Value mapping and transformations can also be applied before the parsed value is written to the target item. This allows, for example, converting textual states to numeric values, scaling numbers or rounding them.
Setup
Use the template EVA_DIR/share/svc-tpl/svc-tpl-controller-lm.yml:
# Logic manager programmable controller
command: svc/eva-controller-lm
bus:
path: var/bus.ipc
config:
rules: []
#- id: rule1
#oid: sensor:#
#prop: status # status, value or act (for units)
# full condition notation, can be shortened as x = -1
#condition:
#min: -1
#max: -1
#min_eq: true
#max_eq: true
#break: false # do not process further rules if mathces
#chillout_time: 10 # ignore further events, seconds
#run: lmacro:tests/sensor_down
#initial: process # process, skip, only
#block: false # block rule processing until the macro is finished
#- id: rule2
#oid: unit:#
#prop: act
#condition:
#min: 1
#run: lmacro:tests/action_started
#args:
#- 1
#- 2
#- "test"
#kwargs:
#from_rule: true
#- id: rule3
#oid: sensor:plc1/alarms
#prop: value
#condition: "x = 1"
#bit: 0 # analyze bit (value only)
#run: lmacro:tests/rule3_handler
cycles: []
#- id: cycle1
#auto_start: false
# (interval, seconds)
#interval: 0.5
# lmacro id to run
#run: lmacro:tests/cycle1_handler
# lmacro args, optional
#args:
#- 1
#- 2
#- "test"
# lmacro kwargs, optional
#kwargs:
#from_cycle: true
#error handler lmacro
#on_error: lmacro:tests/cycle1_error_handler
jobs: []
#- id: job1
# a cron-like schedule:
# second minute hour day month weekday year
#
# the year field can be omitted
# to run the task every N, use */N
#schedule: "* * * * * *"
#run: lmacro:tests/action_started
#args:
#- 1
#- 2
#- "test"
#kwargs:
#from_job: true
openers: []
# Openers provide generic opener robot logic for doors, windows etc
#- oid: unit:tests/window1 # a virtual unit, which represents a door or window
#break_on_status_error: true # break if the current state is unknown
#logic: ac # ac (AC circuit) or rdc (reversible DC circuit)
#port: # a single or multiple relay units, which handle power (+ for DC)
#- unit:relays/r1
#dport: # a single or multiple relay units, which handle direction (- for DC)
#- unit:relays/r2
#port_timeout: 2 # action timeout when switching assigned relay units
#set_state: true # set the virtual unit state after successful action
#steps: # delay (in seconds) between door/window positions, e.g. 2 steps
# for 3 possible positions
#- 5
#- 2
# tuning: 0.2 # delay (in seconds) for fully-open and fully-closed states
#warmup_close: 0.5 # motor warmup delay on close
#warmup_open: 1 # motor warmup delay on open
#ts: 1 # fully close then go to N, if N <= the field value
#te: 2 # fully open then go to N, if N >= the field value
#
parsers: []
#- config: # optional; omit for ignore_events=false, no interval (same as config: {})
# ignore_events is optional (default false). Same semantics as DB collector services:
# when true, bus-driven updates are skipped for this group; interval pull still runs if set.
#ignore_events: false
# interval is optional (seconds, float); omit or null for no periodic pull.
#interval: 5
#items:
#- oid: sensor:equipment/sensor1
# Items without a `map` still participate in pull/interval and bus flow but emit
# no parsed raw-state outputs by design (user config only).
#- oid: sensor:lab/equipment/some-light
#map:
#- path: $.Vcc
#target: sensor:light/vcc
#value_map and transform can be used
# value mapping. map "OFF" to 0, "ON" to 1
#value_map:
#"OFF": 0
#"ON": 1
#transform:
#- func: multiply # multiply the value by N
#params: [ 1000 ]
#- func: divide # divide the value by N
#params: [ 1000 ]
#- func: round # round the value to N digits after comma
#params: [ 2 ]
#- func: calc_speed # use the value as calc-speed gauge (with N seconds delta)
#params: [ 1 ]
#- func: invert # invert the value between 0/1
# #params: []
#- path: $.Wifi.RSSI
#target: sensor:light/wifi/rssi
user: nobody
Create the service using eva-shell:
eva svc create eva.controller.lm1 /opt/eva4/share/svc-tpl/svc-tpl-controller-lm.yml
or using the bus CLI client:
cd /opt/eva4
cat DEPLOY.yml | ./bin/yml2mp | \
./sbin/bus ./var/bus.ipc rpc call eva.core svc.deploy -
(see eva.core::svc.deploy for more info)
EAPI methods
See EAPI commons for the common information about the bus, types, errors and RPC calls.
action
Description |
Executes an opener unit action |
Parameters |
See Unit actions |
Returns |
See Unit actions |
cycle.get
Description |
Gets stats for a cycle |
Parameters |
required |
Returns |
Cycle info and stats (u64 counters) |
Name |
Type |
Description |
Required |
i |
String |
Cycle ID |
yes |
Return payload example:
{
"id": "cycle1",
"interval": 1.0,
"iters_err": 0,
"iters_ok": 71,
"status": "running",
"timed_out": 0
}
cycle.list
Description |
Lists cycles and their stats |
Parameters |
none |
Returns |
List of cycles info and stats (u64 counters) |
Return payload example:
[
{
"id": "cycle1",
"interval": 1.0,
"iters_err": 0,
"iters_ok": 71,
"status": "running",
"timed_out": 0
},
{
"id": "cycle2",
"interval": 1.0,
"iters_err": 0,
"iters_ok": 92,
"status": "stopped",
"timed_out": 0
}
]
cycle.reset
Description |
Resets a cycle |
Parameters |
required |
Returns |
nothing |
Name |
Type |
Description |
Required |
i |
String |
Cycle ID |
yes |
cycle.start
Description |
Starts a cycle |
Parameters |
required |
Returns |
nothing |
Name |
Type |
Description |
Required |
i |
String |
Cycle ID |
yes |
cycle.stop
Description |
Stops a cycle |
Parameters |
required |
Returns |
nothing |
Name |
Type |
Description |
Required |
i |
String |
Cycle ID |
yes |
job.get
Description |
Gets a scheduled job |
Parameters |
required |
Returns |
Scheduled job info |
Name |
Type |
Description |
Required |
i |
String |
Job ID |
yes |
Return payload example:
{
"id": "job2",
"next_launch": "2022-05-22 22:38:50 +02:00",
"run": "lmacro:tests/job2_handler"
}
job.list
Description |
Lists scheduled jobs |
Parameters |
none |
Returns |
List of scheduled jobs infos |
Return payload example:
[
{
"id": "job1",
"next_launch": "2022-05-22 21:38:50 +02:00",
"run": "lmacro:tests/job1_handler"
}
{
"id": "job2",
"next_launch": "2022-05-22 22:38:50 +02:00",
"run": "lmacro:tests/job2_handler"
}
]
kill
Description |
Attempts to terinate/cancel all actions for an opener unit |
Parameters |
See Unit actions |
Returns |
See Unit actions |
rule.get
Description |
Gets a rule |
Parameters |
required |
Returns |
Rule info |
Name |
Type |
Description |
Required |
i |
String |
Rule ID |
yes |
Return payload example:
{
"chillout_event_pending": false,
"chillout_remaining": null,
"chillout_time": null,
"id": "rule1",
"run": "lmacro:tests/temp_handler"
}
rule.list
Description |
Lists rules |
Parameters |
none |
Returns |
List of rules and their info |
Return payload example:
[
{
"chillout_event_pending": false,
"chillout_remaining": null,
"chillout_time": null,
"id": "rule1",
"run": "lmacro:tests/temp_handler"
},
{
"chillout_event_pending": false,
"chillout_remaining": null,
"chillout_time": 10.0,
"id": "rule2",
"run": "lmacro:tests/on_action"
}
]
terminate
Description |
Attempts to terminate/cancel an opener unit action |
Parameters |
See Unit actions |
Returns |
See Unit actions |