Key learning points for TQL101 tutorials

There are three types of constructs/features covered in TQL101, with different levels of learning objectives.

1. Skilled - write your own.

You should not only grasp the concept, structure, and mechanics (how it works), but also can write your own and use it in your IoT applications. You can also explain to others how it works.

2. Knowledgeable - use existing.

You understand the concept and structure. You can use existing (system provided) components, adding your own customization.

3. Aware - know they exist.

You understand the concept and function. But use and creation are not required (they will be covered in future classes).

 

SkilledKnowledgeableAware

ThingModel - Create ThingModels that combines ThingFacet,

ThingFacet - Create ThingFacet for devices based on protocol supported out of the box

Attribute - Ability to define attributes of Primitive and complex (Custom types)

Action - Write Action with standard Workflow that invokes out of the box protocols.

DataModel - Create "Pure" Data only models to capture just enough data attributes to be associated with Things.

Model and model Instances - Deploying models and creating instances of model. Entire lifecycle

of models.

Query (including model to model) - Write queries (CRUD) to be used by app developers, use queries form within models.

Subscription (including model to model) - External websocket based subscription. Subscribe to model changes from within the model.

Building HTML/JavaScript apps - Create standard simple HTML/JS applications.

Scheduling - Schedule piece of TQL code to be executed at scheduled interval.

Macros - What are macros and how they are useful.

Standard System Macros (Pipeline Macros)

 

FacetScript -

Temporary Cache - Context, Facet, Local, Process Data Stores

Deployment package - How is standard TQLStudio Projects deployed

Template Processor - How to process message responses. Use of XPath expressions

   
TQL101 Skills
<Namespace Name="Atomiton">

  <Domain Name="TQL101">

    <Def Name="PostalAddress">

      <String Name="StreetName"/>

      <String Name="City"/>

      <String Name="State"/>

      <String Name="Zipcode"/>

    </Def>

    

    <DataModel Name="Room">

      <Sid Name="RoomID"/>

      <String Name="RoomName"/>

      <Integer Name="RoomSize"/>

      <Reference Name="HouseID" Type="House" Cardinality="1"/>

    </DataModel>

    <DataModel Name="House">

      <Sid Name="HouseID"/>

      <String Name="Owner"/>

      <PostalAddress Name="Address"/>

    </DataModel>

    <ThingFacet Name="TempFacetSerial">

      <PeripheralParams Name="PerifParams"/>

      <String Name="SensorData" update="auto" KnownBy="SensorDataReadAction"/>

      <String Name="ScheduleCalc" KnownBy="ScheduleCalcAction"/>

      <String Name="InitSubscribers" default="false" KnownBy="InitSubAction"/>

      <Integer Name="BaseTemp"/>

      <Integer Name="PctChange"/>

      <String Name="Calculated"/>

      <String Name="SensorURL" Default="phid://"/>

      <String Name="SensorInterfaceIndex"/>

      <String Name="SensorType"/>

      <String Name="SensorInterfaceType"/>

      <String Name="SensorValueFormat"/>

      <String Name="Simulated"/>

      <DateTime Name="Timestamp" Format="$SimpleDateFormat(yyyy-MM-dd'T'HH:mm:ss'Z')"/>

      <Action Name="SensorDataReadAction" Documentation="Sync the value of Sensors from Phidget Interface 8/8/8">

        <Workflow Limit="1" Live="1" Timeout="-1">

          <Task Name="Main" While="true">

            <Event Name="Argument" As="ActionArgument"/>

            <Invoke Name="ReadValue" waitFor="Argument" Get="[%:Event.Argument.SensorURL.Value:%][%:Event.Argument.SensorInterfaceIndex.Value:%]"

              SerialNumber="[%:Event.Argument.SensorInterfaceIndex.Value:%]" DeviceType="[%:Event.Argument.SensorInterfaceType.Value:%]" SensorValueFormat="[%:Event.Argument.SensorValueFormat.Value:%]"

              SensorType="[%:Event.Argument.SensorType.Value:%]" MessagesPerSecond="5" Simulated="[%:Event.Argument.Simulated.Value:%]"/>

            <Output Name="Result" As="ActionResult">

              <Value>

                <SensorData>

                  TEMPC:0#TEMPF:[%:[%:@Output:%]Invoke.ReadValue.Message.Value:%]#HUMPCT:0#AMB:0

                </SensorData>

              </Value>

            </Output>

          </Task>

        </Workflow>

      </Action>

      

      

      <Action Name="ScheduleCalcAction" Documentation="Start reading temperature from source and calc new value">

        <Workflow Limit="1" Live="1" Timeout="-1">

          <Task Name="Main1" While="true">

            <Event Name="Argument" As="ActionArgument"/>

            <Invoke Name="StartSimulation" waitFor="Argument">

              <FacetScript>

                <If condition="/'[%:Event.Argument.ScheduleCalc.Value:%]' eq 'true'">

                  <then>

                    <Log Message="Starting calculation..[%:Event.Argument.SensorID:%]"/>

                    <ScheduleJob>

                      <JobName>

                        CalcTempValue[%:Event.Argument.SensorID:%]

                      </JobName>

                      <ScheduleInterval>

                        1min

                      </ScheduleInterval>

                      <ActionCode>

                        <CalculateBaseTempValue>

                          <DstTempSensorId>

                            [%:Event.Argument.SensorID:%]

                          </DstTempSensorId>

                        </CalculateBaseTempValue>

                      </ActionCode>

                    </ScheduleJob>

                  </then>

                  <else>

                    <Log Message="Stopping calculation.."/>

                    <DeleteScheduleJob>

                      <JobName>

                        CalcTempValue[%:Event.Argument.SensorID:%]

                      </JobName>

                    </DeleteScheduleJob>

                  </else>

                </If>

              </FacetScript>

            </Invoke>

            <Output Name="Result" As="ActionResult">

              <Value>

                <ScheduleCalc>

                  [%:Event.Argument.ScheduleCalc.Value:%]

                </ScheduleCalc>

              </Value>

            </Output>

          </Task>

        </Workflow>

      </Action>

      <Action Name="InitSubAction">

        <Workflow Limit="1" Live="1" Timeout="-1">

          <Task name="Main" while="true">

            <Event name="Argument" as="ActionArgument"/>

            <Invoke name="InvokeSubs" waitFor="Argument">

              <FacetScript>

                <If Condition="/'[%:Event.Argument.InitSubscribers.Value:%]' eq 'true'">

                  <Log Message="Subscribing to: *Atomiton.TQL101.TempSensor.SensorData.[%:Event.Argument.SensorId:%]*"/>

                  <SubscribeToTQL>

                    <TopicName>*Atomiton.TQL101.TempSensor.SensorData.[%:Event.Argument.SensorId:%]*</TopicName>

                    <ActionName>

                      <ParseAndUpdateBaseTemp>

                        <SensorID>[%:Event.Argument.SensorId:%]</SensorID>

                      </ParseAndUpdateBaseTemp>

                    </ActionName>

                  </SubscribeToTQL>

                </If>

              </FacetScript>

            </Invoke>

            <Output Name="Result" As="ActionResult">

              <Value>

                <InitSubscribers>

                  [%:Event.Argument.InitSubscribers.Value:%]

                </InitSubscribers>

              </Value>

            </Output>

          </Task>

        </Workflow>

      </Action>

    </ThingFacet>

    <ThingModel Name="TempSensor" combines="TempFacetSerial">

      <Sid Name="SensorID"/>

      <Reference Name="RoomID" Type="Room" Cardinality="1"/>

    </ThingModel>







    <Macro Name="SubscribeToTQL">

      <Argument>

        <TopicName>TQL.*</TopicName>

        <TopicId>GenericTopicID</TopicId>

        <ActionName/>

      </Argument>

      <Result>

        <DoRequest target="[:RuntimeParams.TopicFacetIDName:]" Disable="CMD_SERVER">

          <Process return="CMD_NOP">

            <Message type="xml">

              <Value>

                <Subscribe sid="[:$Macro.Argument.TopicId:]" topic="[:$Macro.Argument.TopicName:]">

                  <Action>

                    [:$Macro.Argument.ActionName:]

                  </Action>

                </Subscribe>

              </Value>

            </Message>

          </Process>

        </DoRequest>

      </Result>

    </Macro>




    <Macro Name="DeleteScheduleJob">

      <Argument>

        <JobName/>

      </Argument>

      <Result>

        <DoRequest target="[:$RuntimeParams.SequenceFacetIDName:]" Disable="CMD_SERVER">

          <Process return="CMD_NOP">

            <Message type="xml">

              <Value>

                <Remove eid="[:$Macro.Argument.JobName:]"/>

              </Value>

            </Message>

          </Process>

        </DoRequest>

      </Result>

    </Macro>







    <Macro Name="ScheduleJob">

      <Argument>

        <ScheduleInterval></ScheduleInterval>

        <StartTime>0</StartTime>

        <EndTime></EndTime>

        <ActionCode></ActionCode>

        <JobName></JobName>

      </Argument>

      <Result>

        <DoRequest target="[:RuntimeParams.SequenceFacetIDName:]" Disable="CMD_SERVER">

          <Process return="CMD_NOP">

            <Message>

              <Value>

                <Execute eid="[:$Macro.Argument.JobName:]" schedule="[[:$Macro.Argument.StartTime:]..[:$Macro.Argument.EndTime:]/[:$Macro.Argument.ScheduleInterval:]]">

                  <Action>

                    <ExecuteQuery>

                      <QueryString>

                        [:$Macro.Argument.ActionCode:]

                      </QueryString>

                    </ExecuteQuery>

                  </Action>

                </Execute>

              </Value>

            </Message>

          </Process>

        </DoRequest>

      </Result>

    </Macro>




    <Macro Name="ExecuteQuery">

      <Argument>

        <QueryString>

          <Query/>

        </QueryString>

      </Argument>

      <Result>

        <DoRequest Target="[:RuntimeParams.FacetIDName:]" Disable="CMD_SERVER">

          <Process return="CMD_NOP">

            <Message>

              <Value>[:$Macro.Argument.QueryString:]</Value>

            </Message>

          </Process>

        </DoRequest>

      </Result>

    </Macro>




    <Macro Name="UpdateBaseTempValue">

      <Argument>

        <TempSensorId/>

        <TempF/>

      </Argument>

      <Result>

        <ExecuteQuery>

          <QueryString>

            <Query>

              <Find format="version">

                <TempSensor>

                  <SensorID eq="[:$Macro.Argument.TempSensorId:]"/>

                </TempSensor>

              </Find>

              <SetResponseData>

                <Key>Message.Value.Find.Result.TempSensor.BaseTemp.Value</Key>

                <Value>[:$Macro.Argument.TempF:]</Value>

              </SetResponseData>

              <Update>

                <From>Result</From>

                <Include>$Response.Message.Value.Find</Include>

              </Update>

            </Query>

          </QueryString>

        </ExecuteQuery>

        <DelResponseData key="Message.Value.Find"/>

      </Result>

    </Macro>




    <Macro Name="CalculateBaseTempValue">

      <Argument>

        <DstTempSensorId/>

      </Argument>

      <Result>

        <Log Message="Calculating Base Temp Value for.... [:$Macro.Argument.DstTempSensorId:]"/>

        <ExecuteQuery>

          <QueryString>

            <Query>

              <Find format="version">

                <Room as="var.Room">

                  <RoomName eq="Hall"/>

                </Room>

                <TempSensor>

                  <RoomID eq="var.Room.RoomID"/>

                </TempSensor>

              </Find>

            </Query>

          </QueryString>

        </ExecuteQuery>




        <SetContextData Key="MainTempValue" Value="[:$Response.Message.Value.Find.Result.TempSensor.BaseTemp.Value:]"/>




        <ExecuteQuery>

          <QueryString>

            <Query>

              <Find format="version">

                <TempSensor>

                  <SensorID eq="[:$Macro.Argument.DstTempSensorId:]"/>

                </TempSensor>

              </Find>

            </Query>

          </QueryString>

        </ExecuteQuery>




        <SetContextData Key="PctChange" Value="[:$Response.Message.Value.Find.Result.TempSensor.PctChange.Value:]"/>




        <Log Message="Main Temp Value is.. [:$ContextData.MainTempValue:]"/>

        <Log Message="PctChange Value is.. [:$ContextData.PctChange:]"/>

        <JavaScript>

          var bTemp = [:$ContextData.MainTempValue:];

          var pct = [:$ContextData.PctChange:];

          var tempV = bTemp + (pct/100)*bTemp;

          sffLog.info("NewTempValue is:..." + tempV);

          sffContext.execute(&quot;SetContextData&quot;,&quot;key&quot;,&quot;NewTempValue&quot;,&quot;value&quot;,tempV);

        </JavaScript>




        <Log Message="Calcualted Value is..[:$ContextData.NewTempValue:]"/>

        <UpdateBaseTempValue>

          <TempSensorId>[:$Response.Message.Value.Find.Result.TempSensor.SensorID:]</TempSensorId>

          <TempF>[:$ContextData.NewTempValue:]</TempF>

        </UpdateBaseTempValue>




        <DelContextData Key="MainTempValue"/>

        <DelContextData Key="NewTempValue"/>




        <SetResponseData Key="Response.Message.Value.Status" Value="Success"/>

        <SetResponseData Key="Response.Message.Value.Message" Value="[:$ContextData.NewTempValue:]"/>

      </Result>

    </Macro>




    <Macro Name="ParseAndUpdateBaseTemp">

      <Argument>

        <SensorID/>

      </Argument>

      <Result>

        <ExecuteQuery>

          <QueryString>

            <Query>

              <Find format="all">

                <TempSensor>

                  <SensorID eq="[:$Macro.Argument.SensorID:]"/>

                </TempSensor>

              </Find>

            </Query>

          </QueryString>

        </ExecuteQuery>

        <SetContextData Key="SData" Value="[:$Response.Message.Value.Find.Result.TempSensor.SensorData.Known:]"/>

        <JavaScript>

          var str = "[:$ContextData.SData:]";

          sffLog.info("***************SensorData**************" + str);

          var

          sensorToken =

          str.split("#");

          var

          updateBaseTemp = ListMap.static.newInstance();

          for(i=0; i&lt;sensorToken.length; i++) {

          sval

          =sensorToken[i].split(":");

          if (sval[0] ==

          "TEMPF") {

          var upQ =

          updateBaseTemp.instanceAdd("UpdateBaseTempValue");

          upQ.put("TempSensorId",

          "[:$Macro.Argument.SensorID:]");

          upQ.put("TempF",

          sval[1]);

          break;

          }

          }

          sffLog.info(updateBaseTemp);

          updateBaseTemp;

        </JavaScript>

        <DelContextData Key="SData"/>

      </Result>

    </Macro>

  </Domain>

</Namespace>