Skip to content

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
  • Loading branch information
GitHub4Eddy committed Aug 19, 2020
1 parent 256714f commit 8bcae90
Show file tree
Hide file tree
Showing 5 changed files with 1 addition and 0 deletions.
1 change: 1 addition & 0 deletions Sensor_Community_04.fqa
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"name":"Sensor Community","type":"com.fibaro.multilevelSensor","apiVersion":"1.2","initialProperties":{"viewLayout":{"$jason":{"body":{"header":{"style":{"height":"0"},"title":"quickApp_device_388"},"sections":{"items":[{"components":[{"name":"label5","style":{"weight":"1.2"},"text":"SENSOR COMMUNITY","type":"label"},{"style":{"weight":"0.5"},"type":"space"}],"style":{"weight":"1.2"},"type":"vertical"},{"components":[{"name":"label1","style":{"weight":"1.2"},"text":"Label1","type":"label"},{"style":{"weight":"0.5"},"type":"space"}],"style":{"weight":"1.2"},"type":"vertical"},{"components":[{"name":"label2","style":{"weight":"1.2"},"text":"Label2","type":"label"},{"style":{"weight":"0.5"},"type":"space"}],"style":{"weight":"1.2"},"type":"vertical"},{"components":[{"name":"label3","style":{"weight":"1.2"},"text":"Label3","type":"label"},{"style":{"weight":"0.5"},"type":"space"}],"style":{"weight":"1.2"},"type":"vertical"},{"components":[{"name":"label4","style":{"weight":"1.2"},"text":"Label4","type":"label"},{"style":{"weight":"0.5"},"type":"space"}],"style":{"weight":"1.2"},"type":"vertical"}]}},"head":{"title":"quickApp_device_388"}}},"uiCallbacks":[],"quickAppVariables":[{"name":"Address","value":"http://data.sensor.community/airrohr/v1/sensor/"},{"name":"SensorID","value":"13463"},{"name":"Interval","value":"146"},{"name":"Timeout","value":"120"},{"name":"UserID","value":"2"}],"typeTemplateInitialized":true},"files":[{"name":"main","isMain":true,"isOpen":true,"content":"-- QuickApp SENSOR.COMMUNITY \n\n-- This QuickApp reads the PM2.5, PM10 values directly from a sensor somewhere in this world\n-- That sensor doesn't have to be your sensor, any sensor can be used, just find one in your neighborhood. \n-- For locating a sensor(ID) in your neighborhood see: https://sensor.community/en/\n-- The PM2.5 and PM10 readings are stored in the value of two (child) devices, so you can read the value from your own scenes\n-- This QuickApp will send notifications when PM2.5 or PM10 readings reach a breakpoint\n\n\n-- Version 0.4 (16th August 2020) \n\n-- Changes version 0.4:\n-- Added child devices for PM2.5 and PM10\n-- Added time of measurement, adjusted to your timezone\n-- Added Timeout QuickApp variable with high http timeout value to prevent errors\n-- Error message instead off debug message in case of an error\n-- Changed method of adding QuickApp variables, so they can be edited\n\n\n-- See also https://luftdaten.info\n-- See also for CVS files: https://archive.luftdaten.info\n-- See also https://github.com/opendata-stuttgart/\n-- API documentation: https://github.com/opendata-stuttgart/meta/wiki/EN-APIs\n\n-- Variables (mandatory): \n-- Address = http://data.sensor.community/airrohr/v1/sensor/[SensorID]/\n-- SensorID = [number] (your own SensorID or from someone else, 13463 is an example)\n-- Interval = [number] (in seconds)\n-- Timeout = [number] (in seconds for http timeout)\n-- UserID = [number] userID to notify of PM2.5 / PM10 breakpoints\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-- No editing of this code is needed \n\n\nclass 'PolutionSensorPM25'(QuickAppChild)\nfunction PolutionSensorPM25:__init(dev)\n QuickAppChild.__init(self,dev)\n --self:trace(\"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 EVERE (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)\n\nend\n\nclass 'PolutionSensorPM10'(QuickAppChild)\nfunction PolutionSensorPM10:__init(dev)\n QuickAppChild.__init(self,dev)\n --self:trace(\"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(\"PPM10 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 EVERE (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)\n\nend\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\nfunction QuickApp:onInit()\n __TAG = \"SENSOR_COMMUNITY_\"..self.id\n self:debug(\"onInit\") \n\n local cdevs = api.get(\"/devices?parentId=\"..self.id) or {} -- Pick up all my children \n function self:initChildDevices() end -- Null function, else Fibaro calls it after onInit()...\n\n if #cdevs==0 then -- No children, create children\n local initChildData = { -- Just my own local table to be able to make a loop - you may get your initial data elsewhere...\n {className=\"PolutionSensorPM25\", name=\"PM2.5\", 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 = {}, -- Add interfaces if you need\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 -- Ok, we already have children, instantiate them with the correct class\n -- This is more or less what self:initChildDevices does but this can handle mapping different classes to the same type...\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\n\n -- Get all variables \n local Address = self:getVariable(\"Address\")\n local SensorID = self:getVariable(\"SensorID\")\n local Interval = tonumber(self:getVariable(\"Interval\")) \n local Timeout = tonumber(self:getVariable(\"Timeout\")) \n local UserID = tonumber(self:getVariable(\"UserID\")) \n\n -- Check existence of the mandatory variables, if not, create them with default values\n if Address == \"\" or Address == nil then\n Address = \"http://data.sensor.community/airrohr/v1/sensor/\" -- Default Address\n self:setVariable(\"Address\",Address)\n self:trace(\"Added QuickApp variable Address\")\n end\n if SensorID ==\"\" or SensorID == nil then\n SensorID = \"13463\" -- Default SensorID is 13463 (just random sensor)\n self:setVariable(\"SensorID\",SensorID)\n self:trace(\"Added QuickApp variable SensorID\")\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 Timeout == \"\" or Timeout == nil then\n Timeout = \"120\" -- Default timeout is 120 (higher than normal to prevent errors)\n self:setVariable(\"Timeout\",Timeout)\n self:trace(\"Added QuickApp variable Timeout\")\n Timeout = tonumber(Timeout)\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 UserID\")\n UserID = tonumber(UserID)\n end\n\n -- Start of reading the data from the sensor\n\n local http = net.HTTPClient({timeout=tonumber(Timeout)*1000}) -- High timeout value to prevent errors\n\n local pm25prev,pm10prev = 0,0\n local pm10Text,pm25Text,pm25Trend,pm10Trend = \"\",\"\",\"\",\"\"\n\n local Address = Address .. SensorID ..\"/\" \n\n --self:debug(\"-------------- QUICKAPP SENSOR COMMUNITY -------------\")\n\n local function collectData()\n http:request(Address, {\n options={\n headers = {\n Accept = \"application/json\"\n },\n method = 'GET'\n }, \n success = function(response)\n --self:debug(\"response status:\", response.status) \n --self:debug(\"headers:\", response.headers[\"Content-Type\"])\n local apiResult = response.data\n --self:debug(\"Api result: \",apiResult)\n\n local jsonTable = json.decode(apiResult) -- JSON decode from api to lua-table\n local data = {}\n\n -- Get the values \n data.pm10 = jsonTable[1].sensordatavalues[1].value\n data.pm25 = jsonTable[1].sensordatavalues[2].value\n data.timestamp = jsonTable[1].timestamp \n \n -- Check timezone and daylight saving time\n local timezone = os.difftime(os.time(), os.time(os.date(\"!*t\",os.time())))/3600\n if os.date(\"*t\").isdst then -- Check daylight saving time \n timezone = timezone + 1\n end\n --self:debug(\"Timezone + dst: \",timezone)\n\n -- Convert time of measurement to local timezone\n local pattern = \"(%d+)-(%d+)-(%d+) (%d+):(%d+):(%d+)\"\n local runyear, runmonth, runday, runhour, runminute, runseconds = data.timestamp:match(pattern)\n local convertedTimestamp = os.time({year = runyear, month = runmonth, day = runday, hour = runhour, min = runminute, sec = runseconds})\n local newtimestamp = os.date(\"%d-%m-%Y %X\", convertedTimestamp +(timezone*3600))\n --self:debug(\"newtimestamp:\", newtimestamp)\n\n -- Update labels\n self:updateView(\"label1\", \"text\", \"PM2.5: \" ..data.pm25 ..\" µg/m³\")\n self:updateView(\"label2\", \"text\", \"PM10: \" ..data.pm10 ..\" µg/m³\")\n self:updateView(\"label3\", \"text\", \"Sensor ID: \" ..SensorID)\n self:updateView(\"label4\", \"text\", \"Measurement: \" ..newtimestamp)\n\n --Update properties\n self:updateProperty(\"log\", newtimestamp)\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 self:debug(\"Measurement: \" ..newtimestamp ..\" / PM2.5: \"..data.pm25 ..\" µg/m³ / PM10: \" ..data.pm10 ..\" µg/m³ / Sensor ID: \" ..SensorID)\n \n --self:debug(\"--------------------- END --------------------\")\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 fibaro.setTimeout(Interval*1000, collectData) -- Check every [Interval] seconds for new data\n\n end\n\n collectData() -- start checking data\n\nend\n\n\n"}]}
Binary file added sensor.community1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added sensor.community2.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added sensor.community3.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added sensor.community4.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 8bcae90

Please sign in to comment.