Reactor Services

Reactor Services

[return to the Reactor main page]

Actions

A ReactorSensor acts like a "security sensor," implementing the majority of Vera's urn:micasaverde-com:serviceId:SecuritySensor1 service. The only action defined by this service is "SetArmed," which takes a single parameter ("newArmedValue", "0" or "1"), to set or clear the arming state of the sensor.

In addition, ReactorSensors implement a few actions of their own. These provide additional control over the sensor's behavior. All of these actions are in the urn:toggledbits-com:serviceId:ReactorSensor service.

SetEnabled

The "SetEnabled" action takes a single parameter ("newEnabledValue", 0 or 1) to set whether the ReactorSensor is enabled or not. When disabled, a ReactorSensor stops updating and evaluating conditions, and will not change its "Tripped" state.

luup.call_action( "urn:toggledbits-com:serviceId:ReactorSensor", "SetEnabled", { "newEnabledValue": 0 }, device_number )

Reset

The "Reset" action takes no parameters, and resets the "Tripped" state of the sensor until the next state change and condition evaluation occurs.

luup.call_action( "urn:toggledbits-com:serviceId:ReactorSensor", "Reset", { }, device_number )

Trip

The "Trip" action takes no parameters, and sets the "Tripped" state of the sensor (to true) until the next condition evaluation and state change occurs.

luup.call_action( "urn:toggledbits-com:serviceId:ReactorSensor", "Trip", { }, device_number )

Restart

The "Restart" action, which takes no parameters, restarts the ReactorSensor (without reloading Luup). If conditions are changed to introduce new devices/services, the sensor will not know to watch them until it is reset.

luup.call_action( "urn:toggledbits-com:serviceId:ReactorSensor", "Restart", { }, device_number )

ResetRuntime

The "ResetRuntime" action, which takes no parameters, resets the "Runtime" and "TripCount" accumulators, and resets "RuntimeSince" (see below).

luup.call_action( "urn:toggledbits-com:serviceId:ReactorSensor", "ResetRuntime", { }, device_number )

RunScene

The "RunScene" action is an analog to Vera's action of the same name, which runs a scene. When Reactor's RunScene is used, you get the benefits of Reactor's tracking of scene progress, and continuation of delayed scene groups across Luup reloads and reboots. That is, if Luup restarts, or Vera reboots due to a crash or power failure/restore, Reactor will resume running any delayed scene groups, on schedule (or immediately, in correct order, if the scheduled time passed during the event).

luup.call_action( "urn:toggledbits-com:serviceId:Reactor", "RunScene", { SceneNum=15 }, reactor_master_device_number )

You will note that the above RunScene action call is very similar to the Vera-native call, with two notable exceptions: (1) the service ID is different, and (2) the device number must be that of Reactor (rather than 0). It is intended to be as direct a replacement as possible.

Reactor's RunScene action allows the SceneNum parameter to be a number, in which case it is the number of the scene, or a scene name. If a name is given, Reactor will use a case-insensitive match to find it, but it must otherwise match exactly. That is, if SceneNum is given as "My Scene" it will match "MY SCENE" and "My Scene" and "my scene" but not "myscene" (missing space between words) or "my scene 1" (extra characters).

Reactor's RunScene action will honor scene Lua wiht the standard Luup behavior: if a scene contains Lua, it will be run first. The return value of the Lua is expected to be a boolean, true or false, indicating if the remainder of the scene should be run (i.e. if true is returned by the scene Lua, the scene activity groups will be run, otherwise, they are skipped and the scene run is aborted). An extension to the standard Luup scene Lua behavior is that two variables, named reactor_device and reactor_ext_arg, will be in scope (non-nil). The reactor_device is the device number of the Reactor Sensor or Reactor that is causing the scene to run. The reactor_ext_arg is the value of the externalArgument option, if given (nil otherwise), further described below. Best practice for the use of these variables should include a test for their existence (i.e. whether they are nil or not); when scene Lua is run by a facility other than Reactor, they will not exist.

Reactor's RunScene also takes an additional "Options" argument, if you want to pass it. The sample below shows how the options are used. Currently, there is only one available option: stopPriorScenes and externalArgument.

The stopPriorScenes option controls whether the current task list of running scenes is cleared before starting the new scene, or if the new scene is simply added to the list. By default (stopPriorScenes=false), Reactor will run every scene you ask it to (i.e. just add the new scene to its list of tasks), so if you call RunScene with 10 different scenes, Reactor will run all 10 scenes, including all their delayed activity groups. If you set the stopPriorScenes action to true, Reactor will stop execution of any and all prior scenes you've asked it to run, thus after such an action, the only scene running will be that requested in the last call.

luup.call_action( "urn:toggledbits-com:serviceId:Reactor", "RunScene", { SceneNum=15, Options={ stopPriorScenes=true } }, reactor_device_number )

The externalArgument option, if provided, must be a string (only). This string will be passed into the scene Lua as a variable named reactor_ext_arg. This allows you to pass data into a scene for its execution.

Here is sample scene Lua:

if reactor_ext_arg ~= nil then
    luup.log("I am a scene being run by Reactor! My name is " .. reactor_ext_arg)
else
    luup,log("I am a scene being run by Vera's default scene runner.")
end
return true

If the above code is run by the following action call:

luup.call_action( "urn:toggledbits-com:serviceId:Reactor", "RunScene", { SceneNum=15, Options={ externalArgument="Boris" } }, reactor_device_number )

...then the logged message will be "I am a scene being run by Reactor! My name is Boris". If the same scene is run using the standard Luup/Vera scene action:

luup.call_action( "urn:micasaverde-com:serviceId:HomeAutomationGateway1", "RunScene", { SceneNum=15 }, 0 )

....then the logged message will be "I am a scene being run by Vera's default scene runner."

AddSensor

The "AddSensor" action (in service urn:toggledbits-com:serviceId:Reactor), which takes no parameters, creates a new ReactorSensor. This always causes a Luup reload (part of the process of creating a child device in Luup). It is not normally called directly--this action can be performed by using the "Add Sensor" button the Reactor root device's control panel.

State Variables

A ReactorSensor acts like a "security sensor," implementing the majority of Vera's urn:micasaverde-com:serviceId:SecuritySensor1 service. The state variables "Armed," "Tripped," "ArmedTripped," "LastTrip," and "AutoUntrip" have their usual meanings and applications for this service.

ReactorSensor's own state variables serve primarily two purposes: provide operational data that can be used externally, or modify behavior of the ReactorSensor. While those that provide data are generally safe to play with, those that modify behavior can have serious performance consequences, as the default behaviors of Reactor are considered "optimized" for the best balance of functionality and performance/stability. Altering Reactor's behaviors can have serious consequences, up to and including increasing Luup reloads and system crashes, so if you think you need to modify any of those variables, feel free to contact me and consult about your application--I'll be happy to guide you on the best way to meet your objectives.

Except as otherwise indicated below, these variables live in the urn:toggledbits-com:serviceId:ReactorSensor service.

Expression Results (Multiple State Variables)

When a ReactorSensor uses expressions, it stores two state variables for each expression, one with the same name as the variable name given when creating the expression, and the error with that name and "_Error" appending. The former contains the most recent value of the expression evaluation (i.e. what the expression returned), while the latter contains an error message resulting from the evaluation. For example, if one creates an expression with variable name "TempC", there will be a state variable named "TempC" that contains the expression result, and a state variable named "TempC_Error" that contains any error message from the expression evaluation.

The values are associated with the urn:toggledbits-com:serviceId:ReactorValues service, so if you use these variables in Lua, Luup HTTP requests, or other facilities that require you to specify the service ID, make sure you are using the right one.

TripCount

TripCount increments on a ReactorSensor each time it trips. It may be handy for graphing or other analysis of how often conditions are met. It can be reset by writing 0 to it directly, or by using the ResetRuntime action.

Runtime

Runtime accrues the total time (in seconds) that a ReactorSensor has been tripped, which may be handy for graphing or other analysis. It can be reset by writing 0 to it directly, or by using the ResetRuntime action.

RuntimeSince

The RuntimeSince state variable contains a timestamp at which TripCount and Runtime were last reset by the ResetRuntime action.

LastReset

Luup maintains a "LastTrip" state variable (in service urn:micasaverde-com:serviceId:SecuritySensor1) that keeps the (Unix) timestamp of the last trip event, but there is no corresponding variable in that service for the time of the last reset. ReactorSensors therefore create this variable (in their own service, not Luup's) for this purpose, should you need it.

MaxUpdateRate/MaxChangeRate

"MaxUpdateRate" and "MaxChangeRate" control the pace of updates a ReactorSensor is allowed to set. The "MaxUpdateRate" is the maximum number of updates (per minute) that the sensor will perform (an update is a re-evaluation of conditions in response to device state changes in those conditions), and defaults to 30. The "MaxChangeRate" is the maximum number of tripped-state changes the sensor is allowed per minute (default: 5). If the sensor exceeds either of these two parameters, it self-throttles and stops updating for a brief period. This is meant to prevent a defective or misbehaving device from driving Reactor crazy, and subsequently Reactor driving the system crazy (high CPU utilization, reduced UI and event performance, crashes, etc.). It also is effective at preventing loops in your logic from taking your system down (i.e. you make a ReactorSensor A that is conditioned on a ReactorSensor B tripping, and you then condition B on A tripping as well--you've created a loop that would cause the two sensors to just trip and untrip each other at machine speed).

ContinuousTimer

Reactor relies on Luup's variable watch mechanism to trigger immediately when a device/service variable changes. However, not all service variables cause an immediate trigger event, and whether or not they do is service-definition-dependent, and therefore dependent entirely on the plugin-author's discretion (if the service being tested is part of another plugin, e.g. Sonos, DelayLight, AltHue, etc.) or Vera (for "native" devices). If the service variable isn't watch-capable, Reactor has no way to be notified when it changes (the "watch" that Reactor puts on it will simply have no effect). In that case, the only way for Reactor to see changes in the variable is to poll it (periodically query for the value). Setting "ContinuousTimer" to 1 accomplishes this--Reactor will refetch all condition values and re-evaluate all conditions every minute, unconditionally. Note that this applies to all values and all conditions within the ReactorSensor for which ContinuousTimer is set. The performance impact, however, is usually negligible (you'd have to make some pretty long and complex conditions to make a detectable dent there).

Retrigger

The "Retrigger" state variable (default: 0) tells a ReactorSensor whether it should signal Tripped every time the evaluation of a condition group is true, or only the first time the evaluation becomes true. Because Reactor is generally edge-driven for devices (it responds to device changes immediately), the default value of 0 is usually the correct choice and this value usually should not be changed. When changed, it will, for example, cause a scene triggered by the ReactorSensor to run multiple times, and this may not be (usually is not) desirable, and could have serious performance consequences if not approached carefully. Please contact the author for consultation before setting this value to anything other than the default 0.

It is important that time-based and "House Mode" conditions not be used in a ReactorSensor that has Retrigger set to 1. The reason for this is that house mode must be polled (Reactor polls it every minute), and time conditions can be polled every minute as well depending on structure, and this result in a lot of retriggers/retrips. To work around this, move any time-based or house mode conditions out to separate ReactorSensor (that does not/must not have Retrigger=1), as test that ReactorSensor rather than time or house mode directly. Contact me if you're confused.

[return to the Reactor main page]