Page 21 of 37

Re: ELV Max! Heating control system

Posted: Tuesday 08 November 2016 20:32
by Skippiemanz
Ive updated the wiki to the best of my knowledge.. Maybe you guys can make a quick go through to check if its ok!

Re: ELV Max! Heating control system

Posted: Tuesday 08 November 2016 21:04
by hasan
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?

Re: ELV Max! Heating control system

Posted: Tuesday 08 November 2016 21:25
by l0gic
blackdog65 wrote:Hi kevin,

What's in script_time_EQ3_Cube.lua?

Did you try the test script to do a basic read?


Sean
Hi Sean,
yeah the test code pulls out all the data as expected.
I just have issues with this specific code piece.
Googling seems to indicate either issues with paths / env settings (which I've checked) or version checks.

'tis weird

Kevin

Re: ELV Max! Heating control system

Posted: Tuesday 08 November 2016 21:44
by blackdog65
Hi Kevin,
most of us linux users found issues with where lua5.2 installs as it was different to previous versions. This may be the same or similar with windows.

Sean

Re: ELV Max! Heating control system

Posted: Tuesday 08 November 2016 21:46
by Skippiemanz
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?
Please put all devices in manual mode with the max app.

You need to create thermostat setpoint dummy devices in domoticz with the following name: Loznice-Stat

Also make sure you've set the use wall mount thermostat to false!

Re: ELV Max! Heating control system

Posted: Tuesday 08 November 2016 21:48
by mvzut
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!
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.

Re: ELV Max! Heating control system

Posted: Wednesday 09 November 2016 0:12
by daveabbott007
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)

Code: Select all

table.insert(commandArray, { ['OpenURL'] = 'http://127.0.0.1:'..DomoticzPort..'/json.htm?type=command&param=udevice&idx='..otherdevices_idx[name]..'&nvalue=0&svalue='..setpoint})
with

Code: Select all

table.insert(commandArray, { ['UpdateDevice'] = otherdevices_idx[name]..'|0|'..setpoint})
which could give the notorious timeout messages but should work regardlessly.

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:

Code: Select all

		  table.insert(commandArray, { ['UpdateDevice'] = otherdevices_idx[room]..'|0|'..temp})
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.
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).
again, many thanks to you all for your work and code, this code has not only made my life easier but now the wife dosnt complain about being too hot or cold - YAY!!

Re: ELV Max! Heating control system

Posted: Wednesday 09 November 2016 8:00
by toffel969
Hello everyone
Im expieriencing exactly the same problem, module bassex not found.

Code: Select all

luarocks list
returns

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 
gives me

Code: Select all

Lua 5.2.3  Copyright (C) 1994-2013 Lua.org, PUC-Rio
>
Maybe just an addition, I had to install

Code: Select all

sudo apt-get install libssl-dev
in order to install luasec, as this is the only thing that resolved the "openssl" not found issue during the build process.

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 ?

Re: ELV Max! Heating control system

Posted: Wednesday 09 November 2016 8:03
by hasan
I found solution yesterday. I'll update Wiki during today and let you know

Odesláno z mého LG-D855 pomocí Tapatalk

Re: ELV Max! Heating control system

Posted: Wednesday 09 November 2016 16:22
by mvzut
Skippiemanz wrote:The Window sensors are not(yet) seen in domoticz so no devices are Needed
FYI:
I have ordered a window sensor myself today, since I would like to understand how they can be read and integrated into the script.
I am also experimenting with am alternative version of the script that automatically generates the devices for you the first time it is used. No guarantees that this is going to work reliably of course...

Martijn

Re: ELV Max! Heating control system

Posted: Wednesday 09 November 2016 16:24
by Skippiemanz
Great news! I know the first maxbuddy script made the devices automatic. Maybe you can get some inspiration from that?

Re: ELV Max! Heating control system

Posted: Wednesday 09 November 2016 17:01
by blackdog65
Wow! This project has really grown legs and is off and running :lol:
I'm really pleased to have been along for the ride :D

Sean

Re: ELV Max! Heating control system

Posted: Wednesday 09 November 2016 17:02
by hasan
toffel969 wrote:Hello everyone
Im expieriencing exactly the same problem, module bassex not found.

Code: Select all

luarocks list
returns

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 
gives me

Code: Select all

Lua 5.2.3  Copyright (C) 1994-2013 Lua.org, PUC-Rio
>
Maybe just an addition, I had to install

Code: Select all

sudo apt-get install libssl-dev
in order to install luasec, as this is the only thing that resolved the "openssl" not found issue during the build process.

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 ?
Hi, I did some adjustment of Wiki, so you should try it. You will need these two files:
usrlocalsharelua5p2.tar
(117.12 KiB) Downloaded 664 times
usrlocalliblua5p2.tar
(119.53 KiB) Downloaded 555 times

Re: ELV Max! Heating control system

Posted: Wednesday 09 November 2016 17:36
by toffel969
Thanks so much, will only be home tomorrow night to try and give feedback

Re: ELV Max! Heating control system

Posted: Wednesday 09 November 2016 19:03
by l0gic
I've had a sign today, my Windows PC locked up.
So, due to this thread I've decided to swing back over to a Pi setup. :)
Don't let me down guys.

I will be running the Pi on a HDD set up as having SD cards corrupting put me off using a Pi last time.
As soon as the order arrives I'll be on the case.

Looking at the code I'm guessing it will not be too hard to invoke a 'all rads open' for when my woodburner is on.
I'm guessing this function should do all I need, just send a manual mode with a high temperature to all rads while we are burning wood.

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
With a bit of code wrapped around it.

Just as well the Domoticz database is lift and drop between OS's.

Cheers guys

Kevin

Re: ELV Max! Heating control system

Posted: Wednesday 09 November 2016 19:45
by mvzut
Skippiemanz wrote:Great news! I know the first maxbuddy script made the devices automatic. Maybe you can get some inspiration from that?
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.

ELV Max! Heating control system

Posted: Thursday 10 November 2016 0:29
by mvzut
UPDATE 12-11-2016 15:30 - Some changes to code

Is anybody willing to test this alternative script_time_max.lua script?

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&param=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&param=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&param=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&param=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&param=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&param=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
It should automatically create devices for all your MAX! modules: a virtual thermostat for each wall mounted thermostat (or for each valve if you have set "useWMT" to false), a temperature sensor for each wall mounted thermostat, and a percentage device for each valve.

Note that they will be invisible at first, you have to add them to the used devices in Domoticz via Settings > Devices. In principle, you can give them any name that you want when adding them, but I suggest to still use the naming scheme as agreed (i.e. use the "-Ras" and "-Stat" suffixes) to make sure the second script keeps working. It can be a bit confusing to know which is which, since by default all newly created devices are called "Unknown". I suggest you check the current temperatures, setpoints etc. on the displays, so that you can recognize the devices by their values.

The script adds a new hardware module called "MAX!" which is an instance of the dummy hardware module (unless you already had one with that name).

Let me know your results. It works at my side! :D

UPDATE:
I almost forgot to mention, but this version uses JSON decoding via an external library (JSON.lua). You can download one at https://www.domoticz.com/wiki/Lua_-_json.lua. Copy the JSON.lua file in your domoticz/scripts/lua folder.

Re: ELV Max! Heating control system

Posted: Thursday 10 November 2016 0:33
by Skippiemanz
Great! Wil test this morning! Where on a roll here hehe... Next stop a hardware plugin?

Re: ELV Max! Heating control system

Posted: Thursday 10 November 2016 6:56
by Teatech
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.

ELV Max! Heating control system

Posted: Thursday 10 November 2016 7:52
by mvzut
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.
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.