Re: ELV Max! Heating control system
Posted: Tuesday 08 November 2016 20:32
Ive updated the wiki to the best of my knowledge.. Maybe you guys can make a quick go through to check if its ok!
Open source Home Automation System
https://forum.domoticz.com/
Code: Select all
Device status
-------------
Valve Loznice-Rad Setpoint=22.5 Temp=0 Valve pos=10 Battery=OK Mode=Auto
Valve Koupelna-Rad Setpoint=22 Temp=25.1 Valve pos=0 Battery=OK Mode=Auto
Valve Kuchyn-Rad Setpoint=24 Temp=0 Valve pos=46 Battery=OK Mode=Auto
Valve Obyvak-Rad Setpoint=24 Temp=25.4 Valve pos=61 Battery=OK Mode=Auto
Valve Predsin-Rad Setpoint=20 Temp=0 Valve pos=0 Battery=OK Mode=Auto
Hi Sean,blackdog65 wrote:Hi kevin,
What's in script_time_EQ3_Cube.lua?
Did you try the test script to do a basic read?
Sean
Please put all devices in manual mode with the max app.hasan wrote:Hi, it looks betters now. In my flat I have only 5 Radiator Thermostat without wall thermostat.Code: Select all
Device status ------------- Valve Loznice-Rad Setpoint=22.5 Temp=0 Valve pos=10 Battery=OK Mode=Auto Valve Koupelna-Rad Setpoint=22 Temp=25.1 Valve pos=0 Battery=OK Mode=Auto Valve Kuchyn-Rad Setpoint=24 Temp=0 Valve pos=46 Battery=OK Mode=Auto Valve Obyvak-Rad Setpoint=24 Temp=25.4 Valve pos=61 Battery=OK Mode=Auto Valve Predsin-Rad Setpoint=20 Temp=0 Valve pos=0 Battery=OK Mode=Auto
I`m able to read only Percentage. What is needed to be able to read Setpoint and Temperature? Or is it possible?
Thanks! I changed parts of the text explaining the naming scheme, as it was not 100% corrrect, and added a bit more explanation on how to configure things if you don't have wall mounted thermostats.Skippiemanz wrote:Ive updated the wiki to the best of my knowledge.. Maybe you guys can make a quick go through to check if its ok!
Many thanks for your help, i have the round TRV's, all temps are now working with the add on line you recommended (subject to standard reading issues if valve hasnt moved). also, i needed to reboot the MAX! (i think all the testing confused it) i only have 1 thermostat currently in my setup (will add the other's after xmas).mvzut wrote:
Temperature will indeed not be updated if you don't have wall thermostats. Earlier versions of the script updated the Domoticz temperature device(s) with the actual temperature(s) received from the valves, but I removed that since the valves only send the current temperature when the motor is running. That didn't give very usable day graphs for the room temperature. We still need to explain this in the Wiki, actually you don't even have to create temperature devices in Domoticz if you don't have wall thermostats.
Apart from that, it seems you have everything set up correctly. The log says the Domoticz setpoints are updated, and it seems to send the commands. At least I assume so, because it says "Fetching url...", which is the expected message since I use API calls to do this. That is because of a bug Domoticz where updating setpoints via lua "UpdateDevice" commands results in script timeouts). Only the commands apparently never reach the setpoint devices. Are you using the right port number for the API calls to Domoticz?
You could try and replace (twice)withCode: Select all
table.insert(commandArray, { ['OpenURL'] = 'http://127.0.0.1:'..DomoticzPort..'/json.htm?type=command¶m=udevice&idx='..otherdevices_idx[name]..'&nvalue=0&svalue='..setpoint})
which could give the notorious timeout messages but should work regardlessly.Code: Select all
table.insert(commandArray, { ['UpdateDevice'] = otherdevices_idx[name]..'|0|'..setpoint})
P.S. I now see all your valves seem to report an actual temperature... This would contradict my story above. Can you maybe check, e.g. by running the lua test script a couple of times, if those temperatures are actually updated regularly? Maybe you have other valves than myself (I use the basic model)?!
If your valve temperatures are updated regularly, or if you don't have a problem with virtual Domoticz temperature sensors that are only updated every now and then, you can get temperature reading back into the script again by adding this line:directly below the "if not useWMT then" line. This will update the virtual temperature sensor(s) named after the room name(s), using the current temperature as reported by each valve.Code: Select all
table.insert(commandArray, { ['UpdateDevice'] = otherdevices_idx[room]..'|0|'..temp})
Code: Select all
luarocks list
Code: Select all
Installed rocks:
----------------
basexx
0.3.0-1 (installed) - /usr/local/lib/luarocks/rocks
luasec
0.6-1 (installed) - /usr/local/lib/luarocks/rocks
luasocket
3.0rc1-2 (installed) - /usr/local/lib/luarocks/rocks
Code: Select all
lua
Code: Select all
Lua 5.2.3 Copyright (C) 1994-2013 Lua.org, PUC-Rio
>
Code: Select all
sudo apt-get install libssl-dev
FYI:Skippiemanz wrote:The Window sensors are not(yet) seen in domoticz so no devices are Needed
Hi, I did some adjustment of Wiki, so you should try it. You will need these two files:toffel969 wrote:Hello everyone
Im expieriencing exactly the same problem, module bassex not found.returnsCode: Select all
luarocks list
Code: Select all
Installed rocks: ---------------- basexx 0.3.0-1 (installed) - /usr/local/lib/luarocks/rocks luasec 0.6-1 (installed) - /usr/local/lib/luarocks/rocks luasocket 3.0rc1-2 (installed) - /usr/local/lib/luarocks/rocks
gives meCode: Select all
lua
Maybe just an addition, I had to installCode: Select all
Lua 5.2.3 Copyright (C) 1994-2013 Lua.org, PUC-Rio >
in order to install luasec, as this is the only thing that resolved the "openssl" not found issue during the build process.Code: Select all
sudo apt-get install libssl-dev
I followed the wiki step by step last night, but am stuck at this point right now. Does anyone see where I'm going wrong ?
Code: Select all
function MaxCmdSend(id, room, mode, setpoint)
bits = setpoint * 2
smode = string.upper(mode)
if smode == 'MANUAL' then
bits = 64 + bits
elseif smode == 'BOOST' then
bits = 192 + bits
elseif smode == 'VACATION' then
bits = 128 + bits
end
hex = "000440000000"..id..room..string.format("%x",bits)
sendStr = Basexx.to_base64(Basexx.from_hex(hex))
i, status = tcp:send("s:"..sendStr.."\r\n")
if not i then
print("MAX TCP send failed - "..status)
return
end
end
That is indeed where I got my inspiration from. I know the JSON commands to do this for temperature and percentage sensors, and I think I can also get it if to work for thermostats. I'll let you know when I have some success.Skippiemanz wrote:Great news! I know the first maxbuddy script made the devices automatic. Maybe you can get some inspiration from that?
Code: Select all
package.loadlib("core.so", "*")
Socket = require "socket"
Basexx = require "basexx"
json = (loadfile "/home/pi/domoticz/scripts/lua/JSON.lua")() -- for Linux
--json = (loadfile "D:\\Domoticz\\scripts\\lua\\json.lua")() -- for Windows
http = require "socket.http"
MaxIP='192.168.178.46'
MaxPort = 62910
DomoticzPort = 8080
useWMT = true --Set to true if there is a wall mounted thermostat in every room
interval = 5 --Polling interval in minutes, possible range 1-59. Cube doesn't seem to like too frequent communication, 5 minutes is a safe value
Rooms = {}
Devices = {}
Room_nums = {}
function get_MAX_ID()
result, statuscode, content = http.request('http://127.0.0.1:'..DomoticzPort..'/json.htm?type=hardware')
r,e = json:decode(result)
if r.status == "OK" then
for k,v in pairs(r.result) do
if v.Name == "MAX!" then return v.idx end
end
end
end
function Thermostat(DID)
result, statuscode, content = http.request('http://127.0.0.1:'..DomoticzPort..'/json.htm?type=devices')
r,e = json:decode(result)
if r.status == "OK" then
for k,v in pairs(r.result) do
if v.ID == DID then return v.SetPoint,v.LastUpdate end
end
end
return 0, '2016-01-01 00:00:00' -- value to return if device was not found
end
function age(timestring)
t = {}
t.year = string.sub(timestring,1,4)
t.month = string.sub(timestring,6,7)
t.day = string.sub(timestring,9,10)
t.hour = string.sub(timestring,12,13)
t.min = string.sub(timestring,15,16)
t.sec = string.sub(timestring,18,19)
return os.difftime(os.time(),os.time(t))
end
function maxCmd_H(data)
-- print('H='..data)
end
function maxCmd_M(data)
i = 0
j = 0
while true do -- find next comma
i = string.find(data, ",", i+1)
if not i then break end
j = i
end
s = data:sub(j+1)
dec = Basexx.from_base64(s)
num_rooms = string.byte(dec,3)
if num_rooms == 0 or num_rooms == nil then table.insert(commandArray, {['SendNotification'] = 'MAX! problem#Configuration lost?#1'}) end
pos=4
for i=1, num_rooms do
room_num = string.byte(dec, pos)
name_len = string.byte(dec, pos+1)
pos = pos+2
name = dec:sub(pos, pos+name_len-1)
pos = pos+name_len
adr = Basexx.to_hex(dec:sub(pos, pos+2))
Rooms[room_num] = name
pos = pos+3
end
num_devs = string.byte(dec, pos)
for i=1, num_devs do
dtype = string.byte(dec, pos+1)
adr = Basexx.to_hex(dec:sub(pos+2, pos+4))
snum = dec:sub(pos+5, pos+14)
name_len = string.byte(dec, pos+15)
pos = pos+16
name = dec:sub(pos, pos+name_len-1)
pos = pos+name_len
room_num = string.byte(dec, pos)
Room_nums[adr] = room_num
Devices[adr] = name
end
end
function maxCmd_C(data)
-- print('C='..data)
end
function maxCmd_L(data)
pos = 1
dec = Basexx.from_base64(data)
L_hex = Basexx.to_hex(dec)
L_len = string.len(L_hex)
while (pos < L_len) do
s = L_hex:sub(pos,(pos+1))
data_len = tonumber(s,16) + 1
hex = L_hex:sub(pos,pos+(data_len*2))
adr = hex:sub(3,8)
room_num = string.format("%02X", Room_nums[adr])
room = Rooms[Room_nums[adr]]
name = Devices[adr]
if not name then name=adr end
valve_info = tonumber(hex:sub(13,14),16)
batt = bit32.extract(valve_info,7,1)
bst = bit32.extract(valve_info,3,1)
mode = bit32.extract(valve_info,0,2)
if (batt==0) then sbat="OK" else sbat="Low" end
if (mode==0) then smode="Auto" elseif (mode==1) then smode="Manual"
elseif (mode==2) then smode="Holiday" elseif (mode==3) then smode="Boost" end
if (data_len == 13) then -- WallMountedThermostat (dev_type 3)
valve_pos = -1
s = hex:sub(17,18)
setpoint = tonumber(s,16) / 2
s = hex:sub(23,26)
temp = tonumber(s,16) / 10
dtype = "Thermostat"
elseif (data_len == 12) then -- HeatingThermostat (dev_type 1 or 2)
s = hex:sub(15,16)
valve_pos = tonumber(s,16)
s = hex:sub(17,18)
setpoint = tonumber(s,16) / 2
if (mode ~= 2) then
s = hex:sub(19,22)
temp = tonumber(s,16) / 10
else
temp = 0
end
dtype = "Valve"
end
--Following two lines correct temperatures over 25.5 degrees, since e.g. 26 degrees is reported as 0.5 degrees
--This is due to the fact that temperatures seem to be stored as two Hex characters only (= max 255 in decimal)
--Pending better solution
if temp < 5 then temp = temp + 25.5 end
if setpoint > 50 then setpoint = setpoint - 64 end
-- Update virtual devices in Domoticz and update MAX! setpoints if necessary
--print(dtype.." "..name.." Setpoint="..setpoint.." Temp="..temp.." Valve pos="..valve_pos)
if dtype == "Valve" then
table.insert(commandArray, {['OpenURL'] = 'http://127.0.0.1:'..DomoticzPort..'/json.htm?type=command¶m=udevice&hid='..MAX_ID..'&did='..adr..'&dunit=1&dtype=243&dsubtype=6&nvalue=0&svalue='..valve_pos})
if not useWMT then --Use valve to check setpoint mismatch
if temp ~=25.5 then
table.insert(commandArray, {['OpenURL'] = 'http://127.0.0.1:'..DomoticzPort..'/json.htm?type=command¶m=udevice&hid='..MAX_ID..'&did='..adr..'&dunit=1&dtype=80&dsubtype=5&nvalue=0&svalue='..temp})
end
setpoint_Domoticz, LastUpdate = Thermostat('0'..adr)
if tonumber(setpoint_Domoticz) ~= setpoint then
if age(LastUpdate) > interval * 60 then --Domoticz thermostat value must be updated
table.insert(commandArray, {['OpenURL'] = 'http://127.0.0.1:'..DomoticzPort..'/json.htm?type=command¶m=udevice&hid='..MAX_ID..'&did=0'..adr..'&dunit=1&dtype=242&dsubtype=1&nvalue=0&svalue='..setpoint})
print('Domoticz setpoint ' .. name .. ' updated')
else --Max! setpoint must be updated
MaxCmdSend(adr, room_num, "manual", setpoint_Domoticz)
print('MAX! setpoint ' .. name .. ' updated')
end
end
end
elseif dtype == "Thermostat" and smode ~= 'Auto' then
table.insert(commandArray, {['OpenURL'] = 'http://127.0.0.1:'..DomoticzPort..'/json.htm?type=command¶m=udevice&hid='..MAX_ID..'&did='..adr..'&dunit=1&dtype=80&dsubtype=5&nvalue=0&svalue='..temp})
setpoint_Domoticz, LastUpdate = Thermostat('0'..adr)
if tonumber(setpoint_Domoticz) ~= setpoint then
if age(LastUpdate) > interval * 60 then --Domoticz thermostat value must be updated
table.insert(commandArray, {['OpenURL'] = 'http://127.0.0.1:'..DomoticzPort..'/json.htm?type=command¶m=udevice&hid='..MAX_ID..'&did=0'..adr..'&dunit=1&dtype=242&dsubtype=1&nvalue=0&svalue='..setpoint})
print('Domoticz setpoint ' .. name .. ' updated')
else --Max! setpoint must be updated
MaxCmdSend(adr, room_num, "manual", setpoint_Domoticz)
print('MAX! setpoint ' .. name .. ' updated')
end
end
end
pos = pos + (data_len*2)
end
end
function MaxCmdSend(id, room, mode, setpoint)
bits = setpoint * 2
smode = string.upper(mode)
if smode == 'MANUAL' then
bits = 64 + bits
elseif smode == 'BOOST' then
bits = 192 + bits
elseif smode == 'VACATION' then
bits = 128 + bits
end
hex = "000440000000"..id..room..string.format("%x",bits)
sendStr = Basexx.to_base64(Basexx.from_hex(hex))
i, status = tcp:send("s:"..sendStr.."\r\n")
if not i then
print("MAX TCP send failed - "..status)
return
end
end
commandArray = {}
m = tonumber(os.date('%M'))
if (m % interval == 0) and (m ~= 0) and (m ~= 30) then
--Get ID of MAX hardware in Domoticz, create if it doesn't exist
MAX_ID = get_MAX_ID()
if MAX_ID == nil then -- "MAX!" dummy hardware not yet created, create it
table.insert(commandArray, {['OpenURL'] = 'http://127.0.0.1:'..DomoticzPort..'/json.htm?type=command¶m=addhardware&htype=15&port=1&name=MAX!&enabled=true'})
return commandArray
end
tcp = Socket.connect(MaxIP, MaxPort)
if not tcp then
print("Socket connect failed for "..MaxIP..':'..MaxPort)
return
end
tcp:settimeout(2)
while true do
s, status, partial = tcp:receive()
if (status) then
print("TCP receive - "..status)
break
end
local line = (s or partial)
local cmd = line:sub(1,1)
local data = line:sub(3)
if (cmd == 'H') then
status = maxCmd_H(data)
if status == 'Error' then break end
elseif (cmd == 'M') then
maxCmd_M(data)
elseif (cmd == 'C') then
maxCmd_C(data)
elseif (cmd == 'L') then
maxCmd_L(data)
break
end
end
tcp:close()
end
return commandArray
Do you use the standard Domoticz port of 8080? At two locations in the script, I forgot to change the default port into the variable "DomoticzPort" which is defined at the start of the script. I uploaded the script in the previous post, maybe you can try that. Unless you are using the default 8080, then it shouldn't make a difference for you. If that's the case, I will need to dive into your issue later.Teatech wrote:I tryed that script and got
2016-11-10 07:55:01.524 Error: EventSystem: in /home/pi/domoticz/scripts/lua/script_time_max.lua: /home/pi/domoticz/scripts/lua/script_time_max.lua:158: attempt to concatenate global 'MAX_ID' (a nil value)
Before trying script I updated my old version of json.lua.
I have one room with wall thermostat and one room without so I changed useWMT=false.