voici les scripts fait en dzVents: 1 pour l'EVP et 1 pour le RFU avec partir des scripts d'aleph0
pour l'EVP
Code : Tout sélectionner
-- Script to estimate potential evapotranspiration according to Penman Monteith formula and FAO-56 method
--
-- 17/12/2021 - inital from https://domoticz.com/forum/viewtopic.php?p=249287#p249287
-- 02/01/2022 - result in a user variable and a counter updated via json to avoid "complication"
-- 12/01/2022 - some fix
-- 29/01/2022 - change RFX counter to increment as result that give abnormal values
-- 18/03/2022 - add a custom sensor to save the EVP no rounded for tracability
-- Weather sensors for EVP
local dev_barometer = 2336 -- Atmospheric pressure (hPa)
local dev_temperature = 2336 -- Outside temperature (°C)
local dev_humidity = 2336 -- Relative humidity (%)
local dev_Rn = 1911 -- Global sun radiation (Lux)
local dev_U = 2338 -- Wind speed (m/s)
local cst_G = 0 -- Thermal flux to the ground (MJ/h/m²)
local cst_h = 5 -- Height of wind speed mesurement (m) !!!
local Cn = 37 -- Hou rly steps...
-- EVP result in mm user variables and device to create w the GUI
local uv_EVP_noRounded = 17 -- Result of the day no rounded in a user variable
local uv_EVP_rounded = 33 -- Result rounded in a user variable
local uv_EVP_deltaNoRounded = 37-- Result delta no rounded in a user variable, resetted by RFU script
local dev_EVP_countIncr = 2476 -- Result rounded for UX in a incremental counter (divider = 10) -- comment if not used
local dev_EVP_custom = 2520 -- Result not rounded for tracking in a custom counter -- comment if not used
local dev_EVP_rain = 2475 -- Result rounded for UX in a rain counter -- comment if not used
-------------
local dev_EVP_countIncrOLD = 2423 -- Result rounded for UX in a incremental counter (divider = 10) -- comment if not used
--------
local TIME_INTERVAL = 'every 5 minutes except at 00:00-01:00' -- issue with counter after 00:00, to limit issue ; not necessary by night
local TEST = 203 -- to uncomment to use: launch the script w/o waiting
local LOG_DEBUG = 0 -- 0 =>ERROR / 1 => FORCE / 2 => DEBUG
local LOG_LEVEL
local LOGGING
if LOG_DEBUG == 2 then
LOGGING = domoticz.LOG_DEBUG
LOG_LEVEL = domoticz.LOG_DEBUG
elseif LOG_DEBUG == 1 then
LOGGING = domoticz.LOG_FORCE
LOG_LEVEL = domoticz.LOG_FORCE
else
LOGGING = domoticz.LOG_ERROR
LOG_LEVEL = domoticz.LOG_INFO
end
return {
logging = { level = LOGGING,
},
on = {
devices = {TEST},
timer = {TIME_INTERVAL}
},
execute = function(dz, item, triggerInfo)
_G.logMarker = dz.moduleLabel -- set logmarker to scriptname
local _u = dz.utils
local openURLAfterSec = 3
local function logWrite(str, level)
if level == nil then level = LOG_LEVEL end
dz.log(tostring(str), level)
end
local function jsonCounter(p_IDX, p_value)
logWrite('IDX= ' .. p_IDX .. ' value= ' .. p_value)
local cmd = '/json.htm?type=command¶m=udevice&idx=' .. p_IDX .. '&svalue=' .. p_value
local url = 'http://127.0.0.1:8080' .. cmd
logWrite('url= ' .. url)
dz.openURL(url).afterSec(openURLAfterSec) -- to avoid error w several openURL at the same time ?
openURLAfterSec = openURLAfterSec + 1
return
end
local function jsonCounterIncr(p_IDX, p_incr)
logWrite('IDX= ' .. p_IDX .. ' incr= ' .. p_incr)
local cmd = '/json.htm?type=command¶m=udevice&idx=' .. p_IDX .. '&nvalue=0&svalue=' .. p_incr
local url = 'http://127.0.0.1:8080' .. cmd
logWrite('url= ' .. url)
dz.openURL(url).afterSec(openURLAfterSec) -- to avoid error w several openURL at the same time ?
openURLAfterSec = openURLAfterSec + 1
return
end
---------------------------
-- reading of sensors
local P = dz.devices(dev_barometer).barometer
local T = dz.devices(dev_temperature).temperature
local Hr = dz.devices(dev_humidity).humidity
local Rn = (dz.devices(dev_Rn).lux) * 0.0079 -- W/m²
local U2 = dz.devices(dev_U).speedMs
local Cd
if dz.time.isDayTime then
Cd=0.24 -- at day
else
Cd=0.96 -- at night
end
--[[
logWrite('P: ' .. P)
logWrite('T: ' .. T)
logWrite('Hr: ' .. Hr)
logWrite('Rn: ' .. Rn)
logWrite('U2: ' .. U2)
logWrite('Cn: ' .. Cn)
logWrite('Cd: ' .. Cd)
logWrite('cst_h:' .. cst_h)
--]]
-- unit convertions
P = P/10 -- must be in kPa
Hr = Hr/100
Rn = Rn/277.77778 -- must be in MJ/h/m²
U2 = U2*4.87/math.log(67.8*cst_h-5.42) -- windspeed at 2m height, in m/s
--[[
logWrite("P': " .. P)
logWrite("Hr': " .. Hr)
logWrite("Rn': " .. Rn)
logWrite("U2': " .. U2)
--]]
-- Intermediates calculations
local Esat = 0.6108*math.exp(17.27*T/(T+237.3)) -- saturated vapor pressure (kPa)
local Ea = Hr*Esat -- current vapor pressure (kPa)
local Delta = 4098*Esat/((T+237.3)^2)
local Gamma = 0.665*P/1000
logWrite("Pressure of saturated vapor: "..Esat.." kPa")
logWrite("Pressure of actual vapor: "..Ea.." kPa")
logWrite("Delta: ".. Delta)
logWrite("Gamma: "..Gamma)
local ET0=(0.408*Delta*(Rn-cst_G)+Gamma*Cn/(T+273)*U2*(Esat-Ea))/(Delta+Gamma*(1+Cd*U2)) -- EVP in mm/h
logWrite("ET0 => ".. ET0 .." mm/h", dz.LOG_FORCE)
---------------------------------------
-- with RFX meter
local lastEVPUpdateInSec, EVP_delta, EVP_prevNoRouded, EVP_prevRounded, EVP_newNoRound, EVP_newRounded, EVP_last, EVP_deltaRounded
lastEVPUpdateInSec = dz.variables(uv_EVP_noRounded).lastUpdate.secondsAgo
logWrite('EVP updated ' .. lastEVPUpdateInSec .. ' sec ago')
EVP_delta = ET0 * lastEVPUpdateInSec / 3600
logWrite('EVP_delta => ' .. EVP_delta .. ' mm', dz.LOG_FORCE)
-- to user variable
local EVP_deltaPrev = dz.variables(uv_EVP_deltaNoRounded).value
logWrite('EVP_deltaPrev => ' .. EVP_deltaPrev .. ' mm', dz.LOG_FORCE)
local EVP_deltaNew = EVP_deltaPrev + EVP_delta
logWrite('EVP_deltaNew => ' .. EVP_deltaNew .. ' mm', dz.LOG_FORCE)
dz.variables(uv_EVP_deltaNoRounded).set(EVP_deltaNew)
if dz.variables(uv_EVP_noRounded).lastUpdate.isToday then
logWrite('Same day')
EVP_prevNoRouded = dz.variables(uv_EVP_noRounded).value
logWrite('EVP_prevNoRouded: ' .. EVP_prevNoRouded)
EVP_newNoRound = EVP_prevNoRouded + EVP_delta
EVP_prevRounded = dz.variables(uv_EVP_rounded).value
logWrite('EVP_prevRounded: ' .. EVP_prevRounded)
else
logWrite('New day')
EVP_newNoRound = EVP_delta
EVP_prevRounded = 0
end
logWrite('EVP => ' .. EVP_newNoRound .. ' mm', dz.LOG_FORCE)
-- to user variable
dz.variables(uv_EVP_noRounded).set(EVP_newNoRound)
-- to custom sensor
if dev_EVP_custom ~= nil then
jsonCounterIncr(dev_EVP_custom, EVP_newNoRound)
end
EVP_newRounded = math.floor(EVP_newNoRound * 10) / 10
logWrite('EVP_newRounded: ' .. EVP_newRounded)
dz.variables(uv_EVP_rounded).set(EVP_newRounded)
-- to a rain counter
if dev_EVP_rain ~= nil then
logWrite('Update rain counter' .. dz.devices(dev_EVP_rain).name)
dz.devices(dev_EVP_rain).updateRain(_u.round(ET0 * 100,3), EVP_newRounded) -- updateRain(rate, counter): Function. (rate in mm * 100 per hour, counter is total in mm)
end
-- to increment counter
if dev_EVP_countIncr ~= nil then
logWrite('Update incr counter' .. dz.devices(dev_EVP_countIncr).name)
EVP_deltaRounded = EVP_newRounded - EVP_prevRounded
logWrite('EVP_deltaRounded: ' .. EVP_deltaRounded)
jsonCounterIncr(dev_EVP_countIncrOLD, EVP_deltaRounded * 10) -- Divider
--dz.devices(dev_EVP_countIncr).updateCounter(EVP_deltaRounded)
jsonCounterIncr(dev_EVP_countIncr, EVP_deltaRounded * 10) -- Divider
end
logWrite("*** FIN ***")
end
}
pour le RFU
Code : Tout sélectionner
--[[
Estimation du RFU
Idée : Toutes les 5 minutes, on fait le bilan
RU=RU+Pluie+arrosage-EVP sur la période précédente, limité en maximum (>320) et minimum (<0)
from https://domoticz.com/forum/viewtopic.php?p=249287#p249287
La variable à créer pour contenir l'humidité s'appelle RFU_RU,
elle varie entre 0 (sol complètement sec, toutes les plantes sont mortes depuis longtemps)
et la constante RUmax, qui dépends de votre sol (dans mon cas 320mm).
Pour initialiser le bilan un jour de grosse pluie,
il suffit de donner manuellement la valeur RUmax à la variable RFU_RU lorsqu'on voit que le sol est saturé.
-- RFU: Réserve Facilement Utilisable ou confort hydrique
ajouter coefficient cultural: https://easydomoticz.com/forum/viewtopic.php?p=69436&sid=6bd466a6a7862e21dee9adc66beaec48#p69436
https://fr.wikipedia.org/wiki/R%C3%A9serve_utile_en_eau_d%27un_sol
https://en.wikipedia.org/wiki/Available_water_capacity
-- 28/12/2021 - initial
--]]
local RU_MAX = 420 --
local wateredSurface = 40 -- m2
-- Actual values updated in other scripts
--local uv_EVP_day = 17 -- user variable for actual EVP (day)
local uv_EVP_deltaNoRounded = 37 -- user variable EVP delta no rounded from EVP script, resetted by RFU script
--local dev_rain = 2334 -- device for actual rain
local uv_rain = 28 -- user variable for rain (day)
local dev_watering1 = 1897 -- device for actual watering 1/2 (pelouse 1)
local dev_watering2 = 1899 -- device for actual watering 2/2 (pelouse 2)
local dev_RU = 2319 -- device for RFU (custom)
local dev_RFU_cb = 2328
-- Values from the previous run (mm) updated in this script
local uv_EVPPrevious = 21 -- user variable for previous EVP
local uv_rainPrevious = 20 -- user variable for previous Rain
local uv_RU = 22 -- user variable for previous RFU
local uv_wateringPrevious = 19 -- user variable for previous Watering
--local TIME_INTERVAL = 'every 5 minutes except at 00:00-01:00' -- issue with counter after 00:00, to limit issue ; not necessary by night
--local TEST = 207 -- a dummy switch to trigger the script w/o waiting (for testing)
local LOG_DEBUG = 2 -- 0 =>ERROR / 1 => FORCE / 2 => DEBUG
local LOG_LEVEL
local LOGGING
if LOG_DEBUG == 2 then
LOGGING = domoticz.LOG_DEBUG
LOG_LEVEL = domoticz.LOG_DEBUG
elseif LOG_DEBUG == 1 then
LOGGING = domoticz.LOG_FORCE
LOG_LEVEL = domoticz.LOG_FORCE
else
LOGGING = domoticz.LOG_ERROR
LOG_LEVEL = domoticz.LOG_INFO
end
return {
logging = {
level = LOGGING
},
on = {
devices = {TEST},
timer = {TIME_INTERVAL},
variables = {uv_EVP_deltaNoRounded}
},
execute = function(dz, item, triggerInfo)
_G.logMarker = dz.moduleLabel -- set logmarker to scriptname
local _u = dz.utils
local function logWrite(str, level)
if level == nil then level = LOG_LEVEL end
dz.log(tostring(str), level)
end
---------------------------
logWrite("*** START ***")
--local EVPActual = _u.round(dz.variables(uv_EVP_day).value, 3)
--local EVPPrevious = dz.variables(uv_EVPPrevious).value
local EVPDelta = dz.variables(uv_EVP_deltaNoRounded).value
logWrite('EVPDelta: ' .. EVPDelta .. ' mm', dz.LOG_FORCE)
--logWrite('EVPActual: ' .. EVPActual .. ' EVPPrevious: ' .. EVPPrevious .. ' mm')
local rainActual
if uv_rain ~= nil then
rainActual = _u.round(dz.variables(uv_rain).value, 3)
elseif dev_rain ~= nil then
rainActual = _u.round(dz.devices(dev_rain).rain, 3)
else
logWrite('rainActual not defined', dz.LOG_ERROR)
end
local newDay = false
if dz.variables(uv_rainPrevious).lastUpdate.isToday then
logWrite('Same day')
else
logWrite('New day')
newDay = true
end
local rainPrevious = _u.round(dz.variables(uv_rainPrevious).value, 3)
logWrite('rainActual: ' .. rainActual .. ' rainPrevious: ' .. rainPrevious .. ' mm')
if rainActual < rainPrevious then
logWrite('rainActual < rainPrevious: ' .. rainActual .. ' < ' .. rainPrevious .. ' mm')
if not newDay then
logWrite('rain data issue ' .. rainActual .. ' < ' .. rainPrevious, dz.LOG_ERROR)
end
rainPrevious = 0
end
local wateringActualVol = _u.round(dz.devices(dev_watering1).counter + dz.devices(dev_watering2).counter, 3)
logWrite('wateringActualVol: ' .. wateringActualVol .. ' m3')
local wateringActualAera = _u.round(wateringActualVol / wateredSurface * 1000, 3) -- to mm in m2
local wateringPreviousArea = _u.round(dz.variables(uv_wateringPrevious).value, 3)
local RUPrevious = _u.round(dz.variables(uv_RU).value, 3)
logWrite('wateringActualAera: ' .. wateringActualAera .. ' wateringPreviousArea: ' .. wateringPreviousArea .. ' mm')
logWrite('RUPrevious: ' .. RUPrevious .. ' mm')
local RUActual
--RUActual = RUPrevious + (wateringActualAera - wateringPreviousArea) + (rainActual - rainPrevious) - (EVPActual - EVPPrevious)
RUActual = RUPrevious + (wateringActualAera - wateringPreviousArea) + (rainActual - rainPrevious) - EVPDelta
logWrite('RUActual: ' .. RUActual)
if RUActual < 0 then
RUActual = 0
logWrite('RU Actual reset to 0')
elseif
RUActual > RU_MAX then
RUActual = RU_MAX
logWrite('RU Actual set to RU MAX: ' .. RU_MAX)
end
if RUActual > RUPrevious then
--logWrite('RU Actual > Previous ; RU ' .. RUActual .. '= RU ' .. RUPrevious .. ' + watering (' .. wateringActualAera .. ' - ' .. wateringPreviousArea .. ') + rain (' .. rainActual .. ' - ' .. rainPrevious .. ') - EVP (' .. EVPActual .. ' - ' .. EVPPrevious .. ')', dz.LOG_FORCE)
logWrite('RU Actual > Previous ; RU ' .. RUActual .. '= RU ' .. RUPrevious .. ' + watering (' .. wateringActualAera .. ' - ' .. wateringPreviousArea .. ') + rain (' .. rainActual .. ' - ' .. rainPrevious .. ') - EVP (' .. EVPDelta .. ')', dz.LOG_FORCE)
end
dz.devices(dev_RU).updateCustomSensor(_u.round(RUActual,1))
local soilMoisture = _u.round(200 * (1 - RUActual / RU_MAX),0)
logWrite('RFU: ' .. soilMoisture .. ' cb')
dz.devices(dev_RFU_cb).updateSoilMoisture(soilMoisture)
dz.variables(uv_RU).set(RUActual)
--dz.variables(uv_EVPPrevious).set(EVPActual)
dz.variables(uv_EVP_deltaNoRounded).set(0).silent() -- reset after being used
dz.variables(uv_rainPrevious).set(rainActual)
dz.variables(uv_wateringPrevious).set(wateringActualAera)
logWrite("*** FIN ***")
end
}

- Screenshot 2022-03-29 233643.png (26.88 Kio) Consulté 4112 fois
Utilisation d'un compteur incremental pour l'EVP pour pouvoir mettre une custom icon
et un custom sensor pour le RFU également avec une icone
Pour les infos météo j'utilise wunderground qui permet d'avoir accès à des stations météo (je trouve plus précis pour la pluie car ce sont des valeurs réelles par rapport à un service de météo général), du coup, je ne sais pas la hauteur de la mesure du vent
