print("-------------------") -- Name of Domoticz devices for both RF and temperatur measurements -- The devices must be of an combined type of both humidity and temperature HUMANDTEMP_DEVICES = {'Krypgrund_SV', 'Krypgrund_SO', 'Krypgrund_NO' } -- Outdoor air temperature measured before the dehumidifier DEVICE_OUTDOOR_TEMP = 'Avfuktare_Uteluft_Temp2' -- Name of Domoticz device for both outdoor RF and outdoor temperature HUMANDTEMP_OUTDOOR_DEVICE = 'Ute' -- Processed wet air temperature measured after the dehumidifier DEVICE_PROCESSAIR_TEMP = 'Avfuktare_Processluft_Temp2' -- Inlet dry air temperature measured after the dehumidifier DEVICE_INLETAIR_TEMP = 'Avfuktare_Tilluft_Temp2' -- If the air temperature increase is greater than this limit, -- the dehumidifier will stop until it is manullay started in Domoticz PROCESSAIR_TEMP_MAXINC = 35 INLETAIR_TEMP_MAXINC = 30 -- Max device oldest update in seconds HUMID_DEVICE_TIMEOUT = 5*60 -- Dehumidifier minimum runtime in seconds MIN_RUNTIME = 20*60 -- Dehumidifier minimum runtime in seconds MAX_RUNTIME = 2*60*60 -- Dehumidifier minimum stoptime in seconds MIN_STOPTIME = 60*15 -- Dehumidifier device switch name in Domoticz DEHUMID_DEVICE_SWITCH = 'SWITCH_Avfuktare_Switch' -- User variable, an integer used as an boolean (either 0 or 1) DEHUMID_ISCANCELED = 'Dehumidifier_IsCanceled' -- Max humidity hyesteris in percent MAX_HUMID_HYSTERESIS = 12 -- Min humidity hyesteris in percent MIN_HUMID_HYSTERESIS = - 2 -- Humidity hyesteris time konstant HUMID_HYSTERESIS_KONSTANT = 20 --Name of Domoticz power meter device. --Set to '' if no watt measure device exist DEHUMID_POWER_DEVICE = 'SWITCH_Avfuktare_Power' -- If runtime exceeds this value in seconds, the script checks if dehumidifier is running NO_POWERTEST_TIME = 5*60 -- FUNCTIONS START -- --integer converts a float into an integer function integer(x) return x<0 and math.ceil(x) or math.floor(x) end -- deviceToTime returns a device time string in a format which can be used by the os.difftime function function deviceToTime(time) return os.time { year = string.sub(time, 1, 4), month = string.sub(time, 6, 7), day = string.sub(time, 9, 10), hour = string.sub(time, 12, 13), min = string.sub(time, 15, 16), sec = string.sub(time, 18, 19) } end -- calcDeHumidLevel calucates the RF level for a certain temperature -- If the RF is higher then returned value, dehumidification shall be done -- A safety margin of five percent is added function calcDeHumidLevel(temp) local humidityThreshold if (temp < 0) then humidityThreshold = 100 elseif (temp > 22) then humidityThreshold = 79 - 5 else humidityThreshold = integer(-0.0015 * temp ^ 3+0.1193 * temp ^ 2 - 2.9878 * temp + 102.96) - 5 if (humidityThreshold > 100) then humidityThreshold = 100 elseif (humidityThreshold < 0) then humidityThreshold = 0 end end return humidityThreshold end -- secsToClock return a string representing seconds as (DD:)HH:MM:SS function secsToClock(seconds) if ((seconds == 0) or (seconds == nil) ) then return "00:00:00" else days = integer(seconds / (60 * 60 * 24)) hours = integer((seconds - days * 60 * 60 * 24) / (60 * 60)) mins = integer((seconds - days * 60 * 60 * 24 - hours * 60 * 60) / 60) secs = seconds - days * 60 * 60 * 24 - hours * 60 * 60 - mins * 60; if (days > 99) then return string.format("%03d:%02d:%02d:%02d (DDD:HH:MM:SS)", days, hours, mins, secs) elseif (days > 0) then return string.format("%02d:%02d:%02d:%02d (DD:HH:MM:SS)", days, hours, mins, secs) else return string.format("%02d:%02d:%02d (HH:MM:SS)", hours, mins, secs) end end end -- Print informaiton about humitiy and temperatur and other values function printHumidity(device, currentTemperature, currentHumidity, humidityThreshold) delta = humidityThreshold - currentHumidity -- Fetch outdoor sensor humidity outDoorHum = getHumidityFromDevice(HUMANDTEMP_OUTDOOR_DEVICE) if (outDoorHum ~= nil) then -- OTD = OuTdoor Differense print(string.format("Device %s: %04.1fC, %2d%%, Th = %02d%% (%d%%), OTD = %02d%%, ThOTD = %02d%%", device, currentTemperature, currentHumidity, humidityThreshold, delta, outDoorHum-currentHumidity, outDoorHum-humidityThreshold)) else print(string.format("Device %s: %04.1fC, %2d%%, Th = %02d%% (%d%%)", device, currentTemperature, currentHumidity, humidityThreshold, delta)) end end -- Get humidifier switch state function getDehumidifierSwitchState() if (otherdevices[DEHUMID_DEVICE_SWITCH] ~= nil) then return otherdevices[DEHUMID_DEVICE_SWITCH] else print("Warning! Cannot read from otherdevices['"..DEHUMID_DEVICE_SWITCH.."']") return "Unknown" end end -- Get dehumidifiers run time function getRunTime() if (getDehumidifierSwitchState() == "On") then return os.difftime(os.time(), getDeviceLastUpdated(DEHUMID_DEVICE_SWITCH)) else return 0 end end -- Get the dehumidifer stop time function getStopTime() if (getDehumidifierSwitchState() == "Off") then return os.difftime(os.time(), getDeviceLastUpdated(DEHUMID_DEVICE_SWITCH)) else return 0 end end -- Get the last time a device was updated in Domoticz function getDeviceLastUpdated(device) if (otherdevices_lastupdate[device] ~= nil) then return deviceToTime(otherdevices_lastupdate[device]) else return 0 end end -- Get temperature value from a temperature device in Domoticz function getTempFromDevice(device) if (otherdevices_temperature[device] ~= nil) then return tonumber(otherdevices_temperature[device]) else print("Warning! Cannot read temp device "..device) return nil end end -- Get humidity value from a humidity device in Domoticz function getHumidityFromDevice(device) if (otherdevices_humidity[device] ~= nil) then return tonumber(otherdevices_humidity[device]) else print("Warning! Cannot read humid device "..device) return nil end end -- Get the dehumidifer power in getDehumidifierWatts() function getDehumidifierWatts() if ((DEHUMID_POWER_DEVICE ~= '') and (otherdevices_svalues[DEHUMID_POWER_DEVICE] ~= nil)) then return integer(tonumber(otherdevices_svalues[DEHUMID_POWER_DEVICE])) else print("Warning! Cannot read power from device "..DEHUMID_POWER_DEVICE) return nil end end -- ca dehumidifier state as true or false function setDehumidifierState(state) if ((state == true) or (state == false)) then commandArray['Variable:'..DEHUMID_ISCANCELED] = (state == true and "1" or "0") else print("Error in param to setDehumidifierState, unknown state") end end -- Check if dehumidfier is canceled function isDehumidifierCanceled() if (commandArray['Variable:'..DEHUMID_ISCANCELED] ~= nil) then return (commandArray['Variable:'..DEHUMID_ISCANCELED] == "1" and true or false) elseif (uservariables[DEHUMID_ISCANCELED] ~= nil) then return (uservariables[DEHUMID_ISCANCELED] == "1" and true or false) else print("Warning! Cannot read user variable "..DEHUMID_ISCANCELED) return nil end end -- Calculate the hysteris between dehumidfication start and stop -- Hystersis is decreasing as a function of runtime function calcHysteresis(temp) return (MAX_HUMID_HYSTERESIS - MIN_HUMID_HYSTERESIS) / ((getRunTime() / 60) * (1 / HUMID_HYSTERESIS_KONSTANT) + 1) + MIN_HUMID_HYSTERESIS end -- END OF FUNCTIONS -- commandArray = {} now = os.time() -- Check if dehumidifer switch is off if (getDehumidifierSwitchState() == "Off") then -- Do checks if dehumidifier is not canceled if (isDehumidifierCanceled() == false) then --Check all humid devices local start = false for key,device in pairs(HUMANDTEMP_DEVICES) do temp = getTempFromDevice(device) hum = getHumidityFromDevice(device) -- Only use working devices which has not old values if ((temp ~= nil) and (hum ~= nil) and (os.difftime(now, getDeviceLastUpdated(device)) < HUMID_DEVICE_TIMEOUT)) then startDehumidify = calcDeHumidLevel(temp) if (hum >= startDehumidify) then start = true end printHumidity(device, temp, hum, startDehumidify) else print("Has no updates for device "..device) print("Last seen "..device.." "..secsToClock(getDeviceLastUpdated(device))) end end -- Start if at least one device has triggered a start if (start == true) then -- Only start if MIN_STOPTIME has been reached if (os.difftime(now, getDeviceLastUpdated(DEHUMID_DEVICE_SWITCH)) > MIN_STOPTIME) then print("Starting dehumidification") commandArray[DEHUMID_DEVICE_SWITCH] = "On" return commandArray else print("Dehumidifier has not yet reached minimun stoptime which is "..secsToClock(MIN_RUNTIME)..". Time left is "..secsToClock(MIN_STOPTIME-getStopTime())) end else -- No devices has reached start dehumid level. -- Let's instead do some checks to see if humidifier is really stopped if (getDehumidifierWatts() ~= nil) then -- If device reports power after dehumidifier has been stopped, it is apperently not stopped. if ((getDehumidifierWatts() > 10) and (getStopTime() > NO_POWERTEST_TIME)) then print("Dehumidifier shouldn't be running") print("Stopping Dehumidifier") commandArray[DEHUMID_DEVICE_SWITCH] = "Off" return commandArray else print("Dehumidifier is not running") print("Dehumidifier stoptime is "..secsToClock(getStopTime())) end end end -- Do some checks if dehumidifier is canceled (and dehumidifier switch is off) elseif (isDehumidifierCanceled() == true) then if (getDehumidifierWatts() ~= nil) then -- If device reports power when it is canceled it is not stopped if ((getDehumidifierWatts() > 10)) then print("Dehumidifier is canceled and switch is turned off, but it is still running") print("Stopping Dehumidifier") commandArray[DEHUMID_DEVICE_SWITCH] = "Off" return commandArray else print("Dehumidifier is canceled and cannot be automatically started.") print("Dehumidifier stop time is "..secsToClock(getStopTime())) end end end -- Check if dehumidifer switch is on elseif (getDehumidifierSwitchState() == "On") then -- Do checks if dehumidifier is not canceled if (isDehumidifierCanceled() == false) then outdoorTemp = getTempFromDevice(DEVICE_OUTDOOR_TEMP) processAirTemp = getTempFromDevice(DEVICE_PROCESSAIR_TEMP) inletAirTemp = getTempFromDevice(DEVICE_INLETAIR_TEMP) -- First lets do some checks to see if all temperature is within boundaries -- If not, stop dehumidifier! if (outdoorTemp == nil) then commandArray[DEHUMID_DEVICE_SWITCH] = "Off" print(string.format("Temperature device %s is not available. Last value was set %s", DEVICE_OUTDOOR_TEMP, os.date("%Y-%m-%d %H:%M:%S", getDeviceLastUpdated(DEVICE_OUTDOOR_TEMP)))) print("Canceling dehumidification. Dehumidifier must be manually started") setDehumidifierState(true) return commandArray elseif (processAirTemp == nil) then commandArray[DEHUMID_DEVICE_SWITCH] = "Off" print(string.format("Temperature device %s is not available. Last value was set %s", DEVICE_PROCESSAIR_TEMP, os.date("%Y-%m-%d %H:%M:%S", getDeviceLastUpdated(DEVICE_PROCESSAIR_TEMP)))) print("Canceling dehumidification. Dehumidifier must be manually started") setDehumidifierState(true) return commandArray elseif (inletAirTemp == nil) then commandArray[DEHUMID_DEVICE_SWITCH] = "Off" print(string.format("Temperature device %s is not available. Last value was set %s", DEVICE_INLETAIR_TEMP, os.date("%Y-%m-%d %H:%M:%S", getDeviceLastUpdated(DEVICE_INLETAIR_TEMP)))) print("Canceling dehumidification. Dehumidifier must be manually started") setDehumidifierState(true) return commandArray elseif ((processAirTemp - outdoorTemp) > PROCESSAIR_TEMP_MAXINC) then commandArray[DEHUMID_DEVICE_SWITCH] = "Off" print(string.format("Temperature delta, %2f, over dehumdifiers process air is greater than threshold %2f. Stopping dehumdifier for safety reasons", processAirTemp - outdoorTemp, PROCESSAIR_TEMP_MAXINC)) print("Canceling dehumidification. Dehumidifier must be manually started") setDehumidifierState(true) return commandArray elseif ((inletAirTemp - outdoorTemp) > INLETAIR_TEMP_MAXINC) then commandArray[DEHUMID_DEVICE_SWITCH] = "Off" print(string.format("Temperature delta, %2f, over dehumdifiers inlet air is greater than the threshold %2f. Stopping dehumdifier for safety reasons", inletAirTemp - outdoorTemp, INLETAIR_TEMP_MAXINC)) print("Canceling dehumidification. Dehumidifier must be manually started") setDehumidifierState(true) return commandArray end -- Check if runtime exceed maximum runtime if (getRunTime() > MAX_RUNTIME) then commandArray[DEHUMID_DEVICE_SWITCH] = "Off" print(string.format("Dehumidifier runtime %s exceed maximun runtime of %s. Stopping dehumidification.", secsToClock(getRunTime()), secsToClock(MAX_RUNTIME))) return commandArray end --Check all humid devices local stop = true local hysteresis = calcHysteresis() print(string.format("Dehumid hysteris for runtime %s is %-3.2f", secsToClock(getRunTime()), hysteresis)) for key,device in pairs(HUMANDTEMP_DEVICES) do temp = getTempFromDevice(device) hum = getHumidityFromDevice(device) -- Only use working devices which has not old values if ((temp ~= nil) and (hum ~= nil) and (os.difftime(now, deviceToTime(otherdevices_lastupdate[device])) < HUMID_DEVICE_TIMEOUT)) then stopDehumidify = calcDeHumidLevel(temp) - hysteresis if (hum > stopDehumidify) then stop = false end printHumidity(device, temp, hum, stopDehumidify) else print("Has no updates for device "..device) print("Last seen "..device.." "..secsToClock(getDeviceLastUpdated(device))) end end -- Stop if at least one humid device has triggered a stop if (stop == true) then -- check if MIN_RUNTIME has been reached if (getRunTime() > MIN_RUNTIME) then print("Stopping dehumidification") commandArray[DEHUMID_DEVICE_SWITCH] = "Off" return commandArray else print("Dehumidifier has not yet reached minimun runtime which is "..secsToClock(MIN_RUNTIME)..". Time left is "..secsToClock(MIN_RUNTIME-getRunTime())) end -- No devices has reached stop dehumid level. -- Let's instead do some checks to see if humidifier is really running elseif (getDehumidifierWatts() ~= nil) then -- If device reports no power NO_POWERTEST_TIME after dehumidifier has been started, it is apperently not running if ((getRunTime() > NO_POWERTEST_TIME) and (getDehumidifierWatts() < 10)) then print("Dehumidifier should be running but isn't") print("Restarting dehumidifier") commandArray[DEHUMID_DEVICE_SWITCH] = "On" -- All is working as it supposed to do elseif (getDehumidifierWatts() > 10) then print(string.format("Dehumidifier is running. Dehumidifier power consumption is %d W", getDehumidifierWatts())) print("Dehumidifier runtime is "..secsToClock(getRunTime())) end end -- Do some checks if dehumidifier is canceled (and dehumidifier switch is on) elseif (isDehumidifierCanceled() == true) then print("Dehumidifier is canceled and switch is turned on") print("Stopping Dehumidifier") commandArray[DEHUMID_DEVICE_SWITCH] = "Off" return commandArray end end -- The possibility to the script to reach down here is very low. But if it is, lets return safely return commandArray