Skip to content

Commit

Permalink
v.1.0.0
Browse files Browse the repository at this point in the history
  • Loading branch information
ikubicki committed Dec 18, 2022
1 parent 8b9409b commit aaec139
Show file tree
Hide file tree
Showing 9 changed files with 959 additions and 2 deletions.
69 changes: 69 additions & 0 deletions Config.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
--[[
Configuration handler
@author ikubicki
]]
class 'Config'

function Config:new(app)
self.app = app
self:init()
return self
end

function Config:getUsername()
if self.username and self.username:len() > 3 then
return self.username
end
return nil
end

function Config:getPassword()
return self.password
end

function Config:getDeviceID()
return self.device_id
end

function Config:setDeviceID(device_id)
self.device_id = device_id
end

function Config:getInterval()
return tonumber(self.interval) * 1000
end

--[[
This function takes variables and sets as global variables if those are not set already.
This way, adding other devices might be optional and leaves option for users,
what they want to add into HC3 virtual devices.
]]
function Config:init()
self.username = self.app:getVariable('Username')
self.password = self.app:getVariable('Password')
self.device_id = self.app:getVariable('DeviceID')
self.interval = self.app:getVariable('Interval')

local storedUsername = Globals:get('salus_username', '')
local storedPassword = Globals:get('salus_password', '')

-- handling username
if string.len(self.username) < 4 and string.len(storedUsername) > 3 then
self.app:setVariable("Username", storedUsername)
self.username = storedUsername
elseif (storedUsername == '' and self.username) then
Globals:set('salus_username', self.username)
end
-- handling password
if string.len(self.password) < 4 and string.len(storedPassword) > 3 then
self.app:setVariable("Password", storedPassword)
self.password = storedPassword
elseif (storedPassword == '' and self.password) then
Globals:set('salus_password', self.password)
end
-- handling interval
if not self.interval or self.interval == "" then
self.app:setVariable("Interval", 30)
self.interval = 30
end
end
36 changes: 36 additions & 0 deletions Globals.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
--[[
Global variables handler
@author ikubicki
]]
class 'Globals'

function Globals:get(name, alternative)
local response = api.get('/globalVariables/' .. name)
if response then
local char = string.sub(response.value, 1, 1)
if char == '{' or char == '"' then
return json.decode(response.value)
end
return response.value
end
return alternative
end

function Globals:set(name, value)
local response = api.put('/globalVariables/' .. name, {
name = name,
value = json.encode(value)
})
if not response then
response = api.post('/globalVariables', {
name = name,
value = json.encode(value)
})

end
if response ~= nil then
if response.type == 'ERROR' then
QuickApp:error('GLOBALS ERROR[' .. response.reason .. ']:', response.message)
end
end
end
97 changes: 97 additions & 0 deletions HTTPClient.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
--[[
HTTPClient wrapper
@author ikubicki
]]
class 'HTTPClient'

function HTTPClient:new(options)
if not options then
options = {}
end
self.options = options
return self
end

function HTTPClient:get(url, success, error, headers)
local client = net.HTTPClient({timeout = 10000})
if not headers then
headers = {}
end
client:request(self:url(url), self:requestOptions(success, error, 'GET', nil, headers))
end

function HTTPClient:post(url, data, success, error, headers)
local client = net.HTTPClient({timeout = 10000})
if not headers then
headers = {}
end
client:request(self:url(url), self:requestOptions(success, error, 'POST', data, headers))
end

function HTTPClient:postForm(url, data, success, error, headers)
local client = net.HTTPClient({timeout = 10000})
if not headers then
headers = {}
end
headers["Content-Type"] = 'application/x-www-form-urlencoded;charset=UTF-8'
client:request(self:url(url), self:requestOptions(success, error, 'POST', data, headers, true))
end

function HTTPClient:put(url, data, success, error, headers)
local client = net.HTTPClient({timeout = 10000})
client:request(self:url(url), self:requestOptions(success, error, 'PUT', data, headers))
end

function HTTPClient:delete(url, success, error, headers)
local client = net.HTTPClient({timeout = 10000})
if not headers then
headers = {}
end
client:request(self:url(url), self:requestOptions(success, error, 'DELETE', nil, headers))
end

function HTTPClient:url(url)
if (string.sub(url, 0, 4) == 'http') then
return url
end
if not self.options.baseUrl then
self.options.baseUrl = 'http://localhost'
end
return self.options.baseUrl .. tostring(url)
end

function HTTPClient:requestOptions(success, error, method, data, headers, isFormData)
if error == nil then
error = function (error)
QuickApp:error(json.encode(error))
end
end
if method == nil then
method = 'GET'
end
local options = {
checkCertificate = false,
method = method,
headers = headers,
}
if data ~= nil then
if isFormData then
options.data = ''
for key, value in pairs(data) do
if string.len(options.data) > 0 then
options.data = options.data .. '&'
end
options.data = options.data .. key .. '=' .. value
end
elseif type(data) == 'string' then
options.data = data
else
options.data = json.encode(data)
end
end
return {
options = options,
success = success,
error = error
}
end
31 changes: 29 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,2 +1,29 @@
# fibaro-salus-it600

# Salus IT600 thermostats integration

Virtual device that allow to control Salus IT600 thermostats. It creates three child devices that show current temperature, humidity and heating status in form of binary switch.

## Configuration

`Username` - Velux username

`Password` - Velux password

`DeviceID` - ID of the device

`Interval` - Update interval expressed in seconds (30s by default)


## Installation

Follow regular installation process. After virtual device will be added to your Home Center unit, click on Variables and provide `Username` and `Password`.
Then, click on `Search devices` button which will pull all information from your Salus account that includes Gateways and associated Devices.

If you're installing another device, your Username and Password will be automatically populated from previous device.

To access pulled information, go to logs of the device, review detected devices and use proper IDs as variables of the QuickApp.

To change update interval add Interval property or replace existing one (if there's no edit botton).

## Notes

Salus API is locking account for 30 minutes after few invalid login attempts. If you'll change your password, virtual devices may lock your account.
Loading

0 comments on commit aaec139

Please sign in to comment.