diff --git a/AccuWeather_Pollen.fqa b/AccuWeather_Pollen-01.fqa similarity index 99% rename from AccuWeather_Pollen.fqa rename to AccuWeather_Pollen-01.fqa index f5bfd80..b21172e 100644 --- a/AccuWeather_Pollen.fqa +++ b/AccuWeather_Pollen-01.fqa @@ -1 +1 @@ -{"name":"AccuWeather Pollen","type":"com.fibaro.genericDevice","apiVersion":"1.2","initialProperties":{"viewLayout":{"$jason":{"body":{"header":{"style":{"height":"0"},"title":"quickApp_device_826"},"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"}]}},"head":{"title":"quickApp_device_826"}}},"uiCallbacks":[],"quickAppVariables":[{"name":"interval","type":"string","value":"2400"},{"name":"httpTimeout","type":"string","value":"5"},{"name":"debugLevel","type":"string","value":"1"},{"name":"apiKey","value":"0"},{"name":"locationKey","value":"250542"},{"name":"icon","value":"0"}],"typeTemplateInitialized":true},"files":[{"name":"main","isMain":true,"isOpen":true,"content":"-- QuickApp POLLEN (AccuWeather)\n\n-- This QuickApp gives access to real-time and 5-day forecast pollen count and risk category for grass pollen, mold spores, ragweed pollen and tree pollen of any location from Accuweather.com\n\n-- Pollen is a fine powder produced by trees and plants\n-- Pollen can severely affect people, especially those with different ailments such as asthma and respiratory issues.\n-- It can aggravate these existing conditions or cause these issues in high risk groups\n\n-- Grass Pollen: Pollen grains from grasses\n-- Mold Spores: The fungus produces spores that can become airborne\n-- Radweed Pollen: Ragweeds are annual and perennial herbs and shrubs. A single plant may produce about a billion grains of pollen per season. \n-- Tree Pollen: Pollen from trees such as Birch and Oak\n\n-- The QuickApp provides a risk evaluation with levels in particles/m³\n\n-- Grass Pollen\n-- Category Name Begin Range End Range\n-- Low 0 4.99\n-- Moderate 5 19.99\n-- High 20 199.99\n-- Very High 200\t 299.99\n-- Extreme 300 1000000\n\n-- Mold Spores\n-- Category Name Begin Range End Range\n-- Low 0 6499.99\n-- Moderate 6500 12999.99\n-- High\t 13000 49999.99\n-- Very High 50000 64999.99\n-- Extreme 65000 1000000\n\n-- Ragweed Pollen\n-- Category Name Begin Range End Range\n-- Low 0 9.99\n-- Moderate 10 49.99\n-- High 50 499.99\n-- Very High 500 649.99\n-- Extreme 650 1000000\n \n-- Tree Pollen\n-- Category Name Begin Range End Range\n-- Low 0 14.99\n-- Moderate 15 89.99\n-- High 90 1499.99\n-- Very High 1500 2999.99\n-- Extreme 3000 1000000\n\n\n-- IMPORTANT\n-- You need an API key from https://developer.accuweather.com\n-- The API is free up to 50 API calls/day, one key\n\n\n-- Version 0.1 (22th August 2021)\n-- Initial version\n-- ToDo: convert remaining date/time to format\n\n\n-- Variables (mandatory): \n-- apiKey = Get your free API key from AccuWeather\n-- locationKey = AccuWeather number from your HC3 Lon/Lat\n-- interval = [number] in seconds time to get the data from the API\n-- timeout = [number] in seconds for http timeout\n-- debugLevel = Number (1=some, 2=few, 3=all, 4=simulation mode) (default = 1)\n-- icon = [numbber] User defined icon number (add the icon via an other device and lookup the number)\n\n\n-- No editing of this code is needed \n\n\nclass 'Grass'(QuickAppChild)\nfunction Grass:__init(dev)\n QuickAppChild.__init(self,dev)\n --self:trace(\"Grass initiated, deviceId:\",self.id)\nend\nfunction Grass:updateValue(data) \n self:updateProperty(\"value\",tonumber(data.ValueGrass1))\n self:updateProperty(\"unit\", \"\")\n self:updateProperty(\"log\", data.CategoryGrass1 ..\" risk\")\nend\n\nclass 'Mold'(QuickAppChild)\nfunction Mold:__init(dev)\n QuickAppChild.__init(self,dev)\n --self:trace(\"Mold initiated, deviceId:\",self.id)\nend\nfunction Mold:updateValue(data) \n self:updateProperty(\"value\",tonumber(data.ValueMold1))\n self:updateProperty(\"unit\", \"\")\n self:updateProperty(\"log\", data.CategoryMold1 ..\" risk\")\nend\n\nclass 'Ragweed'(QuickAppChild)\nfunction Ragweed:__init(dev)\n QuickAppChild.__init(self,dev)\n --self:trace(\"Ragweed initiated, deviceId:\",self.id)\nend\nfunction Ragweed:updateValue(data) \n self:updateProperty(\"value\",tonumber(data.ValueRagweed1)) \n self:updateProperty(\"unit\", \"\")\n self:updateProperty(\"log\", data.CategoryRagweed1 ..\" risk\")\nend\n\nclass 'Tree'(QuickAppChild)\nfunction Tree:__init(dev)\n QuickAppChild.__init(self,dev)\n --self:trace(\"Tree initiated, deviceId:\",self.id)\nend\nfunction Tree:updateValue(data) \n self:updateProperty(\"value\",tonumber(data.ValueTree1)) \n self:updateProperty(\"unit\", \"\")\n self:updateProperty(\"log\", data.CategoryTree1 ..\" risk\")\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:updateProperties() --Update properties\n self:logging(3,\"updateProperties\")\n self:updateProperty(\"log\", data.LocalDateTime)\nend\n\n\nfunction QuickApp:updateLabels() -- Update labels\n self:logging(3,\"updateLabels\")\n local labelText = \"\"\n if debugLevel == 4 then\n labelText = labelText ..\"SIMULATION MODE\" ..\"\\n\\n\"\n end\n labelText = labelText ..\"Today \" ..\"\\n\"\n labelText = labelText ..\"Grass Pollen: \" ..data.ValueGrass1 ..\" (\" ..data.CategoryGrass1 ..\" risk)\" ..\"\\n\"\n labelText = labelText ..\"Mold Spores: \" ..data.ValueMold1 ..\" (\" ..data.CategoryMold1 ..\" risk)\" ..\"\\n\"\n labelText = labelText ..\"Ragweed Pollen: \" ..data.ValueRagweed1 ..\" (\" ..data.CategoryRagweed1 ..\" risk)\" ..\"\\n\"\n labelText = labelText ..\"Tree Pollen: \" ..data.ValueTree1 ..\" (\" ..data.CategoryTree1 ..\" risk)\" ..\"\\n\\n\"\n \n labelText = labelText ..\"Date: \" ..data.LocalDateTime2 ..\"\\n\"\n labelText = labelText ..\"Grass Pollen: \" ..data.ValueGrass2 ..\" (\" ..data.CategoryGrass2 ..\" risk)\" ..\"\\n\"\n labelText = labelText ..\"Mold Spores: \" ..data.ValueMold2 ..\" (\" ..data.CategoryMold2 ..\" risk)\" ..\"\\n\"\n labelText = labelText ..\"Ragweed Pollen: \" ..data.ValueRagweed2 ..\" (\" ..data.CategoryRagweed2 ..\" risk)\" ..\"\\n\"\n labelText = labelText ..\"Tree Pollen: \" ..data.ValueTree2 ..\" (\" ..data.CategoryTree2 ..\" risk)\" ..\"\\n\\n\"\n \n labelText = labelText ..\"Date: \" ..data.LocalDateTime3 ..\"\\n\"\n labelText = labelText ..\"Grass Pollen: \" ..data.ValueGrass3 ..\" (\" ..data.CategoryGrass3 ..\" risk)\" ..\"\\n\"\n labelText = labelText ..\"Mold Spores: \" ..data.ValueMold3 ..\" (\" ..data.CategoryMold3 ..\" risk)\" ..\"\\n\"\n labelText = labelText ..\"Ragweed Pollen: \" ..data.ValueRagweed3 ..\" (\" ..data.CategoryRagweed3 ..\" risk)\" ..\"\\n\"\n labelText = labelText ..\"Tree Pollen: \" ..data.ValueTree3 ..\" (\" ..data.CategoryTree3 ..\" risk)\" ..\"\\n\\n\"\n \n labelText = labelText ..\"Date: \" ..data.LocalDateTime4 ..\"\\n\"\n labelText = labelText ..\"Grass Pollen: \" ..data.ValueGrass4 ..\" (\" ..data.CategoryGrass4 ..\" risk)\" ..\"\\n\"\n labelText = labelText ..\"Mold Spores: \" ..data.ValueMold4 ..\" (\" ..data.CategoryMold4 ..\" risk)\" ..\"\\n\"\n labelText = labelText ..\"Ragweed Pollen: \" ..data.ValueRagweed4 ..\" (\" ..data.CategoryRagweed4 ..\" risk)\" ..\"\\n\"\n labelText = labelText ..\"Tree Pollen: \" ..data.ValueTree4 ..\" (\" ..data.CategoryTree4 ..\" risk)\" ..\"\\n\\n\"\n \n labelText = labelText ..\"Date: \" ..data.LocalDateTime5 ..\"\\n\"\n labelText = labelText ..\"Grass Pollen: \" ..data.ValueGrass5 ..\" (\" ..data.CategoryGrass5 ..\" risk)\" ..\"\\n\"\n labelText = labelText ..\"Mold Spores: \" ..data.ValueMold5 ..\" (\" ..data.CategoryMold5 ..\" risk)\" ..\"\\n\"\n labelText = labelText ..\"Ragweed Pollen: \" ..data.ValueRagweed5 ..\" (\" ..data.CategoryRagweed5 ..\" risk)\" ..\"\\n\"\n labelText = labelText ..\"Tree Pollen: \" ..data.ValueTree5 ..\" (\" ..data.CategoryTree5 ..\" risk)\" ..\"\\n\\n\"\n\n labelText = labelText ..\"Measured: \" ..data.LocalDateTime ..\"\\n\"\n \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 data.LocalDateTime1 = jsonTable[1].LocalDateTime\n data.ValueTree1 = string.format(\"%.1f\",jsonTable[1].Value) -- Tree (ID:-14)\n data.CategoryTree1 = jsonTable[1].Category\n data.ValueRagweed1 = string.format(\"%.1f\",jsonTable[2].Value) -- Ragweed (ID:-13)\n data.CategoryRagweed1 = jsonTable[2].Category\n data.ValueMold1 = string.format(\"%.1f\",jsonTable[3].Value) -- Mold (ID:-12)\n data.CategoryMold1 = jsonTable[3].Category\n data.ValueGrass1 = string.format(\"%.1f\",jsonTable[4].Value) -- Grass (ID:-11)\n data.CategoryGrass1 = jsonTable[4].Category\n\n data.LocalDateTime2 = jsonTable[5].LocalDateTime\n data.ValueTree2 = string.format(\"%.1f\",jsonTable[5].Value) -- Tree (ID:-14)\n data.CategoryTree2 = jsonTable[5].Category\n data.ValueRagweed2 = string.format(\"%.1f\",jsonTable[6].Value) -- Ragweed (ID:-13)\n data.CategoryRagweed2 = jsonTable[6].Category\n data.ValueMold2 = string.format(\"%.1f\",jsonTable[7].Value) -- Mold (ID:-12)\n data.CategoryMold2 = jsonTable[7].Category\n data.ValueGrass2 = string.format(\"%.1f\",jsonTable[8].Value) -- Grass (ID:-11)\n data.CategoryGrass2 = jsonTable[8].Category\n\n data.LocalDateTime3 = jsonTable[9].LocalDateTime\n data.ValueTree3 = string.format(\"%.1f\",jsonTable[9].Value) -- Tree (ID:-14)\n data.CategoryTree3 = jsonTable[9].Category\n data.ValueRagweed3 = string.format(\"%.1f\",jsonTable[10].Value) -- Ragweed (ID:-13)\n data.CategoryRagweed3 = jsonTable[10].Category\n data.ValueMold3 = string.format(\"%.1f\",jsonTable[11].Value) -- Mold (ID:-12)\n data.CategoryMold3 = jsonTable[11].Category\n data.ValueGrass3 = string.format(\"%.1f\",jsonTable[12].Value) -- Grass (ID:-11)\n data.CategoryGrass3 = jsonTable[12].Category\n \n data.LocalDateTime4 = jsonTable[13].LocalDateTime\n data.ValueTree4 = string.format(\"%.1f\",jsonTable[13].Value) -- Tree (ID:-14)\n data.CategoryTree4 = jsonTable[13].Category\n data.ValueRagweed4 = string.format(\"%.1f\",jsonTable[14].Value) -- Ragweed (ID:-13)\n data.CategoryRagweed4 = jsonTable[14].Category\n data.ValueMold4 = string.format(\"%.1f\",jsonTable[15].Value) -- Mold (ID:-12)\n data.CategoryMold4 = jsonTable[15].Category\n data.ValueGrass4 = string.format(\"%.1f\",jsonTable[16].Value) -- Grass (ID:-11)\n data.CategoryGrass4 = jsonTable[16].Category\n \n data.LocalDateTime5 = jsonTable[17].LocalDateTime\n data.ValueTree5 = string.format(\"%.1f\",jsonTable[17].Value) -- Tree (ID:-14)\n data.CategoryTree5 = jsonTable[17].Category\n data.ValueRagweed5 = string.format(\"%.1f\",jsonTable[18].Value) -- Ragweed (ID:-13)\n data.CategoryRagweed5 = jsonTable[18].Category\n data.ValueMold5 = string.format(\"%.1f\",jsonTable[19].Value) -- Mold (ID:-12)\n data.CategoryMold5 = jsonTable[19].Category\n data.ValueGrass5 = string.format(\"%.1f\",jsonTable[20].Value) -- Grass (ID:-11)\n data.CategoryGrass5 = jsonTable[20].Category\n \n local EpochDateTime = jsonTable[1].EpochDateTime\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:logging(3,\"Timezone + dst: \" ..timezone)\n data.LocalDateTime = os.date(\"%d-%m-%Y %H:%M\", (EpochDateTime+(timezone*3600)))\n\n -- Convert time of measurement to local timezone\n --local pattern = \"(%d+)-(%d+)-(%d+)T(%d+):(%d+):(%d+)\"\n --data.LocalDateTime1 = data.LocalDateTime1:gsub(\"%.000Z\", \"\") -- Clean up date/time\n --local runyear, runmonth, runday, runhour, runminute, runseconds = data.LocalDateTime1:match(pattern)\n --local convertedTimestamp = os.time({year = runyear, month = runmonth, day = runday, hour = runhour, min = runminute, sec = runseconds})\n --data.LocalDateTime1 = os.date(\"%d-%m-%Y %X\", convertedTimestamp + (timezone*3600))\nend\n\n\nfunction QuickApp:simData() -- Simulate AccuWeather API\n self:logging(3,\"Simulation mode\")\n local apiResult = '[{\"Name\":\"Tree Pollen\",\"ID\":-14,\"Ascending\":false,\"LocalDateTime\":\"2021-08-18T07:00:00+02:00\",\"EpochDateTime\":1629262800,\"Value\":1.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Ragweed Pollen\",\"ID\":-13,\"Ascending\":false,\"LocalDateTime\":\"2021-08-18T07:00:00+02:00\",\"EpochDateTime\":1629262800,\"Value\":2.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Mold\",\"ID\":-12,\"Ascending\":false,\"LocalDateTime\":\"2021-08-18T07:00:00+02:00\",\"EpochDateTime\":1629262800,\"Value\":1.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Grass Pollen\",\"ID\":-11,\"Ascending\":false,\"LocalDateTime\":\"2021-08-18T07:00:00+02:00\",\"EpochDateTime\":1629262800,\"Value\":3.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Tree Pollen\",\"ID\":-14,\"Ascending\":false,\"LocalDateTime\":\"2021-08-19T07:00:00+02:00\",\"EpochDateTime\":1629349200,\"Value\":3.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Ragweed Pollen\",\"ID\":-13,\"Ascending\":false,\"LocalDateTime\":\"2021-08-19T07:00:00+02:00\",\"EpochDateTime\":1629349200,\"Value\":2.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Mold\",\"ID\":-12,\"Ascending\":false,\"LocalDateTime\":\"2021-08-19T07:00:00+02:00\",\"EpochDateTime\":1629349200,\"Value\":1.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Grass Pollen\",\"ID\":-11,\"Ascending\":false,\"LocalDateTime\":\"2021-08-19T07:00:00+02:00\",\"EpochDateTime\":1629349200,\"Value\":1.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Tree Pollen\",\"ID\":-14,\"Ascending\":false,\"LocalDateTime\":\"2021-08-20T07:00:00+02:00\",\"EpochDateTime\":1629435600,\"Value\":1.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Ragweed Pollen\",\"ID\":-13,\"Ascending\":false,\"LocalDateTime\":\"2021-08-20T07:00:00+02:00\",\"EpochDateTime\":1629435600,\"Value\":2.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Mold\",\"ID\":-12,\"Ascending\":false,\"LocalDateTime\":\"2021-08-20T07:00:00+02:00\",\"EpochDateTime\":1629435600,\"Value\":1.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Grass Pollen\",\"ID\":-11,\"Ascending\":false,\"LocalDateTime\":\"2021-08-20T07:00:00+02:00\",\"EpochDateTime\":1629435600,\"Value\":3.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Tree Pollen\",\"ID\":-14,\"Ascending\":false,\"LocalDateTime\":\"2021-08-21T07:00:00+02:00\",\"EpochDateTime\":1629522000,\"Value\":3.0,\"Category\":\"Moderate\",\"CategoryValue\":2,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Ragweed Pollen\",\"ID\":-13,\"Ascending\":false,\"LocalDateTime\":\"2021-08-21T07:00:00+02:00\",\"EpochDateTime\":1629522000,\"Value\":2.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Mold\",\"ID\":-12,\"Ascending\":false,\"LocalDateTime\":\"2021-08-21T07:00:00+02:00\",\"EpochDateTime\":1629522000,\"Value\":1.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Grass Pollen\",\"ID\":-11,\"Ascending\":false,\"LocalDateTime\":\"2021-08-21T07:00:00+02:00\",\"EpochDateTime\":1629522000,\"Value\":1.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Tree Pollen\",\"ID\":-14,\"Ascending\":false,\"LocalDateTime\":\"2021-08-22T07:00:00+02:00\",\"EpochDateTime\":1629608400,\"Value\":1.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Ragweed Pollen\",\"ID\":-13,\"Ascending\":false,\"LocalDateTime\":\"2021-08-22T07:00:00+02:00\",\"EpochDateTime\":1629608400,\"Value\":2.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Mold\",\"ID\":-12,\"Ascending\":false,\"LocalDateTime\":\"2021-08-22T07:00:00+02:00\",\"EpochDateTime\":1629608400,\"Value\":1.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Grass Pollen\",\"ID\":-11,\"Ascending\":false,\"LocalDateTime\":\"2021-08-22T07:00:00+02:00\",\"EpochDateTime\":1629608400,\"Value\":3.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"}]'\n \n self:logging(3,\"apiResult: \" ..apiResult)\n\n jsonTable = json.decode(apiResult) -- Decode the json string from api to lua-table \n \n self:getValues()\n self:updateLabels()\n self:updateProperties()\n\n for id,child in pairs(self.childDevices) do \n child:updateValue(data) \n end\n \n self:logging(3,\"SetTimeout \" ..interval ..\" seconds\")\n fibaro.setTimeout(interval*1000, function() \n self:simData()\n end)\nend\n\n\nfunction QuickApp:getData()\n self:logging(3,\"Start getData\")\n self:logging(2,\"URL: \" ..address)\n \n http:request(address, {\n options = {data = Method, method = \"GET\", headers = {[\"Content-Type\"] = \"application/json\",[\"Accept\"] = \"application/json\",}},\n \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 == \"[]\" or response.status > 200 then -- Check for empty result\n self:warning(\"Temporarily no data from AccuWeather\")\n self:warning(response.data)\n return\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 for id,child in pairs(self.childDevices) do \n child:updateValue(data) \n end\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() -- Get all Quickapp Variables or create them\n data = {}\n data.LocalDateTime = \"\"\n data.LocalDateTime1 = \"\"\n data.ValueGrass1 = \"0\"\n data.ValueMold1 = \"0\"\n data.ValueRagweed1 = \"0\"\n data.ValueTree1 = \"0\"\n data.CategoryGrass1 = \"n/a\"\n data.CategoryMold1 = \"n/a\"\n data.CategoryRagweed1 = \"n/a\"\n data.CategoryTree1 = \"n/a\"\n \n data.LocalDateTime2 = \"\"\n data.ValueGrass2 = \"0\"\n data.ValueMold2 = \"0\"\n data.ValueRagweed2 = \"0\"\n data.ValueTree2 = \"0\"\n data.CategoryGrass2 = \"n/a\"\n data.CategoryMold2 = \"n/a\"\n data.CategoryRagweed2 = \"n/a\"\n data.CategoryTree2 = \"n/a\"\n \n data.LocalDateTime3 = \"\"\n data.ValueGrass3 = \"0\"\n data.ValueMold3 = \"0\"\n data.ValueRagweed3 = \"0\"\n data.ValueTree3 = \"0\"\n data.CategoryGrass3 = \"n/a\"\n data.CategoryMold3 = \"n/a\"\n data.CategoryRagweed3 = \"n/a\"\n data.CategoryTree3 = \"n/a\"\n \n data.LocalDateTime4 = \"\"\n data.ValueGrass4 = \"0\"\n data.ValueMold4 = \"0\"\n data.ValueRagweed4 = \"0\"\n data.ValueTree4 = \"0\"\n data.CategoryGrass4 = \"n/a\"\n data.CategoryMold4 = \"n/a\"\n data.CategoryRagweed4 = \"n/a\"\n data.CategoryTree4 = \"n/a\"\n \n data.LocalDateTime5 = \"\"\n data.ValueGrass5 = \"0\"\n data.ValueMold5 = \"0\"\n data.ValueRagweed5 = \"0\"\n data.ValueTree5 = \"0\"\n data.CategoryGrass5 = \"n/a\"\n data.CategoryMold5 = \"n/a\"\n data.CategoryRagweed5 = \"n/a\"\n data.CategoryTree5 = \"n/a\"\n \nend\n\n\nfunction QuickApp:checkLocationKey() -- Get the locationKey from AccuWeather based on your HC3 Lat/Lon\n self:logging(3,\"Start checkLocationKey\")\n \n if locationKey == \"\" or locationKey == \"0\" or locationKey == nil then\n\n latitude = string.format(\"%.2f\",api.get(\"/settings/location\")[\"latitude\"]) -- Default latitude of your HC3\n longitude = string.format(\"%.2f\",api.get(\"/settings/location\")[\"longitude\"]) -- Default longitude of your HC3\n\n local url = \"http://dataservice.accuweather.com/locations/v1/cities/geoposition/search?apikey=\" ..apiKey ..\"&q=\" ..latitude ..\"%2C\" ..longitude ..\"&details=true\"\n self:logging(2,\"URL: \" ..url)\n\n http:request(url, {\n options = {data = Method, method = \"GET\", headers = {[\"Content-Type\"] = \"application/json\",[\"Accept\"] = \"application/json\",}},\n \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 == \"[]\" or response.status > 200 then -- Check for empty result\n self:warning(\"Temporarily no locationKey from AccuWeather\")\n self:warning(response.data)\n --locationKey = \"250542\" -- De Bilt\n return\n end\n\n geoTable = json.decode(response.data) -- JSON decode from api to lua-table\n locationKey = tostring(geoTable.Key)\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 self:logging(3,\"LocationKey: \" ..LocationKey)\n self:setVariable(\"locationKey\", locationKey)\n self:trace(\"Added QuickApp variable locationKey: \" ..locationKey)\n end\nend\n\n\nfunction QuickApp:getQuickAppVariables() -- Get all variables \n apiKey = self:getVariable(\"apiKey\")\n locationKey = self:getVariable(\"locationKey\")\n interval = tonumber(self:getVariable(\"interval\")) \n httpTimeout = tonumber(self:getVariable(\"httpTimeout\")) \n debugLevel = tonumber(self:getVariable(\"debugLevel\"))\n local icon = tonumber(self:getVariable(\"icon\")) \n\n if apiKey == \"\" or apiKey == \"0\" or apiKey == nil then\n apiKey = \"0\" \n self:setVariable(\"apiKey\",apiKey)\n self:trace(\"Added QuickApp variable apiKey\")\n end\n if locationKey == \"\" or locationKey == \"0\" or locationKey == nil then\n locationKey = \"250542\" \n self:setVariable(\"locationKey\",locationKey)\n self:trace(\"Added QuickApp variable locationKey\")\n end\n if interval == \"\" or interval == nil then\n interval = \"2400\" -- Free account includes up to 50 calls a day, so default value is 2400 (every 40 minutes)\n self:setVariable(\"interval\",interval)\n self:trace(\"Added QuickApp variable interval: \" ..interval)\n interval = tonumber(interval)\n end \n if httpTimeout == \"\" or httpTimeout == nil then\n httpTimeout = \"5\" -- timeoout in seconds\n self:setVariable(\"httpTimeout\",httpTimeout)\n self:trace(\"Added QuickApp variable httpTimeout\")\n httpTimeout = tonumber(httpTimeout)\n end\n if debugLevel == \"\" or debugLevel == nil then\n debugLevel = \"1\" -- Default value for debugLevel response in seconds\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\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 \n address = \"http://dataservice.accuweather.com/indices/v1/daily/5day/\" ..locationKey ..\"/groups/30?apikey=\" ..apiKey ..\"&details=false\"\n\n if apiKey == nil or apiKey == \"\" or apiKey == \"0\" then -- Check mandatory API key \n self:error(\"API key is empty! Get your free API key from AccuWeather\")\n self:warning(\"No API Key: Switched to Simulation Mode\")\n debugLevel = 4 -- Simulation mode due to empty API key\n end\n\nend\n\n\nfunction QuickApp:setupChildDevices()\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 = { \n {className=\"Grass\", name=\"Grass\", type=\"com.fibaro.multilevelSensor\", value=0},\n {className=\"Mold\", name=\"Mold\", type=\"com.fibaro.multilevelSensor\", value=0},\n {className=\"Ragweed\", name=\"Ragweed\", type=\"com.fibaro.multilevelSensor\", value=0},\n {className=\"Tree\", name=\"Tree\", type=\"com.fibaro.multilevelSensor\", value=0},\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 \n self:setupChildDevices() -- Setup the Child Devices\n self:getQuickAppVariables() -- Get Quickapp Variables or create them\n self:createVariables() -- Create Variables\n \n http = net.HTTPClient({timeout=httpTimeout*1000})\n\n if tonumber(debugLevel) >= 4 then \n self:simData() -- Go in simulation\n else\n --self:checkLocationKey() -- Check the locationKey \n self:getData() -- Get data from API\n end\nend\n\n--EOF "}]} \ No newline at end of file +{"name":"AccuWeather Pollen","type":"com.fibaro.genericDevice","apiVersion":"1.2","initialProperties":{"viewLayout":{"$jason":{"body":{"header":{"style":{"height":"0"},"title":"quickApp_device_826"},"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"}]}},"head":{"title":"quickApp_device_826"}}},"uiCallbacks":[],"quickAppVariables":[{"name":"interval","type":"string","value":"2400"},{"name":"httpTimeout","type":"string","value":"5"},{"name":"debugLevel","type":"string","value":"1"},{"name":"apiKey","value":"0"},{"name":"locationKey","value":"250542"},{"name":"icon","value":"0"}],"typeTemplateInitialized":true},"files":[{"name":"main","isMain":true,"isOpen":true,"content":"-- QuickApp POLLEN (AccuWeather)\n\n-- This QuickApp gives access to real-time and 5-day forecast pollen count and risk category for grass pollen, mold spores, ragweed pollen and tree pollen of any location from Accuweather.com\n\n-- Pollen is a fine powder produced by trees and plants\n-- Pollen can severely affect people, especially those with different ailments such as asthma and respiratory issues.\n-- It can aggravate these existing conditions or cause these issues in high risk groups\n\n-- Grass Pollen: Pollen grains from grasses\n-- Mold Spores: The fungus produces spores that can become airborne\n-- Radweed Pollen: Ragweeds are annual and perennial herbs and shrubs. A single plant may produce about a billion grains of pollen per season. \n-- Tree Pollen: Pollen from trees such as Birch and Oak\n\n-- The QuickApp provides a risk evaluation with levels in particles/m³\n\n-- Grass Pollen\n-- Category Name Begin Range End Range\n-- Low 0 4.99\n-- Moderate 5 19.99\n-- High 20 199.99\n-- Very High 200\t 299.99\n-- Extreme 300 1000000\n\n-- Mold Spores\n-- Category Name Begin Range End Range\n-- Low 0 6499.99\n-- Moderate 6500 12999.99\n-- High\t 13000 49999.99\n-- Very High 50000 64999.99\n-- Extreme 65000 1000000\n\n-- Ragweed Pollen\n-- Category Name Begin Range End Range\n-- Low 0 9.99\n-- Moderate 10 49.99\n-- High 50 499.99\n-- Very High 500 649.99\n-- Extreme 650 1000000\n \n-- Tree Pollen\n-- Category Name Begin Range End Range\n-- Low 0 14.99\n-- Moderate 15 89.99\n-- High 90 1499.99\n-- Very High 1500 2999.99\n-- Extreme 3000 1000000\n\n\n-- IMPORTANT\n-- You need an API key from https://developer.accuweather.com\n-- The API is free up to 50 API calls/day, one key\n\n\n-- Version 0.1 (22th August 2021)\n-- Initial version\n-- ToDo: convert remaining date/time to format\n\n\n-- Variables (mandatory): \n-- apiKey = Get your free API key from AccuWeather\n-- locationKey = AccuWeather number from your HC3 Lon/Lat\n-- interval = [number] in seconds time to get the data from the API\n-- timeout = [number] in seconds for http timeout\n-- debugLevel = Number (1=some, 2=few, 3=all, 4=simulation mode) (default = 1)\n-- icon = [numbber] User defined icon number (add the icon via an other device and lookup the number)\n\n\n-- No editing of this code is needed \n\n\nclass 'Grass'(QuickAppChild)\nfunction Grass:__init(dev)\n QuickAppChild.__init(self,dev)\n --self:trace(\"Grass initiated, deviceId:\",self.id)\nend\nfunction Grass:updateValue(data) \n self:updateProperty(\"value\",tonumber(data.ValueGrass1))\n self:updateProperty(\"unit\", \"\")\n self:updateProperty(\"log\", data.CategoryGrass1 ..\" risk\")\nend\n\nclass 'Mold'(QuickAppChild)\nfunction Mold:__init(dev)\n QuickAppChild.__init(self,dev)\n --self:trace(\"Mold initiated, deviceId:\",self.id)\nend\nfunction Mold:updateValue(data) \n self:updateProperty(\"value\",tonumber(data.ValueMold1))\n self:updateProperty(\"unit\", \"\")\n self:updateProperty(\"log\", data.CategoryMold1 ..\" risk\")\nend\n\nclass 'Ragweed'(QuickAppChild)\nfunction Ragweed:__init(dev)\n QuickAppChild.__init(self,dev)\n --self:trace(\"Ragweed initiated, deviceId:\",self.id)\nend\nfunction Ragweed:updateValue(data) \n self:updateProperty(\"value\",tonumber(data.ValueRagweed1)) \n self:updateProperty(\"unit\", \"\")\n self:updateProperty(\"log\", data.CategoryRagweed1 ..\" risk\")\nend\n\nclass 'Tree'(QuickAppChild)\nfunction Tree:__init(dev)\n QuickAppChild.__init(self,dev)\n --self:trace(\"Tree initiated, deviceId:\",self.id)\nend\nfunction Tree:updateValue(data) \n self:updateProperty(\"value\",tonumber(data.ValueTree1)) \n self:updateProperty(\"unit\", \"\")\n self:updateProperty(\"log\", data.CategoryTree1 ..\" risk\")\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:updateProperties() --Update properties\n self:logging(3,\"updateProperties\")\n self:updateProperty(\"log\", data.LocalDateTime)\nend\n\n\nfunction QuickApp:updateLabels() -- Update labels\n self:logging(3,\"updateLabels\")\n local labelText = \"\"\n if debugLevel == 4 then\n labelText = labelText ..\"SIMULATION MODE\" ..\"\\n\\n\"\n end\n labelText = labelText ..\"Today \" ..\"\\n\"\n labelText = labelText ..\"Grass Pollen: \" ..data.ValueGrass1 ..\" (\" ..data.CategoryGrass1 ..\" risk)\" ..\"\\n\"\n labelText = labelText ..\"Mold Spores: \" ..data.ValueMold1 ..\" (\" ..data.CategoryMold1 ..\" risk)\" ..\"\\n\"\n labelText = labelText ..\"Ragweed Pollen: \" ..data.ValueRagweed1 ..\" (\" ..data.CategoryRagweed1 ..\" risk)\" ..\"\\n\"\n labelText = labelText ..\"Tree Pollen: \" ..data.ValueTree1 ..\" (\" ..data.CategoryTree1 ..\" risk)\" ..\"\\n\\n\"\n \n labelText = labelText ..\"Date: \" ..data.LocalDateTime2 ..\"\\n\"\n labelText = labelText ..\"Grass Pollen: \" ..data.ValueGrass2 ..\" (\" ..data.CategoryGrass2 ..\" risk)\" ..\"\\n\"\n labelText = labelText ..\"Mold Spores: \" ..data.ValueMold2 ..\" (\" ..data.CategoryMold2 ..\" risk)\" ..\"\\n\"\n labelText = labelText ..\"Ragweed Pollen: \" ..data.ValueRagweed2 ..\" (\" ..data.CategoryRagweed2 ..\" risk)\" ..\"\\n\"\n labelText = labelText ..\"Tree Pollen: \" ..data.ValueTree2 ..\" (\" ..data.CategoryTree2 ..\" risk)\" ..\"\\n\\n\"\n \n labelText = labelText ..\"Date: \" ..data.LocalDateTime3 ..\"\\n\"\n labelText = labelText ..\"Grass Pollen: \" ..data.ValueGrass3 ..\" (\" ..data.CategoryGrass3 ..\" risk)\" ..\"\\n\"\n labelText = labelText ..\"Mold Spores: \" ..data.ValueMold3 ..\" (\" ..data.CategoryMold3 ..\" risk)\" ..\"\\n\"\n labelText = labelText ..\"Ragweed Pollen: \" ..data.ValueRagweed3 ..\" (\" ..data.CategoryRagweed3 ..\" risk)\" ..\"\\n\"\n labelText = labelText ..\"Tree Pollen: \" ..data.ValueTree3 ..\" (\" ..data.CategoryTree3 ..\" risk)\" ..\"\\n\\n\"\n \n labelText = labelText ..\"Date: \" ..data.LocalDateTime4 ..\"\\n\"\n labelText = labelText ..\"Grass Pollen: \" ..data.ValueGrass4 ..\" (\" ..data.CategoryGrass4 ..\" risk)\" ..\"\\n\"\n labelText = labelText ..\"Mold Spores: \" ..data.ValueMold4 ..\" (\" ..data.CategoryMold4 ..\" risk)\" ..\"\\n\"\n labelText = labelText ..\"Ragweed Pollen: \" ..data.ValueRagweed4 ..\" (\" ..data.CategoryRagweed4 ..\" risk)\" ..\"\\n\"\n labelText = labelText ..\"Tree Pollen: \" ..data.ValueTree4 ..\" (\" ..data.CategoryTree4 ..\" risk)\" ..\"\\n\\n\"\n \n labelText = labelText ..\"Date: \" ..data.LocalDateTime5 ..\"\\n\"\n labelText = labelText ..\"Grass Pollen: \" ..data.ValueGrass5 ..\" (\" ..data.CategoryGrass5 ..\" risk)\" ..\"\\n\"\n labelText = labelText ..\"Mold Spores: \" ..data.ValueMold5 ..\" (\" ..data.CategoryMold5 ..\" risk)\" ..\"\\n\"\n labelText = labelText ..\"Ragweed Pollen: \" ..data.ValueRagweed5 ..\" (\" ..data.CategoryRagweed5 ..\" risk)\" ..\"\\n\"\n labelText = labelText ..\"Tree Pollen: \" ..data.ValueTree5 ..\" (\" ..data.CategoryTree5 ..\" risk)\" ..\"\\n\\n\"\n\n labelText = labelText ..\"Measured: \" ..data.LocalDateTime ..\"\\n\"\n \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 data.LocalDateTime1 = jsonTable[1].LocalDateTime\n data.ValueTree1 = string.format(\"%.1f\",jsonTable[1].Value) -- Tree (ID:-14)\n data.CategoryTree1 = jsonTable[1].Category\n data.ValueRagweed1 = string.format(\"%.1f\",jsonTable[2].Value) -- Ragweed (ID:-13)\n data.CategoryRagweed1 = jsonTable[2].Category\n data.ValueMold1 = string.format(\"%.1f\",jsonTable[3].Value) -- Mold (ID:-12)\n data.CategoryMold1 = jsonTable[3].Category\n data.ValueGrass1 = string.format(\"%.1f\",jsonTable[4].Value) -- Grass (ID:-11)\n data.CategoryGrass1 = jsonTable[4].Category\n\n data.LocalDateTime2 = jsonTable[5].LocalDateTime\n data.ValueTree2 = string.format(\"%.1f\",jsonTable[5].Value) -- Tree (ID:-14)\n data.CategoryTree2 = jsonTable[5].Category\n data.ValueRagweed2 = string.format(\"%.1f\",jsonTable[6].Value) -- Ragweed (ID:-13)\n data.CategoryRagweed2 = jsonTable[6].Category\n data.ValueMold2 = string.format(\"%.1f\",jsonTable[7].Value) -- Mold (ID:-12)\n data.CategoryMold2 = jsonTable[7].Category\n data.ValueGrass2 = string.format(\"%.1f\",jsonTable[8].Value) -- Grass (ID:-11)\n data.CategoryGrass2 = jsonTable[8].Category\n\n data.LocalDateTime3 = jsonTable[9].LocalDateTime\n data.ValueTree3 = string.format(\"%.1f\",jsonTable[9].Value) -- Tree (ID:-14)\n data.CategoryTree3 = jsonTable[9].Category\n data.ValueRagweed3 = string.format(\"%.1f\",jsonTable[10].Value) -- Ragweed (ID:-13)\n data.CategoryRagweed3 = jsonTable[10].Category\n data.ValueMold3 = string.format(\"%.1f\",jsonTable[11].Value) -- Mold (ID:-12)\n data.CategoryMold3 = jsonTable[11].Category\n data.ValueGrass3 = string.format(\"%.1f\",jsonTable[12].Value) -- Grass (ID:-11)\n data.CategoryGrass3 = jsonTable[12].Category\n \n data.LocalDateTime4 = jsonTable[13].LocalDateTime\n data.ValueTree4 = string.format(\"%.1f\",jsonTable[13].Value) -- Tree (ID:-14)\n data.CategoryTree4 = jsonTable[13].Category\n data.ValueRagweed4 = string.format(\"%.1f\",jsonTable[14].Value) -- Ragweed (ID:-13)\n data.CategoryRagweed4 = jsonTable[14].Category\n data.ValueMold4 = string.format(\"%.1f\",jsonTable[15].Value) -- Mold (ID:-12)\n data.CategoryMold4 = jsonTable[15].Category\n data.ValueGrass4 = string.format(\"%.1f\",jsonTable[16].Value) -- Grass (ID:-11)\n data.CategoryGrass4 = jsonTable[16].Category\n \n data.LocalDateTime5 = jsonTable[17].LocalDateTime\n data.ValueTree5 = string.format(\"%.1f\",jsonTable[17].Value) -- Tree (ID:-14)\n data.CategoryTree5 = jsonTable[17].Category\n data.ValueRagweed5 = string.format(\"%.1f\",jsonTable[18].Value) -- Ragweed (ID:-13)\n data.CategoryRagweed5 = jsonTable[18].Category\n data.ValueMold5 = string.format(\"%.1f\",jsonTable[19].Value) -- Mold (ID:-12)\n data.CategoryMold5 = jsonTable[19].Category\n data.ValueGrass5 = string.format(\"%.1f\",jsonTable[20].Value) -- Grass (ID:-11)\n data.CategoryGrass5 = jsonTable[20].Category\n \n local EpochDateTime = jsonTable[1].EpochDateTime\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:logging(3,\"Timezone + dst: \" ..timezone)\n data.LocalDateTime = os.date(\"%d-%m-%Y %H:%M\", (EpochDateTime+(timezone*3600)))\n\n -- Convert time of measurement to local timezone\n --local pattern = \"(%d+)-(%d+)-(%d+)T(%d+):(%d+):(%d+)\"\n --data.LocalDateTime1 = data.LocalDateTime1:gsub(\"%.000Z\", \"\") -- Clean up date/time\n --local runyear, runmonth, runday, runhour, runminute, runseconds = data.LocalDateTime1:match(pattern)\n --local convertedTimestamp = os.time({year = runyear, month = runmonth, day = runday, hour = runhour, min = runminute, sec = runseconds})\n --data.LocalDateTime1 = os.date(\"%d-%m-%Y %X\", convertedTimestamp + (timezone*3600))\nend\n\n\nfunction QuickApp:simData() -- Simulate AccuWeather API\n self:logging(3,\"Simulation mode\")\n local apiResult = '[{\"Name\":\"Tree Pollen\",\"ID\":-14,\"Ascending\":false,\"LocalDateTime\":\"2021-08-18T07:00:00+02:00\",\"EpochDateTime\":1629262800,\"Value\":1.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Ragweed Pollen\",\"ID\":-13,\"Ascending\":false,\"LocalDateTime\":\"2021-08-18T07:00:00+02:00\",\"EpochDateTime\":1629262800,\"Value\":2.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Mold\",\"ID\":-12,\"Ascending\":false,\"LocalDateTime\":\"2021-08-18T07:00:00+02:00\",\"EpochDateTime\":1629262800,\"Value\":1.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Grass Pollen\",\"ID\":-11,\"Ascending\":false,\"LocalDateTime\":\"2021-08-18T07:00:00+02:00\",\"EpochDateTime\":1629262800,\"Value\":3.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Tree Pollen\",\"ID\":-14,\"Ascending\":false,\"LocalDateTime\":\"2021-08-19T07:00:00+02:00\",\"EpochDateTime\":1629349200,\"Value\":3.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Ragweed Pollen\",\"ID\":-13,\"Ascending\":false,\"LocalDateTime\":\"2021-08-19T07:00:00+02:00\",\"EpochDateTime\":1629349200,\"Value\":2.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Mold\",\"ID\":-12,\"Ascending\":false,\"LocalDateTime\":\"2021-08-19T07:00:00+02:00\",\"EpochDateTime\":1629349200,\"Value\":1.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Grass Pollen\",\"ID\":-11,\"Ascending\":false,\"LocalDateTime\":\"2021-08-19T07:00:00+02:00\",\"EpochDateTime\":1629349200,\"Value\":1.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Tree Pollen\",\"ID\":-14,\"Ascending\":false,\"LocalDateTime\":\"2021-08-20T07:00:00+02:00\",\"EpochDateTime\":1629435600,\"Value\":1.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Ragweed Pollen\",\"ID\":-13,\"Ascending\":false,\"LocalDateTime\":\"2021-08-20T07:00:00+02:00\",\"EpochDateTime\":1629435600,\"Value\":2.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Mold\",\"ID\":-12,\"Ascending\":false,\"LocalDateTime\":\"2021-08-20T07:00:00+02:00\",\"EpochDateTime\":1629435600,\"Value\":1.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Grass Pollen\",\"ID\":-11,\"Ascending\":false,\"LocalDateTime\":\"2021-08-20T07:00:00+02:00\",\"EpochDateTime\":1629435600,\"Value\":3.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Tree Pollen\",\"ID\":-14,\"Ascending\":false,\"LocalDateTime\":\"2021-08-21T07:00:00+02:00\",\"EpochDateTime\":1629522000,\"Value\":3.0,\"Category\":\"Moderate\",\"CategoryValue\":2,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Ragweed Pollen\",\"ID\":-13,\"Ascending\":false,\"LocalDateTime\":\"2021-08-21T07:00:00+02:00\",\"EpochDateTime\":1629522000,\"Value\":2.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Mold\",\"ID\":-12,\"Ascending\":false,\"LocalDateTime\":\"2021-08-21T07:00:00+02:00\",\"EpochDateTime\":1629522000,\"Value\":1.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Grass Pollen\",\"ID\":-11,\"Ascending\":false,\"LocalDateTime\":\"2021-08-21T07:00:00+02:00\",\"EpochDateTime\":1629522000,\"Value\":1.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Tree Pollen\",\"ID\":-14,\"Ascending\":false,\"LocalDateTime\":\"2021-08-22T07:00:00+02:00\",\"EpochDateTime\":1629608400,\"Value\":1.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Ragweed Pollen\",\"ID\":-13,\"Ascending\":false,\"LocalDateTime\":\"2021-08-22T07:00:00+02:00\",\"EpochDateTime\":1629608400,\"Value\":2.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Mold\",\"ID\":-12,\"Ascending\":false,\"LocalDateTime\":\"2021-08-22T07:00:00+02:00\",\"EpochDateTime\":1629608400,\"Value\":1.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"},{\"Name\":\"Grass Pollen\",\"ID\":-11,\"Ascending\":false,\"LocalDateTime\":\"2021-08-22T07:00:00+02:00\",\"EpochDateTime\":1629608400,\"Value\":3.0,\"Category\":\"Low\",\"CategoryValue\":1,\"MobileLink\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\",\"Link\":\"http://www.accuweather.com/en/nl/de-bilt/250542/allergies-weather/873892?lang=en-us\"}]'\n \n self:logging(3,\"apiResult: \" ..apiResult)\n\n jsonTable = json.decode(apiResult) -- Decode the json string from api to lua-table \n \n self:getValues()\n self:updateLabels()\n self:updateProperties()\n\n for id,child in pairs(self.childDevices) do \n child:updateValue(data) \n end\n \n self:logging(3,\"SetTimeout \" ..interval ..\" seconds\")\n fibaro.setTimeout(interval*1000, function() \n self:simData()\n end)\nend\n\n\nfunction QuickApp:getData()\n self:logging(3,\"Start getData\")\n self:logging(2,\"URL: \" ..address)\n \n http:request(address, {\n options = {data = Method, method = \"GET\", headers = {[\"Content-Type\"] = \"application/json\",[\"Accept\"] = \"application/json\",}},\n \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 == \"[]\" or response.status > 200 then -- Check for empty result\n self:warning(\"Temporarily no data from AccuWeather\")\n self:warning(response.data)\n return\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 for id,child in pairs(self.childDevices) do \n child:updateValue(data) \n end\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() -- Get all Quickapp Variables or create them\n data = {}\n data.LocalDateTime = \"\"\n data.LocalDateTime1 = \"\"\n data.ValueGrass1 = \"0\"\n data.ValueMold1 = \"0\"\n data.ValueRagweed1 = \"0\"\n data.ValueTree1 = \"0\"\n data.CategoryGrass1 = \"n/a\"\n data.CategoryMold1 = \"n/a\"\n data.CategoryRagweed1 = \"n/a\"\n data.CategoryTree1 = \"n/a\"\n \n data.LocalDateTime2 = \"\"\n data.ValueGrass2 = \"0\"\n data.ValueMold2 = \"0\"\n data.ValueRagweed2 = \"0\"\n data.ValueTree2 = \"0\"\n data.CategoryGrass2 = \"n/a\"\n data.CategoryMold2 = \"n/a\"\n data.CategoryRagweed2 = \"n/a\"\n data.CategoryTree2 = \"n/a\"\n \n data.LocalDateTime3 = \"\"\n data.ValueGrass3 = \"0\"\n data.ValueMold3 = \"0\"\n data.ValueRagweed3 = \"0\"\n data.ValueTree3 = \"0\"\n data.CategoryGrass3 = \"n/a\"\n data.CategoryMold3 = \"n/a\"\n data.CategoryRagweed3 = \"n/a\"\n data.CategoryTree3 = \"n/a\"\n \n data.LocalDateTime4 = \"\"\n data.ValueGrass4 = \"0\"\n data.ValueMold4 = \"0\"\n data.ValueRagweed4 = \"0\"\n data.ValueTree4 = \"0\"\n data.CategoryGrass4 = \"n/a\"\n data.CategoryMold4 = \"n/a\"\n data.CategoryRagweed4 = \"n/a\"\n data.CategoryTree4 = \"n/a\"\n \n data.LocalDateTime5 = \"\"\n data.ValueGrass5 = \"0\"\n data.ValueMold5 = \"0\"\n data.ValueRagweed5 = \"0\"\n data.ValueTree5 = \"0\"\n data.CategoryGrass5 = \"n/a\"\n data.CategoryMold5 = \"n/a\"\n data.CategoryRagweed5 = \"n/a\"\n data.CategoryTree5 = \"n/a\"\n \nend\n\n\nfunction QuickApp:checkLocationKey() -- Get the locationKey from AccuWeather based on your HC3 Lat/Lon\n self:logging(3,\"Start checkLocationKey\")\n \n if locationKey == \"\" or locationKey == \"0\" or locationKey == nil then\n\n latitude = string.format(\"%.2f\",api.get(\"/settings/location\")[\"latitude\"]) -- Default latitude of your HC3\n longitude = string.format(\"%.2f\",api.get(\"/settings/location\")[\"longitude\"]) -- Default longitude of your HC3\n\n local url = \"http://dataservice.accuweather.com/locations/v1/cities/geoposition/search?apikey=\" ..apiKey ..\"&q=\" ..latitude ..\"%2C\" ..longitude ..\"&details=true\"\n self:logging(2,\"URL: \" ..url)\n\n http:request(url, {\n options = {data = Method, method = \"GET\", headers = {[\"Content-Type\"] = \"application/json\",[\"Accept\"] = \"application/json\",}},\n \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 == \"[]\" or response.status > 200 then -- Check for empty result\n self:warning(\"Temporarily no locationKey from AccuWeather\")\n self:warning(response.data)\n --locationKey = \"250542\" -- De Bilt\n return\n end\n\n geoTable = json.decode(response.data) -- JSON decode from api to lua-table\n locationKey = tostring(geoTable.Key)\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 self:logging(3,\"LocationKey: \" ..LocationKey)\n self:setVariable(\"locationKey\", locationKey)\n self:trace(\"Added QuickApp variable locationKey: \" ..locationKey)\n end\nend\n\n\nfunction QuickApp:getQuickAppVariables() -- Get all variables \n apiKey = self:getVariable(\"apiKey\")\n locationKey = self:getVariable(\"locationKey\")\n interval = tonumber(self:getVariable(\"interval\")) \n httpTimeout = tonumber(self:getVariable(\"httpTimeout\")) \n debugLevel = tonumber(self:getVariable(\"debugLevel\"))\n local icon = tonumber(self:getVariable(\"icon\")) \n\n if apiKey == \"\" or apiKey == \"0\" or apiKey == nil then\n apiKey = \"0\" \n self:setVariable(\"apiKey\",apiKey)\n self:trace(\"Added QuickApp variable apiKey\")\n end\n if locationKey == \"\" or locationKey == \"0\" or locationKey == nil then\n locationKey = \"250542\" \n self:setVariable(\"locationKey\",locationKey)\n self:trace(\"Added QuickApp variable locationKey\")\n end\n if interval == \"\" or interval == nil then\n interval = \"2400\" -- Free account includes up to 50 calls a day, so default value is 2400 (every 40 minutes)\n self:setVariable(\"interval\",interval)\n self:trace(\"Added QuickApp variable interval: \" ..interval)\n interval = tonumber(interval)\n end \n if httpTimeout == \"\" or httpTimeout == nil then\n httpTimeout = \"5\" -- timeoout in seconds\n self:setVariable(\"httpTimeout\",httpTimeout)\n self:trace(\"Added QuickApp variable httpTimeout\")\n httpTimeout = tonumber(httpTimeout)\n end\n if debugLevel == \"\" or debugLevel == nil then\n debugLevel = \"1\" -- Default value for debugLevel response in seconds\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\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 \n address = \"http://dataservice.accuweather.com/indices/v1/daily/5day/\" ..locationKey ..\"/groups/30?apikey=\" ..apiKey ..\"&details=false\"\n\n if apiKey == nil or apiKey == \"\" or apiKey == \"0\" then -- Check mandatory API key \n self:error(\"API key is empty! Get your free API key from AccuWeather\")\n self:warning(\"No API Key: Switched to Simulation Mode\")\n debugLevel = 4 -- Simulation mode due to empty API key\n end\n\nend\n\n\nfunction QuickApp:setupChildDevices()\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 = { \n {className=\"Grass\", name=\"Grass\", type=\"com.fibaro.multilevelSensor\", value=0},\n {className=\"Mold\", name=\"Mold\", type=\"com.fibaro.multilevelSensor\", value=0},\n {className=\"Ragweed\", name=\"Ragweed\", type=\"com.fibaro.multilevelSensor\", value=0},\n {className=\"Tree\", name=\"Tree\", type=\"com.fibaro.multilevelSensor\", value=0},\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 \n self:setupChildDevices() -- Setup the Child Devices\n self:getQuickAppVariables() -- Get Quickapp Variables or create them\n self:createVariables() -- Create Variables\n \n http = net.HTTPClient({timeout=httpTimeout*1000})\n\n if tonumber(debugLevel) >= 4 then \n self:simData() -- Go in simulation\n else\n --self:checkLocationKey() -- Check the locationKey \n self:getData() -- Get data from API\n end\nend\n\n--EOF "}]}