Universal Controller

EVA Universal Controller (UC) is a control and monitoring subsystem.

It should be installed if you actually want to control something. UC is controlled via UC EI web interface or eva uc (uc-cmd) console application. Additionally, it can be integrated into other subsystems and third-party programs using UC API.

Universal Controller subsystem

You may use Universal Controller independently or integrate it with other EVA subsystems.

Units receive control actions, the controller forms them into queues and executes them using external scripts. If necessary, it terminates the current script and keeps the command history.

Additionally, Universal Controller collects data from the connected items using active and passive status updates.

Universal Controller can control equipment directly and/or act as a gateway for other local controllers.

Item status and values are stored in the local database. Other subsystems or third-party programs can read them using UC API.

Units and sensors are controlled via UC EI interface, configured via UC API. States are controlled and updated using drivers and item scripts.

All changes of item status, current control commands, and progress logs are sent to the notification system.


EVA is a real-time system. Being one of its essential components, UC also follows this rule. The value of poll delay is set in configuration in seconds (milliseconds using dot), e.g. 0.01.

The value of POLL DELAY means that all timeouts and events in the system should fulfill their functions for not more than TIME_SET + POLL DELAY.

Reducing POLL DELAY will increase the CPU load on the server; in turn, if increased, the UC reaction time will be longer. Recommended values: 0.1 for home and office, 0.01 and less - for industrial applications.

The optimum value of POLL DELAY for UC can be set via eva sfa, or by manually calling UC API functions and comparing reaction/execution time of the commands.

The minimum value of POLL DELAY is 0.001 (1 millisecond).

config/uc/main registry key

config/uc/main registry key contains the controller configuration.

  # system poll delay
  polldelay: 0.01
  # pid file
  pid-file: var/uc.pid
  # log file
  log-file: log/uc.log
  # custom primary log format
  #log-format: '{ "loggerName":"%(name)s", "timestamp":"%(asctime)s", "pathName":"%(pathname)s", "logRecordCreationTime":"%(created)f", "functionName":"%(funcName)s", "levelNo":"%(levelno)s", "lineNo":"%(lineno)d", "time":"%(msecs)d", "levelName":"%(levelname)s", "message":"%(message)s" }'
  # logging to local syslog
  #syslog: true
  # logging to non-standard (/dev/log) local syslog socket
  #syslog: /var/run/syslog
  # logging to remote syslog
  #syslog: hostname:514
  # custom syslog format
  #syslog-format: 'EVA: { "loggerName":"%(name)s", "timestamp":"%(asctime)s", "pathName":"%(pathname)s", "logRecordCreationTime":"%(created)f", "functionName":"%(funcName)s", "levelNo":"%(levelno)s", "lineNo":"%(lineno)d", "time":"%(msecs)d", "levelName":"%(levelname)s", "message":"%(message)s" }'
  # db updates - instant, manual or on-exit
  db-update: instant
  db-file: runtime/db/uc.db
  # use registry to keep states
  #state-to-registry: true
  # use MySQL instead of SQLite
  #db: mysql+pymysql://user:password@localhost/dbname
  # user db file, default = db-file
  # one user db may be used by multiple controllers simultaneously
  #userdb-file: runtime/db/users.db
  # use MySQL instead of SQLite
  #userdb: mysql+pymysql://user:password@localhost/dbname
  # launch external script/program when user is created/got new
  # password/destroyed. additional arguments:
  #    1) create | set_password | destroy
  #    2) user
  #    3) password (for create and set_password operations)
  #user-hook: "/opt/eva/xbin/htpasswd.sh /opt/eva/etc/htpasswd"
  # keep action history in seconds
  keep-action-history: 86400
  # action cleaner interval, in seconds
  action-cleaner-interval: 60
  # keep memory log in seconds
  keep-logmem: 86400
  # minimal log level
  #logging-level: warning
  # keep extended API call log in user db in seconds (0 = disable logging)
  #keep-api-log: 0
  # notify states on start
  notify-on-start: true
  # debug mode
  debug: false
  # log code tracebacks
  #show-traceback: true
  # create crash dump on critical errors
  dump-on-critical: true
  # stop server on critical errors (will be restarted via safe-run)
  # always - stop on all critical errors
  # core - core errors only (ignore driver critical errors)
  # false - don't stop
  stop-on-critical: always
  # default timeout
  timeout: 5
  # default suicide timeout (kill -KILL process on shutdown)
  #suicide-timeout: 30
  # primary thread pool, min workers. comment to pre-spawn all workers
  #pool-min-size: 0
  # primary thread pool, max workers. comment to use automatic value (nCPUs * 5)
  #pool-max-size: 100
  # reactor thread pool size (used by Modbus slave and some utility workers)
  #reactor-thread-pool: 15
  # exec commands before/after config/db save,
  # e.g. mount -o remount,rw / (then back to ro)
  #exec-before-save: "mount -o remount,rw /"
  #exec-after-save: "mount -o remount,ro /"
  # default mqtt notifier for updates for new items
  #mqtt-update-default: "eva_1:2"
  # auto-save created items
  auto-save: true
  # user authentication via MS Active Directory
  #host: ad.yourdomain.com
  #domain: yourdomain.com
  #key-prefix: ""
  #ou: EVA
  #ca: /path/to/ca-file.crt
  # cache credentials for the specified time (seconds)
  # default: 86400 (1 day), 0 to disable caching
  #cache-time: 86400
  # allow UPnP discovery of this controller
  # enable remote file management functions
  file-management: true
  # allow entering setup mode (true for 60 sec or int for seconds)
  setup-mode: true
  # allow rpvt
  rpvt: false
  # web api listen on IP/port
  #ssl-module: builtin # or pyopenssl
  #ssl-cert: test.crt
  #ssl-key: test.key
  #ssl-chain: test.pam
  # session timeout, set to non-zero to enable API session tokens
  session-timeout: 3600
  # session tokens will expire even if active requests are received
  #session-no-prolong: true
  # server thread pool
  #thread-pool: 15
  # disable UC EI
  #ei-enabled: false
  # use frontend X-Real-IP header to get client real IP address
  #x-real-ip: true
  # override real ip header name
  #real-ip-header: X-IP
  # snmp trap handler, default community is eva
  community: eva
  # hosts, allowed to send snmp traps
  # hosts, allowed to send UDP commands
# modbus slave configuration
# modbus slave memory space size: 10000 registers (starting from 0) for each
# type (holding, input, coils, discrete inputs)
#- proto: tcp # udp
#  unit: "0x01"
#  listen:
# framer for serial: rtu, ascii or binary
#- proto: rtu
#  unit: "0x01"
#  listen: /dev/ttyS0:9600:8:N:1
# dp1:
#   cmd: /opt/dp/datapuller1 -c /opt/dp/config.yml
#   timeout: 10 # override default timeout
#   event-timeout: 60 # restart if no events within specified interval
# dp2:
#   cmd: /opt/dp2/datapuller2
# dp3:
#   cmd: datapuller3 -c /etc/dp3.ini

Custom variables

Custom variables can be changed while the server is running via Common methods as well as eva uc cvar_get and cvar_set commands.

For example, let’s create a variable:

eva uc cvar set RELAY1_CMD "snmpset -v1 -c private ."

After UC is started, it will become available for system environment, and unit management script on the port 2 of the given relay will be the following:

${RELAY1_CMD}.1.2.0 i $2

It is possible to assign different values for the variables used for different object groups with the same names, e.g. group1/VAR1, group2/VAR1 etc. In this case the variable will be available only for the specified group.

Action queues

All the unit control actions are queued right after they’re created. Item status update actions are not queued and just run in accordance with the set intervals.

Before execution, the control action is placed in two queues:

  • global queue for all actions

  • certain unit queue

All actions have their “priority” set when they are generated. The default priority is 100. The lower means the higher priority of queued action execution.

Queued action can have the following status:

  • created action has just been created and has not been queued yet

  • pending the action is placed in the global queue. The previous action status, as well as this one, are rarely found because UC API waits for the command to be placed in the queue of a certain unit and then returns the result

  • queued the action has already passed the global queue and is now waiting to be executed in the queue of a certain unit

  • refused unit rejected the action execution because of the item configuration value action_enabled=False

  • dead API failed to wait until the action is placed to the queue of a certain unit and, therefore, marked it as “dead”. Virtually, such status clearly indicates that server is seriously overloaded

  • canceled the command is canceled either from the outside or due to either unit already running the other action (in case action_queue=0 and queue is disabled) or the unit has got new action to execute and action_queue=2 (cancel and terminate the pending actions after getting a new one)

  • ignored the unit rejected the action execution, because its status/value are the same as requested to be changed to, and action_always_exec=False

  • running the action is being executed

  • failed the controller failed to execute the command

  • terminated the controller terminated the action execution due to timeout or by the external request

  • completed the action finished successfully

Startup and shutdown

To manage UC controller server, use:

  • eva uc server start start UC server

  • eva uc server stop stop UC server

  • eva uc server restart restart UC server

  • eva uc server reload restart controller only (without watchdogs)

The controller startup/shutdown is also performed by ./sbin/eva-control which is configured during the system setup.