-
Notifications
You must be signed in to change notification settings - Fork 0
/
Air_Quality_Sensor-12.fqa
1 lines (1 loc) · 30.5 KB
/
Air_Quality_Sensor-12.fqa
1
{"name":"Air Quality Sensor","type":"com.fibaro.genericDevice","apiVersion":"1.2","initialProperties":{"viewLayout":{"$jason":{"body":{"header":{"style":{"height":"0"},"title":"quickApp_device_745"},"sections":{"items":[{"components":[{"name":"label1","style":{"weight":"1.2"},"text":"Label","type":"label","visible":true},{"style":{"weight":"0.5"},"type":"space"}],"style":{"weight":"1.2"},"type":"vertical"},{"components":[{"name":"button1","style":{"weight":"1.2"},"text":"Refresh","type":"button","visible":true},{"style":{"weight":"0.5"},"type":"space"}],"style":{"weight":"1.2"},"type":"vertical"}]}},"head":{"title":"quickApp_device_745"}}},"uiCallbacks":[{"callback":"button1Event","eventType":"onReleased","name":"button1"}],"quickAppVariables":[{"name":"ipAddress","value":"192.168.4.1"},{"name":"interval","value":"146"},{"name":"userID","value":"0"},{"name":"debugLevel","value":"1"},{"name":"icon","value":"0"}],"typeTemplateInitialized":true},"files":[{"name":"main","isMain":true,"isOpen":true,"content":"-- QUICKAPP AIR QUALITY SENSOR\n\n-- This QuickApp reads the PM1, PM2.5, PM4, PM10, Temperature, Humidity and AirPressure values directly from a sensor. \n-- With this sensor you can measure air quality yourself. \n-- This QuickApp will send notifications when PM2.5 or PM10 readings reach a breakpoint. \n\n-- Changes version 1.2 (3rd April 2021)\n -- Added support (child devices) for PM1 and PM4 levels (Plantower and Sensirion sensors)\n -- Added support for BMP280 sensor\n\n-- Changes version 1.1 (31th Januari 2021)\n -- Added support for Plantower Air Quality Sensor (for now without PM1.0)\n -- Added Airpressuretext to log of Child Device Airpressure\n -- Added Quickapp variable for debug level (1=some, 2=few, 3=all). Recommended default value is 1.\n -- Removed QuickApp Variable bme280Sensor (no need for that anymore)\n -- Removed QuickApp Variable path (is now fixed)\n\n-- Changes version 1.0 (23rd January 2021)\n -- Added Child Device for Absolute Humidity\n -- Added \"Refresh\" button\n\n-- Changes version 0.5 (23rd October 2020)\n -- With the new firmware and API function, solved a small bug in presenting WiFi dBm\n -- Changed humidity and airpressure values to zero decimals\n -- Added airpressure unit text \"hPa\"\n -- Changed the master device to \"Generic Device\" \n -- Added QuickApp Variable for user defined icon master device\n -- Solved a bug preventing creation of QuickApp Variable bme280Sensor\n\n-- Changes version 0.4\n -- Added support for BME280 sensor (temperature, humidity and air pressure)\n -- Added QuickApp Variable bme280Sensor (true or false) to indicate the pressence of a BME280 sensor otherwise a DHT22 sensor is assumed\n -- Reduced the amount of labels, now only one label\n -- Removed the firmware version from the log under the icon\n\n-- Changes version 0.3\n -- error message instead of debug message in case of an error\n -- Changed method of adding QuickApp variables, so they can be edited\n -- Added network error to log (under icon)\n\n-- Changes version 0.2\n -- Changed label6 from \"age\" to time of the measurement\n -- Added automatic creation of child devices for Temperature, Humidity, PM2.5 and PM10 (with great help from @jgab from forum.fibaro.com)\n -- Added the value (Temperature, Humidity, PM2.5 and PM10) to the child devices, This can be used in, for instance, extra scenes and shows in the mobile app and dashboard. \n -- Added a short text of the air quality (GOOD, SATISFACTORY, etc.) to the icons in the dashboard (with great help of @petergebruers and 10der from forum.fibaro.com)\n -- Added the trend (up, down, equal) to the sort text of the air quality\n\n-- My configuration of the DIY air quality sensor:\n -- NodeMCU ESP8266 V2 opensource WiFi board\n -- Nova SDS011 or Sensirion SPS30 air quality sensor\n -- BME280 temperature, humidity and airpressure sensor\n\n-- See also https://luftdaten.info\n-- See also https://sensor.community/en/sensors/airrohr/ how to simply build the air quality sensor yourself\n-- See also for map of measurements: https://sensor.community/en/\n-- See also for CVS files: https://archive.luftdaten.info\n-- See also https://github.com/opendata-stuttgart/\n\n-- Variables (mandatory): \n -- ipAddress = IP address of your sensor\n -- interval = Number in seconds, the sensor normally is updated every 145 seconds\n -- userID = User id to notify of PM2.5 / PM10 breakpoints\n -- icon = User defined icon number (add the icon via an other device and lookup the number)\n -- debugLevel = Number (1=some, 2=few, 3=all) (default = 1)\n\n-- Absolute humidity is the measure of water vapor (moisture) in the air, regardless of temperature. It is expressed as grams of moisture per cubic meter of air (g/m3) \n\n-- PM2.5 breakpoints\n -- 0 - 30 GOOD (Minimal)\n -- 31 - 60 SATISFACTORY (Minor breathing discomfort to sensitive people)\n -- 61 - 90 MODERATELY POLLUTED Breathing discomfort to asthma patients, elderly and children\n -- 91 - 120 POOR (Breathing discomfort to all)\n -- 121 - 250 VERY POOR (Respiratory illness on prolonged exposure)\n -- 250+ SEVERE (Health impact even on light physical work. Serious impact on people with heart/lung disease)\n\n-- PM10 breakpoints\n -- 0 - 50 GOOD (Minimal)\n -- 51 - 100 SATISFACTORY (Minor breathing discomport to sensitive people)\n -- 101 - 250 MODERATELY POLLUTED Breathing discomfoort to asthma patients, elderly and children\n -- 251 - 350 POOR (Breathing discomfort to all)\n -- 351 - 430 VERY POOR (Respiratory illness on prolonged exposure)\n -- 430+ SEVERE (Health impact even on light physical work. Serious impact on people with heart/lung disease)\n\n-- Example json output SDS011 / BME280\n-- {\"software_version\": \"NRZ-2020-133\", \"age\":\"42\", \"sensordatavalues\":[{\"value_type\":\"SDS_P1\",\"value\":\"23.85\"},{\"value_type\":\"SDS_P2\",\"value\":\"12.93\"},{\"value_type\":\"BME280_temperature\",\"value\":\"-2.94\"},{\"value_type\":\"BME280_pressure\",\"value\":\"100731.91\"},{\"value_type\":\"BME280_humidity\",\"value\":\"92.88\"},{\"value_type\":\"samples\",\"value\":\"4952487\"},{\"value_type\":\"min_micro\",\"value\":\"28\"},{\"value_type\":\"max_micro\",\"value\":\"20074\"},{\"value_type\":\"interval\",\"value\":\"145000\"},{\"value_type\":\"signal\",\"value\":\"-76\"}]}\n\n-- Example json output Plantower / BME280\n-- {\"software_version\": \"NRZ-2020-133\", \"age\":\"143\", \"sensordatavalues\":[{\"value_type\":\"PMS_P0\",\"value\":\"7.25\"},{\"value_type\":\"PMS_P1\",\"value\":\"16.75\"},{\"value_type\":\"PMS_P2\",\"value\":\"15.00\"},{\"value_type\":\"BME280_temperature\",\"value\":\"25.32\"},{\"value_type\":\"BME280_pressure\",\"value\":\"99718.44\"},{\"value_type\":\"BME280_humidity\",\"value\":\"34.79\"},{\"value_type\":\"samples\",\"value\":\"5062203\"},{\"value_type\":\"min_micro\",\"value\":\"28\"},{\"value_type\":\"max_micro\",\"value\":\"8816\"},{\"value_type\":\"interval\",\"value\":\"145000\"},{\"value_type\":\"signal\",\"value\":\"-61\"}]}\n\n-- Example json output Sensirion SPS30\n-- {\"software_version\": \"NRZ-2020-133\", \"age\":\"72\", \"sensordatavalues\":[{\"value_type\":\"SPS30_P0\",\"value\":\"20.39\"},{\"value_type\":\"SPS30_P2\",\"value\":\"23.44\"},{\"value_type\":\"SPS30_P4\",\"value\":\"24.96\"},{\"value_type\":\"SPS30_P1\",\"value\":\"25.27\"},{\"value_type\":\"SPS30_N05\",\"value\":\"138.40\"},{\"value_type\":\"SPS30_N1\",\"value\":\"160.18\"},{\"value_type\":\"SPS30_N25\",\"value\":\"162.63\"},{\"value_type\":\"SPS30_N4\",\"value\":\"163.13\"},{\"value_type\":\"SPS30_N10\",\"value\":\"163.23\"},{\"value_type\":\"SPS30_TS\",\"value\":\"0.66\"},{\"value_type\":\"samples\",\"value\":\"4947724\"},{\"value_type\":\"min_micro\",\"value\":\"28\"},{\"value_type\":\"max_micro\",\"value\":\"6797\"},{\"value_type\":\"interval\",\"value\":\"145000\"},{\"value_type\":\"signal\",\"value\":\"-35\"}]}\n\n-- No editing of this code is needed \n\n\nclass 'PolutionSensorTemp'(QuickAppChild)\nfunction PolutionSensorTemp:__init(dev)\n QuickAppChild.__init(self,dev)\n --self:trace(\"Air Quality Temperature sensor initiated, deviceId:\",self.id)\nend\nfunction PolutionSensorTemp:updateValue(data,userID) \n --self:debug(\"Temperature: \",data.temperature)\n self:updateProperty(\"value\",tonumber(data.temperature))\nend\n\nclass 'PolutionSensorHumid'(QuickAppChild)\nfunction PolutionSensorHumid:__init(dev)\n QuickAppChild.__init(self,dev)\n --self:trace(\"Air Quality Humidity sensor initiated, deviceId:\",self.id)\nend\nfunction PolutionSensorHumid:updateValue(data,userID) \n self:updateProperty(\"value\",tonumber(data.humidity)) \nend\n\nclass 'PolutionSensorHumidAbs'(QuickAppChild)\nfunction PolutionSensorHumidAbs:__init(dev)\n QuickAppChild.__init(self,dev)\n --self:trace(\"Air Quality Absolute Humidity sensor initiated, deviceId:\",self.id)\nend\nfunction PolutionSensorHumidAbs:updateValue(data,userID) \n self:updateProperty(\"value\",tonumber(data.humidityabsolute)) \n self:updateProperty(\"unit\", \"g/m³\")\nend\n\nclass 'PolutionSensorPressure'(QuickAppChild)\nfunction PolutionSensorPressure:__init(dev)\n QuickAppChild.__init(self,dev)\n --self:trace(\"Air Quality Pressure sensor initiated, deviceId:\",self.id)\nend\nfunction PolutionSensorPressure:updateValue(data,userID) \n self:updateProperty(\"value\",tonumber(data.airpressure)) \n self:updateProperty(\"unit\", \"hPa\")\n self:updateProperty(\"log\", data.airpressuretext)\nend\n\nclass 'PolutionSensorPM1'(QuickAppChild)\nfunction PolutionSensorPM1:__init(dev)\n QuickAppChild.__init(self,dev)\n --self:trace(\"Air Quality PM1 sensor initiated, deviceId:\",self.id)\nend\nfunction PolutionSensorPM1:updateValue(data,userID) \n self:updateProperty(\"value\",tonumber(data.pm1)) \n self:updateProperty(\"unit\", \"㎍/㎥\")\nend\n\nclass 'PolutionSensorPM4'(QuickAppChild)\nfunction PolutionSensorPM4:__init(dev)\n QuickAppChild.__init(self,dev)\n --self:trace(\"Air Quality PM4 sensor initiated, deviceId:\",self.id)\nend\nfunction PolutionSensorPM4:updateValue(data,userID) \n self:updateProperty(\"value\",tonumber(data.pm4)) \n self:updateProperty(\"unit\", \"㎍/㎥\")\nend\n\nclass 'PolutionSensorPM25'(QuickAppChild)\nfunction PolutionSensorPM25:__init(dev)\n QuickAppChild.__init(self,dev)\n --self:trace(\"Air Quality PM2.5 sensor initiated, deviceId:\",self.id)\nend\n\nfunction PolutionSensorPM25:updateValue(data,userID) \n\n local pm25,pm25prev = data.pm25,data.pm25prev\n\n -- Send notifications when PM2.5 level reach breakpoints \n -- PM2.5 breakpoint 0 - 30 GOOD (Minimal)\n if (tonumber(pm25) > 0 and tonumber(pm25) <= 30) then\n pm25Text = \"GOOD\"\n if (pm25prev > 30) then\n fibaro.alert(\"push\", {userID}, \"PM2.5 \"..pm25 ..\" µg/m³\" ..\" level GOOD (Minimal)\")\n self:debug(\"PM2.5 level GOOD (Minimal)\",pm25 ..\" µg/m³\")\n end\n end\n -- PM2.5 breakpoint 31 - 60 SATISFACTORY (Minor breathing discomfort to sensitive people)\n if (tonumber(pm25) >= 31 and tonumber(pm25) <= 60) then\n pm25Text = \"SATISFACTORY\"\n if (pm25prev < 31 or pm25prev > 60) then\n fibaro.alert(\"push\", {userID}, \"PM2.5 \"..pm25 ..\" µg/m³\" ..\" level SATISFACTORY (Minor breathing discomfort to sensitive people)\")\n self:debug(\"PM2.5 level SATISFACTORY (Minor breathing discomfort to sensitive people)\",pm25 ..\" µg/m³\")\n end\n end\n -- PM2.5 breakpoint 61 - 90 MODERATELY POLLUTED Breathing discomfort to asthma patients, elderly and children\n if (tonumber(pm25) >= 61 and tonumber(pm25) <= 90) then\n pm25Text = \"MODERATELY POLLUTED\"\n if (pm25prev < 61 or pm25prev > 90) then\n fibaro.alert(\"push\", {userID}, \"PM2.5 \"..pm25 ..\" µg/m³\" ..\" level MODERATELY POLLUTED Breathing discomfort to asthma patients, elderly and children\")\n self:debug(\"PM2.5 level MODERATELY POLLUTED Breathing discomfort to asthma patients, elderly and children\",pm25 ..\" µg/m³\")\n end \n end\n -- PM2.5 breakpoint 91 - 120 POOR (Breathing discomfort to all)\n if (tonumber(pm25) >= 91 and tonumber(pm25) <= 120) then\n pm25Text = \"POOR\"\n if (pm25prev < 91 or pm25prev > 120) then\n fibaro.alert(\"push\", {userID}, \"PM2.5 \"..pm25 ..\" µg/m³\" ..\" level POOR (Breathing discomfort to all)\")\n self:debug(\"PM2.5 level POOR (Breathing discomfort to all)\",pm25 ..\" µg/m³\")\n end\n end\n -- PM2.5 breakpoint 120 - 250 VERY POOR (Respiratory illness on prolonged exposure)\n if (tonumber(pm25) >= 120 and tonumber(pm25) <= 250) then\n pm25Text = \"VERY POOR\"\n if (pm25prev < 121 or pm25prev > 250) then\n fibaro.alert(\"push\", {userID}, \"PM2.5 \"..pm25 ..\" µg/m³\" ..\" level VERY POOR (Respiratory illness on prolonged exposure)\")\n self:debug(\"PM2.5 level VERY POOR (Respiratory illness on prolonged exposure)\",pm25 ..\" µg/m³\")\n end\n end\n -- PM2.5 breakpoint 250+ SEVERE (Health impact even on light physical work. Serious impact on people with heart/lung disease)\n if (tonumber(pm25) >= 250 ) then\n pm25Text = \"SEVERE\"\n if (pm25prev < 250) then\n fibaro.alert(\"push\", {userID}, \"PM2.5 \"..pm25 ..\" µg/m³\" ..\" level SEVERE (Health impact even on light physical work. Serious impact on people with heart/lung disease)\")\n self:debug(\"PM2.5 level SEVERE (Health impact even on light physical work. Serious impact on people with heart/lung disease)\",pm25 ..\" µg/m³\")\n end\n end\n\n if tonumber(pm25) > tonumber(pm25prev) then\n pm25Trend = \" ↑\"\n elseif tonumber(pm25) < tonumber(pm25prev) then\n pm25Trend = \" ↓\"\n else\n pm25Trend = \" =\"\n end \n\n -- Update properties for PM2.5 sensor\n self:updateProperty(\"value\", tonumber(pm25)) \n self:updateProperty(\"unit\", \"㎍/㎥\")\n self:updateProperty(\"log\", pm25Text ..pm25Trend)\nend\n\nclass 'PolutionSensorPM10'(QuickAppChild)\nfunction PolutionSensorPM10:__init(dev)\n QuickAppChild.__init(self,dev)\n --self:trace(\"Air Quality PM10 sensor initiated, deviceId:\",self.id)\nend\n\nfunction PolutionSensorPM10:updateValue(data,userID) \n local pm10,pm10prev = data.pm10,data.pm10prev\n\n -- Send notifications when PM10 level reach breakpoints \n -- PM10 breakpoint 0 - 50 GOOD (Minimal)\n if (tonumber(pm10) > 0 and tonumber(pm10) <= 50) then\n pm10Text = \"GOOD\"\n if (pm10prev > 50) then\n fibaro.alert(\"push\", {userID}, \"PM10 \"..pm10 ..\" µg/m³\" ..\" level GOOD (Minimal)\")\n self:debug(\"PM10 level GOOD (Minimal)\",pm10 ..\" µg/m³\")\n end\n end\n -- PM10 breakpoint 51 - 100 SATISFACTORY (Minor breathing discomfort to sensitive people)\n if (tonumber(pm10) >= 51 and tonumber(pm10) <= 100) then\n pm10Text = \"SATISFACTORY\"\n if (pm10prev < 51 or pm10prev > 100) then\n fibaro.alert(\"push\", {userID}, \"PM10 \"..pm10 ..\" µg/m³\" ..\" level SATISFACTORY (Minor breathing discomfort to sensitive people)\")\n self:debug(\"PM10 level SATISFACTORY (Minor breathing discomfort to sensitive people)\",pm10 ..\" µg/m³\")\n end\n end\n -- PM10 breakpoint 101 - 250 MODERATELY POLLUTED Breathing discomfort to asthma patients, elderly and children\n if (tonumber(pm10) >= 101 and tonumber(pm10) <= 250) then\n pm10Text = \"MODERATELY POLLUTED\"\n if (pm10prev < 101 or pm10prev > 250) then\n fibaro.alert(\"push\", {userID}, \"PM10 \"..pm10 ..\" µg/m³\" ..\" level MODERATELY POLLUTED Breathing discomfort to asthma patients, elderly and children\")\n self:debug(\"PM10 level MODERATELY POLLUTED Breathing discomfort to asthma patients, elderly and children\",pm10 ..\" µg/m³\")\n end\n end\n -- PM10 breakpoint 251 - 350 POOR (Breathing discomfort to all)\n if (tonumber(pm10) >= 251 and tonumber(pm10) <= 350) then\n pm10Text = \"POOR\"\n if (pm10prev < 251 or pm10prev > 350) then\n fibaro.alert(\"push\", {userID}, \"PM10 \"..pm10 ..\" µg/m³\" ..\" level POOR (Breathing discomfort to all)\")\n self:debug(\"PM10 level POOR (Breathing discomfort to all)\",pm10 ..\" µg/m³\")\n end\n end\n -- PM10 breakpoint 351 - 430 VERY POOR (Respiratory illness on prolonged exposure)\n if (tonumber(pm10) >= 351 and tonumber(pm10) <= 439) then\n pm10Text = \"VERY POOR\"\n if (pm10prev < 351 or pm10prev > 430) then\n fibaro.alert(\"push\", {userID}, \"PM10 \"..pm10 ..\" µg/m³\" ..\" level VERY POOR (Respiratory illness on prolonged exposure)\")\n self:debug(\"PM10 level VERY POOR (Respiratory illness on prolonged exposure)\",pm10 ..\" µg/m³\")\n end\n end\n -- PM10 breakpoint 430+ SEVERE (Health impact even on light physical work. Serious impact on people with heart/lung disease)\n if (tonumber(pm10) >= 439 ) then\n pm10Text = \"SEVERE\"\n if (pm10prev < 430) then\n fibaro.alert(\"push\", {userID}, \"PM10 \"..pm10 ..\" µg/m³\" ..\" level SEVERE (Health impact even on light physical work. Serious impact on people with heart/lung disease)\")\n self:debug(\"PM10 level SEVERE (Health impact even on light physical work. Serious impact on people with heart/lung disease)\",pm10 ..\" µg/m³\")\n end\n end\n\n if tonumber(pm10) > tonumber(pm10prev) then\n pm10Trend = \" ↑\"\n elseif tonumber(pm10) < tonumber(pm10prev) then\n pm10Trend = \" ↓\"\n else\n pm10Trend = \" =\"\n end\n\n -- Update properties for PM10 sensor\n self:updateProperty(\"value\",tonumber(pm10)) \n self:updateProperty(\"unit\", \"㎍/㎥\")\n self:updateProperty(\"log\", pm10Text ..pm10Trend)\nend\n\n\n-- QuickApp functions\n\n\nlocal function getChildVariable(child,varName)\n for _,v in ipairs(child.properties.quickAppVariables or {}) do\n if v.name==varName then return v.value end\n end\n return \"\"\nend\n\n\nfunction QuickApp:logging(level,text) -- Logging function for debug\n if tonumber(debugLevel) >= tonumber(level) then \n self:debug(text)\n end\nend\n\n\nfunction QuickApp:setPressuretext(text) -- Setup for airpressuretext\n self:logging(3,\"setPressuretext\")\n press = tonumber(text)\n if press < 974 then \n return \"Thunderstorms\"\n elseif press < 990 then\n return \"Stormy\"\n elseif press < 1002 then\n return \"Rain\"\n elseif press < 1010 then\n return \"Cloudy\"\n elseif press < 1022 then\n return \"Unstable\"\n elseif press < 1035 then\n return \"Stable\"\n else\n return \"Very dry\"\n end\nend\n\n\nfunction QuickApp:button1Event()\n self:updateView(\"button1\", \"text\", \"Please wait...\")\n self:getData()\n fibaro.setTimeout(5000, function() -- Pause for [timeout] seconds (default 5 seconds)\n self:updateView(\"button1\", \"text\", \"Refresh\")\n end)\nend\n\n\n-- Calculate Absolute Humidity (based on Temperature, Relative Humidity and Airpressure)\nfunction QuickApp:getHumidityAbs(hum,temp,press) -- Source from muhmuh at Fibaro forum\n self:logging(3,\"getHumidityAbs\")\n local EXP = 2.71828182845904523536028747135266249775724709369995\n local humidityAbs = 0.622 * hum/100 * (1.01325 * 10^(5.426651 - 2005.1 / (temp + 273.15) + 0.00013869 * ((temp + 273.15) * (temp + 273.15) - 293700) / (temp + 273.15) * (10^(0.000000000011965 * ((temp + 273.15) * (temp + 273.15) - 293700) * ((temp + 273.15) * (temp + 273.15) - 293700)) - 1) - 0.0044 * 10^((-0.0057148 * (374.11 - temp)^1.25))) + (((temp + 273.15) / 647.3) - 0.422) * (0.577 - ((temp + 273.15) / 647.3)) * EXP^(0.000000000011965 * ((temp + 273.15) * (temp + 273.15) - 293700) * ((temp + 273.15) * (temp + 273.15) - 293700)) * 0.00980665) / (press/1000 - hum/100 * (1.01325 * 10^(5.426651 - 2005.1 / (temp + 273.15) + 0.00013869 * ((temp + 273.15) * (temp + 273.15) - 293700) / (temp + 273.15) * (10^(0.000000000011965 * ((temp + 273.15) * (temp + 273.15) - 293700) * ((temp + 273.15) * (temp + 273.15) - 293700)) - 1) - 0.0044 * 10^((-0.0057148 * (374.11 - temp)^1.25))) + (((temp + 273.15) / 647.3) - 0.422) * (0.577 - ((temp + 273.15) / 647.3)) * EXP^(0.000000000011965 * ((temp + 273.15) * (temp + 273.15) - 293700) * ((temp + 273.15) * (temp + 273.15) - 293700)) * 0.00980665)) * press/1000 * 100000000 / ((temp + 273.15) * 287.1)\n self:logging(3,\"Absolute humidty: \" ..string.format(\"%.2f\",humidityAbs))\n return string.format(\"%.2f\",humidityAbs)\nend\n\n\nfunction QuickApp:updateProperties() -- Update properties\n self:logging(3,\"updateProperties\")\n self:updateProperty(\"log\", os.date(\"%d-%m-%Y %X\", os.time()-data.age) ..\"\\nWiFi \" ..data.wifisignal ..\"dBm\")\nend\n\n\nfunction QuickApp:updateLabels() -- Update labels\n self:logging(3,\"updateLabels\")\n labelText = \"Measurement: \" ..os.date(\"%d-%m-%Y %X\", os.time()-data.age) ..\"\\n\" ..\"\\n\"\n if data.pm1 ~= \"0\" then\n labelText = labelText ..\"PM1.0: \" ..data.pm1 ..\" µg/m³\" ..\"\\n\"\n end\n labelText = labelText ..\"PM2.5: \" ..data.pm25 ..\" µg/m³\" ..\"\\n\"\n if data.pm4 ~= \"0\" then\n labelText = labelText ..\"PM4.0: \" ..data.pm4 ..\" µg/m³\" ..\"\\n\"\n end\n labelText = labelText ..\"PM10: \" ..data.pm10 ..\" µg/m³\" ..\"\\n\"\n labelText = labelText ..\"Temperature: \" ..data.temperature ..\" °C\" ..\"\\n\"\n labelText = labelText ..\"Humidity: \" ..data.humidity ..\" %\" ..\"\\n\"\n labelText = labelText ..\"Absolute Humidity: \" ..data.humidityabsolute ..\" g/m³\" ..\"\\n\" \n labelText = labelText ..\"Airpressure: \" ..data.airpressure ..\" hPa (\" ..data.airpressuretext ..\")\" ..\"\\n\" \n labelText = labelText ..\"\\n\" ..\"WiFi signal: \" ..data.wifisignal ..\" dBm\" ..\"\\n\"\n labelText = labelText ..\"Firmware version: \" ..data.firmware \n self:logging(2,\"labelText: \" ..labelText)\n self:updateView(\"label1\", \"text\", labelText)\nend\n\n\nfunction QuickApp:getValues() -- Get the values\n self:logging(3,\"getValues\")\n local n = 18\n for i=1,n do\n \n --PM1 level\n if jsonTable.sensordatavalues[i].value_type == \"PMS_P0\" or jsonTable.sensordatavalues[i].value_type == \"SPS30_P0\" then\n data.pm1 = jsonTable.sensordatavalues[i].value\n\n -- PM2.5 level \n elseif jsonTable.sensordatavalues[i].value_type == \"SDS_P2\" or jsonTable.sensordatavalues[i].value_type == \"PMS_P2\" or jsonTable.sensordatavalues[i].value_type == \"SPS30_P2\" then\n data.pm25 = jsonTable.sensordatavalues[i].value\n\n -- PM4 level\n elseif jsonTable.sensordatavalues[i].value_type == \"SPS30_P4\" then\n data.pm4 = jsonTable.sensordatavalues[i].value\n\n -- PM10 level\n elseif jsonTable.sensordatavalues[i].value_type == \"SDS_P1\" or jsonTable.sensordatavalues[i].value_type == \"PMS_P1\" or jsonTable.sensordatavalues[i].value_type == \"SPS30_P1\" then\n data.pm10 = jsonTable.sensordatavalues[i].value\n\n -- Temperature value\n elseif jsonTable.sensordatavalues[i].value_type == \"BME280_temperature\" or jsonTable.sensordatavalues[i].value_type == \"temperature\" or jsonTable.sensordatavalues[i].value_type == \"BMP280_temperature\" or jsonTable.sensordatavalues[i].value_type == \"BMP_temperature\" then\n data.temperature = jsonTable.sensordatavalues[i].value\n\n -- Humidity value\n elseif jsonTable.sensordatavalues[i].value_type == \"BME280_humidity\" or jsonTable.sensordatavalues[i].value_type == \"humidity\" or jsonTable.sensordatavalues[i].value_type == \"BMP280_humidity\" or jsonTable.sensordatavalues[i].value_type == \"BMP_humidity\" then\n data.humidity = string.format(\"%.0f\",tonumber(jsonTable.sensordatavalues[i].value))\n\n -- Air Presssure\n elseif jsonTable.sensordatavalues[i].value_type == \"BME280_pressure\" or jsonTable.sensordatavalues[i].value_type == \"pressure\" or jsonTable.sensordatavalues[i].value_type == \"BMP280_pressure\" or jsonTable.sensordatavalues[i].value_type == \"BMP_pressure\" then\n data.airpressure = string.format(\"%.0f\",tonumber(jsonTable.sensordatavalues[i].value)/100)\n\n -- WiFi signal\n elseif jsonTable.sensordatavalues[i].value_type == \"signal\" then\n data.wifisignal = jsonTable.sensordatavalues[i].value\n\n self:logging(3,\"Values: PM1\" ..data.pm1 ..\" PM25: \" ..data.pm25 ..\" PM4: \" ..data.pm4 ..\" PM10: \" ..data.pm10 ..\" Temp: \" ..data.temperature ..\" Hum: \" ..data.humidity ..\" Press: \" ..data.airpressure)\n\n -- Serveral other values\n data.age = jsonTable.age\n data.firmware = jsonTable.software_version\n data.humidityabsolute = self:getHumidityAbs(data.humidity,data.temperature,data.airpressure) -- Calculate Absolute Humidity\n data.airpressuretext = self:setPressuretext(data.airpressure) -- Setup airpressuretext\n return\n end\n end\nend\n\n\nfunction QuickApp:getData()\n self:logging(3,\"Start getData\")\n self:logging(2,\"URL: \" ..url)\n http:request(url, {\n options={headers = {Accept = \"application/json\"},method = 'GET'}, \n success = function(response)\n self:logging(3,\"response status: \" ..response.status)\n self:logging(3,\"headers: \" ..response.headers[\"Content-Type\"])\n self:logging(2,\"Response data: \" ..response.data)\n\n if response.data == nil or response.data == \"\" or response.data == \"[]\" then -- Check for empty result\n self:warning(\"Temporarily no data from Air Quality Sensor\")\n self:logging(3,\"SetTimeout \" ..interval ..\" seconds\")\n fibaro.setTimeout(interval*1000, function() \n self:getdata()\n end)\n end\n \n jsonTable = json.decode(response.data) -- JSON decode from api to lua-table\n\n self:getValues()\n self:updateLabels()\n self:updateProperties()\n \n data.pm25prev=pm25prev\n data.pm10prev=pm10prev\n\n for id,child in pairs(self.childDevices) do \n child:updateValue(data,userID) \n end\n\n pm25prev = tonumber(data.pm25)\n pm10prev = tonumber(data.pm10)\n\n end,\n error = function(error)\n self:error(\"error: \" ..json.encode(error))\n self:updateProperty(\"log\", \"error: \" ..json.encode(error))\n end\n }) \n \n self:logging(3,\"SetTimeout \" ..interval ..\" seconds\")\n fibaro.setTimeout(interval*1000, function() \n self:getData()\n end)\nend\n\n\nfunction QuickApp:createVariables() -- Create all Variables \n httpTimeout = 5 -- Default value for http Timeout\n pm25prev,pm10prev = 0,0\n pm10Text,pm25Text,pm25Trend,pm10Trend = \"\",\"\",\"\",\"\"\n data = {}\n data.pm1 = \"0\"\n data.pm25 = \"0\"\n data.pm4 = \"0\"\n data.pm10 = \"0\"\n data.temperature = \"21\"\n data.humidity = \"50\"\n data.airpressure = \"1013\"\n data.wifisignal = \"0\"\n data.age = \"0\"\n data.firmware = \"\"\n data.humidityabsolute = \"0\"\n data.airpressuretext = \"\"\nend\n\n\nfunction QuickApp:getQuickAppVariables() -- Get all Quickapp Variables or create them\n local ipAddress = self:getVariable(\"ipAddress\")\n local path = \"/data.json\" -- Default path is /data.json\n interval = tonumber(self:getVariable(\"interval\")) \n userID = tonumber(self:getVariable(\"userID\")) \n debugLevel = tonumber(self:getVariable(\"debugLevel\"))\n local icon = tonumber(self:getVariable(\"icon\")) \n\n -- Check existence of the mandatory variables, if not, create them with default values\n if ipAddress == \"\" or ipAddress == nil then\n ipAddress = \"192.168.4.1\" -- Default IP address is 192.168.4.1\n self:setVariable(\"ipAddress\",ipAddress)\n self:trace(\"Added QuickApp variable ipAddress\")\n end\n if interval == \"\" or interval == nil then\n interval = \"146\" -- Default interval is 146, normally the sensor renews its readings every 145 seconds \n self:setVariable(\"interval\",interval)\n self:trace(\"Added QuickApp variable interval\")\n interval = tonumber(interval)\n end\n if userID == \"\" or userID == nil then \n userID = \"2\" -- Default userID\n self:setVariable(\"userID\",userID)\n self:trace(\"Added QuickApp variable iserID\")\n userID = tonumber(userID)\n end\n if debugLevel == \"\" or debugLevel == nil then\n debugLevel = \"1\" -- Default value for debugLevel\n self:setVariable(\"debugLevel\",debugLevel)\n self:trace(\"Added QuickApp variable debugLevel\")\n debugLevel = tonumber(debugLevel)\n end\n if icon == \"\" or icon == nil then \n icon = \"0\" -- Default icon ID\n self:setVariable(\"icon\",icon)\n self:trace(\"Added QuickApp variable icon\")\n icon = tonumber(icon)\n end\n if icon ~= 0 then \n self:updateProperty(\"deviceIcon\", icon) -- set user defined icon \n end\n url = \"http://\" ..ipAddress ..path\nend\n\n\nfunction QuickApp:setupChildDevices()\n local cdevs = api.get(\"/devices?parentId=\"..self.id) or {} -- Pick up all Child Devices\n function self:initChildDevices() end -- Null function, else Fibaro calls it after onInit()...\n\n if #cdevs == 0 then -- If no Child Devices, create them\n local initChildData = { \n {className=\"PolutionSensorTemp\", name=\"Temperature\", type=\"com.fibaro.temperatureSensor\", value=0, unit=\"°C\"},\n {className=\"PolutionSensorHumid\", name=\"Humidity\", type=\"com.fibaro.humiditySensor\", value=0, unit=\"%\"},\n {className=\"PolutionSensorHumidAbs\", name=\"Absolute Humidity\", type=\"com.fibaro.multilevelSensor\", value=0, unit=\"g/m³\"},\n {className=\"PolutionSensorPressure\", name=\"Airpressure\", type=\"com.fibaro.multilevelSensor\", value=0, unit=\"hPa\"},\n {className=\"PolutionSensorPM1\", name=\"PM1\", type=\"com.fibaro.multilevelSensor\", value=0, unit=\"µg/m³\"},\n {className=\"PolutionSensorPM25\", name=\"PM2.5\", type=\"com.fibaro.multilevelSensor\", value=0, unit=\"µg/m³\"},\n {className=\"PolutionSensorPM4\", name=\"PM4\", type=\"com.fibaro.multilevelSensor\", value=0, unit=\"µg/m³\"},\n {className=\"PolutionSensorPM10\", name=\"PM10\", type=\"com.fibaro.multilevelSensor\", value=0, unit=\"µg/m³\"},\n }\n for _,c in ipairs(initChildData) do\n local child = self:createChildDevice(\n {name = c.name,\n type=c.type,\n value=c.value,\n unit=c.unit,\n initialInterfaces = {},\n },\n _G[c.className] -- Fetch class constructor from class name\n )\n child:setVariable(\"className\",c.className) -- Save class name so we know when we load it next time\n end \n else \n for _,child in ipairs(cdevs) do\n local className = getChildVariable(child,\"className\") -- Fetch child class name\n local childObject = _G[className](child) -- Create child object from the constructor name\n self.childDevices[child.id]=childObject\n childObject.parent = self -- Setup parent link to device controller \n end\n end\nend\n\n\nfunction QuickApp:onInit()\n __TAG = fibaro.getName(plugin.mainDeviceId) ..\" ID:\" ..plugin.mainDeviceId\n self:debug(\"onInit\") \n self:setupChildDevices()\n self:getQuickAppVariables() \n self:createVariables()\n http = net.HTTPClient({timeout=httpTimeout*1000})\n self:getData()\nend\n\n--EOF"}]}