Background
In order to model a real-world IoT application or a solution it is imperative to combine things with data. Let's take an example of real-world use case.
Real-world use-case
Image Modified
For the purpose of this tutorial let's model the Greenhouse monitoring system with following configuration.
- Greenhouse: size: 40 feet by 110 feet
- crop types, tomatoes and peppers
- 3 lanes, each lane has 10 zones
- Total 30 zones (each zone is 10 feet by 10 feet. Lay out is 3 by 10): 20 zones (2 by 10) are tomatoes, 10 zones are peppers
Each zone subdivided into 9 grids. Each grid is 3.33 feet by 3.33 feet. Total 270 grids
Zone Content:
- 1 temperature sensor (total 30)
- 1 humidity sensor (total 30)
- 1 camera (total 30)
- 1 irrigation motor (total 30)
Zone Grid Content:
- 1 ambient light sensor (total 270)
- 1 light (total 270)
- 1 irrigation nozzle (total 270)
External Conditions:
- 1 ambient light sensor
- 1 temperature sensor
- 1 humidity sensor
Tutorial Requirement
For the purpose of this tutorial, let's create a Greenhouse, Lane, Zone, Grid and combine Temperature Sensor from tutorial 1 to a particular zone.
TQLEngine provides DataModel to store "pure" data, DataModels do not combine facets. They are simply models to store application data that is essential to create a meaningful real-world IoT application.
Custom Types
We create two custom types to store GeoLocation and BoundingBox.
GeoLocation - To Store GeoLocation
Code Block |
---|
language | xml |
---|
title | GeoLocation Type |
---|
linenumbers | true |
---|
|
<Def Name="GeoLocation">
<Number Name="latitude"/>
<Number Name="longitude"/>
</Def> |
BoundingBox - To Store Geo Boundary of Zone, etc
Code Block |
---|
language | xml |
---|
title | BoundingBox Type |
---|
linenumbers | true |
---|
|
<Def Name="BoundingBox">
<GeoLocation Name="Vertex1"/>
<GeoLocation Name="Vertex2"/>
<GeoLocation Name="Vertex3"/>
<GeoLocation Name="Vertex4"/>
</Def> |
EnvInfo - Capture all the important environment related information like temperature, humidity, light, pressuue
Code Block |
---|
language | xml |
---|
title | EnvInfo Type |
---|
linenumbers | true |
---|
|
<Def Name="EnvInfo">
<Number Name="Temperature"/>
<Number Name="Humidity"/>
<Number Name="Light"/>
<Number Name="Pressure"/>
<Number Name="SoilMoisture"/>
<Number Name="Wind"/>
<String Name="LastUpdatedByProvider"/>
</Def> |
List of DataModels
Greenhouse : Overall DataModel holder for Greenhouse. GHLanes is defined as Reference to include all the Lanes from Lane model.
Code Block |
---|
language | xml |
---|
title | Greenhouse DataModel |
---|
linenumbers | true |
---|
|
<DataModel Name="Greenhouse">
<Sid Name="GreenhouseID"/>
<String Name="GreenhouseName"/>
<GeoLocation Name="Location"/>
<String Name="LocationName"/>
<BoundingBox Name="Boundary"/>
<Integer Name="LaneCount"/>
<Double Name="LaneWidth"/>
<Double Name="ZoneLength"/>
<Integer Name="ZoneInLane"/>
<Integer Name="ZoneCount"/>
<Double Name="GHLength"/>
<Double Name="GHWidth"/>
<EnvInfo Name="ExternalEnv"/>
<EnvInfo Name="InternalEnv"/>
<String Name="VentOnOffState"/>
<String Name="FansOnOffState"/>
<Boolean Name="SunnyDay"/>
<Boolean Name="Running" default="false"/> <!-- true / false -->
<Reference Name="GHLanes"/>
<Reference Name="GHExternalEnv"/>
<Reference Name="GHInternalEnv"/>
</DataModel> |
GHExternalEnv & GHInternalEnv
Code Block |
---|
language | xml |
---|
title | GHExternalEnv and GHInternalEnv Data Model |
---|
linenumbers | true |
---|
|
<DataModel Name="ExternalEnv">
<Sid Name="ExternalEnvID"/>
<Number Name="ExtTemperature"/>
<Number Name="ExtHumidity"/>
<Number Name="ExtLight"/>
<Reference Name="GreenhouseID" Type="Greenhouse" Cardinality="1"/>
</DataModel>
<DataModel Name="InternalEnv">
<Sid Name="InternalEnvID"/>
<Number Name="IntTemperature"/>
<Number Name="IntHumidity"/>
<Number Name="IntLight"/>
<Reference Name="GreenhouseID" Type="Greenhouse" Cardinality="1"/>
</DataModel> |
Grid - DataModel for storing Grid information.
Code Block |
---|
language | xml |
---|
title | Grid DataModel |
---|
linenumbers | true |
---|
|
<DataModel Name="Grid">
<Sid Name="GridID"/>
<String Name="GridName"/>
<BoundingBox Name="GridLocation"/>
<Integer Name="GridNSPosition"/>
<Integer Name="GridWEPosition"/>
<Double Name="GridLength"/>
<Double Name="GridWidth"/>
<Double Name="SoilMoisture"/>
<Double Name="AmbientLight"/>
<Reference Name="ZoneID" Type="Zone" Cardinality="1"/>
</DataModel> |
Zone - DataModel for storing Zone information. Does a Smart Reference to Grid at instantiation time by simply defining ZoneGrids as Reference type. The Find query can be add at the instantiation time.
Code Block |
---|
language | xml |
---|
title | Zone DataModel |
---|
linenumbers | true |
---|
|
<DataModel Name="Zone">
<Sid Name="ZoneID"/>
<String Name="ZoneName"/>
<BoundingBox Name="ZoneLocation"/>
<GeoLocation Name="Location"/>
<Double Name="ZoneWidth"/>
<Double Name="ZoneLength"/>
<Integer Name="GridOnLength"/>
<Integer Name="GridOnWidth"/>
<Integer Name="GridCount"/>
<Double Name="GridLength"/>
<Double Name="GridWidth"/>
<String Name="EndZone"/>
<Double Name="ZoneTemperature"/>
<Double Name="ZoneHumidity"/>
<Double Name="ZoneAvgSM"/>
<Double Name="ZoneAvgLight"/>
<String Name="CropType"/>
<Date Name="SeedingDate" format="$SimpleDateFormat(dd-MM-yyyy)"/>
<Date Name="LastFertilisationDate" format="$SimpleDateFormat(dd-MM-yyyy)"/>
<String Name="HarvestingSeason"/>
<Integer Name="NoOfPlants"/>
<Double Name="VPD"/>
<String Name="Live"/> <!-- Yes/No -->
<Reference Name="LaneID" Type="Lane" Cardinality="1"/>
<Reference Name="ZoneGrids"/>
</DataModel> |
Lane - DataModel to hold Lane information. Defines Smart Reference to Zones.
Code Block |
---|
language | xml |
---|
title | Lane DataModel |
---|
linenumbers | true |
---|
|
<DataModel Name="Lane">
<Sid Name="LaneID"/>
<String Name="LaneName"/>
<Double Name="LaneLength"/>
<Double Name="LaneWidth"/>
<Integer Name="ZoneInLane"/>
<String Name="BorderLane"/>
<BoundingBox Name="LaneLocation"/>
<Reference Name="GreenhouseID" Type="Greenhouse" Cardinality="1"/>
<Reference Name="LaneZones"/
</DataModel> |
Data + Things
We have to assign 1 temperature sensor per zone. We do this by:
- Use the content of MultipleSensors tutorial project and bring in all the model content into this tutorial.
- Use Simple Reference in TempSensorModel to a particular Zone using ZoneID
Other sensors and actuators can be referenced in a similar fashion.
Code Block |
---|
language | xml |
---|
title | TempSensorModel with reference to Zone |
---|
linenumbers | true |
---|
|
<Def Name="PeripheralParams">
<String Name="Peripheral"/>
<String Name="InterfacePort"/>
<String Name="Interface"/>
<String Name="UniqueId" default="56789"/>
<String Name="Baudrate"/>
<String Name="Format" default="ascii"/>
<String Name="Operation"/>
<String Name="Payload"/>
</Def>
<ThingFacet Name="TempFacetSerial">
<String Name="SensorData" update="auto" KnownBy="SensorDataReadAction"/>
<PeripheralParams Name="PerifParams"/>
<Action Name="SensorDataReadAction">
<Workflow Limit="1" Live="1" Timeout="-1">
<Task name="Main" while="true">
<Event name="Argument" as="ActionArgument"/>
<Invoke name="InvokeSerialRead" waitFor="Argument" get="perif://">
<Message>
<Value>
<InterfacePort>
"[%:Event.Argument.PerifParams.InterfacePort.Value:%]"
</InterfacePort>
<Baudrate>
"[%:Event.Argument.PerifParams.Baudrate.Value:%]"
</Baudrate>
<Interface>
"[%:Event.Argument.PerifParams.Interface.Value:%]"
</Interface>
<UniqueId>
"[%:Event.Argument.PerifParams.UniqueId.Value:%]"
</UniqueId>
<Operation>
"[%:Event.Argument.PerifParams.Operation.Value:%]"
</Operation>
<Peripheral>
"[%:Event.Argument.PerifParams.Peripheral.Value:%]"
</Peripheral>
<Payload>
"[%:Event.Argument.PerifParams.Payload.Value:%]"
</Payload>
<Format>
"[%:Event.Argument.PerifParams.Format.Value:%]"
</Format>
</Value>
</Message>
</Invoke>
<Output Name="Result" As="ActionResult">
<Value>
<SensorData>
[%:Invoke.InvokeSerialRead.Message.Value/normalize-space(received):%]
</SensorData>
</Value>
</Output>
</Task>
</Workflow>
</Action>
</ThingFacet>
<ThingModel Name="TempSensor" combines="TempFacetSerial">
<Sid Name="sensorId"/>
<Reference Name="ZoneID" Type="Zone" Cardinality="1"/>
</ThingModel> |
Queries
Let's start writing some queries to create and read the data.
Create Grids
Code Block |
---|
language | xml |
---|
title | Create Grid |
---|
linenumbers | true |
---|
|
<Query>
<DeleteAll format="version,current">
<Grid>
<GridID ne=""/>
</Grid>
</DeleteAll>
<Create>
<Grid>
<GridName>
Intel-Grid
</GridName>
<GridID>
livegrid
</GridID>
<ZoneID>
livezone
</ZoneID>
<GridLength>
1
</GridLength>
<GridWidth>
1
</GridWidth>
<GridNSPosition>
1
</GridNSPosition>
<GridWEPosition>
2
</GridWEPosition>
<GridLocation>
<Vertex1>
1
</Vertex1>
<Vertex2>
1
</Vertex2>
<Vertex3>
1
</Vertex3>
<Vertex4>
1
</Vertex4>
</GridLocation>
<SoilMoisture>
53
</SoilMoisture>
<AmbientLight>
0
</AmbientLight>
</Grid>
</Create>
</Query> |
Create Zone
Code Block |
---|
language | xml |
---|
title | Create Zone |
---|
linenumbers | true |
---|
|
<Query>
<DeleteAll format="version,current">
<Zone>
<ZoneID ne = ""/>
</Zone>
</DeleteAll>
<Create>
<Zone>
<ZoneID>
livezone
</ZoneID>
<ZoneName>
Intel-Zone
</ZoneName>
<LaneID>
livelane
</LaneID>
<ZoneLength>
1
</ZoneLength>
<ZoneWidth>
1
</ZoneWidth>
<ZoneLocation>
<Vertex1>
1
</Vertex1>
<Vertex2>
1
</Vertex2>
<Vertex3>
1
</Vertex3>
<Vertex4>
1
</Vertex4>
</ZoneLocation>
<EndZone>
endzone
</EndZone>
<GridOnLength>
1
</GridOnLength>
<GridOnWidth>
1
</GridOnWidth>
<GridCount>
1
</GridCount>
<GridLength>
1
</GridLength>
<GridWidth>
1
</GridWidth>
<ZoneTemperature>
26
</ZoneTemperature>
<ZoneHumidity>
53
</ZoneHumidity>
<ZoneAvgSM>
20
</ZoneAvgSM>
<ZoneAvgLight>
2
</ZoneAvgLight>
<CropType>
Apple
</CropType>
<SeedingDate>
11-04-2016
</SeedingDate>
<LastFertilisationDate>
14-04-2016
</LastFertilisationDate>
<HarvestingSeason>
April
</HarvestingSeason>
<NoOfPlants>
5
</NoOfPlants>
<VPD>
0
</VPD>
<Location>
<latitude>
1.11
</latitude>
<longitude>
1.12
</longitude>
</Location>
<Live>
yes
</Live>
</Zone>
</Create>
</Query> |
Create Lane
Code Block |
---|
language | xml |
---|
title | Create Lane |
---|
linenumbers | true |
---|
|
<Query>
<DeleteAll format="version,current">
<Lane>
<LaneID ne = ""/>
</Lane>
</DeleteAll>
<Create>
<Lane>
<LaneID>
livelane
</LaneID>
<GreenhouseID>
livegreenhouse
</GreenhouseID>
<LaneName>
lane-1
</LaneName>
<LaneLength>
5
</LaneLength>
<LaneWidth>
1
</LaneWidth>
<ZoneInLane>
4
</ZoneInLane>
<BorderLane>
1
</BorderLane>
<BoundingBox>
<Vertex1>
5
</Vertex1>
<Vertex2>
28
</Vertex2>
<Vertex3>
105
</Vertex3>
<Vertex4>
38
</Vertex4>
</BoundingBox>
</Lane>
</Create>
</Query> |
Create Greenhouse
Code Block |
---|
language | xml |
---|
title | Create Greenhouse |
---|
linenumbers | true |
---|
|
<<Query>
<DeleteAll format="version,current">
<Greenhouse>
<GreenhouseID ne=""/>
</Greenhouse>
</DeleteAll>
<Create>
<Greenhouse>
<GreenhouseID>
livegreenhouse
</GreenhouseID>
<GreenhouseName>
Intel-GreenHouse
</GreenhouseName>
<BoundingBox>
<Vertex1>
0
</Vertex1>
<Vertex2>
0
</Vertex2>
<Vertex3>
110
</Vertex3>
<Vertex4>
40
</Vertex4>
</BoundingBox>
<LaneCount>
3
</LaneCount>
<LaneWidth>
110
</LaneWidth>
<ZoneLength>
10
</ZoneLength>
<ZoneInLane>
5
</ZoneInLane>
<ZoneCount>
15
</ZoneCount>
<GHLength>
110
</GHLength>
<GHWidth>
40
</GHWidth>
<ExternalEnv>
<Temperature>
26
</Temperature>
<Humidity>
53
</Humidity>
<Light>
1
</Light>
<SoilMoisture>
20
</SoilMoisture>
<Wind>
19.5
</Wind>
</ExternalEnv>
<InternalEnv>
<Temperature>
20
</Temperature>
<Humidity>
53
</Humidity>
<Light>
1
</Light>
<SoilMoisture>
1
</SoilMoisture>
</InternalEnv>
<GHLanes>
</GHLanes>
<SunnyDay>
True
</SunnyDay>
<Location>
<latitude>
37.3718999
</latitude>
<longitude>
-122.0022377
</longitude>
</Location>
</Greenhouse>
</Create>
</Query> |
Initialize Temperature Sensor
TempSensorInZone value is the ZoneID value of the Zone.
Code Block |
---|
language | xml |
---|
title | Create Temperature Sensor |
---|
linenumbers | true |
---|
|
<Query>
<DeleteAll format="version,current">
<TempSensor>
<sensorId ne=""/>
</TempSensor>
</DeleteAll>
<Save format="version,current">
<!-- This will read -->
<TempSensor>
<PerifParams>
<Peripheral>
serial
</Peripheral>
<Baudrate>
9600
</Baudrate>
<InterfacePort>
/dev/cu.usbserial-A1025R0Y
</InterfacePort>
<Interface>
serial
</Interface>
<Format>
ascii
</Format>
<Operation>
receive
</Operation>
<UniqueId>
76522
</UniqueId>
<Payload>
$Null()
</Payload>
</PerifParams>
<SensorData>
$Null()
</SensorData>
<TempSensorInZone>
livezone
</TempSensorInZone>
</TempSensor>
</Save>
</Query> |
Find Greenhouse
Code Block |
---|
language | xml |
---|
title | Find Greenhouse |
---|
linenumbers | true |
---|
|
<Query>
<Find nested="*">
<Greenhouse>
<GreenhouseID ne=""/>
</Greenhouse>
</Find>
</Query> |