Versions Compared

Key

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

Key Concepts

tip
Tip
iconfalse
 Related docs
Model-to-Model SubscriptionPhidget Protocol Handler Type
Device initialization Composit
attributesDevice actuation 
FacetScript  

 

iconfalse
 Related docsModel-to-Model Subscription Type Composit attributes FacetScript 

 

Background

Hardware

 

Hardware Setup

In order to run the tutorial, you need to set up the hardware. You can find detailed instructions here.

Write a ThingFacet, Workflow and Device Logic (Message Transformation)

Write a ThingFacet 

To abstract the interactions with the phidget servo motor setup in the previous section, we create a PhidgetServoFacet ThingFacet.  

Expand
titleThingFacet
Info Include PageThingFacetsThingFacets

Go to page

 

As described in writing ThingFacet section there are two kinds of attributes that must be added to a ThingFacet.

  • Attributes that store Protocol Specific Parameters
  • Attributes that are required to Control a Device (Actuator) OR Receive Data from a Device (Sensor).

For the purpose of this tutorial we have protocol specific parameters as:

  • Protocol URL
  • Device Interface
  • Device Type

We will be controlling the Servo Motor by changing the Angle.

  • ServoAngle

Code Block
languagexml
titlePhidgetServoFacet Attributes
linenumberstrue
<ThingFacet Name="PhidgetServoFacet">
  <String Name="ServoProtocolURL" Default="phid://"/>
  <String Name="DeviceInterfaceIndex"/>
  <String Name="PhidgetDeviceType"/>
  <Integer Name="ServoAngle"/>
</ThingFacet>

Write a Action with Workflow

The next step in ThingFacet is writing a Action which contains a workflow responsible for making external protocol specific call and store the output in the appropriate ThingFacet attribute.  An important decision while writing Action is correct protocol selection. See the /wiki/spaces/TQLDocs/pages/1179871 in the Working with Things section. For Phidget Servo Motor we need the phid:// protocol handler which is part of the TQLEngine.

1. Write an Action name as PhidgetServoAction

Go to page

Code Block
languagexml
titleSerialReadAction
linenumberstrue
<ThingFacet Name="PhidgetServoFacet">
	...
	<Action Name="PhidgetServoAction" Documentation="Control Servo Motor">
		...
	</Action>
</ThingFacet>
Expand
titleAction
Info
Include Page
ActionsActions

 

2. Create a Workflow within the Action, with one single continuous running Task and waiting for the Event with its ActionArgument.

Go to page

Go to page

</ThingFacet>
Expand
titleWorkflow
Info
Include Page
WorkflowsWorkflows
Expand
titleWorkflow structure
Info
Include Page
Structure of a workflowStructure of a workflow

 

2. Create a Workflow within the Action, with one single continuous running Task and waiting for the Event with its ActionArgument.

Code Block
languagexml
titleWorkflow
linenumberstrue
<Action Name="PhidgetServoAction">
	<Workflow Limit="1" Live="1" Timeout="-1">
    	<Task name="Main" while="true">
        	<Event name="Argument" as="ActionArgument"/>
			...
    	</Task>
	</Workflow>
</Action>

Here we used three modifiers for this workflow. Limit = "1" means there can be at most one instance of this workflow waiting. Live = "1" means there can be at most one instance of this workflow running. Timeout ="-1" means this workflow will never be timed out. We used a modifier while = "true" with the Task to make the workflow running in a continuous loop, because it needs to run repeatedly, not just once. For more details, refer to workflow modifiers and the lifecycle of a workflow.

The task will be activated by the event handler Event called ActionArgument. "ActionArgument" is the event generated whenever the attribute(s) associated with this Action is modified (See Associate Action with a ThingFacet Attribute). ActionArgument carries all the current values of the ThingFacet attributes, which can be used in the task if needed.

Expand
titleActionArgument
Info Include PageActionArgumentActionArgumentGo to page

3. Invoke Phid call: Phid supports Get and Post methods. For the Phidget Servo Motor we use method Post to actuate the servo. The parameters required Phid are passed as part of <Message> and <Value>. More details of the phid:// are here in the Working with Things Section.

Code Block
languagexml
titleInvoke Phidget Protocol Handler
linenumberstrue
<Invoke name="ReadValue" waitFor="Argument" post="[%:Event.Argument.ServoProtocolURL.Value:%]" 
        SerialNumber="[%:Event.Argument.SensorInterfaceIndex.Value:%]"
        DeviceType="[%:Event.Argument.PhidgetDeviceType.Value:%]">
  <Message>
    <Value>
      <ServoAngle>
        [%:Event.Argument.ServoAngle.Value:%]
      </ServoAngle>
    </Value>
  </Message>
</Invoke>

Here Invoke gets the attribute values that the Event ActionArgument (or Argument) carries. It uses them as the parameter values for the Phid by substitution. For example, 

Code Block
languagexml
titleMessage parsing using TP and XPath
<ServoAngle>[%:Event.Argument.ServoAngle.Value:%]</ServoAngle>

means replacing the value of Message.Value.ServoAngle with the value of Event.Argument.ServoAngle.Value.

Value substitution (rather than assignment) is very common in TQL, given that it is a declarative language. The notation [%: is part of the /wiki/spaces/TEACH/pages/21170773. More details on /wiki/spaces/TEACH/pages/21170773 can be found in the Developer's Guide.

4. Process the message received from the Protocol Handler. It simply returns the Angle that is set on the device.

Code Block
languagexml
titleMessage parsing using TP and XPath
<Output name="Result" as="ActionResult">
  <Value>
    <ServoAngle>
      [%:[%:@Output:%]Invoke.ReadValue.Message.Value/number():%]
    </ServoAngle>
    <Log Message="====Phidget Servo Angle ==== [%:[%:@Output:%]Invoke.ReadValue.Message.Value:%]"/>
  </Value>
</Output>

Here we used an XPath statement to convert String returned by Phid protocol handler to number.  Alternatively, you can use Javascript. An example of using JavaScript for message processing within an Action can be found in another tutorial here.

We used a TP notation "@" in @Outupt. It means substitution should not happen before processing is completed - means should be replaced at the end of the process. More details on /wiki/spaces/TEACH/pages/21170773 can be found in the Developer's Guide.

Associate Action with a ThingFacet Attribute

We will now have to associate a ThingFacet Attribute (ServoAngle) with the Action using the KnownBy modifier. When ServoAngle is "KnownBy" PhidgetServoAction, any ServoAngle value changes will activate the PhidgetServoAction.

Actionable attributes

Go to page

Code Block
languagexml
titleAttribute ServoAngle
linenumberstrue
<ThingFacet Name="PhidgetServoFacet">
	...
	<Integer Name="ServoAngle" KnownBy="PhidgetServoAction" />
</ThingFacet>
Expand
title
Info
Include Page
Actionable attributesActionable attributes

Combining ThingFacet with a ThingModel

Finally, in order to use ThingFacet we have to combine it with a ThingModel. We define ThingModel to contain only a unique system identifier.

Go to page

Go to page
Code Block
languagexml
titleThingModel PhidgetServoModel
linenumberstrue
<ThingModel Name="PhidgetServoModel" Combines="PhidgetServoFacet">
  <Sid Name="PhidServoId"/>
</ThingModel>
Expand
titleModels
Info
Include Page
ModelsModels
Expand
titleThingModels
Info
Include Page
ThingModelsThingModels

 

PhidgetServoModel ThingModel "combines"  with PhidgetServoFacet. PhidgetServoModel will inherit all the attributes from PhidgetServoFacet, in addition to its own attributes. The ThingFacet PhidgetServoFacet hence serves as a reusable component.

More details on the use of "combines" can be found here. Information on Sid cab be found here.

Deploy and test via queries and subscriptions

Export, import and deploy

Once the models are built in a TQLStudio project, you can export the project. URL of the Zip file containing the content of your project will be sent over to your email account. Once you have downloaded the engine – launch the TQLEngine User Interface in the browser and select Import Project. You can copy the URL from Export Project Email and hit import button. Go to ThingSpaces and Deploy the project.

Instantiation

First initialize the device:

Code Block
languagexml
titleServo Motor instantiation
linenumberstrue
<Query>
  <DeleteAll>
    <PhidgetServoModel>
      <PhidServoId ne=""/>
    </PhidgetServoModel>
  </DeleteAll>
  <Save format="version,current">
    <PhidgetServoModel>
      <ServoProtocolURL>phid://</ServoProtocolURL>
      <PhidgetDeviceType>PhidgetAdvancedServo</PhidgetDeviceType>
      <DeviceInterfaceIndex>0</DeviceInterfaceIndex>
      <ServoAngle>110</ServoAngle>
    </PhidgetServoModel>
  </Save>
</Query>

Query and subscription

Get Detail Information about PhidgetServoModel

Code Block
languagexml
titleFind PhidgetServoModel Query
linenumberstrue
<Query>
  <Find format="all">
    <PhidgetServoModel>
      <PhidServoId ne="" />
    </PhidgetServoModel>
  </Find>
</Query>

You will see the result from as follows:

Code Block
languagexml
titleFind PhidgetServoModel Query Result
linenumberstrue
collapsetrue
<Find Status="Success" Format="all">
  <Result>
    <PhidgetServoModel QName="Atomiton.ServoMotors.PhidgetServoModel">
      <PhidServoId>KM2OBPQVAAAAUAABA5GUNPZI</PhidServoId>
      <PhidgetDeviceType Value="PhidgetAdvancedServo" Known="PhidgetAdvancedServo" Version="1" Timestamp="1456881057303" DateTime="2016-03-01 17:10:57.303"
        QName="Atomiton.ServoMotors.PhidgetServoModel.PhidgetDeviceType" FName="PhidgetDeviceType"/>
      <ServoProtocolURL Value="phid://" Known="phid://" Version="1" Timestamp="1456881057301" DateTime="2016-03-01 17:10:57.301"
        QName="Atomiton.ServoMotors.PhidgetServoModel.ServoProtocolURL" FName="ServoProtocolURL"/>
      <DeviceInterfaceIndex Value="0" Known="0" Version="1" Timestamp="1456881057302" DateTime="2016-03-01 17:10:57.302"
        QName="Atomiton.ServoMotors.PhidgetServoModel.DeviceInterfaceIndex" FName="DeviceInterfaceIndex"/>
      <ServoAngle Value="110" Known="110" Version="1" Timestamp="1456881057303" DateTime="2016-03-01 17:10:57.303" QName="Atomiton.ServoMotors.PhidgetServoModel.ServoAngle"
        FName="ServoAngle"/>
    </PhidgetServoModel>
  </Result>
</Find>

 

Expand
titleQueries
Info

Include Page
Queries
Queries

Go to page

 

In case of Actuators we may not need Subscription to updates.
The full content of the code is here.

 

Code Block
languagexml
titlePhidgetMotor Complete Model
linenumberstrue
collapsetrue
<Namespace Name="Atomiton">
  <Domain Name="ServoMotors">
    <ThingFacet Name="PhidgetServoFacet">
      <String Name="ServoProtocolURL" Default="phid://" />
      <String Name="DeviceInterfaceIndex" />
      <String Name="PhidgetDeviceType" />
      <Integer Name="ServoAngle" KnownBy="PhidgetServoAction" />
      <Action Name="PhidgetServoAction" Documentation="Control servo motor">
        <Workflow Limit="1" Live="1" Timeout="-1">
          <Task name="Main" while="true">
            <Event name="Argument" as="ActionArgument" />
            <Invoke name="ReadValue" waitFor="Argument"
                    post="[%:Event.Argument.ServoProtocolURL.Value:%]" 
                    SerialNumber="[%:Event.Argument.DeviceInterfaceIndex.Value:%]"
                    DeviceType="[%:Event.Argument.PhidgetDeviceType.Value:%]">
              <Message>
                <Value>
                  <ServoAngle>
                    [%:Event.Argument.ServoAngle.Value:%]
                  </ServoAngle>
                </Value>
              </Message>
            </Invoke>
            <Log Message="====After Invoke phidget ===="/>
            <Output name="Result" as="ActionResult">
              <Value>
                <ServoAngle>
                  [%:[%:@Output:%]Invoke.ReadValue.Message.Value/number():%]
                </ServoAngle>
                <Log Message="====Phidget Servo Angle ==== [%:[%:@Output:%]Invoke.ReadValue.Message.Value:%]"/>
              </Value>
            </Output>
          </Task>
        </Workflow>
      </Action>
    </ThingFacet>
    <ThingModel Name="PhidgetServoModel" Combines="PhidgetServoFacet">
       <Sid Name="PhidServoId"/>
    </ThingModel>
  </Domain>
</Namespace>