Page 1 of 1

capture who initiated switch

Posted: Friday 06 November 2020 20:10
by CronoS
Hi,

I am using a bathroom fan DZvents script in combination with a Shelly 2.5 to turn the fan on. Now, there is also a physical perilex switch connected to the shelly which can also turn the fan on that way.

The bathroom DZvents script is working OK, basically when the humidity rises by 2% the switch is turned on and off again when it is below this threshold. Unfortunately this interfered with the state of my physical button which basically turn on the same switchdevice in the end on Domoticz.
Now, my question..I need to have a solution where the DZvent script leaves the fan alone when the physical button switched it on. So a solution could be that I can read the state of the switch but with an option who triggered it last so that I can compare who enabled it last and find out if the script is allowed to change it. I was looking for other methods; but can't find them easiliy. If I am using a variable or a shadow button in the script, It will not help initialy. Any help is appreciated

Thanks.

Re: capture who initiated switch

Posted: Friday 06 November 2020 22:11
by waaren
CronoS wrote: Friday 06 November 2020 20:10 I am using a bathroom fan DZvents script in combination with a Shelly 2.5 to turn the fan on. Now, there is also a physical perilex switch connected to the shelly which can also turn the fan on that way.

The bathroom dzVents script is working OK, basically when the humidity rises by 2% the switch is turned on and off again when it is below this threshold. Unfortunately this interfered with the state of my physical button which basically turn on the same switchdevice in the end on Domoticz.
Thanks.
To help me understand your remark "in the end"; when does switching the physical button leaves a trace in domoticz?
Are there any other options then the script and the physical switch what can influence the state of this switch?
Can you share the dzVents script you use? It will make it easier to help you and to propose something.

Re: capture who initiated switch

Posted: Saturday 07 November 2020 9:32
by CronoS
I am using this script; viewtopic.php?t=16765. I have got a domoticz switch "Shelly Fan High" and a "Shelly Fan Low" switch. I have a physical switch in the kitchen; when I put it on 1, the "Shelly Fan Low" in Domoticz is switched. When I put it on 2, the Shelly fan High is switched. Now my problem is that the bathroom fan script also uses these shelly switches to turn on the fan in high or low based on humidity.
But when doing that, it overrides the setting of the physical button in the kitchen, because it will turn the fan off after one minute if the humidity levels are not correct to leave the fan running. The script knows a Manual override button; but that one is virtual dummy switch in domoticz and it isn't my physical button because that one is wired to the shelly Fan high switch.
Basically what I want to achieve, is that when I turn the physical switch in the kitchen to 2, the script needs to ignore everything until it is turned off again. Otherwise it turns it off immediately after 1 minute. One way of doing that maybe is to look who initiated a on command on the "Shelly Fan high" button and leave everything alone when that user enabled the button? The same with the "Shelly fan low" button.

Re: capture who initiated switch

Posted: Saturday 07 November 2020 11:48
by Doler
The way I handle 'manual override' is:

- I save the state (persistent data) of the switch every time it is changed by the script
- Upon entry of the script I compare the current state with the saved state
- When the compare gives an unequal result, the state must have been changed manually (UI or physical switch) and script actions are ignored (override state).
- Only when the manual action is restored, script actions are valid again.

Hope this helps.

Re: capture who initiated switch

Posted: Saturday 07 November 2020 13:31
by waaren
CronoS wrote: Saturday 07 November 2020 9:32 I am using this script
I don't see an option in the script to operate the two states (low and high) but based on version 1.3 of the script (the one you pointed to) below script could be a way to handle this requirement.

Code: Select all

--[[
bathroomHumControl.lua by BakSeeDaa
Version 1.3.1
    This script controls the humidity in a typical bathroom setting by detecting
    relative rises in humidity in a short period.
    
    20201107 Add override options for physical switch(es).
    
--]]

local FAN_DEVICE = 'Nibe F750 Force Fan' -- Fan device
local FORCE_FAN_DEVICE = 'Flatulence Button' -- (Optional)
local FORCE_FAN_TIME = 10 -- Minutes to force the fan when button pushed
local HUMIDITY_SENSORS =  {'Badrum 1 C+RH', 'Badrum 2 C+RH'}
local FAN_DELTA_TRIGGER = 3 -- % Rise in humidity that will trigger the fan
local FAN_MAX_TIME = 24 -- Maximum minutes that the fan can be on in case we never reach the target humidity
local TARGET_OFFSET = 2 -- Fan goes off if target + offset is reached
local TEST_MODE_HUMIDITY_READING = 0 -- Set to a value between 1 and 100. Set to 0 to disable test mode
local READING_SAMPLES = 15

-- Create the data declarations
local data = {}
for i, device in pairs(HUMIDITY_SENSORS) do
    data[device] = {history = true, maxItems = READING_SAMPLES + 1}
    data['dehumidProgramActive'..i] = {history = true, maxItems = 1} -- Need history to get time stamp
    data['forceFan'] = {history = true, maxItems = 1} -- Need history to get time stamp
    data['targetHum'..i] = {initial=0}
end

return {

    logging = {
        level = domoticz.LOG_DEBUG, -- Select one of LOG_DEBUG, LOG_INFO, LOG_ERROR, LOG_FORCE to override system log level
        marker = "bathRoom"
    },
    on = {
        devices = {
            FORCE_FAN_DEVICE
        },
        timer = {
            'every 1 minutes'
        }
    },
    
    data = data,
    
    execute = function(domoticz, device, triggerInfo)
        local forceFanReadings = domoticz.data.forceFan

        local low = dz.devices('Shelly Fan Low')
        local high = dz.devices('Shelly Fan High')
        
        local function isExternalSwitched()
            if dz.data.lowState == nil then dz.data.lowState = low.state end -- initial set
            if dz.data.highState == nil then dz.data.highState = high.state end -- initial set
            if not (low.active or high.active) then return false end
            if dz.data.lowState == low.state and dz.data.highState == high.state then return false end
            return true
        end
        
        local function setPersistentStates(lowState, highState)
            dz.data.lowState = lowState
            dz.data.highState = highState
        end
        
        if isExternalSwitched() then return end -- The switch is operated physical
        
        if (triggerInfo.type == domoticz.EVENT_TYPE_TIMER) then
            local fanCmd = 'Off'
            for i = 1, #HUMIDITY_SENSORS do
                local humidityReadings = domoticz.data[HUMIDITY_SENSORS[i]]
                -- Store the read value in the persistant data
                for j = 1, (humidityReadings.size == 0 and READING_SAMPLES + 1 or 1) do
                    humidityReadings.add((TEST_MODE_HUMIDITY_READING == 0
                        and domoticz.devices(HUMIDITY_SENSORS[i]).humidity or TEST_MODE_HUMIDITY_READING))
                end

                -- INIT
                local programActiveReadings = domoticz.data['dehumidProgramActive'..i]
                if (programActiveReadings.size == 0) then
                    domoticz.log('programActiveReadings, Initialization was needed', domoticz.LOG_INFO)
                    programActiveReadings.add(false)
                end
                local targetHum = domoticz.data['targetHum'..i]
                if (targetHum == nil) then
                    domoticz.log('targetHum'..i..', Initialization was needed', domoticz.LOG_INFO)
                    domoticz.data['targetHum'..i] = 0
                    targetHum = 0
                end
                if (forceFanReadings.size == 0) then
                    domoticz.log('forceFanReadings, Initialization was needed', domoticz.LOG_INFO)
                    forceFanReadings.add('Init')
                end

                local programActiveState = programActiveReadings.getLatest()
                if (programActiveState.data) then -- The fan control program is active
                    -- Has the fan control program timed out or have we reached the target humidity?
                    local maxTime = (programActiveState.time.minutesAgo > FAN_MAX_TIME)
                    local targetHumReached = (humidityReadings.getLatest().data <= targetHum)
                    if (maxTime or targetHumReached) then
                        domoticz.log('Dehumidification program stops for: '..HUMIDITY_SENSORS[i], domoticz.LOG_INFO)
                        domoticz.log('Reason(s): '..(maxTime and 'Max time. ' or '')..(targetHumReached and 'Target humidity reached.' or ''), domoticz.LOG_INFO)
                        programActiveReadings.add(false)
                        programActiveState = programActiveReadings.getLatest()
                    else
                        domoticz.log('Dehumidification program is active for: '..HUMIDITY_SENSORS[i], domoticz.LOG_INFO)
                        fanCmd = 'On'
                    end
                else -- The fan is currently not running under the control of this program
                    -- Has there been a significant rise in humidity lately?
                    local humDelta = humidityReadings.getLatest().data - humidityReadings.min(2, READING_SAMPLES + 1)
                    -- Calculate a target humidity but never try to push humidity below 40
                    targetHum = math.max(humidityReadings.min(2, READING_SAMPLES + 1) + TARGET_OFFSET, 40)
                    if (humDelta > FAN_DELTA_TRIGGER and humidityReadings.getLatest().data > targetHum) then
                        domoticz.data['targetHum'..i] = targetHum
                        programActiveReadings.add(true)
                        programActiveState = programActiveReadings.getLatest()
                        fanCmd = 'On'
                        domoticz.log('Dehumidification program starts as a respond to: '..HUMIDITY_SENSORS[i], domoticz.LOG_INFO)
                    else
                        domoticz.log('Dehumidification program doesn\'t run  for: '..HUMIDITY_SENSORS[i], domoticz.LOG_INFO)
                    end
                    domoticz.log('targetHum: '..targetHum..', Current humidity: '..humidityReadings.getLatest().data..', humDelta: '..humDelta, domoticz.LOG_INFO)
                end
            end

            if ((forceFanReadings.getLatest().time.minutesAgo < FORCE_FAN_TIME)
            and (forceFanReadings.getLatest().data == 'On')) then fanCmd = 'On' end

            if (domoticz.devices(FAN_DEVICE).state ~= fanCmd) then
                domoticz.log('Turning the fan '..fanCmd, domoticz.LOG_INFO)
                domoticz.devices(FAN_DEVICE).toggleSwitch()
                domoticz.data.lowState = fanCmd
                domoticz.data.highState = fanCmd
            end
        else
            -- The script gets executed due to a device-change event
            if (device.name == FORCE_FAN_DEVICE and device.state == 'On') then
                forceFanReadings.add('On')
                domoticz.log('The fan has been forced on for '..FORCE_FAN_TIME..'minutes.', domoticz.LOG_INFO)
                -- domoticz.helpers.speak(domoticz, 'joke sting')
                if (domoticz.devices(FAN_DEVICE).state ~= 'On') then 
                    domoticz.devices(FAN_DEVICE).switchOn() 
                    domoticz.data.lowState = 'On'
                    domoticz.data.highState = 'On'
                end
            end
        end

    end
}

Re: capture who initiated switch

Posted: Sunday 08 November 2020 19:50
by CronoS
That is correct. I have added a line below the "program doesn't run", when the humidity is higher then 50 that the low setting should be enabled..That seems to work ok.. But I don't have a solution with a physical button, because that will trigger the same switches.