Skip to content

Plugin file

Plugin configuration file
{
  "name": "arwin_technology_lrs10701",
  "version": "1.0.0",
  "description": "Indoor Air Quality (IAQ) Sensor",
  "author": "Thinger.io",
  "license": "MIT",
  "repository": {
    "type": "git",
    "url": "https://github.com/thinger-io/plugins.git",
    "directory": "arwin-technology-lrs10701"
  },
  "metadata": {
    "name": "Arwin-Technology LRS10701",
    "description": "Indoor Air Quality (IAQ) Sensor",
    "image": "assets/lrs10701.png",
    "category": "devices",
    "vendor": "arwin-technology"
  },
  "resources": {
    "products": [
      {
        "description": "Indoor Air Quality (IAQ) Sensor",
        "enabled": true,
        "name": "Arwin-Technology LRS10701",
        "product": "arwin_technology_lrs10701",
        "profile": {
          "api": {
            "downlink": {
              "enabled": true,
              "handle_connectivity": false,
              "request": {
                "data": {
                  "path": "/downlink",
                  "payload": "{\n    \"data\"    : \"{{payload.data=\"\"}}\",\n    \"port\"    :  {{payload.port=85}},\n    \"priority\":  {{payload.priority=3}},\n    \"confirmed\" :  {{payload.confirmed=false}},\n    \"uplink\"  :  {{property.uplink}} \n}",
                  "payload_function": "",
                  "payload_type": "",
                  "plugin": "{{property.uplink.source}}",
                  "target": "plugin_endpoint"
                }
              }
            },
            "uplink": {
              "device_id_resolver": "getId",
              "enabled": true,
              "handle_connectivity": true,
              "request": {
                "data": {
                  "payload": "{{payload}}",
                  "payload_function": "",
                  "payload_type": "source_payload",
                  "resource_stream": "uplink",
                  "target": "resource_stream"
                }
              }
            }
          },
          "autoprovisions": {
            "device_autoprovisioning": {
              "config": {
                "mode": "pattern",
                "pattern": "lrs10701-.*"
              },
              "enabled": true
            }
          },
          "buckets": {
            "device_data": {
              "backend": "mongodb",
              "data": {
                "payload": "{{payload}}",
                "payload_function": "decodeThingerUplink",
                "payload_type": "source_payload",
                "resource": "uplink",
                "source": "resource",
                "update": "events"
              },
              "enabled": true,
              "retention": {
                "period": 3,
                "unit": "months"
              },
              "tags": []
            }
          },
          "code": {
            "code": "function decodeThingerUplink(thingerData) {\n    // 0. If data has already been decoded, we will return it\n    if (thingerData.decodedPayload) return thingerData.decodedPayload;\n    \n    // 1. Extract and Validate Input\n    // We need 'payload' (hex string) and 'fPort' (integer)\n    const hexPayload = thingerData.payload || \"\";\n    const port = thingerData.fPort || 1;\n\n    // 2. Convert Hex String to Byte Array\n    const bytes = [];\n    for (let i = 0; i < hexPayload.length; i += 2) {\n        bytes.push(parseInt(hexPayload.substr(i, 2), 16));\n    }\n\n    // 3. Dynamic Function Detection and Execution\n    \n    // CASE A: (The Things Stack v3)\n    if (typeof decodeUplink === 'function') {\n        try {\n            const input = {\n                bytes: bytes,\n                fPort: port\n            };\n            var result = decodeUplink(input);\n            \n            if (result.data) return result.data;\n\n            return result; \n        } catch (e) {\n            console.error(\"Error inside decodeUplink:\", e);\n            throw e;\n        }\n    }\n\n    // CASE B: Legacy TTN (v2)\n    else if (typeof Decoder === 'function') {\n        try {\n            return Decoder(bytes, port);\n        } catch (e) {\n            console.error(\"Error inside Decoder:\", e);\n            throw e;\n        }\n    }\n\n    // CASE C: No decoder found\n    else {\n        throw new Error(\"No compatible TTN decoder function (decodeUplink or Decoder) found in scope.\");\n    }\n}\n\n\n// TTN decoder\nvar lrs10701_events = ['heartbeat/button', 'rsvd', 'T/H', 'CO2', 'EC1', 'EC2', 'TVOC', 'PMx'];\nvar sensor_list = ['T/H', 'TVOC', 'CO2', 'PMx', 'Gas1', 'Gas2'];\nvar gas_sensor_type = ['None', 'NH3', 'H2S', 'NO2', 'CO', 'HCHO', 'Custom'];\n\nfunction hex2dec(hex) {\n  var dec = hex&0xffff;\n  if (dec & 0x8000)\n    dec = -(0x10000-dec);\n  return dec;\n}\n\nfunction decodeUplink(input) {\n  switch (input.fPort) {\n    case 10: // sensor data\n      var evt=\"\";\n      for (let i=0; i<8; i++) {\n        if ((0x01<<i)&input.bytes[0]) \n          if (evt===\"\")\n            evt=lrs10701_events[i];\n          else\n            evt=evt+\",\"+lrs10701_events[i];\n      }\n      var aqi_co2_t = input.bytes[1]<<24|input.bytes[2]<<16|input.bytes[3]<<8|input.bytes[4];\n      return {\n        data: {\n              event: evt,\n              aqi: (aqi_co2_t>>23)&0x1ff,\n              co2: (aqi_co2_t>>10&0x1fff),\n              temperature: (hex2dec(aqi_co2_t&0x3ff)-300)/10,\n              humidity: input.bytes[5]*0.5,\n              gas1: (input.bytes[6]<<8|input.bytes[7])/1000,\n              gas2: (input.bytes[8]<<8|input.bytes[9])/1000,\n              battery: input.bytes[10],\n            },\n        };\n    case 11: // sensor data\n      return {\n        data: {\n          tvoc: (input.bytes[0]<<8|input.bytes[1]),\n          \"pm1.0\": (input.bytes[2]<<16|input.bytes[3]<<8|input.bytes[4])/1000,\n          \"pm2.5\": (input.bytes[5]<<16|input.bytes[6]<<8|input.bytes[7])/1000,\n          \"pm10\": (input.bytes[8]<<16|input.bytes[9]<<8|input.bytes[10])/1000,\n        }\n      };\n    case 8: // version\n      var ver = input.bytes[0]+\".\"+(\"00\"+input.bytes[1]).slice(-2)+\".\"+(\"000\"+(input.bytes[2]<<8|input.bytes[3])).slice(-3);    \n      return {\n        data: {\n          firmwareVersion: ver,\n        }\n      };\n    case 12: // device settings\n      var sensor_ok=\"\";\n      for (let i=0; i<8; i++) {\n        if ((0x01<<i)&input.bytes[3]) \n          if (sensor_ok===\"\")\n            sensor_type=sensor_list[i];\n          else\n            sensor_type=sensor_type+\",\"+sensor_list[i];\n        if ((0x01<<i)&input.bytes[4]) \n          if (sensor_ok===\"\")\n            sensor_ok=sensor_list[i];\n          else\n            sensor_ok=sensor_ok+\",\"+sensor_list[i];\n      }\n      return {\n        data: {\n          dataUploadInterval: hex2dec(input.bytes[0]<<8|input.bytes[1]),\n          statusLED: input.bytes[2] === 1 ? \"on\" : \"off\",\n          sensorType: sensor_type,\n          sensorStatus: sensor_ok,\n          gas1Type: gas_sensor_type[input.bytes[5]],\n          gas2Type: gas_sensor_type[input.bytes[6]],\n        }\n      };\n    case 13: // threshold settings\n      switch (input.bytes[0]) {\n        case 0:\n          return {\n            data: {\n              highTemperatureThreshold: hex2dec(input.bytes[1]<<8|input.bytes[2]),\n              lowTemperatureThreshold: hex2dec(input.bytes[3]<<8|input.bytes[4]),\n              highHumidityThreshold: (input.bytes[5]),\n              lowHumidityThreshold: (input.bytes[6]),\n            }\n          };\n        case 1:\n          return {\n            data: {\n              co2Threshold: (input.bytes[1]<<8|input.bytes[2]),\n              tvocThreshold: (input.bytes[3]<<8|input.bytes[4]),\n              gas1Threshold: (input.bytes[5]<<8|input.bytes[6])/1000,\n              gas2Threshold: (input.bytes[7]<<8|input.bytes[8])/1000,\n            }\n          };\n        case 2:\n          return {\n            data: {\n              'pm1.0 Threshold': (input.bytes[1]<<16|input.bytes[2]<<8|input.bytes[3]),\n              'pm2.5 Threshold': (input.bytes[4]<<16|input.bytes[5]<<8|input.bytes[6]),\n              'pm10 Threshold': (input.bytes[7]<<16|input.bytes[8]<<8|input.bytes[9]),\n            }\n          };\n        default:\n          return {\n            errors: ['unknown packet type']\n          };\n      }\n      break;\n    default:\n      return {\n        errors: ['unknown FPort'],\n      };\n  }\n}\n\nfunction encodeDownlink(input) {\n  var payload = [];\n\n  if (input.data.cmd === 'getFirmwareVersion') {\n    return {\n      fPort: 20,\n      bytes: [0]\n    };\n  }\n  else if (input.data.cmd === 'getDeviceSettings') {\n    return {\n      fPort: 21,\n      bytes: [0]\n    };\n  }\n  else if (input.data.cmd === 'getThresholdSettings') {\n    return {\n      fPort: 21,\n      bytes: [1]\n    } ;   \n  }\n  else if (input.data.cmd === 'setDeviceSettings') {\n    var ult = input.data.dataUploadInterval;\n    var led = input.data.statusLED === 'on'?1:0;\n    var dack = 1;\n    return {\n      fPort: 22,\n      bytes: payload.concat(ult>>8,ult&0xff,led,dack)\n    };\n  }\n  else if (input.data.cmd === 'setTHThresholds') {\n    var htth = (input.data.highTemperatureThreshold&0xffff);\n    var ltth = (input.data.lowTemperatureThreshold&0xffff);\n    var hhth = input.data.highHumidityThreshold;\n    var lhth = input.data.lowHumidityThreshold;\n    return {\n      fPort: 23,\n      bytes: payload.concat(0,htth>>8,htth&0xff,ltth>>8,ltth&0xff,hhth,lhth)\n    };\n  }\n  else if (input.data.cmd === 'setGasesThresholds') {\n    var co2th = input.data.co2Threshold;\n    var tvocth = input.data.tvocThreshold;\n    var g1th = input.data.gas1Threshold*1000;\n    var g2th = input.data.gas2Threshold*1000;\n    return {\n      fPort: 23,\n      bytes: payload.concat(1,co2th>>8,co2th&0xff,tvocth>>8,tvocth&0xff,g1th>>8,g1th&0xff,g2th>>8,g2th&0xff)\n    };   \n  }\n  else if (input.data.cmd === 'setPMThresholds') {\n    var pm1p0th = input.data['pm1.0 Threshold'];\n    var pm2p5th = input.data['pm2.5 Threshold'];\n    var pm10th = input.data['pm10 Threshold'];\n    return {\n      fPort: 23,\n      bytes: payload.concat(2,pm1p0th>>16,(pm1p0th>>8)&0xff,pm1p0th&0xff,pm2p5th>>16,(pm2p5th>>8)&0xff,pm2p5th&0xff,pm10th>>16,(pm10th>>8)&0xff,pm10th&0xff)\n    };\n  }\n}\n",
            "environment": "javascript",
            "storage": "",
            "version": "1.0"
          },
          "properties": {
            "uplink": {
              "data": {
                "payload": "{{payload}}",
                "payload_function": "",
                "payload_type": "source_payload",
                "resource": "uplink",
                "source": "resource",
                "update": "events"
              },
              "default": {
                "source": "value"
              },
              "enabled": true
            }
          }
        },
        "_resources": {
          "properties": [
            {
              "property": "dashboard",
              "value": {
                "tabs": [
                  {
                    "name": "Air Quality",
                    "widgets": [
                      {
                        "layout": {
                          "col": 0,
                          "row": 0,
                          "sizeX": 2,
                          "sizeY": 6
                        },
                        "panel": {
                          "color": "#ffffff",
                          "currentColor": "#ffffff",
                          "showOffline": {
                            "type": "none"
                          },
                          "title": "Air Quality Index (AQI)"
                        },
                        "properties": {
                          "color": "#1abc9c",
                          "max": 500,
                          "min": 0,
                          "unit": "AQI"
                        },
                        "sources": [
                          {
                            "bucket": {
                              "backend": "mongodb",
                              "id": "device_data",
                              "mapping": "aqi",
                              "tags": {
                                "device": [],
                                "group": []
                              }
                            },
                            "color": "#1abc9c",
                            "name": "AQI",
                            "source": "bucket",
                            "timespan": {
                              "mode": "latest"
                            }
                          }
                        ],
                        "type": "donutchart"
                      },
                      {
                        "layout": {
                          "col": 2,
                          "row": 0,
                          "sizeX": 2,
                          "sizeY": 6
                        },
                        "panel": {
                          "color": "#ffffff",
                          "currentColor": "#ffffff",
                          "showOffline": {
                            "type": "none"
                          },
                          "title": "CO2 Level"
                        },
                        "properties": {
                          "color": "#e74c3c",
                          "max": 5000,
                          "min": 0,
                          "unit": "ppm"
                        },
                        "sources": [
                          {
                            "bucket": {
                              "backend": "mongodb",
                              "id": "device_data",
                              "mapping": "co2",
                              "tags": {
                                "device": [],
                                "group": []
                              }
                            },
                            "color": "#e74c3c",
                            "name": "CO2",
                            "source": "bucket",
                            "timespan": {
                              "mode": "latest"
                            }
                          }
                        ],
                        "type": "donutchart"
                      },
                      {
                        "layout": {
                          "col": 4,
                          "row": 0,
                          "sizeX": 2,
                          "sizeY": 6
                        },
                        "panel": {
                          "color": "#ffffff",
                          "currentColor": "#ffffff",
                          "showOffline": {
                            "type": "none"
                          },
                          "title": "TVOC"
                        },
                        "properties": {
                          "color": "#9b59b6",
                          "max": 2000,
                          "min": 0,
                          "unit": "ppb"
                        },
                        "sources": [
                          {
                            "bucket": {
                              "backend": "mongodb",
                              "id": "device_data",
                              "mapping": "tvoc",
                              "tags": {
                                "device": [],
                                "group": []
                              }
                            },
                            "color": "#9b59b6",
                            "name": "TVOC",
                            "source": "bucket",
                            "timespan": {
                              "mode": "latest"
                            }
                          }
                        ],
                        "type": "donutchart"
                      },
                      {
                        "layout": {
                          "col": 0,
                          "row": 6,
                          "sizeX": 3,
                          "sizeY": 12
                        },
                        "panel": {
                          "color": "#ffffff",
                          "currentColor": "#ffffff",
                          "showOffline": {
                            "type": "none"
                          },
                          "title": "Air Quality History"
                        },
                        "properties": {
                          "axis": true,
                          "fill": false,
                          "legend": true,
                          "multiple_axes": true
                        },
                        "sources": [
                          {
                            "bucket": {
                              "backend": "mongodb",
                              "id": "device_data",
                              "mapping": "aqi",
                              "tags": {
                                "device": [],
                                "group": []
                              }
                            },
                            "color": "#1abc9c",
                            "name": "AQI",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "hour",
                              "mode": "relative",
                              "period": "latest",
                              "value": 24
                            }
                          },
                          {
                            "bucket": {
                              "backend": "mongodb",
                              "id": "device_data",
                              "mapping": "co2",
                              "tags": {
                                "device": [],
                                "group": []
                              }
                            },
                            "color": "#e74c3c",
                            "name": "CO2",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "hour",
                              "mode": "relative",
                              "period": "latest",
                              "value": 24
                            }
                          }
                        ],
                        "type": "chart"
                      },
                      {
                        "layout": {
                          "col": 3,
                          "row": 6,
                          "sizeX": 3,
                          "sizeY": 12
                        },
                        "panel": {
                          "color": "#ffffff",
                          "currentColor": "#ffffff",
                          "showOffline": {
                            "type": "none"
                          },
                          "title": "TVOC History"
                        },
                        "properties": {
                          "axis": true,
                          "fill": false,
                          "legend": true,
                          "multiple_axes": false
                        },
                        "sources": [
                          {
                            "bucket": {
                              "backend": "mongodb",
                              "id": "device_data",
                              "mapping": "tvoc",
                              "tags": {
                                "device": [],
                                "group": []
                              }
                            },
                            "color": "#9b59b6",
                            "name": "TVOC",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "hour",
                              "mode": "relative",
                              "period": "latest",
                              "value": 24
                            }
                          }
                        ],
                        "type": "chart"
                      }
                    ]
                  },
                  {
                    "name": "Environmental",
                    "widgets": [
                      {
                        "layout": {
                          "col": 0,
                          "row": 0,
                          "sizeX": 2,
                          "sizeY": 6
                        },
                        "panel": {
                          "color": "#ffffff",
                          "currentColor": "#ffffff",
                          "showOffline": {
                            "type": "none"
                          },
                          "title": "Temperature"
                        },
                        "properties": {
                          "color": "#ff6b6b",
                          "max": 50,
                          "min": -10,
                          "unit": "°C"
                        },
                        "sources": [
                          {
                            "bucket": {
                              "backend": "mongodb",
                              "id": "device_data",
                              "mapping": "temperature",
                              "tags": {
                                "device": [],
                                "group": []
                              }
                            },
                            "color": "#ff6b6b",
                            "name": "Temperature",
                            "source": "bucket",
                            "timespan": {
                              "mode": "latest"
                            }
                          }
                        ],
                        "type": "donutchart"
                      },
                      {
                        "layout": {
                          "col": 2,
                          "row": 0,
                          "sizeX": 2,
                          "sizeY": 6
                        },
                        "panel": {
                          "color": "#ffffff",
                          "currentColor": "#ffffff",
                          "showOffline": {
                            "type": "none"
                          },
                          "title": "Humidity"
                        },
                        "properties": {
                          "color": "#4ecdc4",
                          "max": 100,
                          "min": 0,
                          "unit": "%RH"
                        },
                        "sources": [
                          {
                            "bucket": {
                              "backend": "mongodb",
                              "id": "device_data",
                              "mapping": "humidity",
                              "tags": {
                                "device": [],
                                "group": []
                              }
                            },
                            "color": "#4ecdc4",
                            "name": "Humidity",
                            "source": "bucket",
                            "timespan": {
                              "mode": "latest"
                            }
                          }
                        ],
                        "type": "donutchart"
                      },
                      {
                        "layout": {
                          "col": 4,
                          "row": 0,
                          "sizeX": 2,
                          "sizeY": 6
                        },
                        "panel": {
                          "color": "#ffffff",
                          "currentColor": "#ffffff",
                          "showOffline": {
                            "type": "none"
                          },
                          "title": "Battery"
                        },
                        "properties": {
                          "color": "#f1c40f",
                          "max": 100,
                          "min": 0,
                          "unit": "%"
                        },
                        "sources": [
                          {
                            "bucket": {
                              "backend": "mongodb",
                              "id": "device_data",
                              "mapping": "battery",
                              "tags": {
                                "device": [],
                                "group": []
                              }
                            },
                            "color": "#f1c40f",
                            "name": "Battery",
                            "source": "bucket",
                            "timespan": {
                              "mode": "latest"
                            }
                          }
                        ],
                        "type": "donutchart"
                      },
                      {
                        "layout": {
                          "col": 0,
                          "row": 6,
                          "sizeX": 6,
                          "sizeY": 12
                        },
                        "panel": {
                          "color": "#ffffff",
                          "currentColor": "#ffffff",
                          "showOffline": {
                            "type": "none"
                          },
                          "title": "Temperature & Humidity History"
                        },
                        "properties": {
                          "axis": true,
                          "fill": false,
                          "legend": true,
                          "multiple_axes": true
                        },
                        "sources": [
                          {
                            "bucket": {
                              "backend": "mongodb",
                              "id": "device_data",
                              "mapping": "temperature",
                              "tags": {
                                "device": [],
                                "group": []
                              }
                            },
                            "color": "#ff6b6b",
                            "name": "Temperature",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "hour",
                              "mode": "relative",
                              "period": "latest",
                              "value": 24
                            }
                          },
                          {
                            "bucket": {
                              "backend": "mongodb",
                              "id": "device_data",
                              "mapping": "humidity",
                              "tags": {
                                "device": [],
                                "group": []
                              }
                            },
                            "color": "#4ecdc4",
                            "name": "Humidity",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "hour",
                              "mode": "relative",
                              "period": "latest",
                              "value": 24
                            }
                          }
                        ],
                        "type": "chart"
                      }
                    ]
                  },
                  {
                    "name": "Particulate Matter",
                    "widgets": [
                      {
                        "layout": {
                          "col": 0,
                          "row": 0,
                          "sizeX": 2,
                          "sizeY": 6
                        },
                        "panel": {
                          "color": "#ffffff",
                          "currentColor": "#ffffff",
                          "showOffline": {
                            "type": "none"
                          },
                          "title": "PM1.0"
                        },
                        "properties": {
                          "color": "#95e1d3",
                          "max": 500,
                          "min": 0,
                          "unit": "μg/m³"
                        },
                        "sources": [
                          {
                            "bucket": {
                              "backend": "mongodb",
                              "id": "device_data",
                              "mapping": "pm1.0",
                              "tags": {
                                "device": [],
                                "group": []
                              }
                            },
                            "color": "#95e1d3",
                            "name": "PM1.0",
                            "source": "bucket",
                            "timespan": {
                              "mode": "latest"
                            }
                          }
                        ],
                        "type": "donutchart"
                      },
                      {
                        "layout": {
                          "col": 2,
                          "row": 0,
                          "sizeX": 2,
                          "sizeY": 6
                        },
                        "panel": {
                          "color": "#ffffff",
                          "currentColor": "#ffffff",
                          "showOffline": {
                            "type": "none"
                          },
                          "title": "PM2.5"
                        },
                        "properties": {
                          "color": "#f38181",
                          "max": 500,
                          "min": 0,
                          "unit": "μg/m³"
                        },
                        "sources": [
                          {
                            "bucket": {
                              "backend": "mongodb",
                              "id": "device_data",
                              "mapping": "pm2.5",
                              "tags": {
                                "device": [],
                                "group": []
                              }
                            },
                            "color": "#f38181",
                            "name": "PM2.5",
                            "source": "bucket",
                            "timespan": {
                              "mode": "latest"
                            }
                          }
                        ],
                        "type": "donutchart"
                      },
                      {
                        "layout": {
                          "col": 4,
                          "row": 0,
                          "sizeX": 2,
                          "sizeY": 6
                        },
                        "panel": {
                          "color": "#ffffff",
                          "currentColor": "#ffffff",
                          "showOffline": {
                            "type": "none"
                          },
                          "title": "PM10"
                        },
                        "properties": {
                          "color": "#aa96da",
                          "max": 500,
                          "min": 0,
                          "unit": "μg/m³"
                        },
                        "sources": [
                          {
                            "bucket": {
                              "backend": "mongodb",
                              "id": "device_data",
                              "mapping": "pm10",
                              "tags": {
                                "device": [],
                                "group": []
                              }
                            },
                            "color": "#aa96da",
                            "name": "PM10",
                            "source": "bucket",
                            "timespan": {
                              "mode": "latest"
                            }
                          }
                        ],
                        "type": "donutchart"
                      },
                      {
                        "layout": {
                          "col": 0,
                          "row": 6,
                          "sizeX": 6,
                          "sizeY": 12
                        },
                        "panel": {
                          "color": "#ffffff",
                          "currentColor": "#ffffff",
                          "showOffline": {
                            "type": "none"
                          },
                          "title": "Particulate Matter History"
                        },
                        "properties": {
                          "axis": true,
                          "fill": false,
                          "legend": true,
                          "multiple_axes": false
                        },
                        "sources": [
                          {
                            "bucket": {
                              "backend": "mongodb",
                              "id": "device_data",
                              "mapping": "pm1.0",
                              "tags": {
                                "device": [],
                                "group": []
                              }
                            },
                            "color": "#95e1d3",
                            "name": "PM1.0",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "hour",
                              "mode": "relative",
                              "period": "latest",
                              "value": 24
                            }
                          },
                          {
                            "bucket": {
                              "backend": "mongodb",
                              "id": "device_data",
                              "mapping": "pm2.5",
                              "tags": {
                                "device": [],
                                "group": []
                              }
                            },
                            "color": "#f38181",
                            "name": "PM2.5",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "hour",
                              "mode": "relative",
                              "period": "latest",
                              "value": 24
                            }
                          },
                          {
                            "bucket": {
                              "backend": "mongodb",
                              "id": "device_data",
                              "mapping": "pm10",
                              "tags": {
                                "device": [],
                                "group": []
                              }
                            },
                            "color": "#aa96da",
                            "name": "PM10",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "hour",
                              "mode": "relative",
                              "period": "latest",
                              "value": 24
                            }
                          }
                        ],
                        "type": "chart"
                      }
                    ]
                  },
                  {
                    "name": "Gas Sensors",
                    "widgets": [
                      {
                        "layout": {
                          "col": 0,
                          "row": 0,
                          "sizeX": 3,
                          "sizeY": 6
                        },
                        "panel": {
                          "color": "#ffffff",
                          "currentColor": "#ffffff",
                          "showOffline": {
                            "type": "none"
                          },
                          "title": "Gas Sensor 1"
                        },
                        "properties": {
                          "color": "#f6b93b",
                          "max": 10,
                          "min": 0,
                          "unit": "ppm"
                        },
                        "sources": [
                          {
                            "bucket": {
                              "backend": "mongodb",
                              "id": "device_data",
                              "mapping": "gas1",
                              "tags": {
                                "device": [],
                                "group": []
                              }
                            },
                            "color": "#f6b93b",
                            "name": "Gas1",
                            "source": "bucket",
                            "timespan": {
                              "mode": "latest"
                            }
                          }
                        ],
                        "type": "donutchart"
                      },
                      {
                        "layout": {
                          "col": 3,
                          "row": 0,
                          "sizeX": 3,
                          "sizeY": 6
                        },
                        "panel": {
                          "color": "#ffffff",
                          "currentColor": "#ffffff",
                          "showOffline": {
                            "type": "none"
                          },
                          "title": "Gas Sensor 2"
                        },
                        "properties": {
                          "color": "#e55039",
                          "max": 10,
                          "min": 0,
                          "unit": "ppm"
                        },
                        "sources": [
                          {
                            "bucket": {
                              "backend": "mongodb",
                              "id": "device_data",
                              "mapping": "gas2",
                              "tags": {
                                "device": [],
                                "group": []
                              }
                            },
                            "color": "#e55039",
                            "name": "Gas2",
                            "source": "bucket",
                            "timespan": {
                              "mode": "latest"
                            }
                          }
                        ],
                        "type": "donutchart"
                      },
                      {
                        "layout": {
                          "col": 0,
                          "row": 6,
                          "sizeX": 6,
                          "sizeY": 12
                        },
                        "panel": {
                          "color": "#ffffff",
                          "currentColor": "#ffffff",
                          "showOffline": {
                            "type": "none"
                          },
                          "title": "Gas Sensors History"
                        },
                        "properties": {
                          "axis": true,
                          "fill": false,
                          "legend": true,
                          "multiple_axes": false
                        },
                        "sources": [
                          {
                            "bucket": {
                              "backend": "mongodb",
                              "id": "device_data",
                              "mapping": "gas1",
                              "tags": {
                                "device": [],
                                "group": []
                              }
                            },
                            "color": "#f6b93b",
                            "name": "Gas1",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "hour",
                              "mode": "relative",
                              "period": "latest",
                              "value": 24
                            }
                          },
                          {
                            "bucket": {
                              "backend": "mongodb",
                              "id": "device_data",
                              "mapping": "gas2",
                              "tags": {
                                "device": [],
                                "group": []
                              }
                            },
                            "color": "#e55039",
                            "name": "Gas2",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "hour",
                              "mode": "relative",
                              "period": "latest",
                              "value": 24
                            }
                          }
                        ],
                        "type": "chart"
                      }
                    ]
                  },
                  {
                    "name": "All Data",
                    "widgets": [
                      {
                        "layout": {
                          "col": 0,
                          "row": 0,
                          "sizeX": 6,
                          "sizeY": 18
                        },
                        "panel": {
                          "color": "#ffffff",
                          "currentColor": "#ffffff",
                          "showOffline": {
                            "type": "none"
                          },
                          "title": "Recent Measurements"
                        },
                        "properties": {
                          "source": "code",
                          "template": "<div style=\"width:100%; height:100%; overflow-y:auto\">\n  <table class=\"table table-striped table-condensed\">\n    <thead>\n      <tr>\n        <th>Timestamp</th>\n        <th>Temp (°C)</th>\n        <th>Humidity (%)</th>\n        <th>AQI</th>\n        <th>CO2 (ppm)</th>\n        <th>TVOC (ppb)</th>\n        <th>PM2.5</th>\n        <th>Battery (%)</th>\n      </tr>\n    </thead>\n    <tbody>\n      <tr ng-repeat=\"entry in value\">\n        <td>{{ entry.ts | date:'medium' }}</td>\n        <td>{{ entry.temperature | number:1 }}</td>\n        <td>{{ entry.humidity | number:1 }}</td>\n        <td>{{ entry.aqi }}</td>\n        <td>{{ entry.co2 }}</td>\n        <td>{{ entry.tvoc }}</td>\n        <td>{{ entry['pm2.5'] | number:3 }}</td>\n        <td>{{ entry.battery }}</td>\n      </tr>\n    </tbody>\n  </table>\n</div>\n"
                        },
                        "sources": [
                          {
                            "bucket": {
                              "backend": "mongodb",
                              "id": "device_data",
                              "mapping": "ts",
                              "tags": {
                                "device": [],
                                "group": []
                              }
                            },
                            "color": "#1abc9c",
                            "name": "ts",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "hour",
                              "mode": "relative",
                              "period": "latest",
                              "value": 24
                            }
                          },
                          {
                            "bucket": {
                              "backend": "mongodb",
                              "id": "device_data",
                              "mapping": "temperature",
                              "tags": {
                                "device": [],
                                "group": []
                              }
                            },
                            "color": "#ff6b6b",
                            "name": "temperature",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "hour",
                              "mode": "relative",
                              "period": "latest",
                              "value": 24
                            }
                          },
                          {
                            "bucket": {
                              "backend": "mongodb",
                              "id": "device_data",
                              "mapping": "humidity",
                              "tags": {
                                "device": [],
                                "group": []
                              }
                            },
                            "color": "#4ecdc4",
                            "name": "humidity",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "hour",
                              "mode": "relative",
                              "period": "latest",
                              "value": 24
                            }
                          },
                          {
                            "bucket": {
                              "backend": "mongodb",
                              "id": "device_data",
                              "mapping": "aqi",
                              "tags": {
                                "device": [],
                                "group": []
                              }
                            },
                            "color": "#1abc9c",
                            "name": "aqi",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "hour",
                              "mode": "relative",
                              "period": "latest",
                              "value": 24
                            }
                          },
                          {
                            "bucket": {
                              "backend": "mongodb",
                              "id": "device_data",
                              "mapping": "co2",
                              "tags": {
                                "device": [],
                                "group": []
                              }
                            },
                            "color": "#e74c3c",
                            "name": "co2",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "hour",
                              "mode": "relative",
                              "period": "latest",
                              "value": 24
                            }
                          },
                          {
                            "bucket": {
                              "backend": "mongodb",
                              "id": "device_data",
                              "mapping": "tvoc",
                              "tags": {
                                "device": [],
                                "group": []
                              }
                            },
                            "color": "#9b59b6",
                            "name": "tvoc",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "hour",
                              "mode": "relative",
                              "period": "latest",
                              "value": 24
                            }
                          },
                          {
                            "bucket": {
                              "backend": "mongodb",
                              "id": "device_data",
                              "mapping": "pm2.5",
                              "tags": {
                                "device": [],
                                "group": []
                              }
                            },
                            "color": "#f38181",
                            "name": "pm2.5",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "hour",
                              "mode": "relative",
                              "period": "latest",
                              "value": 24
                            }
                          },
                          {
                            "bucket": {
                              "backend": "mongodb",
                              "id": "device_data",
                              "mapping": "battery",
                              "tags": {
                                "device": [],
                                "group": []
                              }
                            },
                            "color": "#f1c40f",
                            "name": "battery",
                            "source": "bucket",
                            "timespan": {
                              "magnitude": "hour",
                              "mode": "relative",
                              "period": "latest",
                              "value": 24
                            }
                          }
                        ],
                        "type": "html_time"
                      }
                    ]
                  }
                ]
              }
            }
          ]
        }
      }
    ]
  }
}