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

Moderator: leecollings

Post Reply
Patricen
Posts: 108
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: 621
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: 108
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: 621
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: 108
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: 108
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 2614 times
willemd
Posts: 621
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().
Post Reply

Who is online

Users browsing this forum: No registered users and 1 guest