Page 16 of 37

Re: ELV Max! Heating control system

Posted: Wednesday 02 November 2016 8:46
by blackdog65
@Westcott
Thanks for jumping in here (and big thanks for your earlier work) as I'm out of my depth wth coding.

Do you have any clues about the

Code: Select all

attempt to concatenate field '?' (a nil value)
problem?

Sean

Re: ELV Max! Heating control system

Posted: Wednesday 02 November 2016 10:44
by Westcott
Hi Sean,

If I can see the offending Lua, I'll suggest a mod.

Re: ELV Max! Heating control system

Posted: Wednesday 02 November 2016 10:48
by Skippiemanz
Westcott wrote:Hi Skippiemanz,

Con you post the Lua file that You use, please?
I'll mod it for you.
Thanks for the help!

Here is the script(Copy past from WiKi, with adapted IP and Wll thermostat to False)

Code: Select all

--./script_time_max.lua
----------------------------------------------------------------------------------------------------------
-- Script parameters
----------------------------------------------------------------------------------------------------------
package.loadlib("core.so", "*")
local Socket = require "socket"
local Basexx = require "basexx"
local Rooms = {}
local Devices = {}
local Room_nums = {}
 
local MaxIP = "192.168.2.123"
local MaxPort = 62910
local useWMT = false             --# Set to true if there is a wall mounted thermostat in every room, then this one will be used for setpoint getting/setting
 
Debug = "YES"                       --# Turn debugging on ("YES") or off ("NO")
 
----------------------------------------------------------------------------------------------------------
-- Script functions
----------------------------------------------------------------------------------------------------------
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)
   --if Debug=="YES" then print('H='..data) end
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)
   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)
   --if Debug=="YES" then print('C='..data) end
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
 
        --Temperaturdevices den Status aktualisieren
       if temp ~= 0 and dtype == "Valve" then
           table.insert(commandArray, { ['UpdateDevice'] = otherdevices_idx[name.." (Valve)"]..'|0|'..temp..';'..valve_pos..';0'})
        elseif  temp ~= 0 and dtype == "Thermostat" then
            table.insert(commandArray, { ['UpdateDevice'] = otherdevices_idx[room]..'|0|'..temp})
        end
 
        if smode=="Manual" then
         --Update virtual devices in Domoticz and update MAX! setpoints if necessary
         if Debug=="YES" then print(dtype.."  "..name.."  Setpoint="..setpoint.."  Temp="..temp.."  Valve pos="..valve_pos) end
         if dtype == "Valve" then
            --table.insert(commandArray, { ['UpdateDevice'] = otherdevices_idx[name.." (Valve)"]..'|0|'..temp..';'..valve_pos..';0'})
            if not useWMT and tonumber(otherdevices_svalues[name])~=nil then                                                                      --Use valve to check setpoint mismatch
               setpoint_Domoticz = tonumber(otherdevices_svalues[name])
               ---if name ~= "EcoTaster" and name ~= "Switch-SZ" and name ~= "Switch-WZ" then
                  if setpoint_Domoticz ~= setpoint then
                       print(otherdevices_lastupdate[name])
                       print(age(otherdevices_lastupdate[name]))
                     if otherdevices_lastupdate[name]~=nil and age(otherdevices_lastupdate[name]) > 120 then       --Domoticz thermostat value must be updated
                        table.insert(commandArray, { ['UpdateDevice'] = otherdevices_idx[name]..'|0|'..setpoint})
                        if Debug=="YES" then print("Domoticz setpoint updated") end
                     else                                                                    --Max! setpoint must be updated
                        MaxCmdSend(adr, room_num, "manual", setpoint_Domoticz)
                        if Debug=="YES" then print("MAX!Valve setpoint updated") end
                     end
                  end
               ---end
            end  
        table.insert(commandArray, { ['UpdateDevice'] = otherdevices_idx[name]..'|0|'..valve_pos})    
         elseif dtype == "Thermostat" then
            --table.insert(commandArray, { ['UpdateDevice'] = otherdevices_idx[room]..'|0|'..temp})
            setpoint_Domoticz = tonumber(otherdevices_svalues[name])
            if setpoint_Domoticz ~= setpoint then
               print(otherdevices_lastupdate[name])
               print(age(otherdevices_lastupdate[name]))
               if otherdevices_lastupdate[name]~=nil and age(otherdevices_lastupdate[name]) > 120 then             --Domoticz thermostat value must be updated
                   table.insert(commandArray, { ['UpdateDevice'] = otherdevices_idx[name]..'|0|'..setpoint})
                   if Debug=="YES" then print("Domoticz setpoint updated") end
               else                                                                         --Max! setpoint must be updated
                   MaxCmdSend(adr, room_num, "manual", setpoint_Domoticz)
                   if Debug=="YES" then print("MAX!WMT setpoint updated") end
               end
            end
         end
      end   
      dtype=""
      name=""
      setpoint=""
      temp=""
      valve_pos=""
      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
----------------------------------------------------------------------------------------------------------
commandArray = {}
    local m = os.date('%M')
    if (m % 2 == 0) then
        --print("The 3 minute script interval reached")
       tcp = Socket.connect(MaxIP, MaxPort)
 
       if not tcp then
          print("MAX! Socket connect failed for "..MaxIP..':'..MaxPort)
          return
       end
 
       tcp:settimeout(2)
       local time = os.date("*t")
 
       while (time.min ~= 0) do
          s, status, partial = tcp:receive()
          if (status) then
             print("MAX! 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
             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()
    end
return commandArray

Re: ELV Max! Heating control system

Posted: Wednesday 02 November 2016 10:53
by blackdog65
Hi Westcott
here it is

Code: Select all

--./script_time_max.lua
----------------------------------------------------------------------------------------------------------
-- Script parameters
----------------------------------------------------------------------------------------------------------
package.loadlib("core.so", "*")
local Socket = require "socket"
local Basexx = require "basexx"
local Rooms = {}
local Devices = {}
local Room_nums = {}

local MaxIP = "192.168.1.131"
local MaxPort = 62910
local useWMT = true             --# Set to true if there is a wall mounted thermostat in every room, then this one will be used for setpoint getting/setting

Debug = "YES"                       --# Turn debugging on ("YES") or off ("NO")
 
----------------------------------------------------------------------------------------------------------
-- Script functions
----------------------------------------------------------------------------------------------------------
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)
   --if Debug=="YES" then print('H='..data) end
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)
   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)
   --if Debug=="YES" then print('C='..data) end
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

        --Temperaturdevices den Status aktualisieren
       if temp ~= 0 and dtype == "Valve" then
           table.insert(commandArray, { ['UpdateDevice'] = otherdevices_idx[name.." (Valve)"]..'|0|'..temp..';'..valve_pos..';0'})
        elseif  temp ~= 0 and dtype == "Thermostat" then
            table.insert(commandArray, { ['UpdateDevice'] = otherdevices_idx[room]..'|0|'..temp})
        end
       
        if smode=="Manual" then
         --Update virtual devices in Domoticz and update MAX! setpoints if necessary
         if Debug=="YES" then print(dtype.."  "..name.."  Setpoint="..setpoint.."  Temp="..temp.."  Valve pos="..valve_pos) end
         if dtype == "Valve" then
            --table.insert(commandArray, { ['UpdateDevice'] = otherdevices_idx[name.." (Valve)"]..'|0|'..temp..';'..valve_pos..';0'})
            if not useWMT and tonumber(otherdevices_svalues[name])~=nil then                                                                      --Use valve to check setpoint mismatch
               setpoint_Domoticz = tonumber(otherdevices_svalues[name])
               ---if name ~= "EcoTaster" and name ~= "Switch-SZ" and name ~= "Switch-WZ" then
                  if setpoint_Domoticz ~= setpoint then
                       print(otherdevices_lastupdate[name])
                       print(age(otherdevices_lastupdate[name]))
                     if otherdevices_lastupdate[name]~=nil and age(otherdevices_lastupdate[name]) > 120 then       --Domoticz thermostat value must be updated
                        table.insert(commandArray, { ['UpdateDevice'] = otherdevices_idx[name]..'|0|'..setpoint})
                        if Debug=="YES" then print("Domoticz setpoint updated") end
                     else                                                                    --Max! setpoint must be updated
                        MaxCmdSend(adr, room_num, "manual", setpoint_Domoticz)
                        if Debug=="YES" then print("MAX!Valve setpoint updated") end
                     end
                  end
               ---end
            end  
        table.insert(commandArray, { ['UpdateDevice'] = otherdevices_idx[name]..'|0|'..valve_pos})    
         elseif dtype == "Thermostat" then
            --table.insert(commandArray, { ['UpdateDevice'] = otherdevices_idx[room]..'|0|'..temp})
            setpoint_Domoticz = tonumber(otherdevices_svalues[name])
            if setpoint_Domoticz ~= setpoint then
               print(otherdevices_lastupdate[name])
               print(age(otherdevices_lastupdate[name]))
               if otherdevices_lastupdate[name]~=nil and age(otherdevices_lastupdate[name]) > 120 then             --Domoticz thermostat value must be updated
                   table.insert(commandArray, { ['UpdateDevice'] = otherdevices_idx[name]..'|0|'..setpoint})
                   if Debug=="YES" then print("Domoticz setpoint updated") end
               else                                                                         --Max! setpoint must be updated
                   MaxCmdSend(adr, room_num, "manual", setpoint_Domoticz)
                   if Debug=="YES" then print("MAX!WMT setpoint updated") end
               end
            end
         end
      end   
      dtype=""
      name=""
      setpoint=""
      temp=""
      valve_pos=""
      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
----------------------------------------------------------------------------------------------------------
commandArray = {}
    local m = os.date('%M')
    if (m % 2 == 0) then
        --print("The 3 minute script interval reached")
       tcp = Socket.connect(MaxIP, MaxPort)
   
       if not tcp then
          print("MAX! Socket connect failed for "..MaxIP..':'..MaxPort)
          return
       end
   
       tcp:settimeout(2)
       local time = os.date("*t")
   
       while (time.min ~= 0) do
          s, status, partial = tcp:receive()
          if (status) then
             print("MAX! 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
             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()
    end
return commandArray
line 131 is where the error occurs

Code: Select all

           table.insert(commandArray, { ['UpdateDevice'] = otherdevices_idx[name.." (Valve)"]..'|0|'..temp..';'..valve_pos..';0'})
Many thanks

Sean

Re: ELV Max! Heating control system

Posted: Wednesday 02 November 2016 11:23
by Westcott
Thanks, both - I'm looking at them.

You are both failing on this command -

table.insert(commandArray, { ['UpdateDevice'] = otherdevices_idx[name.." (Valve)"]..'|0|'..temp..';'..valve_pos..';0'})

so there is no device called name.." (Valve)"

We need to change this bit of code somewhere near line 130 -

--Temperaturdevices den Status aktualisieren
if temp ~= 0 and dtype == "Valve" then

to -

--Temperaturdevices den Status aktualisieren
idx = otherdevices_idx[name.." (Valve)"]
if not idx then
print("No device "..name.." (Valve)")
print(data)
elseif temp ~= 0 and dtype == "Valve" then

I haven't tested it, but what could possibly go wrong?

Re: ELV Max! Heating control system

Posted: Wednesday 02 November 2016 11:35
by mvzut
blackdog65 wrote:line 131 is where the error occurs

Code: Select all

           table.insert(commandArray, { ['UpdateDevice'] = otherdevices_idx[name.." (Valve)"]..'|0|'..temp..';'..valve_pos..';0'})
Many thanks

Sean
I think this error occurs because the script tries to find the IDX of a device named "<valve device name> (Valve)", i.e. it expects the device name to end with " (Valve)". Nowhere else in the Wiki it is stated that this is the required naming scheme, it actually suggests valves to end with "-Rad".
Since this device probably doesn't exist, it also cannot find the IDX, and returns nil. And LUA cannot concatenate strings where one of the composing elements has a nil value.
I need to dive into it deeper to see how to solve this error is, but I actually think this line is obsolete: it is apparently intended to update a combined percentage/temeprature sensor to represent the status of a valve, where further down the script other devices are already updated for the temperature and the valve percentage separately.

Re: ELV Max! Heating control system

Posted: Wednesday 02 November 2016 11:59
by blackdog65
Ah!
So the solution may be as simple as changing "valve" to "rad" or deleting function altogether. Great news!

Thanks for the continued help ans support guys.

As soon as we iron this out I'll update the wiki too

Sean

Re: ELV Max! Heating control system

Posted: Wednesday 02 November 2016 21:37
by jmbjmbjmb
After reading the wiki (great work, by the way), I am assuming that each and every room must have a wall thermostat. Is that correct ?
I believe that MaxBuddy was able somehow (and maybe in a quite unreliable way) to pull the current temperature right from the thermostat (i.e., without any wall thermostat). Is the code implementing this method too ?

Thanks

Re: ELV Max! Heating control system

Posted: Wednesday 02 November 2016 21:51
by blackdog65
latest scrip_time_max.lua has a variable for with/without stat
:D

Re: ELV Max! Heating control system

Posted: Wednesday 02 November 2016 22:18
by jmbjmbjmb
Thanks. I will try that now.
Just a question about the nameing scheme.
In a particular room, I do have 2 radiators.
So, if that room is called "Salon", I can't have two radiators named "Salon-Rad" (the max app wont allow that anyways..).
Any clue ?

Re: ELV Max! Heating control system

Posted: Wednesday 02 November 2016 22:28
by blackdog65
I'd suggest "Salon1-Rad" and "Salon2-Rad"
Although that sounds like you have 2 salons :)

Re: ELV Max! Heating control system

Posted: Wednesday 02 November 2016 22:37
by jmbjmbjmb
I've done pretty much that.
When running the test script I am getting:

Code: Select all

Rooms
-----
Alienor 08F556
Cuisine
       	0B0442
Salon   08F541
Garcons 08F6D7
Couloir 08F616

Devices
-------
Salon-Stat	09B650
Alienor-Rad	08F556
Cuisine-Rad	0B0442
Salon-rue-Rad	08F6D4
Salon-jardin-Rad	08F541
Couloir-Rad	08F616
Garcon-Rad	08F6D7

Device status
-------------
lua: maxtest.lua:91: attempt to index global 'bit32' (a nil value)
stack traceback:
	maxtest.lua:91: in function 'maxCmd_L'
	maxtest.lua:148: in main chunk
	[C]: ?

Re: ELV Max! Heating control system

Posted: Wednesday 02 November 2016 22:43
by Skippiemanz
Try SalonRue-Rad and SalonJardin-Rad

Re: ELV Max! Heating control system

Posted: Wednesday 02 November 2016 22:48
by jmbjmbjmb
Just did, now I am getting this (I can uncomment the debug lines to print the Max Messages if that helps debugging):

Code: Select all

Rooms
-----
Alienor 08F556
Cuisine
       	0B0442
Salon   08F541
Garcons 08F6D7
Couloir 08F616

Devices
-------
Salon-Stat	09B650
Alienor-Rad	08F556
Cuisine-Rad	0B0442
SalonRue-Rad	08F6D4
SalonJardin-Rad	08F541
Couloir-Rad	08F616
Garcon-Rad	08F6D7

Device status
-------------
lua: maxtest.lua:91: attempt to index global 'bit32' (a nil value)
stack traceback:
	maxtest.lua:91: in function 'maxCmd_L'
	maxtest.lua:148: in main chunk
	[C]: ?

Re: ELV Max! Heating control system

Posted: Wednesday 02 November 2016 22:58
by Skippiemanz
Can you try alienor-room, cuisine-room and so on?

Re: ELV Max! Heating control system

Posted: Wednesday 02 November 2016 23:08
by jmbjmbjmb
Nothing in the code is expecting the "room" string in rooms names so I am not expecting this change to make a difference.
The rooms names in the wiki example are "Sitting Room", "Kitchen" (note that this one does not have "room" in it) and "Another Room".
None of the code checks for "-Rad" or "Stat" either.
So while this may matter once running this from domoticz, it should have no impact when simply running the lua code.
In case that helps finding out what one of the expected value is 'nil', I ma pasting the output including the debug prints that show the messages:

Code: Select all

lua maxtest.lua
H=JEQ0543318,03f77a,0113,00000000,5e12eb04,2a,32,100b02,1707,03,0000
Rooms
-----
Alienor 08F556
Cuisine
       	0B0442
Salon   08F541
Garcons 08F6D7
Couloir 08F616

Devices
-------
Salon-Stat	09B650
Alienor-Rad	08F556
Cuisine-Rad	0B0442
SalonRue-Rad	08F6D4
SalonJardin-Rad	08F541
Couloir-Rad	08F616
Garcon-Rad	08F6D7
C=03f77a,7QP3egATAf9KRVEwNTQzMzE4AQsABEAAAAAAAAAAAP///////////////////////////wsABEAAAAAAAAAAQf///////////////////////////2h0dHA6Ly93d3cubWF4LXBvcnRhbC5lbHYuZGU6ODAvY3ViZQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAENFVAAACgADAAAOEENFU1QAAwACAAAcIA==
C=0b0442,0gsEQgICEABLRVEwNTcxNzk4JiE9CQcYAzAM/wBESE0URSBFIEUgRSBFIEUgRSBFIEUgRSBFIERITRRFIEUgRSBFIEUgRSBFIEUgRSBFIEUgREhNFEUgRSBFIEUgRSBFIEUgRSBFIEUgRSBESE0URSBFIEUgRSBFIEUgRSBFIEUgRSBFIERITRRFIEUgRSBFIEUgRSBFIEUgRSBFIEUgREhNFEUgRSBFIEUgRSBFIEUgRSBFIEUgRSBESE0URSBFIEUgRSBFIEUgRSBFIEUgRSBFIA==
C=08f6d7,0gj21wIDEP9LRVEwNTcwOTAzJiE9CQcYAzAM/wBESE0URSBFIEUgRSBFIEUgRSBFIEUgRSBFIERITRRFIEUgRSBFIEUgRSBFIEUgRSBFIEUgREhNFEUgRSBFIEUgRSBFIEUgRSBFIEUgRSBESE0URSBFIEUgRSBFIEUgRSBFIEUgRSBFIERITRRFIEUgRSBFIEUgRSBFIEUgRSBFIEUgREhNFEUgRSBFIEUgRSBFIEUgRSBFIEUgRSBESE0URSBFIEUgRSBFIEUgRSBFIEUgRSBFIA==
C=08f616,0gj2FgIFEP9LRVEwNTY5OTA3JiE9CQcYAzAM/wBESE0URSBFIEUgRSBFIEUgRSBFIEUgRSBFIERITRRFIEUgRSBFIEUgRSBFIEUgRSBFIEUgREhNFEUgRSBFIEUgRSBFIEUgRSBFIEUgRSBESE0URSBFIEUgRSBFIEUgRSBFIEUgRSBFIERITRRFIEUgRSBFIEUgRSBFIEUgRSBFIEUgREhNFEUgRSBFIEUgRSBFIEUgRSBFIEUgRSBESE0URSBFIEUgRSBFIEUgRSBFIEUgRSBFIA==
C=08f6d4,0gj21AIBEABLRVEwNTcwOTA2JiE9CQcYAzAM/wBESE0URSBFIEUgRSBFIEUgRSBFIEUgRSBFIERITRRFIEUgRSBFIEUgRSBFIEUgRSBFIEUgREhNFEUgRSBFIEUgRSBFIEUgRSBFIEUgRSBESE0URSBFIEUgRSBFIEUgRSBFIEUgRSBFIERITRRFIEUgRSBFIEUgRSBFIEUgRSBFIEUgREhNFEUgRSBFIEUgRSBFIEUgRSBFIEUgRSBESE0URSBFIEUgRSBFIEUgRSBFIEUgRSBFIA==
C=09b650,zgm2UAMBEP9LRVEwODYzNzAwJiE9CURITRRFIEUgRSBFIEUgRSBFIEUgRSBFIEUgREhNFEUgRSBFIEUgRSBFIEUgRSBFIEUgRSBESE0URSBFIEUgRSBFIEUgRSBFIEUgRSBFIERITRRFIEUgRSBFIEUgRSBFIEUgRSBFIEUgREhNFEUgRSBFIEUgRSBFIEUgRSBFIEUgRSBESE0URSBFIEUgRSBFIEUgRSBFIEUgRSBFIERITRRFIEUgRSBFIEUgRSBFIEUgRSBFIEUgBxgw
C=08f541,0gj1QQIBEP9LRVEwNTY5NjkzJiE9CQcYAzAM/wBESE0URSBFIEUgRSBFIEUgRSBFIEUgRSBFIERITRRFIEUgRSBFIEUgRSBFIEUgRSBFIEUgREhNFEUgRSBFIEUgRSBFIEUgRSBFIEUgRSBESE0URSBFIEUgRSBFIEUgRSBFIEUgRSBFIERITRRFIEUgRSBFIEUgRSBFIEUgRSBFIEUgREhNFEUgRSBFIEUgRSBFIEUgRSBFIEUgRSBESE0URSBFIEUgRSBFIEUgRSBFIEUgRSBFIA==
C=08f556,0gj1VgIEEABLRVEwNTY5NzE0KyE9CQcYAzAM/wBESE0URSBFIEUgRSBFIEUgRSBFIEUgRSBFIERITRRFIEUgRSBFIEUgRSBFIEUgRSBFIEUgREhNFEUgRSBFIEUgRSBFIEUgRSBFIEUgRSBESE0URSBFIEUgRSBFIEUgRSBFIEUgRSBFIERITRRFIEUgRSBFIEUgRSBFIEUgRSBFIEUgREhNFEUgRSBFIEUgRSBFIEUgRSBFIEUgRSBESE0URSBFIEUgRSBFIEUgRSBFIEUgRSBFIA==

Device status
-------------
lua: maxtest.lua:91: attempt to index global 'bit32' (a nil value)
stack traceback:
	maxtest.lua:91: in function 'maxCmd_L'
	maxtest.lua:148: in main chunk
	[C]: ?

Re: ELV Max! Heating control system

Posted: Wednesday 02 November 2016 23:19
by jmbjmbjmb
Basically the code that throws the error is:

Code: Select all

      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)
I've added the following to understand why this getting 'nil'

Code: Select all

print("valve_info for "..pos.." out of "..L_len)
print(valve_info)
Output is:

Code: Select all

Device status
-------------
valve_info for 1 out of 170
25
lua: maxtest.lua:93: attempt to index global 'bit32' (a nil value)
stack traceback:
	maxtest.lua:93: in function 'maxCmd_L'
	maxtest.lua:150: in main chunk
	[C]: ?
As the decimal value is 25, the binary is:
00011001
and if I get the code right then it should feed batt, bst and mode respectively with 1, 1 and 00
so I'm not sure why I am getting this error message.

Re: ELV Max! Heating control system

Posted: Thursday 03 November 2016 0:07
by jmbjmbjmb
Found the issue. I had lua 5.1 which does not have bit32.

Re: ELV Max! Heating control system

Posted: Thursday 03 November 2016 8:47
by blackdog65
:lol: @jmbjmbjmb
jmbjmbjmb wrote:Found the issue. I had lua 5.1 which does not have bit32.
"DOH! Don't you just hate it when that happens? Good catch. Is everything else working now?

@mvzut & Westcott the "attempt to concatenate field '?' (a nil value)" issue occurs when a wall stat has a "Valve pos=0" reading.
So... is

Code: Select all

--Temperaturdevices den Status aktualisieren
idx = otherdevices_idx[name.." (Valve)"]
if not idx then
print("No device "..name.." (Valve)")
print(data)
elseif temp ~= 0 and dtype == "Valve" then
the cure? Not questioning your skills, just wanted confirmation before trying... as it's f***ing FREEZING here today! :shock:

Re: ELV Max! Heating control system

Posted: Thursday 03 November 2016 9:04
by blackdog65
Erm... no

Code: Select all

 2016-11-03 08:02:00.861 LUA: No device SittingRoom-Stat (Valve)
2016-11-03 08:02:00.861 LUA: DBNwNQkSGQEoAAAAzQwU7Z0JElkBJgAAAL0LE4YvCRIZACgAzQALE4ZeCRIZACIAAAALFVXz8RoZACIAtwALDrjoCRIZZCgAAAAMFPDNCRIZASgAAAC1DBNwhAkSGQEiAAAArQ==
2016-11-03 08:02:00.861 LUA: Thermostat SittingRoom-Stat Setpoint=20 Temp=20.5 Valve pos=-1
2016-11-03 08:02:00.861 LUA: No device V-Bed-Stat (Valve)
2016-11-03 08:02:00.862 LUA: DBNwNQkSGQEoAAAAzQwU7Z0JElkBJgAAAL0LE4YvCRIZACgAzQALE4ZeCRIZACIAAAALFVXz8RoZACIAtwALDrjoCRIZZCgAAAAMFPDNCRIZASgAAAC1DBNwhAkSGQEiAAAArQ==
2016-11-03 08:02:00.862 LUA: Thermostat V-Bed-Stat Setpoint=19 Temp=18.9 Valve pos=-1
2016-11-03 08:02:00.862 LUA: No device SittingRoom-Rad (Valve)
2016-11-03 08:02:00.862 LUA: DBNwNQkSGQEoAAAAzQwU7Z0JElkBJgAAAL0LE4YvCRIZACgAzQALE4ZeCRIZACIAAAALFVXz8RoZACIAtwALDrjoCRIZZCgAAAAMFPDNCRIZASgAAAC1DBNwhAkSGQEiAAAArQ==
2016-11-03 08:02:00.862 LUA: Valve SittingRoom-Rad Setpoint=20 Temp=20.5 Valve pos=0
2016-11-03 08:02:00.862 LUA: No device Z-Bed-Rad (Valve)
2016-11-03 08:02:00.862 LUA: DBNwNQkSGQEoAAAAzQwU7Z0JElkBJgAAAL0LE4YvCRIZACgAzQALE4ZeCRIZACIAAAALFVXz8RoZACIAtwALDrjoCRIZZCgAAAAMFPDNCRIZASgAAAC1DBNwhAkSGQEiAAAArQ==
2016-11-03 08:02:00.862 LUA: Valve Z-Bed-Rad Setpoint=17 Temp=0 Valve pos=0
2016-11-03 08:02:00.863 LUA: No device V-Bed-Rad (Valve)
2016-11-03 08:02:00.863 LUA: DBNwNQkSGQEoAAAAzQwU7Z0JElkBJgAAAL0LE4YvCRIZACgAzQALE4ZeCRIZACIAAAALFVXz8RoZACIAtwALDrjoCRIZZCgAAAAMFPDNCRIZASgAAAC1DBNwhAkSGQEiAAAArQ==
2016-11-03 08:02:00.863 LUA: Valve V-Bed-Rad Setpoint=17 Temp=18.3 Valve pos=0
2016-11-03 08:02:00.863 LUA: No device Kitchen-Rad (Valve)
2016-11-03 08:02:00.863 LUA: DBNwNQkSGQEoAAAAzQwU7Z0JElkBJgAAAL0LE4YvCRIZACgAzQALE4ZeCRIZACIAAAALFVXz8RoZACIAtwALDrjoCRIZZCgAAAAMFPDNCRIZASgAAAC1DBNwhAkSGQEiAAAArQ==
2016-11-03 08:02:00.864 LUA: Valve Kitchen-Rad Setpoint=20 Temp=0 Valve pos=100
2016-11-03 08:02:00.864 LUA: No device Kitchen-Stat (Valve)
2016-11-03 08:02:00.864 LUA: DBNwNQkSGQEoAAAAzQwU7Z0JElkBJgAAAL0LE4YvCRIZACgAzQALE4ZeCRIZACIAAAALFVXz8RoZACIAtwALDrjoCRIZZCgAAAAMFPDNCRIZASgAAAC1DBNwhAkSGQEiAAAArQ==
2016-11-03 08:02:00.864 LUA: Thermostat Kitchen-Stat Setpoint=20 Temp=18.1 Valve pos=-1
2016-11-03 08:02:00.864 LUA: No device Z-Bed-Stat (Valve)
2016-11-03 08:02:00.864 LUA: DBNwNQkSGQEoAAAAzQwU7Z0JElkBJgAAAL0LE4YvCRIZACgAzQALE4ZeCRIZACIAAAALFVXz8RoZACIAtwALDrjoCRIZZCgAAAAMFPDNCRIZASgAAAC1DBNwhAkSGQEiAAAArQ==