Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

In TQL an An Action is a named element that describes a unit of executable functionality.

An Action has the name modifiera name:  

Code Block
languagexml
titleAction Named Element
linenumberstrue
<Action#
Action(Name=: "RotateCameraAction", Documentation=: "Simple Action to Rotate IP-based Camera by x degrees"/> 

An Action can be defined in:

  • ThingFacet
  • AppFacet
  • Subscribe
  • Sequence
) 

An Action must describe define executable code in any Atomic Domain Languages (Workflow, FacetScript, TQL, Subscribe, Sequence and ) or any of their combinations.

NOTE: In case of ThingFacet or AppFacet an Action must start with a Workflow Language.

In case of ThingFacet an Action represents:

  • Device State Change, for example, current reading sent by a Temperature Sensor
  • Device Actuation Commands, for example, Changing the State of the device (Camera Rotation, Starting a Servo Motor, Reducing the flow of a Greenhouse Sprayer etc).

 

Code Block
languagexml
titleAction Reading RFID Value
linenumberstrue
collapsetrue
<Action name="NextRfidAction" documentation="Read next RFID tag">
  <Workflow Limit="1" Live="1" Timeout="0">
    <Task name="Main" while="true">
      <Event name="Argument" as="ActionArgument"/>
      <Invoke name="ReadId" waitFor="Argument" get="[%:Event.Argument.URL.Value:%]" StopChar="0x0D" ReadTimeout="-1" WriteTimeout="-1" RepeatDelay="1"/>
      <Output name="Result" as="ActionResult">
        <Value>
          <RFID>[%:[%:@Output:%]Invoke.ReadId.Message.Value:%]</RFID>
        </Value>
      </Output>
    </Task>
  </Workflow>
</Action>
Code Block
languagexml
titlePreset Camera
linenumberstrue
collapsetrue
<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="[%:[:AD:].Preset/no-value(Value):%]" delayAfter="PT5S"
        get="[%:[:AA:].URL.Value:%]/cgi-bin/decoder_control.cgi?[:UP:][%:amp:%]command=15[%:amp:%]sit=[%:[:AD:].Preset.Value:%]"/>
      <Output name="Result" as="ActionResult">
        <Value>
          <State> [%:[%:@Output:%]/if([:POK:]) then 'ON' else 'OFF':%]</State>
          <Preset>[%:[%:@Output:%]/if([:POK:]) then '[%:[:AD:].Preset.Value:%]' else null():%]</Preset>
        </Value>
      </Output>
    </Task>
  </Workflow>
</Action>
Code Block
languagexml
titleTake Picture From a Camera
linenumberstrue
collapsetrue
<Action name="TakePictureAction" 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>

In case of AppFacet an Action represents:

...

Code Block
languagexml
titleSend an Email
linenumberstrue
collapsetrue
<Action name="EmailAction" documentation="Send Email">
  <Workflow Limit="1" Live="1" Timeout="0">
    <Task name="Main" while="true">
      <Event name="Argument" as="ActionArgument"/>
      <Invoke name="ReadValue" waitFor="Argument" post="smtp://[%:Event.Argument.Hostname.Value:%]" Hostname="[%:Event.Argument.Hostname.Value:%]">
        <Message>
          <Value>
            <Port>[%:Event.Argument.Port.Value:%]</Port>
            <Username>[%:Event.Argument.Username.Value:%]</Username>
            <Password>[%:Event.Argument.Password.Value:%]</Password>
            <From>[%:Event.Argument.From.Value:%]</From>
            <To>[%:Event.Argument.To.Value:%]</To>
            <CC>[%:Event.Argument.CC.Value:%]</CC>
            <Subject>[%:Event.Argument.Subject.Value:%]</Subject>
            <Body>[%:Event.Argument.Body.Value:%]</Body>
            <StartTLS>[%:Event.Argument.StartTLS.Value:%]</StartTLS>
          </Value>
        </Message>
      </Invoke>
    </Task>
  </Workflow>
</Action>

 

Code Block
languagexml
titleStart Simulation by Executing External Script
linenumberstrue
collapsetrue
<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

, within one of the following elements:

NOTE: In the case of ThingFacet or AppFacet an Action must start with a Workflow.

Action is associated with attribute(s)

An Action must be associated or attached to a Model Facet 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 AppFacetmodel attribute. In ThingFacets or AppFacets, an Action is associated with an model attribute of the same ThingFacet or AppFacet using the "KnownBy" modifier as below. The associated attribute becomes an actionable attribute.

Code Block
languagexml
titleAction Named Element
linenumberstrue
<Double#
Double(Name=: "RotateValue" KnownBy="RotateCameraAction"/>

Associating Multiple Thing Actions

...

,

...

Code Block
languagexml
titleAssoicating Multiple Thing Actions
linenumberstrue
<String name="State" KnownBy="SyncImageAction,SyncPresetAction"/>
Code Block
languagexml
titleMultiple Thing Actions
linenumberstrue
collapsetrue
<!-- 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 the change of Attribute's "Known" Value:

...

"RotateCameraAction")

Please refer to <subscribe> and <sequence> for their respective action associations.

See also Associate multiple thing actions.

Action results in changes of the "Known" value(s) of any attributes

From the Action, using the output of the workflow, you can update any attributes of the ThingFacet of AppFacetmodel. Note that It is always the "Known" value of the attribute that will be updated by Actions. In this example, Action is changing the State and Image Attributesattributes.

Code Block
languagexml
titleAction Result
linenumberstrue
collapsetrue
<Output name=#
Output(name: "Result", as=: "ActionResult">):
  Value:
<Value>    State: <State>"[%:[%:@Output:%]/if([:IOK:]) then 'ON' else 'OFF':%]</State>"
    Image: <Image>"[%:[%:@Output:%]/if([:IOK:]) then Invoke/GetImage/Message/Value/text() else '/img/no-image.jpg':%]</Image>
  </Value>
</Output>

...

"

Note: the output of the workflow can update any attribute of the model. This is not limited to the actionable attribute.

Action is triggered by the modification of associated (KnownBy) attribute values

Trigger is an execution phase of an Action. Execution of an Action is asynchronous and can be triggered in any number of ways. Please refer 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:

 

ThingModels and AppModels any updates to the associated attribute(s) values will trigger the Action. This include the initialization of the attributes (i.e. when it first acquires its value). The attribute value updates can only be achieved via TQL queries, in one of the following forms: 

  • External applications using TQL queries to update the value of the attributes. This includes the following example of a Save query to instantiate the model. Here giving the attribute RFID a value of $Null( ) will trigger the Action "KnownBy" this attribute.
  • Internally TQL queries updating the value of the attributes (e.g. TQL queries can be used by models to update values of other model's attributes).

Code Block
languagexml
titleInstantiate a Device using TQL Query
linenumberstrue
collapsetrue
<Query>
#
Query:
 <Save Save(format=: "version,current">):
    <RfidReader ReaderId=RfidReader(ReaderId: "R1", URL=: "perif://">):
        <RFID value=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
languagexml
titleAction Result
linenumberstrue
<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
languagexml
titleAutomatic Action Example
linenumberstrue
collapsetrue
<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.

 

 

...

, version: "1")

See also Automatic Action trigger.