blackdog65 wrote:My current script is based on the max buddy set up and activates the heating if 2 or more valves are open more than 50%. This works well for me so I plan to cannibalise it to work with your script (if my ability allows).
and it doesn't
I've been going round in circles with this and getting further confused.
I have 2 scripts
Script "A" based on the script written by
l0gic viewtopic.php?f=34&t=841&start=60#p38160
Code: Select all
-- script_time_Heating Valves.lua
-- Version 1.8 26/03/15
-- Script to read the % open of radiator valves
-- All radiator valves are labelled "RV <room name>"
-- search is made for "RV " (Note space) to indicate a radiator valve
-- If found it will be interrogated for % open value
-- Thermostat are named "Stat <room name>" so a search is made for "Sta" to indicate thermostats
-- If found it will be interrogated for temperature value
-- If demand is greater than BoilerOnPercent value then fire up boiler
-- If demand is less than BoilerOnPercent minus HysterysisOffPercent then switch off boiler
-- Preset Values
BoilerOnPercent = 50 -- percentage valve open at which the boiler will be turned on
HysterysisOffPercent = 20 -- percentage below BoilerOnPercent to switch off the boiler
MinValves = 2 -- Number of Valves that need to be open before boiler is turned on
ValvePercentOveride = 99 -- Percentage value of valve open required to override MinValves value (one room is very cold)
HolidayMinTemp = 10 -- Minimum room temperature before boiler is turned on during holiday period
HolidayHysterysisTemp = 2 -- Value to increase house temperature by while in holiday mode if boiler is turned on due to low temperatures
MissingDevicesTime = 3600 -- Value in seconds to allow before reporting a device has not been updated
email = "[email protected]" -- email address for warnings
-- Script Variables
PercentMax = 0
TempMin = 100
ValveCount = 0
MissingDeviceCount = 0
SendAnEmail = false
-- Set printing to log options (true / false)
-- printData = false
printData = false
printDebug = false
-- printDebug = true
-- Get current date & time
t1 = os.time()
local currentDate = os.date("*t"); -- sets up currentDate.[table]
-- (currentDate.year [full], .month [1-12], .day [1-31], .hour [0-23], .min [0-59], .sec [0-59], .wday [0-6 {Sun-Sat}])
sCurrentTime = currentDate.year .. "-" .. currentDate.month .. "-" .. currentDate.day .. " " .. currentDate.hour .. ":" .. currentDate.min .. ":" .. currentDate.sec
function TimeElapsed(s) -- expects date & time in the form of 2010-01-23 12:34:56
year = string.sub(s, 1, 4)
month = string.sub(s, 6, 7)
day = string.sub(s, 9, 10)
hour = string.sub(s, 12, 13)
minutes = string.sub(s, 15, 16)
seconds = string.sub(s, 18, 19)
t1 = os.time()
t2 = os.time{year=year, month=month, day=day, hour=hour, min=minutes, sec=seconds}
difference = os.difftime (t1, t2)
return difference -- in seconds
end
commandArray = {}
-- print blank line in log
if printData == true then
print (" ")
print (" *** Heating Script Output ***")
print (" ")
end
-- Get Data from Radiator Valves
for i, v in pairs(otherdevices) do -- Get all devices in the database
v = i:sub(1,3) -- Grab the first three characters of the device name
if (v == 'RV ') then -- are the first three characters "RV "? If so we have a Radiator Valve
RoomName = i:sub(4) -- Get the rest of the name, which will be the room name
sSetTempValue, sValvePercentOpen = otherdevices_svalues[i]:match("([^;]+);([^;]+)") -- get the valve set Point and the valve % open (Temp, Humidity)
sLastUpdateTime = otherdevices_lastupdate[i]
sElapsedTime = TimeElapsed(otherdevices_lastupdate[i])
message = RoomName .. " valve is open " .. sValvePercentOpen .. " percent " .. " Setpoint temperature is " .. sSetTempValue .. "C" -- for debug
message2 = RoomName .. " last seen " .. sLastUpdateTime .. " Elapsed time " .. sElapsedTime
if printData == true then
print (message)
print (message2)
end
-- check for missing devices
if sElapsedTime > MissingDevicesTime then
SendAnEmail = false
MissingDeviceCount = MissingDeviceCount + 1
end
-- get the % value of the most open Radiator Valve
if tonumber(sValvePercentOpen) > PercentMax then
PercentMax = tonumber(sValvePercentOpen)
end
-- Count the number of valves that are open more than BoilerOnPercent
if tonumber(sValvePercentOpen) >= BoilerOnPercent then
ValveCount = ValveCount + 1
end
end
end
if printData == true then
print (" ")
end
-- Get Data from Thermostats
for i, v in pairs(otherdevices) do -- Get all devices in the database
v = i:sub(1,5) -- Grab the first three characters of the device name
if (v == 'Stat ') then -- are the first five characters "Stat "? If so we have an EQ-3 Thermostat
RoomName = i:sub(6) -- Get the rest of the name, which will be the room name
sTemp = otherdevices_svalues[i] -- get the temperature
sLastUpdateTime = otherdevices_lastupdate[i]
sElapsedTime = TimeElapsed(otherdevices_lastupdate[i])
message = RoomName.." temperature is " .. sTemp .. " Centigrade " -- for debug
message2 = RoomName .. " last seen " .. sLastUpdateTime .. " Elapsed time " .. sElapsedTime
if printData == true then
print(message)
print(message2)
end
-- get the lowest temperature of the thermostats
if tonumber(sTemp) < TempMin then
TempMin = tonumber(sTemp)
end
-- check for missing devices
if sElapsedTime > MissingDevicesTime then
SendAnEmail = true -- change this to false if you do not require emails to be sent
MissingDeviceCount = MissingDeviceCount + 1
end
end
end
if printData == true then
print (" ")
print ("Number of valves open more than " .. BoilerOnPercent .. "% is " .. ValveCount .." valves")
print("Highest valve open value is " .. PercentMax .." percent ")
print("Lowest thermostat reading is " .. TempMin .." Centigrade ")
print (" ")
end
if printData == true then
if (otherdevices['CH_Switch'] == 'On')then
print ("Current state - Boiler is ON ")
else
print ("Current state - Boiler is OFF ")
end
end
-- Check the elapsed time and email if overdue
if (SendAnEmail == true) then
print (" ")
print("Heating Script: missing device email sent to " .. (email) );
notifyString = os.date("Domoticz Alert # The current time is %X on %A Lost contact with " .. MissingDeviceCount .. " Heating script devices, check if Max!Buddy is running. #") .. (email)
commandArray['SendEmail'] = notifyString
end
-- Perform logic
if printDebug == true then
-- view the settings to understand logic performance
print ("PercentMax (" .. PercentMax .. "%) " .. "Boiler On value (" .. BoilerOnPercent .. "%) " .. "Boiler Off value (" .. (BoilerOnPercent - HysterysisOffPercent) .. ")% ")
print ("Number of valves open more than " .. BoilerOnPercent .. "% is " .. ValveCount .." valves. Minimum valves setting " .. MinValves )
print ("Maximum open value " .. PercentMax .. "%" .. " Override value " .. ValvePercentOveride .."%")
print (" ")
end
if (otherdevices['Holiday'] == 'Off')then -- Not on holiday
if (otherdevices['Heating'] == 'On')then -- It's time to heat the house
if (otherdevices['CH_Switch'] == 'Off') then --If a minimum of 'MinValves' valves are on by more that pre-set value BoilerOnPercent
if printDebug == true then
print ("Test passed - Boiler is OFF ")
end
if (PercentMax > BoilerOnPercent) then
if printDebug == true then
print ("Test passed - Radiators are open beyond the threshold ")
end
if (ValveCount >= MinValves) or (BoilerOnPercent >= ValvePercentOveride) then
if printDebug == true then
print ("Test passed - Either multiple valves are open or override count is reached ")
end
commandArray['CH_Switch']='On' -- turn on boiler
if printData == true then
print ("Command sent - Turn ON Boiler ")
end
end
end
end
end
if (PercentMax < (BoilerOnPercent - HysterysisOffPercent) or (ValveCount < MinValves)) and (otherdevices['CH_Switch'] == 'On') then -- If the number of valves open more than BoilerOnPercent minus HysterysisOffPercent
commandArray['CH_Switch']='Off' -- turn off boiler
if printData == true then
print ("Command sent - Turn OFF Boiler ")
end
end
else -- on holiday
if (TempMin <= HolidayMinTemp) and (otherdevices['CH_Switch'] == 'Off') then -- house is very cold
commandArray['CH_Switch']='On' -- turn on boiler
end
if (TempMin >= (HolidayMinTemp + HolidayHysterysisTemp)) and (otherdevices['CH_Switch'] == 'On') then -- house is warm enough
commandArray['CH_Switch']='Off' -- turn on boiler
end
end
if printData == true then
print (" ")
end
return commandArray
This reads the cube, creates devices and controls my heating based on temperature, valve open% and holiday settings. All very clever but relies on maxbuddy and cannot change setpoints.
And the
mvzut script
viewtopic.php?f=34&t=841&start=220#p88647
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
which reads direct without maxbuddy and can change setpoints but doesn't have the heating control.
I've been pulling my hair out trying to see a way to combine the two to create the perfect heating control script. Can any kind soul offer some pointers.
My 1st thought was to strip the "Find devices" part from l0gic's script and get the mvzut script to fill in the missing information... but as a non-coder I over-heated my brain and I'm lucky to still have functioning heating at all!
Please help me!
Sean