Logic manager

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. $.Vcc

  • nested fields, e.g. $.Wifi.RSSI

  • array 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)

Parameters

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

Parameters

Name

Type

Description

Required

i

String

Cycle ID

yes

cycle.start

Description

Starts a cycle

Parameters

required

Returns

nothing

Parameters

Name

Type

Description

Required

i

String

Cycle ID

yes

cycle.stop

Description

Stops a cycle

Parameters

required

Returns

nothing

Parameters

Name

Type

Description

Required

i

String

Cycle ID

yes

job.get

Description

Gets a scheduled job

Parameters

required

Returns

Scheduled job info

Parameters

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

Parameters

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