...
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
<Action Name="StartSimulatorAction" Documentation="Start the simulator"> <Workflow Limit="1" Live="1" Timeout="-1"> <Task name="Main"> <StartOsWindows>StartProcess.exe cmd.exe "/K c:\Users\Dev\Documents\atomiton\bitbucket\tqlsimulator\build\install\TQLSimulator\bin\TQLSimulator.bat local -runAsFleetEventsGen eventOptions=10"</StartOsWindows> <StartOsUnix>bash config/startupscript.sh</StartOsUnix> <StartOsMac>[:CmdOsUnix:]</StartOsMac> <StopOsWindows>TaskKill.exe /PID [%:Output.ActionArgument.currentSimulatorState/Known/text():%]</StopOsWindows> <StopOsUnix>kill [%:Output.ActionArgument.currentSimulatorState/Known/text():%]</StopOsUnix> <StopOsMac>[:CmdOsUnix:]</StopOsMac> <Event name="Argument" as="ActionArgument"/> <Invoke name="InvokeScript" waitFor="ActionArgument" skip-if="[%:Output.ActionArgument.currentSimulatorState/starts-with(Value, 'off'):%]" execute="[:Start[:OsTag:]:]"> </Invoke> <Output name="ActionResult"> <Value> <currentSimulatorState> [%:Invoke/InvokeScript/Message/Value/text():%] </currentSimulatorState> </Value> </Output> </Task> </Workflow> </Action> |
Action Association
An Action must be associated or attached to a Model Attribute. This association varies depending on where an Action is defined. Please refer to <subscribe> and <sequence> for their respective action associations.
In case of ThingFacet or AppFacet, an Action is associated with an attribute of ThingFacet or AppFacet using "KnonwByKnownBy" Modifier as below.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
<Double Name="RotateValue" KnownBy="RotateCameraAction"/> |
Action Trigger
Triggering an Action:
- Starting of an Action is asynchronous and triggered by external / internal event (change of state of a device).
An action is the specification of an executable statement and is the fundamental unit of processing or behavior in an Thing or App Model that represents some transformation in the modeled system, triggered by an external event.
An action forms an abstraction of a computational procedure which is an atomic execution and therefore completes without interruption. An action can either be completed in zero time and cannot be interrupted, once started or it can be a more complex collection of behavior that may run for a long duration. In this scenario, action may be interrupted by events, in which case, it does not run to completion. Zero time execution vs long lasting execution gets defined by the definition of the workflow.
An action of ThingFacet is a result of a device state change or intent to change the state of the device, and is realized by sending a message to an instance or modifying a value of an actionable attribute.
Action is defined as encapsulated workflow, which gets triggered on updates of actionable attributes in ThingModel and/or AppModel. Action can perform synchronous set of activities defined in the workflow.
Where can Action be used in TQL (only in ThingFacets and AppFacets?)
What is the general structure of an Action in TQL? (1 or more workflows?)
...
Associating Multiple Thing Actions
One can associate multiple thing actions to a Thingfacet Attribute. You can do this by providing comma separated list of Action names. For example,
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
<String name="State" KnownBy="SyncImageAction,SyncPresetAction"/> |
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
<!-- Actions -->
<Action Name="SyncPresetAction" Documentation="Synchronize camera state and preset">
<Workflow Limit="1" Live="1" Timeout="PT20S">
<Task Name="Main" While="true">
<Event Name="Argument" As="ActionArgument"/>
<Invoke Name="SetPreset" waitFor="Argument" skip-if="[%:[:AA:].Preset/no-value(Value):%]" delayAfter="PT5S"
get="[%:[:AA:].URL.Value:%]/cgi-bin/decoder_control.cgi?[:UP:][%:amp:%]command=15[%:amp:%]sit=[%:[:AA:].Preset.Value:%]"/>
<Output name="Result" as="ActionResult">
<Value>
<State> [%:[%:@Output:%]/if([:POK:]) then 'ON' else 'OFF':%]</State>
<Preset>[%:[%:@Output:%]/if([:POK:]) then '[%:[:AA:].Preset.Value:%]' else null():%]</Preset>
</Value>
</Output>
</Task>
</Workflow>
</Action>
<Action name="SyncImageAction" documentation="Synchronize camera state and snapshot image">
<Workflow Limit="1" Live="1" Timeout="PT10S">
<Task name="Main" while="true">
<Event name="Argument" as="ActionArgument"/>
<Invoke name="GetImage" waitFor="Argument" delay="PT1S" get="[%:[:AA:].URL.Value:%]/cgi-bin/video_snapshot.cgi?[:UP:]"/>
<Output name="Result" as="ActionResult">
<Value>
<State>[%:[%:@Output:%]/if([:IOK:]) then 'ON' else 'OFF':%]</State>
<Image>[%:[%:@Output:%]/if([:IOK:]) then Invoke/GetImage/Message/Value/text() else '/img/no-image.jpg':%]</Image>
</Value>
</Output>
</Task>
</Workflow>
</Action> |
Here you can see two actions: SyncPresetAction and SyncImageActon which deal with camera preset and snapshot image respectively. Both also update camera state.
In case when multiple attributes are updated, the system will select minimum number of actions with highest preference to perform the update[s]. That is, if only state needs to be updated, the engine will use SyncImageAction action and when both state and preset need updates, SyncPresetAction will be used.
Action Results in Change of Attribute's "Known" Value:
In this example, Action is changing State and Image Attributes.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
<Output name="Result" as="ActionResult">
<Value>
<State>[%:[%:@Output:%]/if([:IOK:]) then 'ON' else 'OFF':%]</State>
<Image>[%:[%:@Output:%]/if([:IOK:]) then Invoke/GetImage/Message/Value/text() else '/img/no-image.jpg':%]</Image>
</Value>
</Output> |
Action Trigger
Trigger is an execution phase of an Action. Execution of an Action is asynchronous and can be triggered in any number of ways. Please to to <subscribe> and <sequence> for their respective action triggers.
In case of ThingFacet / AppFacet Action can be triggered as a result of :
- External devices (sensors / actuators) changing their state
- Internal Models changing the state of Attributes using TQL Queries
- External applications using TQL Queries. For example, to Instantiate a Device, we use a TQL Query:
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
<Query>
<Save format="version,current">
<RfidReader ReaderId="R1" URL="perif://">
<RFID value="$Null()" version="1"/>
</RfidReader>
</Save>
</Query> |
Automatic Action Trigger
In case of certain devices - like sensors which send data continuously, one can set the trigger of action execution to happen automatically using update="auto" attribute at the time of Action association. For example:
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
<Integer Name="SensorValue" update="auto" KnownBy="PhidgetSensorAction"/> |
Normally, all thing updates are initiated by their correspondent [cached] model instance update. I.e. you set Image attribute of camera model to null (or other value) in order to initiate image update workflow which is normally a request/response exchange with the camera. Some devices, however, do not follow this communication pattern. Instead, they need to be put in a waiting state and then will “spontaneously” generate an event.
Code Block | ||||||
---|---|---|---|---|---|---|
| ||||||
<Action name="RFIDReaderAction" documentation="Read RFID tag and update the instance">
<Workflow Limit="1" Live="1" Timeout="-1">
<Task name="Main" while="true">
<Event name="Argument" as="ActionArgument"/>
<Invoke name="ReadId" waitFor="Argument" get="[%:Event.Argument.URL.Value:%]"/>
<Output name="Result" as="ActionResult">
<Value>
<RFID>[%:[%:@Output:%]Invoke.ReadId.Message.Value:%]</RFID>
</Value>
</Output>
</Task>
</Workflow>
</Action> |
For example, if you initiate an RFID reader in standard fashion, it will wait for ONE reader event, update the known value of its model instance and stop. You’ll need to update its instance again to make it wait for the next event and so on. Update=”auto” allows to automate such workflow re-activation. Every time it processes an event, thing workflow will automatically restart itself to be ready for the next device event. This way you can have a continuous stream of events from the device without explicit request/re-activation after each one.
Note that using this option without any device throttling may result in continuous infinite loop of device updates, so it is most suitable for the devices which normally only generate events in response to external actions (e.g. detecting a RFID tag in reader’s proximity). That is, RFID workflow DOES NOT solicit device events by itself, it only listens for them. In case of IP camera snapshot, the situation would be very different because camera workflow actually asks the camera to produce one, so if you automatically restart it then it will ask again and again and again. While this may be a desirable behavior, caution must be exercised to limit the rate of such requests (for example, you can put a 1 sec delay on the get snapshot invoke to ensure that it will always wait at least a second before asking for the next snapshot).
Note that streaming of events / message from devices normally happens via Protocol Handler that is invoked. Protocol Handlers may provide additional parameter to facilitate throttling.
Jira Legacy | ||||||||
---|---|---|---|---|---|---|---|---|
|