9. Combining Things With Data
Key Concepts
Â
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
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.
DataModel to store non-thing related data
TQLEngine provides DataModel to store "pure" data, DataModels do not combine model 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
GeoLocation Type<Def Name="GeoLocation"> <Number Name="latitude"/> <Number Name="longitude"/> </Def>
BoundingBox - To Store Geo Boundary of Zone, etc
BoundingBox Type<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
EnvInfo Type<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.
Greenhouse DataModel<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
GHExternalEnv and GHInternalEnv Data Model<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.
Grid DataModel<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.
Zone DataModel<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.
Lane DataModel<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.
<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
<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
<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
<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
<<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.
<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
<Query> <Find nested="*"> <Greenhouse> <GreenhouseID ne=""/> </Greenhouse> </Find> </Query>