ELV Max! Heating control system

For heating/cooling related questions in Domoticz
mvzut
Posts: 319
Joined: Thursday 12 November 2015 11:55
Target OS: Raspberry Pi
Domoticz version: Beta
Location: Marum, The Netherlands
Contact:

ELV Max! Heating control system

Post by mvzut » Sunday 17 December 2017 21:14

The maxtest.lua script on the Wiki does not work with door/window sensors. Here's a newer version that does:

Code: Select all

 package.loadlib("core.so", "*")
local Socket = require "socket"
local Basexx = require "basexx"

local MaxIP='192.168.178.46'  -- change with the IP adress of your own Cube
local MaxPort = 62910

local Rooms   = {}
local Devices = {}
local Types   = {}

function maxCmd_H(data)
  --print('H='..data)
end

function maxCmd_M(data)
   --print('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)
   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)
      pos  = pos+name_len
      adr  = Basexx.to_hex(dec:sub(pos, pos+2))
      Rooms[adr] = name
      pos = pos+3
   end
   
   print("Rooms\n-----")
   for adr, name in pairs(Rooms) do 
      print(name, adr)
   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)
      pos  = pos+name_len
      room_num = string.byte(dec, pos)
      Devices[adr] = name
      Types[adr] = dtype
   end
   
   print("\nDevices\n-------")
      for adr, name in pairs(Devices) do 
      print(name .. '  ' .. adr)
   end

end

function maxCmd_C(data)
  C_hex = data
  C_len =  string.len(C_hex)
  --print(C_hex)
  pos = 1
  s = C_hex:sub(pos,(pos+1))
  data_len  = tonumber(s,16) + 1
  hex  = C_hex:sub(pos,pos+(data_len*2))
  adr  = hex:sub(3,8)
  name = Devices[adr]
  dtype = hex:sub(9,10)
end

function maxCmd_L(data)
print("\nDevice status\n-------------")
   pos = 1
   dec = Basexx.from_base64(data)
   L_hex = Basexx.to_hex(dec)
   --print(L_hex)
   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)
      name = Devices[adr]
      dtype = Types[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 dtype == 3 then   -- WallMountedThermostat
         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 dtype == 1 or dtype == 2 then -- HeatingThermostat
         s = hex:sub(15,16)
         valve_pos = tonumber(s,16)
         s = hex:sub(17,18)
         setpoint = tonumber(s,16) / 2
         s = hex:sub(19,22)
         temp = tonumber(s,16) / 10
         dtype = "Valve    "
       elseif dtype == 4 then -- Door/window sensor
         if mode == 2 then smode = "Open" else smode = "Closed" end
         setpoint = -1
         temp = -1
         dtype = "Door sensor"
       end
print(dtype, name, "Setpoint="..setpoint, "Temp="..temp, "Valve pos="..valve_pos, "Battery="..sbat, "Mode="..smode)
      pos = pos + (data_len*2)
   end
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)
   --print(line)
   local cmd  = line:sub(1,1)
   local data = line:sub(3)
   
   if (cmd == 'H') then
      maxCmd_H(data)
   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()
I tried to update the Wiki, but for some reason I have login problems.

Hope this works!
Raspberry Pi 2B - RFXtrx433 - Aeon Z-Stick gen5 - Opentherm Gateway - P1 smart meter - Netatmo - Philips Hue - ELV Max! - ESP8266 DIY water meter - Sonos Connect & PLAY:1 - Kodi - Wall mounted tablet + Imperihome - MANY switches/sensors

oasisnl
Posts: 22
Joined: Wednesday 22 November 2017 0:43
Target OS: Raspberry Pi
Domoticz version:
Contact:

Re: ELV Max! Heating control system

Post by oasisnl » Tuesday 19 December 2017 22:43

Thanks mvzut,

still waiting for my doorsensors, but script worked like a charm without them!
Hopefully it will work also when the sensors have arrived.

Lahim
Posts: 4
Joined: Wednesday 03 January 2018 0:47
Target OS: Raspberry Pi
Domoticz version:
Contact:

Re: ELV Max! Heating control system

Post by Lahim » Wednesday 03 January 2018 0:54

I have same problem as Vitalij

Code: Select all

pi@raspberrypi:~/domoticz $ sudo lua maxscript.lua
lua: /home/pi/domoticz/scripts/lua/JSON.lua:660: html passed to JSON:decode(): <html><head><title>Unauthorized</title></head><body><h1>401 Unauthorized</h1></body></html>
stack traceback:
        [C]: in function 'assert'
        /home/pi/domoticz/scripts/lua/JSON.lua:660: in function 'onDecodeOfHTMLError'
        /home/pi/domoticz/scripts/lua/JSON.lua:975: in function 'decode'
        maxscript.lua:42: in function 'get_MAX_ID'
        maxscript.lua:228: in main chunk
        [C]: in ?
It is fresh installation of Domoticz 3.8798 - Beta because with stable version Domoticz was Offline - problem with libssl :(

maxtest.lua (last mvzut script) works but:

Code: Select all

Rooms
-----
Wojtek  0D821E
Gaba    010908
Łazienka0D8186
Salon   009275

Devices
-------
Wojtek-Rad      0D821E
Gaba-Rad        010908
Łazienka-Rad    0D8186
Przycisk Eco 1  05C439
Salon-Rad       009275
PuTTY
Device status
-------------
lua: maxtest.lua:115: attempt to concatenate global 'setpoint' (a nil value)
stack traceback:
        maxtest.lua:115: in function 'maxCmd_L'
        maxtest.lua:148: in main chunk
        [C]: in ?


Lahim
Posts: 4
Joined: Wednesday 03 January 2018 0:47
Target OS: Raspberry Pi
Domoticz version:
Contact:

Re: ELV Max! Heating control system

Post by Lahim » Wednesday 03 January 2018 1:53

I just found the solution - if you will delete login and password from Settings / Website protection - maxscript.lua works from command line and add all to the Domoticz :)
I just add it to the crontab so we will see.

But maxtest.lua still produces the error

Code: Select all

lua: maxtest.lua:115: attempt to concatenate global 'setpoint' (a nil value)
stack traceback:
        maxtest.lua:115: in function 'maxCmd_L'
        maxtest.lua:148: in main chunk

mvzut
Posts: 319
Joined: Thursday 12 November 2015 11:55
Target OS: Raspberry Pi
Domoticz version: Beta
Location: Marum, The Netherlands
Contact:

Re: ELV Max! Heating control system

Post by mvzut » Wednesday 03 January 2018 10:16

Lahim wrote:But maxtest.lua still produces the error

Code: Select all

lua: maxtest.lua:115: attempt to concatenate global 'setpoint' (a nil value)
stack traceback:
        maxtest.lua:115: in function 'maxCmd_L'
        maxtest.lua:148: in main chunk
Have you tried the newer version of maxtest.lua which I posted a few posts back?
Raspberry Pi 2B - RFXtrx433 - Aeon Z-Stick gen5 - Opentherm Gateway - P1 smart meter - Netatmo - Philips Hue - ELV Max! - ESP8266 DIY water meter - Sonos Connect & PLAY:1 - Kodi - Wall mounted tablet + Imperihome - MANY switches/sensors

Lahim
Posts: 4
Joined: Wednesday 03 January 2018 0:47
Target OS: Raspberry Pi
Domoticz version:
Contact:

Re: ELV Max! Heating control system

Post by Lahim » Wednesday 03 January 2018 10:19

Yes, I use your script.
Crontab task with script works ok.
The problem might be after reboot but I have to check it.

twimpy
Posts: 33
Joined: Saturday 25 January 2014 15:06
Target OS: Raspberry Pi
Domoticz version: V2.3790
Contact:

Re: ELV Max! Heating control system

Post by twimpy » Wednesday 31 January 2018 13:01

Same problem here and I used the script few posts back.

Rooms
-----
Schuur 0F99E6
Kantoor 0D3599
Badkamer 18A9EB

Devices
-------
Schuur-Rad 0F99E6
Badkamer-Rad 18A9EB
Kantoor Achter-Sens 0D62DC
Kantoor Voor-Rad 0D2D99
Kantoor Achter-Rad 0D3599
Eco Switch 1 0B3D7A
Kantoor-Stat 0EBED9
Kantoor Voor-Sens 0D62E8

Device status
-------------
lua: maxtest.lua:131: attempt to concatenate global 'valve_pos' (a nil value)
stack traceback:
maxtest.lua:131: in function 'maxCmd_L'
maxtest.lua:165: in main chunk
[C]: in ?

Peggy
Posts: 32
Joined: Saturday 09 September 2017 23:38
Target OS: Windows
Domoticz version:
Contact:

Re: ELV Max! Heating control system

Post by Peggy » Monday 05 February 2018 18:16

Hello MZVut,

I worked a bit on your script, but I let the MaxCmdSend method intact. I get a weird behaviour when setting a new setpoint to any valve. I share my log, for information, just in case. You'll see the initial command from domoticz in green color, then the weird behaviour in red. In short, when I send a command, during 5 to 30mn the cube send back weird data from all valves, then weird data from the commanded valve, then go back to normal.
Spoiler: show

16:32:29 -

EQ3 state :

Name ID Mod Setp Temp % Bst Raw
Rad_A 145C7B Manual 09.5 00.0 00 0 10011 | 00011001
Rad_B 145CB0 Manual 12.0 12.4 00 0 10011 | 00011001
Rad_C 145C74 Auto 17.5 00.0 100 0 000111 | 00111000
Rad_D 13E81F Auto 17.0 16.8 16 0 00011 | 00011000
Rad_E 145C7E Auto 12.0 28.3 00 0 00011 | 00011000
Rad_F 145C63 Manual 12.0 00.0 00 0 10011 | 00011001
Rad_G 145C83 Auto 17.5 00.0 100 0 00011 | 00011000

Changes :

Rad_E mode update from domoticz : Manual (previously Auto)
Sending to valve Rad_E mode MANUAL setpoint 19.5


END

16:37:29 -

EQ3 state :

Name ID Mod Setp Temp % Bst Raw
Rad_D 13E81F Auto 17.0 17.5 12 0 00011 | 00011000
BST is nil for : Rad_A
BST is nil for : Rad_B
BST is nil for : Rad_C
BST is nil for : Rad_E
BST is nil for : Rad_F
BST is nil for : Rad_G

END

16:43:29
Name ID Mod Setp Temp % Bst Raw
Rad_A 145C7B Manual 09.5 00.0 00 0 10011 | 00011001
Rad_B 145CB0 Manual 12.0 00.0 00 0 10011 | 00011001
Rad_C 145C74 Auto 17.5 00.0 100 0 000111 | 00111000
Rad_D 13E81F Auto 17.0 17.9 08 0 00011 | 00011000
Rad_F 145C63 Manual 12.0 00.0 00 0 10011 | 00011001
Rad_G 145C83 Auto 17.5 00.0 100 0 00011 | 00011000
BST is nil for : Rad_E
END 16:47:30 --

16:47:29 -
Name ID Mod Setp Temp % Bst Raw
Rad_A 145C7B Manual 09.5 00.0 00 0 10011 | 00011001
Rad_B 145CB0 Manual 12.0 00.0 00 0 10011 | 00011001
Rad_C 145C74 Auto 17.5 00.0 100 0 000111 | 00111000
Rad_D 13E81F Auto 17.0 17.9 08 0 00011 | 00011000
Rad_E 145C7E Auto 12.0 28.7 00 0 00011 | 00011000
Rad_F 145C63 Manual 12.0 00.0 00 0 10011 | 00011001
Rad_G 145C83 Auto 17.5 00.0 100 0 00011 | 00011000
Domoticz mode Rad_E set from Manual to Auto
Domoticz setpoint Rad_E set to 12 degrees instead of 19.5

END

mvzut
Posts: 319
Joined: Thursday 12 November 2015 11:55
Target OS: Raspberry Pi
Domoticz version: Beta
Location: Marum, The Netherlands
Contact:

Re: ELV Max! Heating control system

Post by mvzut » Wednesday 07 February 2018 1:02

To be honest I have never used the command sending function for anything else then MANUAL setpoints., and this works normally. I'm not certain, but it looks like you also have some AUTO setpoints, correct? If so, you could do a test with only MANUAL setpoints to see if that solves the strange behavior. If this is indeed the case, there may be something wrong with the implementation of sending AUTO setpoints.
Raspberry Pi 2B - RFXtrx433 - Aeon Z-Stick gen5 - Opentherm Gateway - P1 smart meter - Netatmo - Philips Hue - ELV Max! - ESP8266 DIY water meter - Sonos Connect & PLAY:1 - Kodi - Wall mounted tablet + Imperihome - MANY switches/sensors

Peggy
Posts: 32
Joined: Saturday 09 September 2017 23:38
Target OS: Windows
Domoticz version:
Contact:

Re: ELV Max! Heating control system

Post by Peggy » Wednesday 07 February 2018 4:08

Thank you for your help. Looks like I've introduced a mistake further in my code, I'll check tomorrow that everything runs fine.

twimpy
Posts: 33
Joined: Saturday 25 January 2014 15:06
Target OS: Raspberry Pi
Domoticz version: V2.3790
Contact:

Re: ELV Max! Heating control system

Post by twimpy » Wednesday 07 February 2018 11:33

Hello MZVut,

First I am very pleased with all the work you all did.
I am not a code writer and this is my first adventure with Lua. But the best thing to learn is understanding written code from others.
I changed some code of the test script to let it work in my situation. The error was because of the Eco switch so I added it in the code. Can you or someone test it and (more important) review the code before changing on the wiki page?
Added eco switch and return commandArray just search on ** for the comments I wrote.

Code: Select all

--maxtest.lua

package.loadlib("core.so", "*")
local Socket = require "socket"
local Basexx = require "basexx"

local MaxIP='172.25.5.8'  -- change with the IP adress of your own Cube
local MaxPort = 62910

local Rooms   = {}
local Devices = {}
local Types   = {}

function maxCmd_H(data)
  --print('H='..data)
end

-- function read total of get rooms and Devices print the names and unique device code

function maxCmd_M(data)
   --print('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)
   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)
      pos  = pos+name_len
      adr  = Basexx.to_hex(dec:sub(pos, pos+2))
      Rooms[adr] = name
      pos = pos+3
   end
   
   print("Rooms\n-----")
   for adr, name in pairs(Rooms) do 
   print(name.. '\t' ..adr)
   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)
      pos  = pos+name_len
      room_num = string.byte(dec, pos)
      Devices[adr] = name
      Types[adr] = dtype
   end
   
   print("\nDevices\n-------")
      for adr, name in pairs(Devices) do 
      print(name .. '\t' .. adr)
   end

end

--function read all data from devices and print type device and data

function maxCmd_C(data)
  C_hex = data
  C_len =  string.len(C_hex)
  --print(C_hex)
  pos = 1
  s = C_hex:sub(pos,(pos+1))
  data_len  = tonumber(s,16) + 1
  hex  = C_hex:sub(pos,pos+(data_len*2))
  adr  = hex:sub(3,8)
  name = Devices[adr]
  dtype = hex:sub(9,10)
--  print(dtype)
end

function maxCmd_L(data)
print("\nDevice status\n-------------")
   pos = 1
   dec = Basexx.from_base64(data)
   L_hex = Basexx.to_hex(dec)
   -- print(L_hex)
   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)
      name = Devices[adr]
      dtype = Types[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 dtype == 3 then   -- WallMountedThermostat
         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 dtype == 1 or dtype == 2 then -- HeatingThermostat
         s = hex:sub(15,16)
         valve_pos = tonumber(s,16)
         s = hex:sub(17,18)
         setpoint = tonumber(s,16) / 2
         s = hex:sub(19,22)
         temp = tonumber(s,16) / 10
         dtype = "Valve"
       elseif dtype == 4 then -- Door/window sensor
	  valve_pos = -1
         if mode == 2 then smode = "Open" else smode = "Closed" end
         setpoint = -1
         temp = -1
         dtype = "Door sensor"

-- ** added eco switch 

       elseif dtype == 5 then -- Eco Switch
         if mode == 2 then smode = "Open" else smode = "Closed" end
         setpoint = -1
         temp = -1
         dtype = "Eco Switch"
       end


print(dtype, name, "Setpoint="..setpoint, "Temp="..temp, "Valve pos="..valve_pos, "Battery="..sbat, "Mode="..smode)

      pos = pos + (data_len*2)
   end
end

commandArray = {}

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)
   --print(line)
   local cmd  = line:sub(1,1)
   local data = line:sub(3)
   
   if (cmd == 'H') then
      maxCmd_H(data)
   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()

-- ** add return commandArray

return commandArray
The output result:
Rooms
-----
Kantoor 0D3599
Schuur 0F99E6
Badkamer 18A9EB

Devices
-------
Kantoor Achter-Rad 0D3599
Kantoor Voor-Sens 0D62E8
Badkamer-Rad 18A9EB
Eco Switch 0B3D7A
Kantoor Voor-Rad 0D2D99
Kantoor Achter-Sens 0D62DC
Schuur-Rad 0F99E6
Kantoor-Stat 0EBED9

Device status
-------------
Door sensor Kantoor Voor-Sens Setpoint=-1 Temp=-1 Valve pos=-1 Battery=OK Mode=Closed
Valve Badkamer-Rad Setpoint=19 Temp=23.2 Valve pos=0 Battery=OK Mode=Auto
Valve Kantoor Voor-Rad Setpoint=21 Temp=0 Valve pos=72 Battery=OK Mode=Manual
Door sensor Kantoor Achter-Sens Setpoint=-1 Temp=-1 Valve pos=-1 Battery=OK Mode=Closed
Valve Schuur-Rad Setpoint=15 Temp=16.1 Valve pos=0 Battery=OK Mode=Auto
Thermostat Kantoor-Stat Setpoint=21 Temp=20.7 Valve pos=-1 Battery=OK Mode=Manual
Eco Switch Eco Switch Setpoint=-1 Temp=-1 Valve pos=-1 Battery=OK Mode=Closed
Valve Kantoor Achter-Rad Setpoint=21 Temp=20.9 Valve pos=72 Battery=OK Mode=Manual
Attachments
maxtest.lua.txt
(4.54 KiB) Downloaded 43 times

Peggy
Posts: 32
Joined: Saturday 09 September 2017 23:38
Target OS: Windows
Domoticz version:
Contact:

Re: ELV Max! Heating control system

Post by Peggy » Monday 19 February 2018 17:06

mvzut wrote:
Wednesday 07 February 2018 1:02
To be honest I have never used the command sending function for anything else then MANUAL setpoints., and this works normally. I'm not certain, but it looks like you also have some AUTO setpoints, correct? If so, you could do a test with only MANUAL setpoints to see if that solves the strange behavior. If this is indeed the case, there may be something wrong with the implementation of sending AUTO setpoints.
Hello again,

Just an easy and useful improvement : for those who want to make the 'Auto' mode use the setpoint predefined in the valve planning (instead of the domoticz one), in the MaxCmdSend function please change this code :

Code: Select all

hex = "000440000000"..id..room..string.format("%x",bits)
Into

Code: Select all

if smode == 'AUTO' then   
	  hex = "000440000000"..id..room.."00"
   else 
	  hex = "000440000000"..id..room..string.format("%x",bits)
   end
Without this change, the auto mode will work but the setpoint given in parameter will be set until the next planning change.

Now I can control all modes from domoticz, but I had to make dirty code so I can't share the whole script, unfortunately.

Image

Peggy
Posts: 32
Joined: Saturday 09 September 2017 23:38
Target OS: Windows
Domoticz version:
Contact:

Re: ELV Max! Heating control system

Post by Peggy » Monday 19 February 2018 17:26

Another trick for those who want to catch exceptions for them to be shown in DOmoticz in red :
In the main script , look for the line "elseif (cmd == 'L')" and put this :

Code: Select all

elseif (cmd == 'L') then
	  success,error = pcall(maxCmd_L,data)
	  if not success then
		print("Exception : "..error)
		io.write('<p style="color:red"> Exception : '..error..'</p>\n')
		http.request('http://127.0.0.1:'..DomoticzPort..'/json.htm?type=command&param=addlogmessage&message='..string.gsub('<span style="color:red">Max script exception '..error..'</span>',' ','%%20'))
	  end
      break
Image

pbattino
Posts: 4
Joined: Wednesday 22 March 2017 10:53
Target OS: Raspberry Pi
Domoticz version:
Contact:

Re: ELV Max! Heating control system

Post by pbattino » Tuesday 27 February 2018 17:40

Swifty wrote:
Friday 01 December 2017 16:34
I found a horstmann controls iqe cp318 Z-Wave timeswitch which looked like it would fit my needs, but a bit of googling suggests that Domoticz isn't able to turn the boiler on, or set the current mode using the Z-Wave - only configure the setpoint for the included thermostat.
I'm in the same situation and I can confirm the iQE CP318 works relatively well with Domoticz. See my post:
viewtopic.php?f=6&t=9014&p=125781#p125781

Basically I paired the 3 devices together: a) the CP318 thermostat b) the CP318 receiver (=the actuator that switches the boiler on and off) and 3) Raspberry + a Z-Wave stick, running Domoticz. All good!

What I can do easily:
1) switch the boiler on/off from Domoticz
2) read temperature and set point from CP318 thermostat

What I can do with some difficulty:
1) change set point in CP318 thermostat from Domoticz. It works, but it takes ages between when you set it and when the change is actually registered. Also, Domoticz UI does not show the change as registered until it is... registered, so it looks like you enter a new value and it does not work but if you wait a looooooong time (30 min or so) it work. You can probably improve it by changing the polling frequency of CP318 thermostat, but in doing so I noticed that the battery was drained in few days rather than months....

What I still need to do:
1) read the status of all the ELV Max!, read the CP318 temp + set point, and trigger a boiler on/off accordingly. Basically all the work in this thread is still do be done for me, but all the rest works, so I would say if you already have the ELV Max! and the Cube, go ahead an buy the cp318 or equivalent (I think the Horstmann SEC SRT321 / SEC SSR303 is OK as well) and... start coding!

I agree with you: I prefer to have a commercial device manage my boiler, it feels safer! In this way I solved the problem: manual control when I want, through the CP318, or automated control through Domoticz reading values from ELV Max!

carpov
Posts: 1
Joined: Friday 09 March 2018 14:06
Target OS: Raspberry Pi
Domoticz version:
Contact:

Re: ELV Max! Heating control system

Post by carpov » Saturday 10 March 2018 14:25

Hello all !!!

Could anyone help me? I decided on do moticz because it supports the EQ3 head. Despite the great step-by-step tutorial on wiki, I can't cope with the implementation of the eq3 system in Domoticz.

The test script maxtest.lua works perfectly ... and shows all data from the eq3 cube.

Code: Select all

pi@raspberrypi:~ $ lua maxtest.lua
Rooms
-----
Łazienka        18ADB4
Salon   16904B
Sypialnia       18AE24

Devices
-------
Łazienka-Rad    18ADB4
Sypialnia-Rad   18AE24
Salon-Rad       16904B

Device status
-------------
Valve           Sypialnia-Rad   Setpoint=12.5   Temp=22.4       Valve pos=0     Battery=OK      Mode=Manual
Valve           Łazienka-Rad    Setpoint=15     Temp=23.5       Valve pos=0     Battery=OK      Mode=Manual
Valve           Salon-Rad       Setpoint=19     Temp=19.9       Valve pos=13    Battery=OK      Mode=Auto
....but the second..main script script_time_max.lua unfortunately, is not :(
I added dummy devices:
  • 3x Dummy temp sensors with name: Łazienka, Salon and Sypialnia
  • 3x dummy percentages: Łazienka-Rad, Salon-Rad and Sypialnia-RAd
Thera are nothing in Domoticz. All values shows "zero"

Please help

mxg10011
Posts: 5
Joined: Tuesday 20 February 2018 0:43
Target OS: Raspberry Pi
Domoticz version:
Contact:

Re: ELV Max! Heating control system

Post by mxg10011 » Saturday 17 March 2018 12:53

Peggy wrote:
Monday 19 February 2018 17:06
mvzut wrote:
Wednesday 07 February 2018 1:02
To be honest I have never used the command sending function for anything else then MANUAL setpoints., and this works normally. I'm not certain, but it looks like you also have some AUTO setpoints, correct? If so, you could do a test with only MANUAL setpoints to see if that solves the strange behavior. If this is indeed the case, there may be something wrong with the implementation of sending AUTO setpoints.
Hello again,

Just an easy and useful improvement : for those who want to make the 'Auto' mode use the setpoint predefined in the valve planning (instead of the domoticz one), in the MaxCmdSend function please change this code :

Code: Select all

hex = "000440000000"..id..room..string.format("%x",bits)
Into

Code: Select all

if smode == 'AUTO' then   
	  hex = "000440000000"..id..room.."00"
   else 
	  hex = "000440000000"..id..room..string.format("%x",bits)
   end
Without this change, the auto mode will work but the setpoint given in parameter will be set until the next planning change.

Now I can control all modes from domoticz, but I had to make dirty code so I can't share the whole script, unfortunately.

Image
Is there any chance to get a "clean" script for the switch? ;-)
I'd really like to change between "Auto" and "Manual" from domoticz.

Zembaty
Posts: 1
Joined: Friday 18 May 2018 21:49
Target OS: Raspberry Pi
Domoticz version:
Contact:

Re: ELV Max! Heating control system

Post by Zembaty » Friday 18 May 2018 21:57

Hello All,

Finally after whole the day I installed Domoticz on my Pi.
I used the newest maxtest.lua scrpit but it doesn't work well:

pi@raspberrypi:~ $ lua maxtest.lua
Rooms
-----
Lazienka G. 0975BA
Wejscie 0975CD
Salon 07400D
Garderoba O.
0BEA5E
Garderoba P. 08C164
Sypialnia
0B251E
Martyna
0B2523
Agata
0B2588
Gabinet
0B2595

Devices
-------
Agata-Sens1 0CBD5D
Salon-Sens2 0C3233
Sypialnia-Sens1 0CBD3D
Salon-Rad1 07400D
Martyna-Stat 094CE9
Lazienka G.-Sens 0CBD4A
Sypialnia-Stat 094F67
Agata-Sens2 0C331D
Sypialnia-Sens2 0CBD5F
Gabinet-Stat 094F71
Gabinet-Sens 0C377B
Martyna-Rad 0B2523
Sypialnia-Rad2 0B25EA
Salon-Rad2 074004
Sypialnia-Rad1 0B251E
Lazienka G.-Rad 0975BA
Wejscie-Rad 0975CD
Gabinet-Rad 0B2595
Salon-Sens3 0C2FA1
Garderoba O.-Stat 103259
Garderoba P.-Stat 108091
Agata-Rad2 0B2581
Salon-Sens1 0C3077
Agata-Stat 094D4D
Salon-Stat 078FCB
Garderoba P.-Rad08C164
Eco 03FB07
Garderoba O.-Rad 0BEA5E
Agata-Rad1 0B2588
Martyna-Sens 0CBCAD
PuTTYPuTTYPuTTYPuTTYPuTTY
Device status
-------------
lua: maxtest.lua:148: attempt to concatenate global 'valve_pos' (a nil value)
stack traceback:
maxtest.lua:148: in function 'maxCmd_L'
maxtest.lua:185: in main chunk
[C]: in ?
pi@raspberrypi:~ $ PuTTYPuTTYPuTTYPuTTYPuTTY


Any idea what is wrong?

biomm
Posts: 5
Joined: Monday 06 February 2017 20:47
Target OS: Windows
Domoticz version:
Contact:

Re: ELV Max! Heating control system

Post by biomm » Wednesday 30 May 2018 12:51

Dear all,
After a few successful years my system (R Pi + eMAX! + Lua script) stopped to response. Lua script (with crontab) - fine, eMAX! devices are OK as well so... the only reason might be new router (!!)
Some minuter later it was obvious that new device is NOT able to set "static IP" and from time to time IP of eMAX! Cube was changing (why new devices are lacking such an important setting??)

As stated in Lua sript it should be possible to use IP or NAME of Cube device:
-- Enter your cube name or ip address and port here
--MaxIP='192.168.x.x'
MaxIP='LEQ1234567'
MaxPort=62910
/source - wiki - EQ3 MAX/

For some reason in my case IP is working fine while NAME is not working at all.
Script test results: Socket connect failed for 'LEQ1234567"

I would appreciate advice / help - checking each time for IP and paste it to max script is possible BUT very annoying - especially winter time while heating is ON.....

Peggy
Posts: 32
Joined: Saturday 09 September 2017 23:38
Target OS: Windows
Domoticz version:
Contact:

Re: ELV Max! Heating control system

Post by Peggy » Wednesday 30 May 2018 23:16

mxg10011 wrote:
Saturday 17 March 2018 12:53
Is there any chance to get a "clean" script for the switch? ;-)
I'd really like to change between "Auto" and "Manual" from domoticz.
Hello,

Here is my work. Most of the code is "readable", but my sync mechanism between Domoticz modes and Max! modes is tricky. I could make something simpler, I didn't :)
This code has been working from february to april, and in the end was rather satisfying. Maybe I've introduced a typo while refactoring the room names.
Spoiler: show

Code: Select all

-- Peggy upgrade from original "mvzut CubeScript" source
-- Please launch the original script at least once in order to create the right devices in domoticz (see under why)
-- Improvements : 
------- Domoticz is updated only if needed
------- Domoticz Modes : Automatic / Confort (Manual) / Eco (Manual) / Boost 
------- Domoticz json device list is requested only once by script run, not once by device
------- Creation and update of a daily HTML log file with device update
------- LUA Log is more verbose
------- Domoticz Log is updated on some events

-- Script which creates & synchronizes devices in Domoticz with values from MAX! cube
-- Change variables below to your own values
-- Start by adding new cronjob "*/5 * * * * /usr/bin/lua /home/pi/domoticz/scripts/lua/maxscript.lua" (using crontab -e) 

MaxIP='192.168.1.10'   -- IP adress of your Cube, best to check via your router
MaxPort = 62910        -- Port used by your Cube, usually 62910
DomoticzPort = 8080    -- Port used by Domoticz, 8080 is the default
useWMT = false         -- Set to true if there is a wall mounted thermostat in every room
interval = 5           -- Polling interval in minutes, fill in same value as in crontab
setpoint_DoorOpen = 5  -- Setpoint when door/window open
holidayTemp = 12 	   -- Holiday temperature is defined here
comfortTemp = 19.5     -- Confort temp (in Manual mode)
autoTemp = 19		   -- Automatic mode in Domoticz

file = io.open("C:\\flat\\cube\\"..os.date("%Y%m%d")..'.html', "a")
io.output(file)
io.write(os.date("%X - "))
events = ""
valves = "<p style='font-family:\"Courier New\"'>\n"..string.gsub("Name         ID       Mod      Setp  Temp  %   Bst  Raw</br>\n"," ","&nbsp;")

-- The following settings are related to the new features and require the manual creation of selector switches in Domoticz having Auto / Manual / Holiday / Boost modes
-- Id of the valve / Id of the domoticz selector switch created
idModeDomoticz = {}
idModeDomoticz["00145C63"] =  "1150" -- ROOM1
idModeDomoticz["00145C7B"] =  "1143" -- ROOM2
idModeDomoticz["00145C7E"] =  "1146" -- ROOM3
idModeDomoticz["00145C83"] =  "1147" -- ROOM4
idModeDomoticz["0013E81F"] =  "1144" -- ROOM5
idModeDomoticz["00145C74"] =  "1145" -- ROOM6
idModeDomoticz["00145CB0"] =  "1151" -- ROOM7

-- Here is a mapping of the domoticz temp device created by the original cube Script : this mapping is needed here to make a comparison between the valve temp and domoticz temp, so that Domoticz is not updated if not needed
idTempDomoticz = {}
idTempDomoticz["145C63"] =  "681" -- ROOM1
idTempDomoticz["145C7B"] =  "691" -- ROOM2
idTempDomoticz["145C7E"] =  "690" -- ROOM3
idTempDomoticz["145C83"] =  "677" -- ROOM4
idTempDomoticz["13E81F"] =  "556" -- ROOM5
idTempDomoticz["145C74"] =  "685" -- ROOM6
idTempDomoticz["145CB0"] =  "688" -- ROOM7
--json   = (loadfile "/home/pi/domoticz/scripts/lua/JSON.lua")()  -- uncomment if you're using Linux (comment next line)
json = (loadfile "C:\\Program Files (x86)\\Domoticz\\scripts\\lua\\JSON.lua")()    -- uncomment if you're using Windows (comment previous line)

----------------------------------------
-- No changes required below this line -
----------------------------------------

package.loadlib("core.so", "*")

Basexx = require "basexx"
Socket = require "socket"
http   = require "socket.http"

Rooms   = {}
Devices = {}
Types   = {}
Room_nums = {}
resultT, statuscodeT, contentT = http.request('http://127.0.0.1:'..DomoticzPort..'/json.htm?type=devices&filter=utility')
rT,eT = json:decode(resultT)
resultM, statuscodeM, contentM = http.request('http://127.0.0.1:'..DomoticzPort..'/json.htm?type=devices&filter=light')
rM,eM = json:decode(resultM)
resultW, statuscodeW, contentW = http.request('http://127.0.0.1:'..DomoticzPort..'/json.htm?type=devices&filter=temp')
rW,eW = json:decode(resultW)
  
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 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 ReadDomoticzThermostat(DID)
  -- result, statuscode, content = http.request('http://127.0.0.1:'..DomoticzPort..'/json.htm?type=devices&filter=utility&used=true')
  if rT.status == "OK" then
    for k,v in pairs(rT.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 ReadDomoticzValve(DID)
  -- result, statuscode, content = http.request('http://127.0.0.1:'..DomoticzPort..'/json.htm?type=devices&filter=utility&used=true')
  if rT.status == "OK" then
    for k,v in pairs(rT.result) do
      if v.ID == '00'..DID then return v.Data,v.LastUpdate end
    end
  end
  return 0, '2016-01-01 00:00:00'  -- value to return if device was not found
end

function ReadDomoticzTemp(DID)  
  -- Retrieving the Domoticz ID from the local hash table
  domoticzID = nil
  for key, valeur in pairs(idTempDomoticz) do 	
    if key == DID then domoticzID = valeur end
  end
  
  if rW.status == "OK" then
    for k,v in pairs(rW.result) do
      if v.idx == domoticzID then return string.format("%.1f", v.Temp),v.LastUpdate end
    end
  end
  return 0, '2016-01-01 00:00:00'  -- value to return if device was not found
end

function ReadDomoticzMode(DID)  
  if rM.status == "OK" then
    for k,v in pairs(rM.result) do
      if v.ID == '0'..DID then 
		if 	   (v.LevelInt ==0)   then  smode="Off" 
		elseif (v.LevelInt ==10)  then smode="Auto" 
		elseif (v.LevelInt ==20)  then smode="Manual"
		elseif (v.LevelInt ==30)  then 
			smode="Holiday"
		elseif (v.LevelInt ==40)  then 
			--print('Domoticz Boost Mode found for '..DID..'| Level '..v.LevelInt..' | Triggered on '..v.LastUpdate )
			events = events..('<p style="color:green;">Domoticz Boost Mode found for '..DID..'| Level '..v.LevelInt..' | Triggered on '..v.LastUpdate.."</p>\n" )
			smode="Boost"
		end		
		return smode,v.LevelInt,v.LastUpdate end
    end
	else 
		print(rM.status)
		events = events..(rM.status.."</br>\n")
  end
  return 0, '2016-01-01 00:00:00'  -- value to return if device was not found
end

function UpdateDomoticzValve(DID, valve_Max)
  domoticzValve = ReadDomoticzValve(DID)
  if domoticzValve ~= valve_Max..'%' then
	print ("Domoticz Valve "..DID.." update from "..domoticzValve.." to "..valve_Max..'%')
	--events = events..("Domoticz Valve "..DID.." update from "..domoticzValve.." to "..valve_Max..'%')
	--http.request('http://127.0.0.1:'..DomoticzPort..'/json.htm?type=command&param=addlogmessage&message='..string.gsub('Domoticz valve for '..DID..' set to '..valve_Max,' ','%%20'))
	http.request('http://127.0.0.1:'..DomoticzPort..'/json.htm?type=command&param=udevice&hid='..MAX_ID..'&did='..DID..'&dunit=1&dtype=243&dsubtype=6&nvalue=0&svalue='..valve_Max)
  end
end

function UpdateDomoticzTemperature(DID, value) -- Update Temp in Domoticz
  domoticzTemp, LastUpdate  = ReadDomoticzTemp(DID)  
  if(domoticzTemp ~= string.format("%.1f", value)) then
	print ("Domoticz Temp "..DID.." update from "..domoticzTemp.." to "..value)
	--events = events..("Domoticz Temp "..DID.." update from "..domoticzTemp.." to "..value.."</br>\n")
	--http.request('http://127.0.0.1:'..DomoticzPort..'/json.htm?type=command&param=addlogmessage&message='..string.gsub('Domoticz temp for '..DID..' set to '..value,' ','%%20'))
	http.request('http://127.0.0.1:'..DomoticzPort..'/json.htm?type=command&param=udevice&hid='..MAX_ID..'&did='..DID..'&dunit=1&dtype=80&dsubtype=5&nvalue=0&svalue='..value)
  end
end

function UpdateDomoticzAutoMode(DID, sMode)
  -- Retrieving the Domoticz ID from the local hash table
  id = nil
  for key, valeur in pairs(idModeDomoticz) do 
    if key == '0'..DID then id = valeur end
  end 						
  
  if sMode == "Auto" then 
    http.request('http://127.0.0.1:'..DomoticzPort..'/json.htm?type=command&param=switchlight&idx='..id..'&switchcmd=Set%20Level&level=10') --&hid='..MAX_ID..'&did='..DID..'&dunit=1&dtype=244&dsubtype=62&svalue=10')
  elseif sMode == "Manual" then	
	http.request('http://127.0.0.1:'..DomoticzPort..'/json.htm?type=command&param=switchlight&idx='..id..'&switchcmd=Set%20Level&level=20')
  elseif sMode == "Holiday" then	
	http.request('http://127.0.0.1:'..DomoticzPort..'/json.htm?type=command&param=switchlight&idx='..id..'&switchcmd=Set%20Level&level=30')	
  elseif sMode == "Boost" then	
	http.request('http://127.0.0.1:'..DomoticzPort..'/json.htm?type=command&param=switchlight&idx='..id..'&switchcmd=Set%20Level&level=40')		
    --http.request('http://127.0.0.1:'..DomoticzPort..'/json.htm?type=command&param=switchlight&hid='..MAX_ID..'&did='..DID..'&dunit=1&dtype=244&dsubtype=62&svalue=20')
  end
end

function SetpointSync(DID, devicename, setpoint_MAX, mode_MAX)  
  updateMax = 'false'
  
  -- Checking Mode update in domoticz
  mode_Domoticz, modeDomoticzInt, LastUpdate = ReadDomoticzMode(DID)
  forceHolidayTemp = 'false'
  forceAutoTemp = 'false'
  forceComfortTemp = 'false'

  isHoliday = (mode_MAX == "Manual" and setpoint_MAX < comfortTemp -2 and mode_Domoticz == "Holiday")
  if(mode_MAX == "Manual" and setpoint_MAX < comfortTemp -2) then 
	mode_MAX = "Holiday" 
  end
  if not isHoliday and mode_Domoticz == "Holiday" and (age(LastUpdate) < interval * 60) then
    forceHolidayTemp = 'true'
	setpoint_MAX = holidayTemp
	updateMax = 'true'
  end
  
  if  mode_Domoticz ~= mode_MAX  then		
  	if (age(LastUpdate) > interval * 60) or mode_MAX == 'Boost'  then -- Domoticz mode value must be updated 		  
  	  UpdateDomoticzAutoMode(DID, mode_MAX)
	  print('Domoticz mode '..devicename..' set from '..mode_Domoticz..' to '..mode_MAX)
  	  events = events..('Domoticz mode '..devicename..' set from '..mode_Domoticz..' to '..mode_MAX.."</br>\n")
	  mode_Domoticz = mode_MAX
  	  http.request('http://127.0.0.1:'..DomoticzPort..'/json.htm?type=command&param=addlogmessage&message='..string.gsub('Domoticz mode for '..devicename..' set to '..mode_MAX,' ','%%20'))
  	else -- MAX! mode must be updated
  		print(devicename..' mode update from domoticz : '..mode_Domoticz..' (before '..mode_MAX..')')
  		events = events..(devicename..' mode update from domoticz : '..mode_Domoticz..' (before '..mode_MAX..")</br>\n")
  		http.request('http://127.0.0.1:'..DomoticzPort..'/json.htm?type=command&param=addlogmessage&message='..string.gsub('Max '..devicename..' mode update from domoticz '..mode_Domoticz..' instead of '..mode_MAX,' ','%%20'))
  		updateMax = 'true'
  		mode_MAX = mode_Domoticz
		if(mode_MAX == "Auto") then	forceAutoTemp = "true" end
		if(mode_MAX == "Manual" and forceHolidayTemp == 'false') then				
			forceComfortTemp = "true" 
			setpoint_MAX = comfortTemp 
		end
  	end  
  end

  -- Checking setpoint update in domoticz
  setpoint_Domoticz, LastUpdate = ReadDomoticzThermostat(DID)
  if(forceHolidayTemp == 'true' and setpoint_Domoticz ~= holidayTemp) then
	  http.request('http://127.0.0.1:'..DomoticzPort..'/json.htm?type=command&param=udevice&hid='..MAX_ID..'&did='..DID..'&dunit=1&dtype=242&dsubtype=1&nvalue=0&svalue='..holidayTemp)
      print('Domoticz setpoint '..devicename..' set to holiday '..holidayTemp..' degrees instead of '..setpoint_Domoticz)      
	  events = events..('Domoticz setpoint '..devicename..' set to holiday '..holidayTemp..' degrees instead of '..setpoint_Domoticz.."</br>\n")      
  end	  
  if(forceComfortTemp == 'true' and setpoint_Domoticz ~= comfortTemp) then
	  http.request('http://127.0.0.1:'..DomoticzPort..'/json.htm?type=command&param=udevice&hid='..MAX_ID..'&did='..DID..'&dunit=1&dtype=242&dsubtype=1&nvalue=0&svalue='..comfortTemp)
      print('Domoticz setpoint '..devicename..' set to comfort '..comfortTemp..' degrees instead of '..setpoint_Domoticz)      
	  events = events..('Domoticz setpoint '..devicename..' set to comfort '..comfortTemp..' degrees instead of '..setpoint_Domoticz.."</br>\n")      		  
  end
  if(forceAutoTemp == 'true' and setpoint_Domoticz ~= autoTemp) then
	  http.request('http://127.0.0.1:'..DomoticzPort..'/json.htm?type=command&param=udevice&hid='..MAX_ID..'&did='..DID..'&dunit=1&dtype=242&dsubtype=1&nvalue=0&svalue='..autoTemp)
      print('Domoticz setpoint '..devicename..' set to auto '..autoTemp..' degrees instead of '..setpoint_Domoticz)      
	  events = events..('Domoticz setpoint '..devicename..' set to auto '..autoTemp..' degrees instead of '..setpoint_Domoticz.."</br>\n")      		  
	  if setpoint_Max ~= autoTemp then
		updateMax = 'true'
		setpoint_Max = autoTemp
	  end
  end
  if tonumber(setpoint_Domoticz) ~= setpoint_MAX and forceHolidayTemp == 'false' and forceComfortTemp == 'false' and forceAutoTemp == 'false' then   
	if (age(LastUpdate) > interval * 60) and mode_MAX ~= 'Boost' then -- Domoticz thermostat value must be updated
      http.request('http://127.0.0.1:'..DomoticzPort..'/json.htm?type=command&param=udevice&hid='..MAX_ID..'&did='..DID..'&dunit=1&dtype=242&dsubtype=1&nvalue=0&svalue='..setpoint_MAX)
      print('Domoticz setpoint '..devicename..' set to '..setpoint_MAX..' degrees instead of '..setpoint_Domoticz)      
	  events = events..('Domoticz setpoint '..devicename..' set to '..setpoint_MAX..' degrees instead of '..setpoint_Domoticz.."</br>\n")      
	  http.request('http://127.0.0.1:'..DomoticzPort..'/json.htm?type=command&param=addlogmessage&message='..string.gsub('Max '..devicename..' setpoint update in domoticz '..setpoint_MAX..' instead of '..setpoint_Domoticz,' ','%%20'))
    elseif mode_MAX ~= "Boost" then -- MAX! setpoint must be updated
	  print(devicename..' setpoint update from domoticz : '..setpoint_Domoticz..' instead of '..setpoint_MAX)
	  events = events..(devicename..' setpoint update from domoticz : '..setpoint_Domoticz..' instead of '..setpoint_MAX.."</br>\n")
	  http.request('http://127.0.0.1:'..DomoticzPort..'/json.htm?type=command&param=addlogmessage&message='..string.gsub('Max '..devicename..' setpoint update from domoticz '..setpoint_Domoticz..' instead of '..setpoint_MAX,' ','%%20'))
	  updateMax = 'true'
	  setpoint_MAX = setpoint_Domoticz	  
	elseif mode_MAX == 'Boost' then
	  updateMax = 'false'
	  print(devicename..' setpoint not updated from domoticz because Boost : '..setpoint_Domoticz..' wont replace '..setpoint_MAX)
	  events = events..(devicename..' setpoint not updated from domoticz because Boost : '..setpoint_Domoticz..' wont replace '..setpoint_MAX.."</br>\n")
	  http.request('http://127.0.0.1:'..DomoticzPort..'/json.htm?type=command&param=addlogmessage&message='..string.gsub('Max '..devicename..' setpoint not updated from domoticz because Boost '..setpoint_Domoticz..' instead of '..setpoint_MAX,' ','%%20'))
    end	
  end

  
  -- Sending new values to Max! if needed
  if updateMax == 'true' then
    if (forceAutoTemp == 'true')     then setpoint_MAX = 0           end --autoTemp 
    if (forceComfortTemp == 'true')  then setpoint_MAX = comfortTemp end
	MaxCmdSend(adr, room_num, string.gsub(mode_MAX,'Holiday','Manual'), setpoint_MAX,devicename)      	
  end  
  
  --print(  'Debug : forceHolidayTemp '..forceHolidayTemp..' forceAutoTemp '..forceAutoTemp..' forceComfortTemp '..forceComfortTemp..' updateMax '..updateMax..' mode_MAX '..mode_MAX)
   
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
    http.request('http://127.0.0.1:'..DomoticzPort..'/json.htm?type=command&param=addlogmessage&message=MAX!%20configuration%20error!')
  end
  print("Found "..num_rooms.." rooms")
  print("------------")
  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
    Types[adr] = dtype
  end
end

function maxCmd_C(data)
--   print('C='..data)
end

function toBits(num)
    -- returns a table of bits, least significant first.
    local t={} -- will contain the bits
    while num>0 do
        rest=math.fmod(num,2)
        t[#t+1]=rest
        num=(num-rest)/2
    end
    return t
end


local hex2bin = {
	["0"] = "0000",
	["1"] = "0001",
	["2"] = "0010",
	["3"] = "0011",
	["4"] = "0100",
	["5"] = "0101",
	["6"] = "0110",
	["7"] = "0111",
	["8"] = "1000",
	["9"] = "1001",
	["a"] = "1010",
        ["b"] = "1011",
        ["c"] = "1100",
        ["d"] = "1101",
        ["e"] = "1110",
        ["f"] = "1111"
	}


function Hex2Bin(s)
local ret = ""
local i = 0
	for i in string.gfind(s, ".") do
		i = string.lower(i)

		ret = ret..hex2bin[i]
	end
	return ret
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]
    dtype = Types[adr]
    if not name then name=adr end
    valve_info = tonumber(hex:sub(13,14),16)
	valve_bits = toBits(valve_info)
	
	valve_bits_V2 = Hex2Bin(hex:sub(13,14))
		
    batt = 0 --bit32.extract(valve_info,7,1)
	mode = valve_bits[1] --bit32.extract(valve_info,0,2)
    bst  = valve_bits[2] --bit32.extract(valve_info,3,1)
	
	--mode 1 = Manuel 0 = Auto
	-- Boost + Manu : bst 1  et mode 1
    --mode 1 + bst 1 = boost
	--mode 1 + bst 0 = manual
	--mode 0 + bst 0 = auto
	
	
    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" else print(table.concat(toBits(valve_info)))
	end
	
	if (bst == nil) then
		print("!!!!!!!!  BST is nil !!!!!!!!!!!!!!!")
		--events = events..('<p style="color:red"> BST is nil for : '..name..'</p>\n')		
		bst = 9 
	end		
	
	if (bst==1) then smode="Boost" end
      
    if dtype == 3 then	-- WallMountedThermostat
	  print("Wall Therm. "..name.." "..adr)
      s = hex:sub(17,18)
      setpoint = tonumber(s,16) / 2
      if setpoint > 50 then setpoint = setpoint - 64 end
      s = hex:sub(23,26)
      temp = tonumber(s,16) / 10	  
      if temp ~= 0 and temp < 5 then temp = temp + 25.5 end  -- temporary solution for 2 digit hex temperature limitation
	  
      SetpointSync('0'..adr, name, setpoint,smode)	
	  --ModeSync('0'..adr, name, setpoint,smode)	

    elseif dtype == 1 or dtype == 2 then -- Valve
	  print("Valve       "..name.." "..adr)
      s = hex:sub(15,16)
      valve_pos = tonumber(s,16)
      s = hex:sub(17,18)
      setpoint = tonumber(s,16) / 2
      if setpoint > 50 then setpoint = setpoint - 64 end
      s = hex:sub(19,22)
      temp = tonumber(s,16) / 10
	  	  
	  print("Raw         "..table.concat(valve_bits).." | "..valve_bits_V2	 		  )
	  if (mode ~= nil) then print("Mode        "..smode) end
	  print("Setpoint    "..setpoint)	  	  
	  print("Temperature "..temp)	  
	  print("Valve       "..valve_pos.."%")
	  if (bst ~= nil) then print("Boost       "..bst) end
	  if (mode ~= nil) then valves = valves..string.gsub(string.format("%-11s  ",name)," ","&nbsp;")..adr.."&nbsp;&nbsp;&nbsp;"..string.gsub(string.format("%-7s  ",smode)," ","&nbsp;")..string.format("%04.1f", setpoint).."&nbsp;&nbsp;"..string.format("%04.1f", temp).."&nbsp;&nbsp;"..string.format("%02d", valve_pos).."&nbsp;&nbsp;"..bst.."&nbsp;&nbsp;&nbsp;&nbsp;"..table.concat(valve_bits).."&nbsp;|&nbsp;"..valve_bits_V2.."</br>\n" 
	  end

      if temp ~= 0 and temp < 5 then 
	    print("Valve  Hack :  "..name.." has a temp of "..temp.." : applying a 25.5 offset")
		temp = temp + 25.5 end  -- temporary solution for 2 digit hex temperature limitation
	  
	  -- Bug? when in holiday mode, the temp is not right
	  if temp ~= 0  and (temp <8 or temp > 30) then 
	    print("Valve       "..name.." has a temp of "..temp.." : bug or Holiday mode")
		events = events..('<p style="color:red"> Valve       '..name.." has a temp of "..temp.." : bug or Holiday mode</p>\n")
		--mode = 2
		--smode = "Holiday" 
	  end
	  
      if temp ~= 0 then UpdateDomoticzValve(adr, valve_pos)  end -- Update Valve in Domoticz
	  
      if not useWMT then -- Use valve for temp & setpoint
        if temp ~= 0 then 
			UpdateDomoticzTemperature(adr, temp)   -- Update Temp in Domoticz
		end
		
        if (mode ~= nil) then SetpointSync('0'..adr, name, setpoint,smode) end		
      end	  
    
	elseif dtype == 4 then -- Door/window sensor
	  print("Door Sensor "..name.." "..adr)
      --if mode == 2 then UpdateDomoticzAutoMode(adr, "On") else UpdateDomoticzAutoMode(adr, "Off") end
    end
	print("------------")
    pos = pos + (data_len*2)	  
  end
end

function MaxCmdSend(id, room, mode, setpoint,name)
   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
  
   if smode == 'AUTO' then   
	  hex = "000440000000"..id..room.."00"
   else 
	  hex = "000440000000"..id..room..string.format("%x",bits)
   end
	  
   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

   print("Sending to valve "..name.." mode "..smode.." setpoint "..setpoint.." bits "..bits.." "..Hex2Bin(i))
   events = events..("Sending to valve "..name.." mode "..smode.." setpoint "..setpoint.." bits "..bits.."</br>\n")
   http.request('http://127.0.0.1:'..DomoticzPort..'/json.htm?type=command&param=addlogmessage&message='..string.gsub("Max update valve "..name.." "..id.." "..smode.." setpoint "..setpoint,' ','%%20') )
   
end

--function MaxCmdSend(id, room, smode, setpoint, name)
--   -- Holiday and manual temperature are static
--   if smode == 'Manual' and setpoint ~=  holidayTemp then
--	  setpoint = comfortTemp
--	  print(name.." update temp override for Manual mode : "..comfortTemp)
--	  io.write(name.." update toverride for Manual mode : "..comfortTemp.."</br>\n")
--   elseif smode == 'Holiday' or (smode == 'Manual' and setpoint ==  holidayTemp) then
--	  smode = 'Auto'
--	  setpoint = holidayTemp
--	  print(name.." update temp override for holiday mode : "..holidayTemp)
--	  io.write(name.." update toverride for holiday mode : "..holidayTemp.."</br>\n")	  
--   end
--   
--   if smode == 'Manual' or smode == 'Holiday'  or smode == 'Auto' then 
--	  bits  = setpoint * 2
--	-- No setpoint change when using the boost feature. Auto could also be untouched, depending of what we expect.
--   else 
--      bits  = 0
--   end
--
--   print("Sending to valve "..name.." mode "..smode.." setpoint "..setpoint)
--   io.write("Sending to valve "..name.." mode "..smode.." setpoint "..setpoint.."</br>\n")
--   http.request('http://127.0.0.1:'..DomoticzPort..'/json.htm?type=command&param=addlogmessage&message='..string.gsub("Max update valve "..name.." "..id.." "..smode.." setpoint "..setpoint,' ','%%20') )
--   if smode == 'Manual' then
--      bits = 64 + bits	  
--   elseif smode == 'Boost' then
--      bits = 192 + bits
--   elseif smode == 'Holiday' 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.."</br>\n")
--   if not i then
--      print("MAX TCP send failed - "..status)
--	  io.write("MAX TCP send failed - "..status.."</br>\n")
--	  http.request('http://127.0.0.1:'..DomoticzPort..'/json.htm?type=command&param=addlogmessage&message=MAX!%20send%20error!%20'..id)
--      return
--   end
--end

-----------------------
-- Main script start --
-----------------------

  --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
	print("MAX! dummy hardware not yet created, create it")
	io.write("MAX! dummy hardware not yet created, create it</br>\n")
    http.request('http://127.0.0.1:'..DomoticzPort..'/json.htm?type=command&param=addhardware&htype=15&port=1&name=MAX!&enabled=true')
  end

  tcp = Socket.connect(MaxIP, MaxPort)
  if not tcp then
    print("Socket connect failed for "..MaxIP..':'..MaxPort)
	io.write("Socket connect failed for "..MaxIP..':'..MaxPort.."</br>\n")
    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
	  success,error = pcall(maxCmd_L,data)
	  if not success then
		print("Exception : "..error)
		io.write('<p style="color:red"> Exception : '..error..'</p>\n')
		http.request('http://127.0.0.1:'..DomoticzPort..'/json.htm?type=command&param=addlogmessage&message='..string.gsub('<span style="color:red">Max script exception '..error..'</span>',' ','%%20'))
	  end
      break
    end
  end

  minute = tonumber(os.date("%M"))
  if(events ~= "" ) then --or ( minute >= 0 and minute < 5)
	io.write(events)
	io.write(valves)
	io.write(os.date("</p>--> END RUN %X --</br>\n</br>\n"))
  end  
  io.close(file)
  tcp:close()

johnyjackson
Posts: 1
Joined: Wednesday 27 June 2018 9:28
Target OS: -
Domoticz version:
Contact:

Re: ELV Max! Heating control system

Post by johnyjackson » Wednesday 27 June 2018 9:31

huneyman wrote:
Tuesday 19 September 2017 16:20
i wana know complete info about Anavar (Oxandrolone)
Heating control system
Please give detailed information?

Post Reply

Who is online

Users browsing this forum: No registered users and 3 guests