Skrev ihop ett LUA-skript för att råda bot på detta. Skriptet körs varje minut i Domoticz som uppdaterar en "device" i Domoticz för både temperatur och fuktighet.
Skriptet konfigurerar också hubben så att alla portar öppnas.
Kod: Markera allt
-- OWFS path
OWFS_PATH = "/mnt/1wire/uncached"
OWFS_DEVICES = {
['26.160592010000'] = 'Krypgrund_SO',
['26.740592010000'] = 'Krypgrund_SV',
['26.802692010000'] = 'Krypgrund_NO'
}
-- Onewire hub file
ONEWIRE_HUB_CONFIG_FILE = "/mnt/1wire/uncached/EF.117120150000/hub/branch.BYTE"
ONEWIRE_HUB_PORT_CONFIG_VALUE = "15"
-- Cache file dir
OWFS_CACHEPATH = '/tmp'
-- Set how many readings in buffer
OWFS_BUFFERSIZE = 10
-- 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
local function ReadFile(path)
local file = io.open(path, "rb") -- r read mode and b binary mode
if not file then
return nil
end
local content = file:read "*a" -- *a or *all reads the whole file
file:close()
return content
end
local function WriteFile(path, content)
local file = io.open(path, "wb") -- w write mode and b binary mode
if not file then
return nil
end
file:write(content)
file:close()
end
local function ReadOWFS(device, filename, stop)
value = ReadFile(string.format("%s/%s/%s", OWFS_PATH, device, filename))
if (value ~= nil) then
return value
else
-- Check if hub is configured with uncorrect value
fileContent = ReadFile(ONEWIRE_HUB_CONFIG_FILE)
if (fileContent ~= ONEWIRE_HUB_PORT_CONFIG_VALUE) then
WriteFile(ONEWIRE_HUB_CONFIG_FILE, ONEWIRE_HUB_PORT_CONFIG_VALUE)
print("-------------------")
print("Onewire hub reconfigured")
end
end
return nil
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(OWFS_temp)
if (OWFS_temp > 22) then
return 79 - 5
else
humid = integer(-0.0015*OWFS_temp^3+0.1193*OWFS_temp^2-2.9878*OWFS_temp+102.96) - 5
if (humid > 100) then
humid = 100
end
return humid
end
end
-- secsToClock return a string representing seconds as 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
-- Implode a string into a table using delimiter
function ImplodeTable(delimiter, list)
local len = #list
if len == 0 then
return ""
end
local string = list[1]
for i = 2, len do
string = string .. delimiter .. list[i]
end
return string
end
-- Explode a table content into a string, separate fields with a delimiter
function ExplodeTable(delimiter, text, numElements)
local list = {}; local pos = 1
local el = 0
while (el < numElements) do
el = el + 1
local first, last = string.find(text, delimiter, pos)
if (first) then
table.insert(list, string.sub(text, pos, first-1))
pos = last+1
else
table.insert(list, string.sub(text, pos))
break
end
end
return list
end
-- Caculate the mean value of a table
function CalcMeanOnTable(t)
local sum = 0
local count= 0
for k,v in pairs(t) do
if (type(v) ~= 'number') then
v = tonumber(v)
end
if (type(v) == 'number') then
sum = sum + v
count = count + 1
end
end
return (sum/count)
end
-- Calculate the standard deviation of a table
function CalcStandardDeviationOnTable(t)
local m
local vm
local sum = 0
local count = 0
local result
m = CalcMeanOnTable(t)
for k,v in pairs(t) do
if (type(v) ~= 'number') then
v = tonumber(v)
end
if (type(v) == 'number') then
vm = v - m
sum = sum + (vm * vm)
count = count + 1
end
end
return math.sqrt(sum / (count-1))
end
-- Calulates values from OWFS taking care of spikes in OWFS values.
-- Using a file as a buffer and calculation of mean and standard deviation.
-- If the value to be inserted deviates more than the standard deviation from mean value,
-- the standard deviation from the mean value in the buffer is returned instead of the actual value.
-- The actual value is stored in the buffer
function getValue(device, value)
local cache, arr, mean, deviation, allowedDeviation, newValue, elementsInBuffer
-- Read history from cached file content
cache = ReadFile(string.format("%s/%s", OWFS_CACHEPATH, device))
-- If no file found
if (cache == nil) then
cache = ";"
end
-- Explode the file content into array elements
arr = ExplodeTable(";", cache, OWFS_BUFFERSIZE)
-- Calculate
deviation = tonumber(CalcStandardDeviationOnTable(arr))
mean = tonumber(CalcMeanOnTable(arr))
-- The allowed deviation shall not be too small
if (deviation < 0.75) then
allowedDeviation = 0.75
else
allowedDeviation = deviation
end
-- Limit the changes in the buffer
if (value > (mean + allowedDeviation)) then
newValue = mean + allowedDeviation
elseif (value < (mean - allowedDeviation)) then
newValue = mean - allowedDeviation
else
newValue = value
end
-- Insert calulated value last in buffer
table.insert(arr, newValue)
elementsInBuffer = # arr
-- Remove values in front of buffer if buffer size is too big
if ((elementsInBuffer) > OWFS_BUFFERSIZE) then
table.remove(arr,1)
elementsInBuffer = elementsInBuffer - 1
end
-- Write the array into file
WriteFile(string.format("%s/%s", OWFS_CACHEPATH, device), ImplodeTable(";", arr))
return elementsInBuffer, device, deviation, mean, tonumber(CalcMeanOnTable(arr))
end
-- END OF FUNCTIONS --
commandArray = {}
i = 0
for OWFS_device, name in pairs(OWFS_DEVICES) do
-- Read temp and humidity from OWFS
OWFS_temp = ReadOWFS(OWFS_device, "temperature")
OWFS_hum = ReadOWFS(OWFS_device, "humidity")
if ((OWFS_temp ~= nil) and (OWFS_hum ~= nil)) then
OWFS_temp = tonumber(OWFS_temp)
OWFS_hum = tonumber(OWFS_hum)
-- Correct OWFS value
bufferSize, device, deviationTemp, meanTemp, tempValue = getValue(string.format("%s_%s", name, "temp"), OWFS_temp)
print(string.format("%s : Bufsize = %3d, Deviation = %-3.2f, Mean = %-3.2f, OWFS = %-3.2f, Real = %-3.2f, Diff = %-3.2f", device, bufferSize, deviationTemp, meanTemp, OWFS_temp, tempValue, math.abs(OWFS_temp - tempValue)))
-- Correct OWFS value
bufferSize, device, deviationHum, meanHum, humValue = getValue(string.format("%s_%s", name, "hum"), OWFS_hum)
print(string.format("%s : Bufsize = %3d, Deviation = %-3.2f, Mean = %-3.2f, OWFS = %-3.2f, Real = %-3.2f, Diff = %-3.2f", device, bufferSize, deviationHum, meanHum, OWFS_hum, humValue, math.abs(OWFS_hum - humValue)))
-- Calculate the wet level
startDehumidify = calcDeHumidLevel(tempValue)
if (humValue > startDehumidify) then
wet = 3
elseif (humValue > startDehumidify * 0.8) then
wet = 0
else
wet = 2
end
-- Insert values into Domoticz device
commandArray[i] = { ['UpdateDevice'] = string.format("%s|0|%3.2f;%3.2f;%d", otherdevices_idx[name], tempValue, humValue, wet) }
i = i + 1
else
print(string.format("No OWFS readings from device %s, %s: %s:%s", name, OWFS_device, OWFS_temp, OWFS_hum))
end
end
return commandArray