From d6141e7ad1454e036bd2a96426638ec675bcb4e8 Mon Sep 17 00:00:00 2001 From: Irek Kubicki Date: Fri, 24 Nov 2023 21:01:04 +0100 Subject: [PATCH] v.1.3.0 More information in QA UI --- Salus_It600.fqa | 32 ++++++++++++++++++++++++++++---- i18n.lua | 4 ++++ main.lua | 12 +++++++++++- 3 files changed, 43 insertions(+), 5 deletions(-) diff --git a/Salus_It600.fqa b/Salus_It600.fqa index c005ca0..72bd6f8 100644 --- a/Salus_It600.fqa +++ b/Salus_It600.fqa @@ -10,7 +10,7 @@ "style": { "height": "0" }, - "title": "Salus_It600" + "title": "salus130" }, "sections": { "items": [ @@ -76,12 +76,35 @@ "weight": "1.2" }, "type": "vertical" + }, + { + "components": [ + { + "name": "label2", + "style": { + "weight": "1.2" + }, + "text": "", + "type": "label", + "visible": true + }, + { + "style": { + "weight": "0.5" + }, + "type": "space" + } + ], + "style": { + "weight": "1.2" + }, + "type": "vertical" } ] } }, "head": { - "title": "Salus_It600" + "title": "salus130" } } }, @@ -121,12 +144,13 @@ ], "typeTemplateInitialized": true }, + "initialInterfaces": [], "files": [ { "name": "main", "isMain": true, "isOpen": false, - "content": "--[[\nSalus IT600 thermostats integration\n@author ikubicki\n@version 1.1.1\n]]\n\nfunction QuickApp:onInit()\n self.config = Config:new(self)\n self.failover = false\n self.salus = Salus:new(self.config)\n self.i18n = i18n:new(api.get(\"/settings/info\").defaultLanguage)\n self:trace('')\n self:trace(string.format(self.i18n:get('name'), self.name))\n self:updateProperty('manufacturer', 'Salus')\n self:updateProperty('model', 'IT600')\n self.childrenIds = {}\n self.interfaces = api.get(\"/devices/\" .. self.id).interfaces\n\n self:updateProperty(\"supportedThermostatModes\", {\"Off\", \"Heat\", \"Auto\"})\n self:updateProperty(\"heatingThermostatSetpointCapabilitiesMax\", 35)\n self:updateProperty(\"heatingThermostatSetpointCapabilitiesMin\", 10)\n\n self:updateView(\"label1\", \"text\", string.format(self.i18n:get('name'), self.name))\n self:updateView(\"button2_1\", \"text\", self.i18n:get('search-devices'))\n self:updateView(\"button2_2\", \"text\", self.i18n:get('refresh'))\n\n self:initChildDevices({\n [\"com.fibaro.temperatureSensor\"] = SalusChildDevice,\n [\"com.fibaro.humiditySensor\"] = SalusChildDevice,\n [\"com.fibaro.binarySwitch\"] = SalusChildDevice,\n })\n for id, device in pairs(self.childDevices) do\n self.childrenIds[device.type] = id\n end\n\n if string.len(self.config:getDeviceID()) > 10 then\n if self.childrenIds[\"com.fibaro.temperatureSensor\"] == nil then\n local child = self:createChildDevice({\n name = self.name .. ' Temperature',\n type = \"com.fibaro.temperatureSensor\",\n }, SalusChildDevice)\n end\n if self.childrenIds[\"com.fibaro.humiditySensor\"] == nil then\n local child = self:createChildDevice({\n name = self.name .. ' Humidity',\n type = \"com.fibaro.humiditySensor\",\n }, SalusChildDevice)\n end\n if self.childrenIds[\"com.fibaro.binarySwitch\"] == nil then\n local child = self:createChildDevice({\n name = self.name .. ' Heating',\n type = \"com.fibaro.binarySwitch\",\n deviceRole = 'Valve',\n isLight = false,\n }, SalusChildDevice)\n end\n self:run()\n else \n self:updateView(\"label1\", \"text\", self.i18n:get('not-configured'))\n end\nend\n\nfunction QuickApp:setThermostatMode(mode)\n self:updateProperty(\"thermostatMode\", mode)\n local holdtype = 0\n if mode == 'Off' then\n holdtype = 7\n elseif mode == 'Heat' then\n holdtype = 2\n end\n local setHoldtypeCallback = function(response)\n self:pullDataFromCloud()\n end\n self.salus:setHoldtype(holdtype, setHoldtypeCallback)\nend\n\nfunction QuickApp:setHeatingThermostatSetpoint(value) \n self:updateProperty(\"heatingThermostatSetpoint\", value)\n local setHeatingSetpointCallback = function(response)\n self:pullDataFromCloud()\n end\n self.salus:setHeatingSetpoint(value, setHeatingSetpointCallback)\nend\n\nfunction QuickApp:refreshEvent(event)\n self:updateView(\"label\", \"text\", self.i18n:get('refreshing'))\n self:pullDataFromCloud()\nend\n\nfunction QuickApp:run()\n self:pullDataFromCloud()\n local interval = self.config:getInterval()\n if self.failover then\n interval = 300000\n end\n if (interval > 0) then\n fibaro.setTimeout(interval, function() self:run() end)\n end\nend\n\nfunction QuickApp:pullDataFromCloud()\n local getFailCallback = function(error)\n self:updateView(\"button2_2\", \"text\", self.i18n:get('refresh'))\n self:updateView(\"label1\", \"text\", \"API Error: \" .. error)\n self.failover = true\n end\n local getPropertiesCallback = function(properties)\n self.failover = false\n -- QuickApp:debug(json.encode(properties))\n self:updateView(\"button2_2\", \"text\", self.i18n:get('refresh'))\n if self.childrenIds[\"com.fibaro.temperatureSensor\"] ~= nil then\n self.childDevices[self.childrenIds[\"com.fibaro.temperatureSensor\"]]:setValue(properties.temperature)\n end\n if self.childrenIds[\"com.fibaro.humiditySensor\"] ~= nil then\n self.childDevices[self.childrenIds[\"com.fibaro.humiditySensor\"]]:setValue(properties.humidity)\n end\n if self.childrenIds[\"com.fibaro.binarySwitch\"] ~= nil then\n local isRunningValue = 0\n if properties.running and properties.running > 0 then\n isRunningValue = 1\n end\n self.childDevices[self.childrenIds[\"com.fibaro.binarySwitch\"]]:setValue(isRunningValue > 0)\n end\n local mode = 'Auto' -- 0 or 1\n if properties.holdtype == 2 then\n mode = 'Heat'\n elseif properties.holdtype == 7 then\n mode = 'Off'\n end\n self:updateProperty(\"thermostatMode\", mode)\n self:updateProperty(\"heatingThermostatSetpoint\", properties.heatingSetpoint)\n self:updateView(\"label1\", \"text\", string.format(self.i18n:get('last-update'), os.date('%Y-%m-%d %H:%M:%S')))\n \n if properties.battery ~= nil then\n self:updateProperty(\"batteryLevel\", Salus:translateBatteryLevel(properties.battery))\n if not utils:contains(self.interfaces, \"battery\") then\n api.put(\"/devices/\" .. self.id, { interfaces = {\n \"quickApp\", \"battery\", \"heatingThermostatSetpoint\", \"thermostatMode\"\n }})\n end\n else\n\n if not utils:contains(self.interfaces, \"power\") then\n api.put(\"/devices/\" .. self.id, { interfaces = {\n \"quickApp\", \"power\", \"heatingThermostatSetpoint\", \"thermostatMode\"\n }})\n end\n end\n end\n self:updateView(\"button2_2\", \"text\", self.i18n:get('refreshing'))\n self.salus:getProperties(getPropertiesCallback, getFailCallback)\nend\n\nfunction QuickApp:searchEvent(param)\n self:debug(self.i18n:get('searching-devices'))\n self:updateView(\"button2_1\", \"text\", self.i18n:get('searching-devices'))\n local searchDevicesCallback = function(gateways)\n -- QuickApp:debug(json.encode(gateways))\n self:updateView(\"button2_1\", \"text\", self.i18n:get('search-devices'))\n -- printing results\n for _, gateway in pairs(gateways) do\n QuickApp:trace(string.format(self.i18n:get('search-row-gateway'), gateway.name, gateway.id))\n QuickApp:trace(string.format(self.i18n:get('search-row-gateway-devices'), #gateway.devices))\n for __, device in ipairs(gateway.devices) do\n QuickApp:trace(string.format(self.i18n:get('search-row-device'), device.name, device.id, device.model))\n end\n end\n self:updateView(\"label2\", \"text\", string.format(self.i18n:get('check-logs'), 'QUICKAPP' .. self.id))\n end\n self.salus:searchDevices(searchDevicesCallback)\nend\n" + "content": "--[[\nSalus IT600 thermostats integration\n@author ikubicki\n@version 1.3.0\n]]\n\nfunction QuickApp:onInit()\n self.config = Config:new(self)\n self.failover = false\n self.salus = Salus:new(self.config)\n self.i18n = i18n:new(api.get(\"/settings/info\").defaultLanguage)\n self:trace('')\n self:trace(string.format(self.i18n:get('name'), self.name))\n self:updateProperty('manufacturer', 'Salus')\n self:updateProperty('model', 'IT600')\n self.childrenIds = {}\n self.interfaces = api.get(\"/devices/\" .. self.id).interfaces\n\n self:updateProperty(\"supportedThermostatModes\", {\"Off\", \"Heat\", \"Auto\"})\n self:updateProperty(\"heatingThermostatSetpointCapabilitiesMax\", 35)\n self:updateProperty(\"heatingThermostatSetpointCapabilitiesMin\", 10)\n\n self:updateView(\"label1\", \"text\", string.format(self.i18n:get('name'), self.name))\n self:updateView(\"button2_1\", \"text\", self.i18n:get('search-devices'))\n self:updateView(\"button2_2\", \"text\", self.i18n:get('refresh'))\n\n self:initChildDevices({\n [\"com.fibaro.temperatureSensor\"] = SalusChildDevice,\n [\"com.fibaro.humiditySensor\"] = SalusChildDevice,\n [\"com.fibaro.binarySwitch\"] = SalusChildDevice,\n })\n for id, device in pairs(self.childDevices) do\n self.childrenIds[device.type] = id\n end\n\n if string.len(self.config:getDeviceID()) > 10 then\n if self.childrenIds[\"com.fibaro.temperatureSensor\"] == nil then\n local child = self:createChildDevice({\n name = self.name .. ' Temperature',\n type = \"com.fibaro.temperatureSensor\",\n }, SalusChildDevice)\n end\n if self.childrenIds[\"com.fibaro.humiditySensor\"] == nil then\n local child = self:createChildDevice({\n name = self.name .. ' Humidity',\n type = \"com.fibaro.humiditySensor\",\n }, SalusChildDevice)\n end\n if self.childrenIds[\"com.fibaro.binarySwitch\"] == nil then\n local child = self:createChildDevice({\n name = self.name .. ' Heating',\n type = \"com.fibaro.binarySwitch\",\n deviceRole = 'Valve',\n isLight = false,\n }, SalusChildDevice)\n end\n self:run()\n else \n self:updateView(\"label1\", \"text\", self.i18n:get('not-configured'))\n end\nend\n\nfunction QuickApp:setThermostatMode(mode)\n self:updateProperty(\"thermostatMode\", mode)\n local holdtype = 0\n if mode == 'Off' then\n holdtype = 7\n elseif mode == 'Heat' then\n holdtype = 2\n end\n local setHoldtypeCallback = function(response)\n self:pullDataFromCloud()\n end\n self.salus:setHoldtype(holdtype, setHoldtypeCallback)\nend\n\nfunction QuickApp:setHeatingThermostatSetpoint(value) \n self:updateProperty(\"heatingThermostatSetpoint\", value)\n local setHeatingSetpointCallback = function(response)\n self:pullDataFromCloud()\n end\n self.salus:setHeatingSetpoint(value, setHeatingSetpointCallback)\nend\n\nfunction QuickApp:refreshEvent(event)\n self:updateView(\"label\", \"text\", self.i18n:get('refreshing'))\n self:pullDataFromCloud()\nend\n\nfunction QuickApp:run()\n self:pullDataFromCloud()\n local interval = self.config:getInterval()\n if self.failover then\n interval = 300000\n end\n if (interval > 0) then\n fibaro.setTimeout(interval, function() self:run() end)\n end\nend\n\nfunction QuickApp:pullDataFromCloud()\n local getFailCallback = function(error)\n self:updateView(\"button2_2\", \"text\", self.i18n:get('refresh'))\n self:updateView(\"label1\", \"text\", \"API Error: \" .. error)\n self:updateView(\"label2\", \"text\", \"\")\n self.failover = true\n end\n local getPropertiesCallback = function(properties)\n local label2Text = \"\"\n self.failover = false\n -- QuickApp:debug(json.encode(properties))\n self:updateView(\"button2_2\", \"text\", self.i18n:get('refresh'))\n if self.childrenIds[\"com.fibaro.temperatureSensor\"] ~= nil then\n self.childDevices[self.childrenIds[\"com.fibaro.temperatureSensor\"]]:setValue(properties.temperature)\n label2Text = properties.temperature .. \"C / \" .. properties.heatingSetpoint .. \"C\" \n end\n if self.childrenIds[\"com.fibaro.humiditySensor\"] ~= nil then\n self.childDevices[self.childrenIds[\"com.fibaro.humiditySensor\"]]:setValue(properties.humidity)\n label2Text = label2Text .. \" / \" .. properties.humidity .. \"%\"\n end\n if self.childrenIds[\"com.fibaro.binarySwitch\"] ~= nil then\n local isRunningValue = 0\n if properties.running and properties.running > 0 then\n isRunningValue = 1\n end\n self.childDevices[self.childrenIds[\"com.fibaro.binarySwitch\"]]:setValue(isRunningValue > 0)\n if isRunningValue > 0 then\n label2Text = self.i18n:get('heating') .. \" / \" .. label2Text\n else\n label2Text = self.i18n:get('off') .. \" / \" .. label2Text\n end\n end\n local mode = 'Auto' -- 0 or 1\n if properties.holdtype == 2 then\n mode = 'Heat'\n elseif properties.holdtype == 7 then\n mode = 'Off'\n end\n self:updateProperty(\"thermostatMode\", mode)\n self:updateProperty(\"heatingThermostatSetpoint\", properties.heatingSetpoint)\n self:updateView(\"label1\", \"text\", string.format(self.i18n:get('last-update'), os.date('%Y-%m-%d %H:%M:%S')))\n self:updateView(\"label2\", \"text\", label2Text)\n \n if properties.battery ~= nil then\n self:updateProperty(\"batteryLevel\", Salus:translateBatteryLevel(properties.battery))\n if not utils:contains(self.interfaces, \"battery\") then\n api.put(\"/devices/\" .. self.id, { interfaces = {\n \"quickApp\", \"battery\", \"heatingThermostatSetpoint\", \"thermostatMode\"\n }})\n end\n else\n\n if not utils:contains(self.interfaces, \"power\") then\n api.put(\"/devices/\" .. self.id, { interfaces = {\n \"quickApp\", \"power\", \"heatingThermostatSetpoint\", \"thermostatMode\"\n }})\n end\n end\n end\n self:updateView(\"button2_2\", \"text\", self.i18n:get('refreshing'))\n self.salus:getProperties(getPropertiesCallback, getFailCallback)\nend\n\nfunction QuickApp:searchEvent(param)\n self:debug(self.i18n:get('searching-devices'))\n self:updateView(\"button2_1\", \"text\", self.i18n:get('searching-devices'))\n local searchDevicesCallback = function(gateways)\n -- QuickApp:debug(json.encode(gateways))\n self:updateView(\"button2_1\", \"text\", self.i18n:get('search-devices'))\n -- printing results\n for _, gateway in pairs(gateways) do\n QuickApp:trace(string.format(self.i18n:get('search-row-gateway'), gateway.name, gateway.id))\n QuickApp:trace(string.format(self.i18n:get('search-row-gateway-devices'), #gateway.devices))\n for __, device in ipairs(gateway.devices) do\n QuickApp:trace(string.format(self.i18n:get('search-row-device'), device.name, device.id, device.model))\n end\n end\n self:updateView(\"label2\", \"text\", string.format(self.i18n:get('check-logs'), 'QUICKAPP' .. self.id))\n end\n self.salus:searchDevices(searchDevicesCallback)\nend\n" }, { "name": "Config", @@ -150,7 +174,7 @@ "name": "i18n", "isMain": false, "isOpen": false, - "content": "--[[\nInternationalization tool\n@author ikubicki\n]]\nclass 'i18n'\n\nfunction i18n:new(langCode)\n if phrases[langCode] == nil then\n langCode = 'en'\n end\n self.phrases = phrases[langCode]\n return self\nend\n\nfunction i18n:get(key)\n if self.phrases[key] then\n return self.phrases[key]\n end\n return key\nend\n\nphrases = {\n pl = {\n ['name'] = 'Salus IT600 - %s',\n ['search-devices'] = 'Szukaj urządzeń',\n ['searching-devices'] = 'Szukam...',\n ['refresh'] = 'Odśwież dane',\n ['refreshing'] = 'Odświeżam...',\n ['device-updated'] = 'Zaktualizowano dane urządzenia',\n ['last-update'] = 'Ostatnia aktualizacja: %s',\n ['not-configured'] = 'Urządzenie nie skonfigurowane',\n ['check-logs'] = 'Zakończono wyszukiwanie. Sprawdź logi tego urządzenia: %s',\n ['search-row-gateway'] = '__ BRAMKA %s (# %s)',\n ['search-row-gateway-devices'] = '__ Wykryto %d urządzeń',\n ['search-row-device'] = '____ URZĄDZENIE %s (DeviceID: %s, Model: %s)',\n },\n en = {\n ['name'] = 'Salus IT600 - %s',\n ['search-devices'] = 'Search devices',\n ['searching-devices'] = 'Searching...',\n ['refresh'] = 'Update data',\n ['refreshing'] = 'Updating...',\n ['device-updated'] = 'Device updates',\n ['last-update'] = 'Last update: %s',\n ['not-configured'] = 'Device not configured',\n ['check-logs'] = 'Check device logs (%s) for search results',\n ['search-row-gateway'] = '__ GATEWAY %s (# %s)',\n ['search-row-gateway-devices'] = '__ %d devices found',\n ['search-row-device'] = '____ DEVICE %s (DeviceID: %s, Model: %s)',\n },\n}" + "content": "--[[\nInternationalization tool\n@author ikubicki\n]]\nclass 'i18n'\n\nfunction i18n:new(langCode)\n if phrases[langCode] == nil then\n langCode = 'en'\n end\n self.phrases = phrases[langCode]\n return self\nend\n\nfunction i18n:get(key)\n if self.phrases[key] then\n return self.phrases[key]\n end\n return key\nend\n\nphrases = {\n pl = {\n ['name'] = 'Salus IT600 - %s',\n ['search-devices'] = 'Szukaj urządzeń',\n ['searching-devices'] = 'Szukam...',\n ['refresh'] = 'Odśwież dane',\n ['refreshing'] = 'Odświeżam...',\n ['device-updated'] = 'Zaktualizowano dane urządzenia',\n ['last-update'] = 'Ostatnia aktualizacja: %s',\n ['not-configured'] = 'Urządzenie nie skonfigurowane',\n ['check-logs'] = 'Zakończono wyszukiwanie. Sprawdź logi tego urządzenia: %s',\n ['search-row-gateway'] = '__ BRAMKA %s (# %s)',\n ['search-row-gateway-devices'] = '__ Wykryto %d urządzeń',\n ['search-row-device'] = '____ URZĄDZENIE %s (DeviceID: %s, Model: %s)',\n ['heating'] = 'Grzanie',\n ['off'] = 'Wyłączony',\n },\n en = {\n ['name'] = 'Salus IT600 - %s',\n ['search-devices'] = 'Search devices',\n ['searching-devices'] = 'Searching...',\n ['refresh'] = 'Update data',\n ['refreshing'] = 'Updating...',\n ['device-updated'] = 'Device updates',\n ['last-update'] = 'Last update: %s',\n ['not-configured'] = 'Device not configured',\n ['check-logs'] = 'Check device logs (%s) for search results',\n ['search-row-gateway'] = '__ GATEWAY %s (# %s)',\n ['search-row-gateway-devices'] = '__ %d devices found',\n ['search-row-device'] = '____ DEVICE %s (DeviceID: %s, Model: %s)',\n ['heating'] = 'Heating',\n ['off'] = 'Off',\n },\n}" }, { "name": "Salus", diff --git a/i18n.lua b/i18n.lua index f98f7c4..c127013 100644 --- a/i18n.lua +++ b/i18n.lua @@ -33,6 +33,8 @@ phrases = { ['search-row-gateway'] = '__ BRAMKA %s (# %s)', ['search-row-gateway-devices'] = '__ Wykryto %d urządzeń', ['search-row-device'] = '____ URZĄDZENIE %s (DeviceID: %s, Model: %s)', + ['heating'] = 'Grzanie', + ['off'] = 'Wyłączony', }, en = { ['name'] = 'Salus IT600 - %s', @@ -47,5 +49,7 @@ phrases = { ['search-row-gateway'] = '__ GATEWAY %s (# %s)', ['search-row-gateway-devices'] = '__ %d devices found', ['search-row-device'] = '____ DEVICE %s (DeviceID: %s, Model: %s)', + ['heating'] = 'Heating', + ['off'] = 'Off', }, } \ No newline at end of file diff --git a/main.lua b/main.lua index a7c0aaa..576132a 100644 --- a/main.lua +++ b/main.lua @@ -1,7 +1,7 @@ --[[ Salus IT600 thermostats integration @author ikubicki -@version 1.1.1 +@versio 1.3.0 ]] function QuickApp:onInit() @@ -102,17 +102,21 @@ function QuickApp:pullDataFromCloud() local getFailCallback = function(error) self:updateView("button2_2", "text", self.i18n:get('refresh')) self:updateView("label1", "text", "API Error: " .. error) + self:updateView("label2", "text", "") self.failover = true end local getPropertiesCallback = function(properties) + local label2Text = "" self.failover = false -- QuickApp:debug(json.encode(properties)) self:updateView("button2_2", "text", self.i18n:get('refresh')) if self.childrenIds["com.fibaro.temperatureSensor"] ~= nil then self.childDevices[self.childrenIds["com.fibaro.temperatureSensor"]]:setValue(properties.temperature) + label2Text = properties.temperature .. "C / " .. properties.heatingSetpoint .. "C" end if self.childrenIds["com.fibaro.humiditySensor"] ~= nil then self.childDevices[self.childrenIds["com.fibaro.humiditySensor"]]:setValue(properties.humidity) + label2Text = label2Text .. " / " .. properties.humidity .. "%" end if self.childrenIds["com.fibaro.binarySwitch"] ~= nil then local isRunningValue = 0 @@ -120,6 +124,11 @@ function QuickApp:pullDataFromCloud() isRunningValue = 1 end self.childDevices[self.childrenIds["com.fibaro.binarySwitch"]]:setValue(isRunningValue > 0) + if isRunningValue > 0 then + label2Text = self.i18n:get('heating') .. " / " .. label2Text + else + label2Text = self.i18n:get('off') .. " / " .. label2Text + end end local mode = 'Auto' -- 0 or 1 if properties.holdtype == 2 then @@ -130,6 +139,7 @@ function QuickApp:pullDataFromCloud() self:updateProperty("thermostatMode", mode) self:updateProperty("heatingThermostatSetpoint", properties.heatingSetpoint) self:updateView("label1", "text", string.format(self.i18n:get('last-update'), os.date('%Y-%m-%d %H:%M:%S'))) + self:updateView("label2", "text", label2Text) if properties.battery ~= nil then self:updateProperty("batteryLevel", Salus:translateBatteryLevel(properties.battery))