How-to: launch action after a certain time  [SOLVED]

Moderator: leecollings

Post Reply
Patricen
Posts: 117
Joined: Tuesday 06 February 2018 18:48
Target OS: Raspberry Pi / ODroid
Domoticz version: Beta rel
Contact:

How-to: launch action after a certain time

Post by Patricen »

Hello,

I'm trying to optimize my boiler start-up sequence, but have an issue coding this.

Currently there is a flowswitch that starts heating as soon as I do open a hot water tap. As there is a 50l hot water tank, I would like to start heating after 30s of water flow.
That was for the story.

Then, I would like to start heating after 30s, only if the water is still flowing, otherwise, no need to start.
If started, as soon as the water is not flowing anymore, stop heating.

Looks easy to write it but I can't figure out how to code it with dzvents.
willemd
Posts: 631
Joined: Saturday 21 September 2019 17:55
Target OS: Raspberry Pi / ODroid
Domoticz version: 2024.1
Location: The Netherlands
Contact:

Re: How-to: launch action after a certain time

Post by willemd »

Looking at the dzvents documentation, you probably have to use the command options to handle this. Did you have a look at that?
Patricen
Posts: 117
Joined: Tuesday 06 February 2018 18:48
Target OS: Raspberry Pi / ODroid
Domoticz version: Beta rel
Contact:

Re: How-to: launch action after a certain time

Post by Patricen »

Sure,

Found out afterSecs control, that I should combine with item.lastUpdate but within if function, item.lastupdate has a restriction. If the item is the one that triggered the event, lastUpdate time is the time before the event is triggered, then it is useless...
Then I need to find a trick.
willemd
Posts: 631
Joined: Saturday 21 September 2019 17:55
Target OS: Raspberry Pi / ODroid
Domoticz version: 2024.1
Location: The Netherlands
Contact:

Re: How-to: launch action after a certain time

Post by willemd »

I understand, you want to trigger the flameswitch 30 seconds after the triggering of the flowswitch, but only of the flowswitch is still on. Could you use a dummy switch as intermediary?

Something like the code below ? (not tested) The script triggers itself a second time by changing the status of a dummyswitch. Not sure if this works, but easy to try out.

I think you also need to consider when you want to fill up the tank again with hot water, otherwise you will run out of hot water at some point.

Code: Select all

local idxFlowSwitch=XX,  -- XX,YY,ZZ to be replaced by device numbers
local idxDummySwitch=YY,
local idxFlameSwitch=ZZ,

return {
    on = {
        devices = {
            idxFlowSwitch,
            idxDummySwitch
        },
    },
    execute=function(domoticz,device)
        if device==idxFlowSwitch then   -- script triggered by flowswitch
            domoticz.devices(idxDummySwitch).switchOff()
            domoticz.devices(idxFlameSwitch).switchOff()
            if device.state=='On' then  -- flowswitch was switched to On
                domoticz.devices(idxDummySwitch).switchOn().afterSec(30)
            end
        else  -- script triggered by dummyswitch (30 seconds after flowswitch)
            if domoticz.devices(idxFlowSwitch)=='On' then  -- flow is still on
                domoticz.devices(idxFlameSwitch).switchOn()
            end
        end
    end
}
Patricen
Posts: 117
Joined: Tuesday 06 February 2018 18:48
Target OS: Raspberry Pi / ODroid
Domoticz version: Beta rel
Contact:

Re: How-to: launch action after a certain time

Post by Patricen »

Thanks, I'll check that.

Indeed, there is the dummy switch solution that I already used for another application, but I was wondering if there could be a way of coding that does not need the dummy switch.
I think you also need to consider when you want to fill up the tank again with hot water, otherwise you will run out of hot water at some point.
This switch is only intended to anticipate starting the flame before the flame starts due to temperature drop, because without the timer I want to set-up, it is very stressful for the ignition system (it is a common known failure for this type of boiler) and it unnecessarily consumes gas for short time water consumption. There is a 50l buffer tank and it looks like 60s would be the right delay time at the end. Basically, running out of hot water only happens for bathtub filling if the flowswitch is not connected to the flame control system.

"Appel ECS" is the water flowswitch and "Chaudière-Chauffe ECS" is the flame control
At the moment the code looks as below but is nos satisfying, as " if(Appel_ECS == 'On' and dz.devices('Appel ECS').lastUpdate.secondsAgo > 10)" does not work properly due to the limitation of item.lastUpdate.secondsAgo > 10 as the item triggered the thread.
dzVents documentation says :
lastUpdate: Time Object: Time when the device was updated. **Note: The lastUpdate for devices that triggered the script at hand is in fact the previousUpdate time. The real lastUpdate time for these “script triggering” devices is the current time.
The solution could be (but I don't find this really smart) to trigger using

Code: Select all

timer = {'Every 20 seconds'}
and removing devices trigger, but I do have no idea about the required computing resources it takes to the RPI.

Code: Select all

return
{
    on =
    {
        
        devices = {
            'Appel ECS',
            'Chaudière-Chauffe ECS'
        },
        timer = {'Every 10 minutes'}, -- just in case the flowswitch off is not detected, to avoid overheating
    },

       logging = 
    {
        level = domoticz.LOG_debug, -- change to domoticz.LOG_ERROR when script is tested and OK
        marker = 'Contrôle ECS',
    },
    execute = function(dz, item)
        Appel_ECS = dz.devices('Appel ECS').state
        dz.log('Appel ECS : ' .. Appel_ECS )
        
        if(Appel_ECS == 'On' and dz.devices('Appel ECS').lastUpdate.secondsAgo > 10)
        then
        dz.devices('Chaudière-Chauffe ECS').switchOn().checkFirst()
        dz.log('Démarrage chauffe ECS')
        
        elseif(Appel_ECS == 'Off')
        then
        dz.devices('Chaudière-Chauffe ECS').switchOff().checkFirst()
        dz.log('Arrêt chauffe ECS')
        end
    end
}
Patricen
Posts: 117
Joined: Tuesday 06 February 2018 18:48
Target OS: Raspberry Pi / ODroid
Domoticz version: Beta rel
Contact:

Re: How-to: launch action after a certain time

Post by Patricen »

Finally I found out a dummy solution without dummy switch...
Capture.PNG
Capture.PNG (22.63 KiB) Viewed 3752 times
willemd
Posts: 631
Joined: Saturday 21 September 2019 17:55
Target OS: Raspberry Pi / ODroid
Domoticz version: 2024.1
Location: The Netherlands
Contact:

Re: How-to: launch action after a certain time

Post by willemd »

You said you wanted a solution in Dzvents?
rrozema
Posts: 470
Joined: Thursday 26 October 2017 13:37
Target OS: Raspberry Pi / ODroid
Domoticz version: beta
Location: Delft
Contact:

Re: How-to: launch action after a certain time  [SOLVED]

Post by rrozema »

Using dzvents you can trigger a custom event. In that custom event you can send a payload. So what you can do is to have a custom event sent using the timed actions 30 seconds after the tap started running, in the payload you put the last update value of the current time the tap was opened. Next when you receive this custom event, you check if the tap is still open (status of the tap switch is "On" and last update equals the time in the payload of the custom event). If the status is "Off" by the time you receive the custom event, the tap must have been open for less han 30 seconds. If the status is "On" and the last update time on the tap switch matches the time in the payload, the tap is open for at least 30 seconds. If the status is "On" but the tap's last update differs from the time in the message's payload, the tap must have been opened, closed then re-opened within your 30 second time. It was NOT on for 30 seconds. Plus, you will probably get another custom message with a new pay load somewhat later, to which you can again do the same tests. I created a test script for this method once with a lot of help of @waaren. I never got to fully implementing it, maybe you can use this as an example for your purpose:

Code: Select all

return {
    on = {
        devices = {
            "myTest"
        },
        customEvents = {
            "Delayed-Auto-On*"
        }
    },

    logging =
    {
        level = domoticz.LOG_ERROR,
    },

    execute = function(domoticz, item)
        
        if item.isDevice then
            -- if the trigger device changed to 'On' ...
            if item.bState then
                
                -- TODO: determine the delay for the device.
                local delay = 20
                
                -- ... and there is a delay > 0 seconds defined for this device...
                if delay ~= nil and delay > 0 then
                    local Time = require('Time')
                    local thisUpdate = Time(os.date("%Y-%m-%d %H:%M:%S", os.time(item.lastUpdate.current)))
        
                    local name = 'Delayed-Auto-On-' .. tostring(item.idx) .. '-' .. thisUpdate.raw
                    local extraData = { ["idx"] = item.idx, ["bState"] = item.bState,  ["thisUpdate"] = thisUpdate }
    
                    -- ... emit a customEvent after the delay.
                    domoticz.emitEvent(name,  extraData).afterSec(delay)
                else
                    -- No delay, activate the action right now.
                    -- TODO: add action here.
                    domoticz.log( 'Triggering action without delay', domotiz.LOG_FORCE)
                end
            end
            
        elseif item.isCustomEvent then
            -- If we get here, the customEvent has been triggered after the delay period. We will 
            -- test that:
            -- 1 : bState on the device equals that which we stored in the [extra data], and
            -- 2 : lastUpdate on the device equals that which we stored in [extra data].
            -- If both conditions are met we know the device is still unchanged after the delay
            -- and we can then start the delayed action.

            if item.json == nil then
                domoticz.log( 'json is missing', domoticz.LOG_ERROR)
            elseif item.json.idx == nil then
                domoticz.log( 'idx is missing', domoticz.LOG_ERROR)
            elseif item.json.bState == nil then
                domoticz.log( 'bstate is missing', domoticz.LOG_ERROR)
            elseif item.json.thisUpdate == nil then  
                domoticz.log( 'thisUpdate is missing', domoticz.LOG_ERROR)
            else
                local device = domoticz.devices(item.json.idx)
                if device == nil then
                    domoticz.log( 'device('..tostring(item.json.idx)..') not found', domoticz.LOG_ERROR)
                else
                    local Time = require('Time')
                    local thisUpdate = Time(os.date("%Y-%m-%d %H:%M:%S", os.time(item.json.thisUpdate)))
                    
                    if device.bState == item.json.bState and device.lastUpdate.compare(thisUpdate).compare == 0 then
                        -- TODO: add action here.
                        domoticz.log( 'Triggering action after delay', domoticz.LOG_FORCE)
                    end 
                end
            end
        else
            domoticz.log( 'Unexpected trigger type', domoticz.LOG_ERROR)
        end
    end
}

To get an even more reliable result you could try to add the length of the period for each period the tap was "On" (i.e. the number of seconds between the "On" and the "Off" event) in a persistent data with "history = true, MaxMinutes = 1" , then when you receive the custom event retrieve the sum of the periods over all times the tap was "On" in the last minute simply by calling the statistical function domoticz.data.myVar.sum().
Gingerpale
Posts: 22
Joined: Wednesday 13 January 2016 16:11
Target OS: Raspberry Pi / ODroid
Domoticz version: 2024.4
Contact:

Re: How-to: launch action after a certain time

Post by Gingerpale »

Why does customEvents = { … } does not support .name attribute? ALmost all other objects support .name.
It would be useful to identify it when handling multiple customEvents in one script. E.g.:

Code: Select all

return {
	on = {
		devices = {'Test1', 'Test2'},
		customEvents = {'delay_1_sec', 'delay_2_sec'},
	},
	logging = {level = domoticz.LOG_INFO, marker = 'Test',},

	execute = function(domoticz, item)
        	if item.isDevice and item.name == 'Test1' and item.state == 'On' then
            		domoticz.emitEvent('delay_1_sec').afterSec(1)
		elseif  item.isDevice and item.name == 'Test2' and item.state == 'On' then
            		domoticz.emitEvent('delay_2_sec').afterSec(2)
        	elseif item.isDevice and item.state == 'Off' then
            		-- do nothing
        	elseif item.isCustomEvent and item.name == 'delay_1_sec' then -- item.name doesn't work!
            		domoticz.devices('Test1').switchOff()
        	elseif item.isCustomEvent and item.name == 'delay_2_sec' then -- item.name doesn't work!
            		domoticz.devices('Test2').switchOff()
		else
	   		-- do nothing
        	end
	end
}
Currently the only workaround is to use the second parameter payload to indicate which one to execute, e.g.:

Code: Select all

return {
	on = {
		devices = {'Test1', 'Test2'},
		customEvents = {'delay_x_sec',},
	},
	logging = {level = domoticz.LOG_INFO, marker = 'Test',},

	execute = function(domoticz, item)
        	if item.isDevice and item.name == 'Test1' and item.state == 'On' then
            		domoticz.emitEvent('delay_x_sec', '1_sec').afterSec(1)
		elseif  item.isDevice and item.name == 'Test2' and item.state == 'On' then
            		domoticz.emitEvent('delay_x_sec', '2_sec').afterSec(2)
        	elseif item.isDevice and item.state == 'Off' then
            		-- do nothing
        	elseif item.isCustomEvent and item.data == '1_sec' then -- item.data does work!
            		domoticz.devices('Test1').switchOff()
        	elseif item.isCustomEvent and item.data == '2_sec' then -- item.data does work!
            		domoticz.devices('Test2').switchOff()
		else
	   		-- do nothing
        	end
	end
}
Is there a reason for it? Or am I missing something?
Rpi4B,RFX433e,PiFace2, LCD, Hue bridge, Alexa (+TTS), HA-Bridge, Sonoff NSPanel, Sonoff RF (+IR) bridge, Nefit CV, Tasmota/MQTT, Enphase Solar, Smartmeter, Alarm I/F, H13726B Weather Station, CM180 Energy meter, Sonoff, KaKu, Tuya, Gledopto, AriLux,...
User avatar
waltervl
Posts: 5734
Joined: Monday 28 January 2019 18:48
Target OS: Linux
Domoticz version: 2024.7
Location: NL
Contact:

Re: How-to: launch action after a certain time

Post by waltervl »

I never used custom events but looking at the wiki you have to use attribute .trigger for this
Eg

Code: Select all

if item.isCustomEvent and item.trigger == 'delay_1_sec' then
Domoticz running on Udoo X86 (on Ubuntu)
Devices/plugins: ZigbeeforDomoticz (with Xiaomi, Ikea, Tuya devices), Nefit Easy, Midea Airco, Omnik Solar, Goodwe Solar
Gingerpale
Posts: 22
Joined: Wednesday 13 January 2016 16:11
Target OS: Raspberry Pi / ODroid
Domoticz version: 2024.4
Contact:

Re: How-to: launch action after a certain time

Post by Gingerpale »

Hi Walter,
I've tested it and it works! This is exactly what I was looking for.
Thx...
Rpi4B,RFX433e,PiFace2, LCD, Hue bridge, Alexa (+TTS), HA-Bridge, Sonoff NSPanel, Sonoff RF (+IR) bridge, Nefit CV, Tasmota/MQTT, Enphase Solar, Smartmeter, Alarm I/F, H13726B Weather Station, CM180 Energy meter, Sonoff, KaKu, Tuya, Gledopto, AriLux,...
manjh
Posts: 748
Joined: Saturday 27 February 2016 12:49
Target OS: Raspberry Pi / ODroid
Domoticz version: 2020.2
Location: NL
Contact:

Re: How-to: launch action after a certain time

Post by manjh »

What if someone opens the hot water tap for 25 seconds? And again, and again? Eventually it would leave the boiler cold!
I know it may sound unlikely, but you should code for the worst...
Hans
Gingerpale
Posts: 22
Joined: Wednesday 13 January 2016 16:11
Target OS: Raspberry Pi / ODroid
Domoticz version: 2024.4
Contact:

Re: How-to: launch action after a certain time

Post by Gingerpale »

Good point,
I found a thread about that, see viewtopic.php?t=33002
Unfortunately dz.emitEvent('myEvent').cancelQueuedCommands() doesn't work but it describes some work-around solutions.
Rpi4B,RFX433e,PiFace2, LCD, Hue bridge, Alexa (+TTS), HA-Bridge, Sonoff NSPanel, Sonoff RF (+IR) bridge, Nefit CV, Tasmota/MQTT, Enphase Solar, Smartmeter, Alarm I/F, H13726B Weather Station, CM180 Energy meter, Sonoff, KaKu, Tuya, Gledopto, AriLux,...
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest