Hackster is hosting Hackster Holidays, Ep. 6: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Monday!Stream Hackster Holidays, Ep. 6 on Monday!
Ben
Published © MIT

Pantry Monitoring IoT Device

Monitoring system tracking the ambient light, humidity, temperature and the air quality of pantries and food storage cabinets.

BeginnerFull instructions provided2 hours2,482

Things used in this project

Hardware components

Rapid IoT Prototyping Kit
NXP Rapid IoT Prototyping Kit
×1
Raspberry Pi Zero
Raspberry Pi Zero
×1

Software apps and online services

InfluxDB
Grafana
Python

Story

Read more

Schematics

Diagram

Code

PantryIOT.py

Python
Python Data Gathering and DB access
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
""" Stores Rapid-IOT PantryBLE values in an InfluxDB database"""

import logging
import time
import pygatt
from influxdb import InfluxDBClient

RPK_ADDRESS = "00:00:00:00:00:00" # Change this with your Device's BT Address

CHAR_UUIDS = {
    "battery" : "08d41e61-ac11-40a2-a95a-e0e0fb5336ff",
    "tvoc" : "08d41e61-ac11-40a2-a95a-e0e0fb5336f9",
    "co2" : "08d41e61-ac11-40a2-a95a-e0e0fb5336fa",
    "pressure" : "08d41e61-ac11-40a2-a95a-e0e0fb5336fc",
    "temperature" : "08d41e61-ac11-40a2-a95a-e0e0fb5336fb",
    "humidity" : "08d41e61-ac11-40a2-a95a-e0e0fb5336fd",
    "ambient-light" : "08d41e61-ac11-40a2-a95a-e0e0fb5336fe"
}

def save_prk_values():
    """ Saves PantryBLE sensor values, got using BLE-GATT, to an InfluxDB database """

    logging.basicConfig(filename='PantryBLE.log', level=logging.WARNING)

    adapter = pygatt.GATTToolBackend()
    db_client = InfluxDBClient('localhost', database="rpkpantry")

    try:
        # Connect to the RPK device
        adapter.start()
        conn = adapter.connect(RPK_ADDRESS)

        time_info = int(time.time()*1000000000.0)

        # Get sensor values
        sensor_values = {}
        for sensor in CHAR_UUIDS:
            value = conn.char_read(CHAR_UUIDS[sensor])
            sensor_values[sensor] = float(value.decode("utf-8").rstrip('\x00'))

        # Save to DB
        measurements = []
        for sensor in sensor_values:
            measurement = {"measurement" : sensor, "time" : time_info, "fields" : {"value" : sensor_values[sensor]}}
            measurements.append(measurement)

        print (measurements)

        db_client.write_points(measurements)

    except Exception as e:
        print ("Error: ", e)
        msg = "PantryBLE: [%d] %s"%(time_info, e)
        logging.warning(msg)

    finally:
        adapter.stop()

if __name__ == '__main__':
    save_prk_values()

pip_requirements.txt

Plain text
Python requirements for running rapidIOT.py
backcall==0.1.0
certifi==2018.11.29
chardet==3.0.4
decorator==4.3.0
enum-compat==0.0.2
idna==2.8
influxdb==5.2.1
ipython==7.2.0
ipython-genutils==0.2.0
jedi==0.13.2
parso==0.3.1
pexpect==4.6.0
pickleshare==0.7.5
pkg-resources==0.0.0
prompt-toolkit==2.0.7
ptyprocess==0.6.0
pygatt==3.2.0
Pygments==2.3.1
pyserial==3.4
python-dateutil==2.7.5
pytz==2018.7
requests==2.21.0
six==1.12.0
traitlets==4.3.2
urllib3==1.24.1
wcwidth==0.1.7

PantryIOT source.zip

Plain text
PantryIOT Rapid IOT full source code
No preview (download only).

PantryIoT_firmware.bin

Plain text
PantryIOT Rapid IOT Firmware:
Disclaimer: This binary is provided "as is" and "with all faults", the author is not responsible of any damage caused to the device.
No preview (download only).

Pantry.json

JSON
Grafana Dashboard for Pantry IOT monitoring
{
  "__inputs": [
    {
      "name": "DS_INFLUXDB",
      "label": "InfluxDB",
      "description": "",
      "type": "datasource",
      "pluginId": "influxdb",
      "pluginName": "InfluxDB"
    }
  ],
  "__requires": [
    {
      "type": "panel",
      "id": "alertlist",
      "name": "Alert List",
      "version": "5.0.0"
    },
    {
      "type": "grafana",
      "id": "grafana",
      "name": "Grafana",
      "version": "5.4.2"
    },
    {
      "type": "panel",
      "id": "graph",
      "name": "Graph",
      "version": "5.0.0"
    },
    {
      "type": "panel",
      "id": "heatmap",
      "name": "Heatmap",
      "version": "5.0.0"
    },
    {
      "type": "datasource",
      "id": "influxdb",
      "name": "InfluxDB",
      "version": "5.0.0"
    },
    {
      "type": "panel",
      "id": "singlestat",
      "name": "Singlestat",
      "version": "5.0.0"
    },
    {
      "type": "panel",
      "id": "text",
      "name": "Text",
      "version": "5.0.0"
    }
  ],
  "annotations": {
    "list": [
      {
        "builtIn": 1,
        "datasource": "-- Grafana --",
        "enable": true,
        "hide": true,
        "iconColor": "rgba(0, 211, 255, 1)",
        "name": "Annotations & Alerts",
        "type": "dashboard"
      }
    ]
  },
  "editable": true,
  "gnetId": null,
  "graphTooltip": 0,
  "id": null,
  "links": [],
  "panels": [
    {
      "cacheTimeout": null,
      "colorBackground": false,
      "colorValue": true,
      "colors": [
        "#299c46",
        "rgba(237, 129, 40, 0.89)",
        "#d44a3a"
      ],
      "format": "celsius",
      "gauge": {
        "maxValue": 100,
        "minValue": 0,
        "show": false,
        "thresholdLabels": false,
        "thresholdMarkers": true
      },
      "gridPos": {
        "h": 3,
        "w": 3,
        "x": 0,
        "y": 0
      },
      "id": 12,
      "interval": null,
      "links": [],
      "mappingType": 1,
      "mappingTypes": [
        {
          "name": "value to text",
          "value": 1
        },
        {
          "name": "range to text",
          "value": 2
        }
      ],
      "maxDataPoints": 100,
      "nullPointMode": "connected",
      "nullText": null,
      "postfix": "",
      "postfixFontSize": "50%",
      "prefix": "",
      "prefixFontSize": "50%",
      "rangeMaps": [
        {
          "from": "null",
          "text": "N/A",
          "to": "null"
        }
      ],
      "sparkline": {
        "fillColor": "rgba(31, 118, 189, 0.18)",
        "full": false,
        "lineColor": "rgb(31, 120, 193)",
        "show": false
      },
      "tableColumn": "",
      "targets": [
        {
          "groupBy": [
            {
              "params": [
                "$__interval"
              ],
              "type": "time"
            },
            {
              "params": [
                "null"
              ],
              "type": "fill"
            }
          ],
          "measurement": "temperature",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "A",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "value"
                ],
                "type": "field"
              },
              {
                "params": [],
                "type": "mean"
              }
            ]
          ],
          "tags": []
        }
      ],
      "thresholds": "25, 35",
      "title": "Temperature",
      "type": "singlestat",
      "valueFontSize": "80%",
      "valueMaps": [
        {
          "op": "=",
          "text": "N/A",
          "value": "null"
        }
      ],
      "valueName": "current"
    },
    {
      "cacheTimeout": null,
      "colorBackground": false,
      "colorValue": false,
      "colors": [
        "rgb(255, 255, 255)",
        "rgb(255, 255, 255)",
        "rgb(255, 255, 255)"
      ],
      "format": "humidity",
      "gauge": {
        "maxValue": 100,
        "minValue": 0,
        "show": true,
        "thresholdLabels": false,
        "thresholdMarkers": false
      },
      "gridPos": {
        "h": 3,
        "w": 3,
        "x": 3,
        "y": 0
      },
      "id": 10,
      "interval": null,
      "links": [],
      "mappingType": 1,
      "mappingTypes": [
        {
          "name": "value to text",
          "value": 1
        },
        {
          "name": "range to text",
          "value": 2
        }
      ],
      "maxDataPoints": 100,
      "nullPointMode": "connected",
      "nullText": null,
      "postfix": "",
      "postfixFontSize": "50%",
      "prefix": "",
      "prefixFontSize": "50%",
      "rangeMaps": [
        {
          "from": "null",
          "text": "N/A",
          "to": "null"
        }
      ],
      "sparkline": {
        "fillColor": "rgba(31, 118, 189, 0.18)",
        "full": false,
        "lineColor": "rgb(31, 120, 193)",
        "show": false
      },
      "tableColumn": "",
      "targets": [
        {
          "groupBy": [
            {
              "params": [
                "$__interval"
              ],
              "type": "time"
            },
            {
              "params": [
                "null"
              ],
              "type": "fill"
            }
          ],
          "measurement": "humidity",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "A",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "value"
                ],
                "type": "field"
              },
              {
                "params": [],
                "type": "mean"
              }
            ]
          ],
          "tags": []
        }
      ],
      "thresholds": "220, 660",
      "title": "Humidity",
      "type": "singlestat",
      "valueFontSize": "80%",
      "valueMaps": [
        {
          "op": "=",
          "text": "N/A",
          "value": "null"
        }
      ],
      "valueName": "current"
    },
    {
      "cacheTimeout": null,
      "colorBackground": false,
      "colorValue": false,
      "colors": [
        "#299c46",
        "rgba(237, 129, 40, 0.89)",
        "#d44a3a"
      ],
      "format": "pressurehpa",
      "gauge": {
        "maxValue": 100,
        "minValue": 0,
        "show": false,
        "thresholdLabels": false,
        "thresholdMarkers": true
      },
      "gridPos": {
        "h": 3,
        "w": 3,
        "x": 6,
        "y": 0
      },
      "id": 11,
      "interval": null,
      "links": [],
      "mappingType": 1,
      "mappingTypes": [
        {
          "name": "value to text",
          "value": 1
        },
        {
          "name": "range to text",
          "value": 2
        }
      ],
      "maxDataPoints": 100,
      "nullPointMode": "connected",
      "nullText": null,
      "postfix": "",
      "postfixFontSize": "50%",
      "prefix": "",
      "prefixFontSize": "50%",
      "rangeMaps": [
        {
          "from": "null",
          "text": "N/A",
          "to": "null"
        }
      ],
      "sparkline": {
        "fillColor": "rgba(31, 118, 189, 0.18)",
        "full": false,
        "lineColor": "rgb(31, 120, 193)",
        "show": false
      },
      "tableColumn": "",
      "targets": [
        {
          "groupBy": [
            {
              "params": [
                "$__interval"
              ],
              "type": "time"
            },
            {
              "params": [
                "null"
              ],
              "type": "fill"
            }
          ],
          "measurement": "pressure",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "A",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "value"
                ],
                "type": "field"
              },
              {
                "params": [],
                "type": "mean"
              },
              {
                "params": [
                  " / 100"
                ],
                "type": "math"
              }
            ]
          ],
          "tags": []
        }
      ],
      "thresholds": "220, 660",
      "title": "Pressure",
      "type": "singlestat",
      "valueFontSize": "80%",
      "valueMaps": [
        {
          "op": "=",
          "text": "N/A",
          "value": "null"
        }
      ],
      "valueName": "current"
    },
    {
      "cacheTimeout": null,
      "colorBackground": false,
      "colorValue": true,
      "colors": [
        "#299c46",
        "rgba(237, 129, 40, 0.89)",
        "#d44a3a"
      ],
      "format": "ppm",
      "gauge": {
        "maxValue": 100,
        "minValue": 0,
        "show": false,
        "thresholdLabels": false,
        "thresholdMarkers": true
      },
      "gridPos": {
        "h": 3,
        "w": 3,
        "x": 9,
        "y": 0
      },
      "id": 7,
      "interval": null,
      "links": [],
      "mappingType": 1,
      "mappingTypes": [
        {
          "name": "value to text",
          "value": 1
        },
        {
          "name": "range to text",
          "value": 2
        }
      ],
      "maxDataPoints": 100,
      "nullPointMode": "connected",
      "nullText": null,
      "postfix": "",
      "postfixFontSize": "50%",
      "prefix": "",
      "prefixFontSize": "50%",
      "rangeMaps": [
        {
          "from": "null",
          "text": "N/A",
          "to": "null"
        }
      ],
      "sparkline": {
        "fillColor": "rgba(31, 118, 189, 0.18)",
        "full": false,
        "lineColor": "rgb(31, 120, 193)",
        "show": false
      },
      "tableColumn": "",
      "targets": [
        {
          "groupBy": [
            {
              "params": [
                "$__interval"
              ],
              "type": "time"
            },
            {
              "params": [
                "null"
              ],
              "type": "fill"
            }
          ],
          "measurement": "co2",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "A",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "value"
                ],
                "type": "field"
              },
              {
                "params": [],
                "type": "last"
              }
            ]
          ],
          "tags": []
        }
      ],
      "thresholds": "1000, 5000",
      "title": "CO2",
      "type": "singlestat",
      "valueFontSize": "80%",
      "valueMaps": [
        {
          "op": "=",
          "text": "N/A",
          "value": "null"
        }
      ],
      "valueName": "current"
    },
    {
      "cacheTimeout": null,
      "colorBackground": false,
      "colorValue": true,
      "colors": [
        "#299c46",
        "rgba(237, 129, 40, 0.89)",
        "#d44a3a"
      ],
      "format": "conppb",
      "gauge": {
        "maxValue": 100,
        "minValue": 0,
        "show": false,
        "thresholdLabels": false,
        "thresholdMarkers": true
      },
      "gridPos": {
        "h": 3,
        "w": 3,
        "x": 12,
        "y": 0
      },
      "id": 8,
      "interval": null,
      "links": [],
      "mappingType": 1,
      "mappingTypes": [
        {
          "name": "value to text",
          "value": 1
        },
        {
          "name": "range to text",
          "value": 2
        }
      ],
      "maxDataPoints": 100,
      "nullPointMode": "connected",
      "nullText": null,
      "postfix": "",
      "postfixFontSize": "50%",
      "prefix": "",
      "prefixFontSize": "50%",
      "rangeMaps": [
        {
          "from": "null",
          "text": "N/A",
          "to": "null"
        }
      ],
      "sparkline": {
        "fillColor": "rgba(31, 118, 189, 0.18)",
        "full": false,
        "lineColor": "rgb(31, 120, 193)",
        "show": false
      },
      "tableColumn": "",
      "targets": [
        {
          "groupBy": [
            {
              "params": [
                "$__interval"
              ],
              "type": "time"
            },
            {
              "params": [
                "null"
              ],
              "type": "fill"
            }
          ],
          "measurement": "tvoc",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "A",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "value"
                ],
                "type": "field"
              },
              {
                "params": [],
                "type": "mean"
              }
            ]
          ],
          "tags": []
        }
      ],
      "thresholds": "220, 660",
      "title": "TVOC",
      "type": "singlestat",
      "valueFontSize": "80%",
      "valueMaps": [
        {
          "op": "=",
          "text": "N/A",
          "value": "null"
        }
      ],
      "valueName": "current"
    },
    {
      "cacheTimeout": null,
      "colorBackground": false,
      "colorValue": true,
      "colors": [
        "rgb(0, 0, 0)",
        "#2f575e",
        "#dedaf7"
      ],
      "decimals": null,
      "format": "short",
      "gauge": {
        "maxValue": 20,
        "minValue": 0,
        "show": true,
        "thresholdLabels": false,
        "thresholdMarkers": true
      },
      "gridPos": {
        "h": 3,
        "w": 3,
        "x": 15,
        "y": 0
      },
      "id": 9,
      "interval": null,
      "links": [],
      "mappingType": 1,
      "mappingTypes": [
        {
          "name": "value to text",
          "value": 1
        },
        {
          "name": "range to text",
          "value": 2
        }
      ],
      "maxDataPoints": 100,
      "nullPointMode": "connected",
      "nullText": null,
      "postfix": "",
      "postfixFontSize": "50%",
      "prefix": "",
      "prefixFontSize": "50%",
      "rangeMaps": [
        {
          "from": "null",
          "text": "N/A",
          "to": "null"
        }
      ],
      "sparkline": {
        "fillColor": "rgba(31, 118, 189, 0.18)",
        "full": false,
        "lineColor": "rgb(31, 120, 193)",
        "show": false
      },
      "tableColumn": "",
      "targets": [
        {
          "groupBy": [
            {
              "params": [
                "$__interval"
              ],
              "type": "time"
            },
            {
              "params": [
                "null"
              ],
              "type": "fill"
            }
          ],
          "measurement": "ambient-light",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "A",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "value"
                ],
                "type": "field"
              },
              {
                "params": [],
                "type": "mean"
              }
            ]
          ],
          "tags": []
        }
      ],
      "thresholds": "5,15",
      "title": "Ambient Light",
      "type": "singlestat",
      "valueFontSize": "80%",
      "valueMaps": [],
      "valueName": "current"
    },
    {
      "cacheTimeout": null,
      "colorBackground": false,
      "colorPostfix": false,
      "colorPrefix": false,
      "colorValue": true,
      "colors": [
        "#d44a3a",
        "rgba(237, 129, 40, 0.89)",
        "#299c46"
      ],
      "format": "percent",
      "gauge": {
        "maxValue": 100,
        "minValue": 0,
        "show": false,
        "thresholdLabels": false,
        "thresholdMarkers": true
      },
      "gridPos": {
        "h": 3,
        "w": 3,
        "x": 18,
        "y": 0
      },
      "id": 5,
      "interval": null,
      "links": [],
      "mappingType": 1,
      "mappingTypes": [
        {
          "name": "value to text",
          "value": 1
        },
        {
          "name": "range to text",
          "value": 2
        }
      ],
      "maxDataPoints": 100,
      "nullPointMode": "connected",
      "nullText": null,
      "postfix": "",
      "postfixFontSize": "50%",
      "prefix": "",
      "prefixFontSize": "50%",
      "rangeMaps": [
        {
          "from": "null",
          "text": "N/A",
          "to": "null"
        }
      ],
      "sparkline": {
        "fillColor": "rgba(31, 118, 189, 0.18)",
        "full": false,
        "lineColor": "rgb(31, 120, 193)",
        "show": false
      },
      "tableColumn": "",
      "targets": [
        {
          "groupBy": [
            {
              "params": [
                "$__interval"
              ],
              "type": "time"
            },
            {
              "params": [
                "null"
              ],
              "type": "fill"
            }
          ],
          "measurement": "battery",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "A",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "value"
                ],
                "type": "field"
              },
              {
                "params": [],
                "type": "mean"
              }
            ]
          ],
          "tags": []
        }
      ],
      "thresholds": "30,60",
      "title": "Battery",
      "type": "singlestat",
      "valueFontSize": "80%",
      "valueMaps": [
        {
          "op": "=",
          "text": "N/A",
          "value": "null"
        }
      ],
      "valueName": "current"
    },
    {
      "content": "# Rapid IOT\n# Pantry",
      "gridPos": {
        "h": 3,
        "w": 3,
        "x": 21,
        "y": 0
      },
      "id": 14,
      "links": [],
      "mode": "markdown",
      "title": "",
      "transparent": false,
      "type": "text"
    },
    {
      "aliasColors": {},
      "bars": false,
      "dashLength": 10,
      "dashes": false,
      "datasource": "${DS_INFLUXDB}",
      "fill": 1,
      "gridPos": {
        "h": 5,
        "w": 12,
        "x": 0,
        "y": 3
      },
      "id": 3,
      "legend": {
        "avg": false,
        "current": false,
        "max": false,
        "min": false,
        "show": true,
        "total": false,
        "values": false
      },
      "lines": true,
      "linewidth": 1,
      "links": [],
      "nullPointMode": "connected",
      "percentage": false,
      "pointradius": 5,
      "points": false,
      "renderer": "flot",
      "seriesOverrides": [],
      "spaceLength": 10,
      "stack": false,
      "steppedLine": false,
      "targets": [
        {
          "groupBy": [
            {
              "params": [
                "$__interval"
              ],
              "type": "time"
            },
            {
              "params": [
                "null"
              ],
              "type": "fill"
            }
          ],
          "measurement": "temperature",
          "orderByTime": "ASC",
          "policy": "default",
          "refId": "A",
          "resultFormat": "time_series",
          "select": [
            [
              {
                "params": [
                  "value"
                ],
                "type": "field"
              },
              {
                "params": [],
                "type": "mean"
              }
            ]
          ],
          "tags": []
        }
      ],
      "thresholds": [],
      "timeFrom": null,
      "timeRegions": [],
      "timeShift": null,
      "title": "Temperature",
      "tooltip": {
        "shared": true,
        "sort": 0,
        "value_type": "individual"
      },
      "type": "graph",
      "xaxis": {
        "buckets": null,
        "mode": "time",
        "name": null,
        "show": true,
        "values": []
      },
      "yaxes": [
        {
          "format": "celsius",
          "label": null,
          "logBase": 1,
          "max": null,
          "min": null,
          "show": true
        },
        {
          "format": "short",
          "label": null,
          "logBase": 1,
          "max": null,
          "min": null,
          "show": true
        }
      ],
      "yaxis": {
        "align": false,
        "alignLevel": null
      }
    },
    {
      "aliasColors": {},
      "bars": false,
      "dashLength": 10,
      "dashes": false,
      "datasource": "${DS_INFLUXDB}",
      "fill": 1,
      "gridPos": {
        "h": 5,
        "w": 12,
        "x": 12,
        "y": 3
      },
      "id": 17,
      "legend": {
        "avg": false,
        "current": false,
        "max": false,
        "min": false,
        "show": true,
        "total": false,
        "values": false
      },
      "lines": true,
      "linewidth": 1,
      "links": [],
      "nullPointMode": "connected",
      "percentage": false,
      "pointradius": 5,
      "points": false,
      "renderer": "flot",
...

This file has been truncated, please download it to see its full contents.

PantryIoT.atmo

JSON
Rapid IoT Studio design file
{
  "name": "PantryBLE",
  "createVersion": "2017-08-12",
  "description": "New Project",
  "lastModified": "2018-12-27T18:56:25.349Z",
  "created": "2018-12-27T18:56:25.349Z",
  "meta": {
    "projectTypeName": "NXP Rapid IoT",
    "projectTypeId": "NxpRpk"
  },
  "planes": {
    "NXP Rapid IoT": {
      "type": "mcuxpresso",
      "compilerVersion": "latest",
      "variants": [
        "NxpRpk"
      ],
      "meta": {},
      "elements": [
        {
          "name": "Interval",
          "type": "EmbeddedInterval",
          "variants": [
            "embedded",
            "triggers",
            "abilities",
            "properties",
            "variables"
          ],
          "properties": {
            "errorData": {},
            "code": {
              "trigger": "\treturn ATMO_Status_Success;",
              "setup": "\n\tATMO_INTERVAL_Handle_t intervalHandle;\n    ATMO_INTERVAL_AddAbilityInterval(\n\t\tATMO_PROPERTY(Interval, instance), \n\t\tATMO_ABILITY(Interval, interval), \n\t\tATMO_PROPERTY(Interval, time), \n\t\t&intervalHandle\n\t);\n\t\n\treturn ATMO_Status_Success;\n\t",
              "interval": "\treturn ATMO_Status_Success;"
            },
            "variables": {},
            "embeddedPropertyConversions": {},
            "codeUserChanged": {
              "setup": false,
              "interval": false
            },
            "instance": 0,
            "time": "60000"
          },
          "meta": {
            "editorX": 104,
            "editorY": 67,
            "lastTrigger": "interval"
          },
          "triggers": {
            "triggered": [],
            "interval": [
              {
                "mapping": {},
                "targetOrder": [],
                "targetElement": "AirQuality_TVOC",
                "targetAbility": "readTVOC"
              },
              {
                "mapping": {},
                "targetOrder": [],
                "targetElement": "AirQuality_CO2",
                "targetAbility": "readCO2"
              },
              {
                "mapping": {},
                "targetOrder": [],
                "targetElement": "Pressure",
                "targetAbility": "readPressure"
              },
              {
                "mapping": {},
                "targetOrder": [],
                "targetElement": "Temperature",
                "targetAbility": "readTemperature"
              },
              {
                "mapping": {},
                "targetOrder": [],
                "targetElement": "Humidity",
                "targetAbility": "readHumidity"
              },
              {
                "mapping": {},
                "targetOrder": [],
                "targetElement": "AmbientLight",
                "targetAbility": "readAmbientLight"
              },
              {
                "mapping": {},
                "targetOrder": [],
                "targetElement": "BatteryInfo",
                "targetAbility": "trigger"
              }
            ]
          },
          "interruptAbilities": {
            "trigger": false,
            "setup": false,
            "interval": true
          },
          "abilities": [
            {
              "name": "trigger",
              "triggers": [
                "triggered"
              ]
            },
            {
              "name": "setup",
              "triggers": []
            },
            {
              "name": "interval",
              "triggers": [
                "interval"
              ]
            }
          ]
        },
        {
          "name": "BLE_TVOC",
          "type": "EmbeddedBLECharacteristicCustom",
          "variants": [
            "embedded",
            "triggers",
            "abilities",
            "properties",
            "variables",
            "ble"
          ],
          "properties": {
            "errorData": {},
            "code": {
              "trigger": "\treturn ATMO_Status_Success;",
              "setup": "\n\tATMO_BLE_GATTSAddService(\n\t\tATMO_PROPERTY(BLE_TVOC, instance),\n\t\t&ATMO_VARIABLE(BLE_TVOC, bleServiceHandle), \n\t\tATMO_PROPERTY(BLE_TVOC, bleServiceUuid));\n\t\n\tuint8_t property = 0;\n\tuint8_t permission = 0;\n\t\n\tproperty |= ATMO_PROPERTY(BLE_TVOC, read) ? ATMO_BLE_Property_Read : 0;\n\tproperty |= ATMO_PROPERTY(BLE_TVOC, write) ? ATMO_BLE_Property_Write : 0;\n\tproperty |= ATMO_PROPERTY(BLE_TVOC, notify) ? ATMO_BLE_Property_Notify : 0;\n\n\tpermission |= ATMO_PROPERTY(BLE_TVOC, read) ? ATMO_BLE_Permission_Read : 0;\n\tpermission |= ATMO_PROPERTY(BLE_TVOC, write) ? ATMO_BLE_Permission_Write : 0;\n\n\tATMO_DATATYPE types[3] = {ATMO_PROPERTY(BLE_TVOC, writeDataType), ATMO_PROPERTY(BLE_TVOC, readDataType), ATMO_PROPERTY(BLE_TVOC, notifyDataType)};\n\t\n\tATMO_BLE_GATTSAddCharacteristic(\n\t\tATMO_PROPERTY(BLE_TVOC, instance),\n\t\t&ATMO_VARIABLE(BLE_TVOC, bleCharacteristicHandle), \n\t\tATMO_VARIABLE(BLE_TVOC, bleServiceHandle), \n\t\tATMO_PROPERTY(BLE_TVOC, bleCharacteristicUuid), \n\t\tproperty, permission, ATMO_GetMaxValueSize(3, 64, types));\n\t\n\tATMO_BLE_GATTSRegisterCharacteristicAbilityHandle(\n\t\tATMO_PROPERTY(BLE_TVOC, instance),\n\t\tATMO_VARIABLE(BLE_TVOC, bleCharacteristicHandle), \n\t\tATMO_BLE_Characteristic_Written, \n\t\tATMO_ABILITY(BLE_TVOC, written));\n\t\n\treturn ATMO_Status_Success;\n\t",
              "setValue": "\n\t\n\t// Convert to the desired write data type\n\tATMO_Value_t convertedValue;\n\tATMO_InitValue(&convertedValue);\n\tATMO_CreateValueConverted(&convertedValue, ATMO_PROPERTY(BLE_TVOC, readDataType), in);\n\n\tATMO_BLE_GATTSSetCharacteristic(\n\t\tATMO_PROPERTY(BLE_TVOC, instance),\n\t\tATMO_VARIABLE(BLE_TVOC, bleCharacteristicHandle),\n\t\tconvertedValue.size, \n\t\t(uint8_t *)convertedValue.data,\n\t\tNULL);\n\t\n\tATMO_FreeValue(&convertedValue);\n\t\t\n\treturn ATMO_Status_Success;\n\t",
              "written": "\n\tATMO_CreateValueConverted(out, ATMO_PROPERTY(BLE_TVOC, writeDataType), in);\n\treturn ATMO_Status_Success;\n\t",
              "subscibed": "\treturn ATMO_Status_Success;",
              "unsubscribed": "\treturn ATMO_Status_Success;"
            },
            "variables": {
              "bleServiceHandle": {
                "type": "ATMO_BLE_Handle_t"
              },
              "bleCharacteristicHandle": {
                "type": "ATMO_BLE_Handle_t"
              }
            },
            "embeddedPropertyConversions": {
              "bleServiceUuid": "string",
              "bleCharacteristicUuid": "string"
            },
            "codeUserChanged": {
              "setup": false,
              "setValue": false,
              "written": false,
              "subscibed": false,
              "unsubscribed": false
            },
            "instance": 0,
            "bleServiceUuid": "08d41e61-ac11-40a2-a95a-e0e0fb5336f8",
            "bleCharacteristicUuid": "08d41e61-ac11-40a2-a95a-e0e0fb5336f9",
            "read": true,
            "write": false,
            "notify": true,
            "readDataType": "ATMO_DATATYPE_STRING",
            "writeDataType": "ATMO_DATATYPE_STRING",
            "notifyDataType": "ATMO_DATATYPE_STRING"
          },
          "meta": {
            "editorX": 603,
            "editorY": 30,
            "lastTrigger": "written"
          },
          "triggers": {
            "triggered": [],
            "written": [],
            "subscibed": [],
            "unsubscribed": []
          },
          "interruptAbilities": {
            "trigger": false,
            "setup": false,
            "setValue": "valueSet",
            "written": true,
            "subscibed": true,
            "unsubscribed": true
          },
          "abilities": [
            {
              "name": "trigger",
              "triggers": [
                "triggered"
              ]
            },
            {
              "name": "setup",
              "triggers": []
            },
            {
              "name": "setValue",
              "triggers": []
            },
            {
              "name": "written",
              "triggers": [
                "written"
              ]
            },
            {
              "name": "subscibed",
              "triggers": [
                "subscibed"
              ]
            },
            {
              "name": "unsubscribed",
              "triggers": [
                "unsubscribed"
              ]
            }
          ]
        },
        {
          "name": "AirQuality_TVOC",
          "type": "EmbeddedCCS811",
          "variants": [
            "embedded",
            "triggers",
            "abilities",
            "properties",
            "variables"
          ],
          "properties": {
            "errorData": {},
            "code": {
              "trigger": "\treturn ATMO_Status_Success;",
              "setup": "\tATMO_CCS811_Config_t config;\n\tconfig.operatingMode = ATMO_PROPERTY(AirQuality_TVOC, operatingMode);\n\tconfig.address = ATMO_PROPERTY(AirQuality_TVOC, i2cAddress);\n\tconfig.i2cDriverInstance = ATMO_PROPERTY(AirQuality_TVOC, i2cInstance);\n\n\treturn ( ATMO_CCS811_Init(&config) == ATMO_CCS811_Status_Success ) ? ATMO_Status_Success : ATMO_Status_Fail;\n",
              "setEnabled": "ATMO_CCS811_SetEnabled(true);\nreturn ATMO_Status_Success;",
              "setDisabled": "ATMO_CCS811_SetEnabled(false);\nreturn ATMO_Status_Success;",
              "setEnabledDisabled": "bool enabled = false;\nATMO_GetBool(in, &enabled);\nATMO_CCS811_SetEnabled(enabled);\nreturn ATMO_Status_Success;",
              "readTVOC": "    uint16_t tvoc;\n\n    if(ATMO_CCS811_GetTVOC(&tvoc) == ATMO_CCS811_Status_Success)\n    {\n        ATMO_CreateValueUnsignedInt(out, (unsigned int)tvoc);\n    }\n    else\n    {\n        ATMO_CreateValueVoid(out);\n    }\n    \n    return ATMO_Status_Success;",
              "readCO2": "    uint16_t co2;\n    \n    if(ATMO_CCS811_GetCO2(&co2) == ATMO_CCS811_Status_Success)\n    {\n        ATMO_CreateValueInt(out, (int)co2);\n    }\n    else\n    {\n        ATMO_CreateValueVoid(out);\n    }\n  \n    return ATMO_Status_Success;"
            },
            "variables": {},
            "embeddedPropertyConversions": {},
            "codeUserChanged": {
              "setup": false,
              "setEnabled": false,
              "setDisabled": false,
              "setEnabledDisabled": false,
              "readTVOC": true,
              "readCO2": false
            },
            "i2cInstance": 1,
            "i2cAddress": "0x5A",
            "operatingMode": "1"
          },
          "meta": {
            "editorX": 300,
            "editorY": 31,
            "lastTrigger": "TVOCRead"
          },
          "triggers": {
            "triggered": [],
            "TVOCRead": [
              {
                "mapping": {},
                "targetOrder": [],
                "targetElement": "BLE_TVOC",
                "targetAbility": "setValue"
              }
            ],
            "CO2Read": []
          },
          "interruptAbilities": {
            "trigger": false,
            "setup": false,
            "setEnabled": false,
            "setDisabled": false,
            "setEnabledDisabled": false,
            "readTVOC": false,
            "readCO2": false
          },
          "abilities": [
            {
              "name": "trigger",
              "triggers": [
                "triggered"
              ]
            },
            {
              "name": "setup",
              "triggers": []
            },
            {
              "name": "setEnabled",
              "triggers": []
            },
            {
              "name": "setDisabled",
              "triggers": []
            },
            {
              "name": "setEnabledDisabled",
              "triggers": []
            },
            {
              "name": "readTVOC",
              "triggers": [
                "TVOCRead"
              ]
            },
            {
              "name": "readCO2",
              "triggers": [
                "CO2Read"
              ]
            }
          ]
        },
        {
          "name": "AirQuality_CO2",
          "type": "EmbeddedCCS811",
          "variants": [
            "embedded",
            "triggers",
            "abilities",
            "properties",
            "variables"
          ],
          "properties": {
            "errorData": {},
            "code": {
              "trigger": "\treturn ATMO_Status_Success;",
              "setup": "\tATMO_CCS811_Config_t config;\n\tconfig.operatingMode = ATMO_PROPERTY(AirQuality_CO2, operatingMode);\n\tconfig.address = ATMO_PROPERTY(AirQuality_CO2, i2cAddress);\n\tconfig.i2cDriverInstance = ATMO_PROPERTY(AirQuality_CO2, i2cInstance);\n\n\treturn ( ATMO_CCS811_Init(&config) == ATMO_CCS811_Status_Success ) ? ATMO_Status_Success : ATMO_Status_Fail;\n",
              "setEnabled": "ATMO_CCS811_SetEnabled(true);\nreturn ATMO_Status_Success;",
              "setDisabled": "ATMO_CCS811_SetEnabled(false);\nreturn ATMO_Status_Success;",
              "setEnabledDisabled": "bool enabled = false;\nATMO_GetBool(in, &enabled);\nATMO_CCS811_SetEnabled(enabled);\nreturn ATMO_Status_Success;",
              "readTVOC": "    uint16_t tvoc;\n\n    if(ATMO_CCS811_GetTVOC(&tvoc) == ATMO_CCS811_Status_Success)\n    {\n        ATMO_CreateValueUnsignedInt(out, (unsigned int)tvoc);\n    }\n    else\n    {\n        ATMO_CreateValueVoid(out);\n    }\n    \n    return ATMO_Status_Success;",
              "readCO2": "    uint16_t co2;\n    \n    if(ATMO_CCS811_GetCO2(&co2) == ATMO_CCS811_Status_Success)\n    {\n        ATMO_CreateValueInt(out, (int)co2);\n    }\n    else\n    {\n        ATMO_CreateValueVoid(out);\n    }\n  \n    return ATMO_Status_Success;"
            },
            "variables": {},
            "embeddedPropertyConversions": {},
            "codeUserChanged": {
              "setup": false,
              "setEnabled": false,
              "setDisabled": false,
              "setEnabledDisabled": false,
              "readTVOC": false,
              "readCO2": false
            },
            "i2cInstance": 1,
            "i2cAddress": "0x5A",
            "operatingMode": "1"
          },
          "meta": {
            "editorX": 299,
            "editorY": 117,
            "lastTrigger": "CO2Read"
          },
          "triggers": {
            "triggered": [],
            "TVOCRead": [
              {
                "mapping": {},
                "targetOrder": [],
                "targetElement": "BLE_CO2",
                "targetAbility": "setValue"
              }
            ],
            "CO2Read": [
              {
                "mapping": {},
                "targetOrder": [],
                "targetElement": "BLE_CO2",
                "targetAbility": "setValue"
              }
            ]
          },
          "interruptAbilities": {
            "trigger": false,
            "setup": false,
            "setEnabled": false,
            "setDisabled": false,
            "setEnabledDisabled": false,
            "readTVOC": false,
            "readCO2": false
          },
          "abilities": [
            {
              "name": "trigger",
              "triggers": [
                "triggered"
              ]
            },
            {
              "name": "setup",
              "triggers": []
            },
            {
              "name": "setEnabled",
              "triggers": []
            },
            {
              "name": "setDisabled",
              "triggers": []
            },
            {
              "name": "setEnabledDisabled",
              "triggers": []
            },
            {
              "name": "readTVOC",
              "triggers": [
                "TVOCRead"
              ]
            },
            {
              "name": "readCO2",
              "triggers": [
                "CO2Read"
              ]
            }
          ]
        },
        {
          "name": "BLE_CO2",
          "type": "EmbeddedBLECharacteristicCustom",
          "variants": [
            "embedded",
            "triggers",
            "abilities",
            "properties",
            "variables",
            "ble"
          ],
          "properties": {
            "errorData": {},
            "code": {
              "trigger": "\treturn ATMO_Status_Success;",
              "setup": "\n\tATMO_BLE_GATTSAddService(\n\t\tATMO_PROPERTY(BLE_CO2, instance),\n\t\t&ATMO_VARIABLE(BLE_CO2, bleServiceHandle), \n\t\tATMO_PROPERTY(BLE_CO2, bleServiceUuid));\n\t\n\tuint8_t property = 0;\n\tuint8_t permission = 0;\n\t\n\tproperty |= ATMO_PROPERTY(BLE_CO2, read) ? ATMO_BLE_Property_Read : 0;\n\tproperty |= ATMO_PROPERTY(BLE_CO2, write) ? ATMO_BLE_Property_Write : 0;\n\tproperty |= ATMO_PROPERTY(BLE_CO2, notify) ? ATMO_BLE_Property_Notify : 0;\n\n\tpermission |= ATMO_PROPERTY(BLE_CO2, read) ? ATMO_BLE_Permission_Read : 0;\n\tpermission |= ATMO_PROPERTY(BLE_CO2, write) ? ATMO_BLE_Permission_Write : 0;\n\n\tATMO_DATATYPE types[3] = {ATMO_PROPERTY(BLE_CO2, writeDataType), ATMO_PROPERTY(BLE_CO2, readDataType), ATMO_PROPERTY(BLE_CO2, notifyDataType)};\n\t\n\tATMO_BLE_GATTSAddCharacteristic(\n\t\tATMO_PROPERTY(BLE_CO2, instance),\n\t\t&ATMO_VARIABLE(BLE_CO2, bleCharacteristicHandle), \n\t\tATMO_VARIABLE(BLE_CO2, bleServiceHandle), \n\t\tATMO_PROPERTY(BLE_CO2, bleCharacteristicUuid), \n\t\tproperty, permission, ATMO_GetMaxValueSize(3, 64, types));\n\t\n\tATMO_BLE_GATTSRegisterCharacteristicAbilityHandle(\n\t\tATMO_PROPERTY(BLE_CO2, instance),\n\t\tATMO_VARIABLE(BLE_CO2, bleCharacteristicHandle), \n\t\tATMO_BLE_Characteristic_Written, \n\t\tATMO_ABILITY(BLE_CO2, written));\n\t\n\treturn ATMO_Status_Success;\n\t",
              "setValue": "\n\t\n\t// Convert to the desired write data type\n\tATMO_Value_t convertedValue;\n\tATMO_InitValue(&convertedValue);\n\tATMO_CreateValueConverted(&convertedValue, ATMO_PROPERTY(BLE_CO2, readDataType), in);\n\n\tATMO_BLE_GATTSSetCharacteristic(\n\t\tATMO_PROPERTY(BLE_CO2, instance),\n\t\tATMO_VARIABLE(BLE_CO2, bleCharacteristicHandle),\n\t\tconvertedValue.size, \n\t\t(uint8_t *)convertedValue.data,\n\t\tNULL);\n\t\n\tATMO_FreeValue(&convertedValue);\n\t\t\n\treturn ATMO_Status_Success;\n\t",
              "written": "\n\tATMO_CreateValueConverted(out, ATMO_PROPERTY(BLE_CO2, writeDataType), in);\n\treturn ATMO_Status_Success;\n\t",
              "subscibed": "\treturn ATMO_Status_Success;",
              "unsubscribed": "\treturn ATMO_Status_Success;"
            },
            "variables": {
              "bleServiceHandle": {
                "type": "ATMO_BLE_Handle_t"
              },
              "bleCharacteristicHandle": {
                "type": "ATMO_BLE_Handle_t"
              }
            },
            "embeddedPropertyConversions": {
              "bleServiceUuid": "string",
              "bleCharacteristicUuid": "string"
            },
            "codeUserChanged": {
              "setup": false,
              "setValue": false,
              "written": false,
              "subscibed": false,
              "unsubscribed": false
            },
            "instance": 0,
            "bleServiceUuid": "08d41e61-ac11-40a2-a95a-e0e0fb5336f8",
            "bleCharacteristicUuid": "08d41e61-ac11-40a2-a95a-e0e0fb5336fa",
            "read": true,
            "write": false,
            "notify": true,
            "readDataType": "ATMO_DATATYPE_STRING",
            "writeDataType": "ATMO_DATATYPE_STRING",
            "notifyDataType": "ATMO_DATATYPE_STRING"
          },
          "meta": {
            "editorX": 602,
            "editorY": 116,
            "lastTrigger": "written"
          },
          "triggers": {
            "triggered": [],
            "written": [],
            "subscibed": [],
            "unsubscribed": []
          },
          "interruptAbilities": {
            "trigger": false,
            "setup": false,
            "setValue": "valueSet",
            "written": true,
            "subscibed": true,
            "unsubscribed": true
          },
          "abilities": [
            {
              "name": "trigger",
              "triggers": [
                "triggered"
              ]
            },
            {
              "name": "setup",
              "triggers": []
            },
            {
              "name": "setValue",
              "triggers": []
            },
            {
              "name": "written",
              "triggers": [
                "written"
              ]
            },
            {
              "name": "subscibed",
              "triggers": [
                "subscibed"
              ]
            },
            {
              "name": "unsubscribed",
              "triggers": [
                "unsubscribed"
              ]
            }
          ]
        },
        {
          "name": "Pressure",
          "type": "EmbeddedMPL3115",
          "variants": [
            "embedded",
            "triggers",
            "abilities",
            "properties",
            "variables"
          ],
          "properties": {
            "errorData": {},
            "code": {
              "trigger": "\treturn ATMO_Status_Success;",
              "setup": "\tATMO_MPL3115_Config_t config;\n\tconfig.address = ATMO_PROPERTY(Pressure, i2cAddress);\n\tconfig.i2cDriverInstance = ATMO_PROPERTY(Pressure, i2cInstance);\n\tconfig.MPLsettings.mode = MPL_MODE_PRESSURE;\n\tconfig.MPLsettings.oversample = MPL_OS_0;\t\t\t// oversampling = 1\n\tconfig.MPLsettings.autoAcquisitionTime = MPL_ST_0;\t// Auto acquisition time = 1s\n\tconfig.MPLsettings.pressureOffset = ATMO_PROPERTY(Pressure, pressureOffset);\t// Offset pressure correction = 4*-128 = -512Pa (8 bits signed integer)\n\tconfig.MPLsettings.altitudeOffset = ATMO_PROPERTY(Pressure, altitudeOffset);\t// Offset altitude correction = 128m (signed 8 bits integer)\n\tconfig.MPLsettings.tempOffset = ATMO_PROPERTY(Pressure, tempOffset);\t\t\t// Offset temperature correction -8C (0.0625C/LSB)\n\tconfig.MPLsettings.fifoMode = FIFO_DISABLED;\t\t// FIFO mode disabled\n\tconfig.MPLsettings.fifoWatermark = 5;\t\t\t\t// 6 bits to set the number of FIFO samples required to trigger a watermark interrupt.\n\tconfig.MPLsettings.fifoINTpin = FIFO_INT1;\t\t\t// set pin INT1 as output for FIFO interrupt\n\n\treturn ( ATMO_MPL3115_Init(&config) == ATMO_MPL3115_Status_Success ) ? ATMO_Status_Success : ATMO_Status_Fail;\n",
              "setEnabled": "ATMO_MPL3115_SetEnabled(true);\nreturn ATMO_Status_Success;",
              "setDisabled": "ATMO_MPL3115_SetEnabled(false);\nreturn ATMO_Status_Success;",
              "setEnabledDisabled": "bool enabled = false;\nATMO_GetBool(in, &enabled);\nATMO_MPL3115_SetEnabled(enabled);\nreturn ATMO_Status_Success;",
              "readAltitude": "    uint32_t altitudeMeters;\n    if(ATMO_MPL3115_GetAltitude(&altitudeMeters) != ATMO_MPL3115_Status_Success)\n    {\n        ATMO_CreateValueVoid(out);\n        return ATMO_Status_Fail;\n    }\n    ATMO_CreateValueInt(out, (int)altitudeMeters);\n    return ATMO_Status_Success;",
              "readPressure": "    uint32_t pressurePa;\n    if(ATMO_MPL3115_GetPressure(&pressurePa) != ATMO_MPL3115_Status_Success)\n    {\n        ATMO_CreateValueVoid(out);\n        return ATMO_Status_Fail;\n    }\n    ATMO_CreateValueInt(out, (int)pressurePa);\n    return ATMO_Status_Success;",
              "readPressureKpa": "    uint32_t pressurePa;\n    if(ATMO_MPL3115_GetPressure(&pressurePa) != ATMO_MPL3115_Status_Success)\n    {\n        ATMO_CreateValueVoid(out);\n        return ATMO_Status_Fail;\n    }\n    ATMO_CreateValueInt(out, (int)(pressurePa/1000));\n    return ATMO_Status_Success;"
            },
            "variables": {},
            "embeddedPropertyConversions": {},
            "codeUserChanged": {
              "setup": false,
              "setEnabled": false,
              "setDisabled": false,
              "setEnabledDisabled": false,
              "readAltitude": false,
              "readPressure": false,
              "readPressureKpa": false
            },
            "i2cInstance": 1,
            "i2cAddress": "0x60",
            "pressureOffset": "0",
            "altitudeOffset": "0",
            "tempOffset": "0"
          },
          "meta": {
            "editorX": 298,
            "editorY": 199,
            "lastTrigger": "pressureRead"
          },
          "triggers": {
            "triggered": [],
            "altitudeRead": [],
            "pressureRead": [
              {
                "mapping": {},
                "targetOrder": [],
                "targetElement": "BLE_Pressure",
                "targetAbility": "setValue"
              }
            ],
            "pressureReadKpa": []
          },
          "interruptAbilities": {
            "trigger": false,
            "setup": false,
            "setEnabled": false,
            "setDisabled": false,
            "setEnabledDisabled": false,
            "readAltitude": false,
            "readPressure": false,
            "readPressureKpa": false
          },
          "abilities": [
            {
              "name": "trigger",
              "triggers": [
                "triggered"
              ]
            },
            {
              "name": "setup",
              "triggers": []
            },
            {
              "name": "setEnabled",
              "triggers": []
            },
            {
              "name": "setDisabled",
              "triggers": []
            },
            {
              "name": "setEnabledDisabled",
              "triggers": []
            },
            {
              "name": "readAltitude",
              "triggers": [
                "altitudeRead"
              ]
            },
            {
              "name": "readPressure",
              "triggers": [
                "pressureRead"
              ]
            },
            {
              "name": "readPressureKpa",
              "triggers": [
                "pressureReadKpa"
              ]
            }
          ]
        },
        {
          "name": "BLE_Pressure",
          "type": "EmbeddedBLECharacteristicCustom",
          "variants": [
            "embedded",
            "triggers",
            "abilities",
            "properties",
            "variables",
            "ble"
          ],
          "properties": {
            "errorData": {},
            "code": {
              "trigger": "\treturn ATMO_Status_Success;",
              "setup": "\n\tATMO_BLE_GATTSAddService(\n\t\tATMO_PROPERTY(BLE_Pressure, instance),\n\t\t&ATMO_VARIABLE(BLE_Pressure, bleServiceHandle), \n\t\tATMO_PROPERTY(BLE_Pressure, bleServiceUuid));\n\t\n\tuint8_t property = 0;\n\tuint8_t permission = 0;\n\t\n\tproperty |= ATMO_PROPERTY(BLE_Pressure, read) ? ATMO_BLE_Property_Read : 0;\n\tproperty |= ATMO_PROPERTY(BLE_Pressure, write) ? ATMO_BLE_Property_Write : 0;\n\tproperty |= ATMO_PROPERTY(BLE_Pressure, notify) ? ATMO_BLE_Property_Notify : 0;\n\n\tpermission |= ATMO_PROPERTY(BLE_Pressure, read) ? ATMO_BLE_Permission_Read : 0;\n\tpermission |= ATMO_PROPERTY(BLE_Pressure, write) ? ATMO_BLE_Permission_Write : 0;\n\n\tATMO_DATATYPE types[3] = {ATMO_PROPERTY(BLE_Pressure, writeDataType), ATMO_PROPERTY(BLE_Pressure, readDataType), ATMO_PROPERTY(BLE_Pressure, notifyDataType)};\n\t\n\tATMO_BLE_GATTSAddCharacteristic(\n\t\tATMO_PROPERTY(BLE_Pressure, instance),\n\t\t&ATMO_VARIABLE(BLE_Pressure, bleCharacteristicHandle), \n\t\tATMO_VARIABLE(BLE_Pressure, bleServiceHandle), \n\t\tATMO_PROPERTY(BLE_Pressure, bleCharacteristicUuid), \n\t\tproperty, permission, ATMO_GetMaxValueSize(3, 64, types));\n\t\n\tATMO_BLE_GATTSRegisterCharacteristicAbilityHandle(\n\t\tATMO_PROPERTY(BLE_Pressure, instance),\n\t\tATMO_VARIABLE(BLE_Pressure, bleCharacteristicHandle), \n\t\tATMO_BLE_Characteristic_Written, \n\t\tATMO_ABILITY(BLE_Pressure, written));\n\t\n\treturn ATMO_Status_Success;\n\t",
              "setValue": "\n\t\n\t// Convert to the desired write data type\n\tATMO_Value_t convertedValue;\n\tATMO_InitValue(&convertedValue);\n\tATMO_CreateValueConverted(&convertedValue, ATMO_PROPERTY(BLE_Pressure, readDataType), in);\n\n\tATMO_BLE_GATTSSetCharacteristic(\n\t\tATMO_PROPERTY(BLE_Pressure, instance),\n\t\tATMO_VARIABLE(BLE_Pressure, bleCharacteristicHandle),\n\t\tconvertedValue.size, \n\t\t(uint8_t *)convertedValue.data,\n\t\tNULL);\n\t\n\tATMO_FreeValue(&convertedValue);\n\t\t\n\treturn ATMO_Status_Success;\n\t",
              "written": "\n\tATMO_CreateValueConverted(out, ATMO_PROPERTY(BLE_Pressure, writeDataType), in);\n\treturn ATMO_Status_Success;\n\t",
              "subscibed": "\treturn ATMO_Status_Success;",
              "unsubscribed": "\treturn ATMO_Status_Success;"
            },
            "variables": {
              "bleServiceHandle": {
                "type": "ATMO_BLE_Handle_t"
              },
              "bleCharacteristicHandle": {
                "type": "ATMO_BLE_Handle_t"
              }
            },
            "embeddedPropertyConversions": {
              "bleServiceUuid": "string",
              "bleCharacteristicUuid": "string"
            },
            "codeUserChanged": {
              "setup": false,
              "setValue": false,
              "written": false,
              "subscibed": false,
              "unsubscribed": false
            },
            "instance": 0,
            "bleServiceUuid": "08d41e61-ac11-40a2-a95a-e0e0fb5336f8",
            "bleCharacteristicUuid": "08d41e61-ac11-40a2-a95a-e0e0fb5336fc",
            "read": true,
            "write": false,
            "notify": true,
            "readDataType": "ATMO_DATATYPE_STRING",
            "writeDataType": "ATMO_DATATYPE_STRING",
            "notifyDataType": "ATMO_DATATYPE_STRING"
          },
          "meta": {
            "editorX": 600,
            "editorY": 199,
            "lastTrigger": "written"
          },
          "triggers": {
            "triggered": [],
            "written": [],
            "subscibed": [],
            "unsubscribed": []
          },
          "interruptAbilities": {
            "trigger": false,
            "setup": false,
            "setValue": "valueSet",
            "written": true,
            "subscibed": true,
            "unsubscribed": true
          },
          "abilities": [
            {
              "name": "trigger",
              "triggers": [
                "triggered"
              ]
            },
            {
              "name": "setup",
              "triggers": []
            },
            {
              "name": "setValue",
              "triggers": []
            },
            {
              "name": "written",
              "triggers": [
                "written"
              ]
            },
            {
              "name": "subscibed",
              "triggers": [
                "subscibed"
              ]
            },
            {
              "name": "unsubscribed",
              "triggers": [
                "unsubscribed"
              ]
            }
          ]
        },
        {
          "name": "Temperature",
          "type": "EmbeddedENS210",
          "variants": [
            "embedded",
            "triggers",
            "abilities",
            "properties",
            "variables"
          ],
          "properties": {
            "errorData": {},
            "code": {
              "trigger": "\treturn ATMO_Status_Success;",
              "setup": "\tATMO_ENS210_Config_t config;\n\tconfig.address = ATMO_PROPERTY(Temperature, i2cAddress);\n\tconfig.i2cDriverInstance = ATMO_PROPERTY(Temperature, i2cInstance);\n\tconfig.tempCalibrationOffset = ATMO_PROPERTY(Temperature, tempCalibrationOffset);\n\n\treturn ( ATMO_ENS210_Init(&config) == ATMO_ENS210_Status_Success ) ? ATMO_Status_Success : ATMO_Status_Fail;\n",
              "setEnabled": "ATMO_ENS210_SetEnabled(true);\nreturn ATMO_Status_Success;",
              "setDisabled": "ATMO_ENS210_SetEnabled(false);\nreturn ATMO_Status_Success;",
              "setEnabledDisabled": "bool enabled = false;\nATMO_GetBool(in, &enabled);\nATMO_ENS210_SetEnabled(enabled);\nreturn ATMO_Status_Success;",
              "readTemperature": "    float tempC;\n    \n    if(ATMO_ENS210_GetTemperatureFloat(&tempC) == ATMO_ENS210_Status_Success)\n    {\n        ATMO_CreateValueFloat(out, tempC);\n    }\n    else\n    {\n        ATMO_CreateValueVoid(out);\n    }\n    \n    return ATMO_Status_Success;",
              "readHumidity": "    float humidityPct;\n\n    if(ATMO_ENS210_GetHumidityFloat(&humidityPct) == ATMO_ENS210_Status_Success)\n    {\n        ATMO_CreateValueFloat(out, humidityPct);\n    }\n    else\n    {\n        ATMO_CreateValueVoid(out);\n    }\n    \n    return ATMO_Status_Success;"
            },
            "variables": {},
            "embeddedPropertyConversions": {},
            "codeUserChanged": {
              "setup": false,
              "setEnabled": false,
              "setDisabled": false,
              "setEnabledDisabled": false,
              "readTemperature": false,
              "readHumidity": false
            },
            "i2cInstance": 1,
            "i2cAddress": "0x43",
            "tempCalibrationOffset": -7
          },
          "meta": {
            "editorX": 299,
            "editorY": 289,
            "lastTrigger": "temperatureRead"
          },
          "triggers": {
            "triggered": [],
            "temperatureRead": [
              {
                "mapping": {},
                "targetOrder": [],
                "targetElement": "BLE_Temperature",
                "targetAbility": "setValue"
              }
            ],
            "humidityRead": []
          },
          "interruptAbilities": {
            "trigger": false,
            "setup": false,
            "setEnabled": false,
            "setDisabled": false,
            "setEnabledDisabled": false,
            "readTemperature": false,
            "readHumidity": false
          },
          "abilities": [
            {
              "name": "trigger",
              "triggers": [
                "triggered"
              ]
            },
            {
              "name": "setup",
              "triggers": []
            },
            {
              "name": "setEnabled",
              "triggers": []
            },
            {
              "name": "setDisabled",
              "triggers": []
            },
            {
              "name": "setEnabledDisabled",
              "triggers": []
            },
            {
              "name": "readTemperature",
              "triggers": [
                "temperatureRead"
              ]
            },
            {
              "name": "readHumidity",
              "triggers": [
                "humidityRead"
              ]
            }
          ]
        },
        {
          "name": "BLE_Temperature",
          "type": "EmbeddedBLECharacteristicCustom",
          "variants": [
            "embedded",
            "triggers",
            "abilities",
            "properties",
            "variables",
            "ble"
          ],
          "properties": {
            "errorData": {},
            "code": {
              "trigger": "\treturn ATMO_Status_Success;",
              "setup": "\n\tATMO_BLE_GATTSAddService(\n\t\tATMO_PROPERTY(BLE_Temperature, instance),\n\t\t&ATMO_VARIABLE(BLE_Temperature, bleServiceHandle), \n\t\tATMO_PROPERTY(BLE_Temperature, bleServiceUuid));\n\t\n\tuint8_t property = 0;\n\tuint8_t permission = 0;\n\t\n\tproperty |= ATMO_PROPERTY(BLE_Temperature, read) ? ATMO_BLE_Property_Read : 0;\n\tproperty |= ATMO_PROPERTY(BLE_Temperature, write) ? ATMO_BLE_Property_Write : 0;\n\tproperty |= ATMO_PROPERTY(BLE_Temperature, notify) ? ATMO_BLE_Property_Notify : 0;\n\n\tpermission |= ATMO_PROPERTY(BLE_Temperature, read) ? ATMO_BLE_Permission_Read : 0;\n\tpermission |= ATMO_PROPERTY(BLE_Temperature, write) ? ATMO_BLE_Permission_Write : 0;\n\n\tATMO_DATATYPE types[3] = {ATMO_PROPERTY(BLE_Temperature, writeDataType), ATMO_PROPERTY(BLE_Temperature, readDataType), ATMO_PROPERTY(BLE_Temperature, notifyDataType)};\n\t\n\tATMO_BLE_GATTSAddCharacteristic(\n\t\tATMO_PROPERTY(BLE_Temperature, instance),\n\t\t&ATMO_VARIABLE(BLE_Temperature, bleCharacteristicHandle), \n\t\tATMO_VARIABLE(BLE_Temperature, bleServiceHandle), \n\t\tATMO_PROPERTY(BLE_Temperature, bleCharacteristicUuid), \n\t\tproperty, permission, ATMO_GetMaxValueSize(3, 64, types));\n\t\n\tATMO_BLE_GATTSRegisterCharacteristicAbilityHandle(\n\t\tATMO_PROPERTY(BLE_Temperature, instance),\n\t\tATMO_VARIABLE(BLE_Temperature, bleCharacteristicHandle), \n\t\tATMO_BLE_Characteristic_Written, \n\t\tATMO_ABILITY(BLE_Temperature, written));\n\t\n\treturn ATMO_Status_Success;\n\t",
              "setValue": "\n\t\n\t// Convert to the desired write data type\n\tATMO_Value_t convertedValue;\n\tATMO_InitValue(&convertedValue);\n\tATMO_CreateValueConverted(&convertedValue, ATMO_PROPERTY(BLE_Temperature, readDataType), in);\n\n\tATMO_BLE_GATTSSetCharacteristic(\n\t\tATMO_PROPERTY(BLE_Temperature, instance),\n\t\tATMO_VARIABLE(BLE_Temperature, bleCharacteristicHandle),\n\t\tconvertedValue.size, \n\t\t(uint8_t *)convertedValue.data,\n\t\tNULL);\n\t\n\tATMO_FreeValue(&convertedValue);\n\t\t\n\treturn ATMO_Status_Success;\n\t",
              "written": "\n\tATMO_CreateValueConverted(out, ATMO_PROPERTY(BLE_Temperature, writeDataType), in);\n\treturn ATMO_Status_Success;\n\t",
              "subscibed": "\treturn ATMO_Status_Success;",
              "unsubscribed": "\treturn ATMO_Status_Success;"
            },
            "variables": {
              "bleServiceHandle": {
                "type": "ATMO_BLE_Handle_t"
              },
              "bleCharacteristicHandle": {
                "type": "ATMO_BLE_Handle_t"
              }
            },
            "embeddedPropertyConversions": {
              "bleServiceUuid": "string",
              "bleCharacteristicUuid": "string"
            },
            "codeUserChanged": {
              "setup": false,
              "setValue": false,
              "written": false,
              "subscibed": false,
              "unsubscribed": false
            },
            "instance": 0,
            "bleServiceUuid": "08d41e61-ac11-40a2-a95a-e0e0fb5336f8",
            "bleCharacteristicUuid": "08d41e61-ac11-40a2-a95a-e0e0fb5336fb",
            "read": true,
            "write": false,
            "notify": true,
            "readDataType": "ATMO_DATATYPE_STRING",
            "writeDataType": "ATMO_DATATYPE_STRING",
            "notifyDataType": "ATMO_DATATYPE_STRING"
          },
          "meta": {
            "editorX": 600,
            "editorY": 289,
            "lastTrigger": "written"
          },
          "triggers": {
            "triggered": [],
            "written": [],
            "subscibed": [],
            "unsubscribed": []
          },
          "interruptAbilities": {
            "trigger": false,
            "setup": false,
            "setValue": "valueSet",
            "written": true,
            "subscibed": true,
            "unsubscribed": true
          },
          "abilities": [
            {
              "name": "trigger",
              "triggers": [
                "triggered"
              ]
            },
            {
              "name": "setup",
              "triggers": []
            },
            {
              "name": "setValue",
              "triggers": []
            },
            {
              "name": "written",
              "triggers": [
                "written"
              ]
            },
            {
              "name": "subscibed",
              "triggers": [
                "subscibed"
              ]
            },
            {
              "name": "unsubscribed",
              "triggers": [
                "unsubscribed"
              ]
            }
          ]
        },
        {
          "name": "Humidity",
          "type": "EmbeddedENS210",
          "variants": [
            "embedded",
            "triggers",
            "abilities",
            "properties",
            "variables"
          ],
          "properties": {
            "errorData": {},
            "code": {
              "trigger": "\treturn ATMO_Status_Success;",
              "setup": "\tATMO_ENS210_Config_t config;\n\tconfig.address = ATMO_PROPERTY(Humidity, i2cAddress);\n\tconfig.i2cDriverInstance = ATMO_PROPERTY(Humidity, i2cInstance);\n\tconfig.tempCalibrationOffset = ATMO_PROPERTY(Humidity, tempCalibrationOffset);\n\n\treturn ( ATMO_ENS210_Init(&config) == ATMO_ENS210_Status_Success ) ? ATMO_Status_Success : ATMO_Status_Fail;\n",
              "setEnabled": "ATMO_ENS210_SetEnabled(true);\nreturn ATMO_Status_Success;",
              "setDisabled": "ATMO_ENS210_SetEnabled(false);\nreturn ATMO_Status_Success;",
              "setEnabledDisabled": "bool enabled = false;\nATMO_GetBool(in, &enabled);\nATMO_ENS210_SetEnabled(enabled);\nreturn ATMO_Status_Success;",
              "readTemperature": "    float tempC;\n    \n    if(ATMO_ENS210_GetTemperatureFloat(&tempC) == ATMO_ENS210_Status_Success)\n    {\n        ATMO_CreateValueFloat(out, tempC);\n    }\n    else\n    {\n        ATMO_CreateValueVoid(out);\n    }\n    \n    return ATMO_Status_Success;",
              "readHumidity": "    float humidityPct;\n\n    if(ATMO_ENS210_GetHumidityFloat(&humidityPct) == ATMO_ENS210_Status_Success)\n    {\n        ATMO_CreateValueFloat(out, humidityPct);\n    }\n    else\n    {\n        ATMO_CreateValueVoid(out);\n    }\n    \n    return ATMO_Status_Success;"
            },
            "variables": {},
            "embeddedPropertyConversions": {},
            "codeUserChanged": {
              "setup": false,
              "setEnabled": false,
              "setDisabled": false,
              "setEnabledDisabled": false,
              "readTemperature": false,
              "readHumidity": false
            },
            "i2cInstance": 1,
            "i2cAddress": "0x43",
            "tempCalibrationOffset": -7
          },
          "meta": {
            "editorX": 303,
            "editorY": 384,
            "lastTrigger": "humidityRead"
          },
          "triggers": {
            "triggered": [],
            "temperatureRead": [
              {
                "mapping": {},
                "targetOrder": [],
                "targetElement": "BLE_Humidity",
                "targetAbility": "setValue"
              }
            ],
            "humidityRead": [
              {
...

This file has been truncated, please download it to see its full contents.

Credits

Ben

Ben

4 projects • 10 followers

Comments