Page 1 of 1

thisUpdate? (as opposed to lastUpdate)

Posted: Tuesday 02 June 2020 13:55
by rrozema
A question: inside dzvents' execute( dz, item) where item is a device, the value for device.lastUpdate seems to be that of the previous change to the device. Is it possible to retrieve from inside this trigger the value that lastUpdate will have after the device has changed? i.e. sort of a "thisUpdate"? I'm trying to see in a customEvent trigger if the device has changed since the customEvent was emitted and I'm trying to use the lastUpdate value for this. But the lastUpdate value I pass with the customEvent is always different than that which is on the device when I get the customEvent trigger.

My (dzvents) code so far:

Code: Select all

return {
	on = {
		devices = {
		    "myTest"
		},
		customEvents = {
			"myTestEvent*"
		}
	},
    execute = function(domoticz, object, triggerInfo)
        if object.isDevice then
            domoticz.log('Device ' .. object.name .. ': state ' ..tostring(object.bState).. '.', domoticz.LOG_FORCE)
            if object.bState == true then
                local name = 'myTestEvent_' .. tostring(object.idx) .. '_' .. object.lastUpdate.raw
                
                domoticz.emitEvent(name, { idx = object.idx, bState = object.bState, lastUpdate = object.lastUpdate } ).afterSec(10)
            end
        elseif object.isCustomEvent then
            if object.json == nil then
                domoticz.log('CustomEvent, ' .. object.customEvent .. ', json is nil.', domoticz.LOG_ERROR)
            else
                domoticz.log('CustomEvent, ' .. object.customEvent .. ', idx = '.. tostring(object.json.idx) .. ', bState = ' ..tostring( object.json.bState) .. '.', domoticz.LOG_FORCE)
                if object.json.idx == nil then
                    domoticz.log('CustomEvent, ' .. object.customEvent .. ', json.idx is nil.', domoticz.LOG_ERROR)
                else                
                    local dev = domoticz.devices(object.json.idx)
                    if dev == nil then
                        domoticz.log('CustomEvent, ' .. object.customEvent .. ', device ' .. tostring(object.json.idx) .. ' not found.', domoticz.LOG_ERROR)
                    else
                        if dev.bState == object.json.bState and dev.lastUpdate.compare(object.json.lastUpdate).compare == 0 then
                            domoticz.log('CustomEvent, ' .. object.customEvent .. ', device ' .. dev.name .. ' is still on.', domoticz.LOG_ERROR)
                        else
                            domoticz.log('CustomEvent, ' .. object.customEvent .. ', device ' .. dev.name .. ' is no longer on. : ' .. tostring(dev.lastUpdate.rawDateTime) .. ' <> ' .. tostring(object.json.lastUpdate.rawDateTime) .. '.', domoticz.LOG_ERROR)
--                            domoticz.utils.dumpTable(object.json.lastUpdate)
--                            domoticz.utils.dumpTable(dev.lastUpdate)
                        end
                    end
                end
            end
        else
            domoticz.log( "unexpected trigger type.", domoticz.LOG_FORCE)
        end
	end
}

Output from the log (had to filter all other devices' output out):

Code: Select all

2020-06-02 13:41:02.776 (dummy) Light/Switch (myTest)
2020-06-02 13:41:02.760 Status: User: Admin initiated a switch command (552/myTest/Off)
2020-06-02 13:41:03.014 Status: dzVents: !Info: Device myTest: state false.


2020-06-02 13:41:04.066 (dummy) Light/Switch (myTest)
2020-06-02 13:41:04.057 Status: User: Admin initiated a switch command (552/myTest/On)
2020-06-02 13:41:04.275 Status: dzVents: !Info: Device myTest: state true.


2020-06-02 13:41:14.534 Status: dzVents: !Info: CustomEvent, myTestEvent_552_2020-06-02 13:41:02, idx = 552, bState = true.
2020-06-02 13:41:14.553 Error: dzVents: Error: (3.0.5) CustomEvent, myTestEvent_552_2020-06-02 13:41:02, device myTest is no longer on. : 2020-06-02 13:41:04 <> 2020-06-02 13:41:02.
The last line in the log shows that my customEvent has the value for the 'Off'-event at "2020-06-02 13:41:02.760". I am looking for a way to get the "2020-06-02 13:41:04.057" value for the 'On'-event when the customEvent gets emitted.

2020-06-02 13:41:14.553 Error: dzVents: Error: (3.0.5) CustomEvent, myTestEvent_552_2020-06-02 13:41:02, device myTest is no longer on. : 2020-06-02 13:41:04 <> 2020-06-02 13:41:02.

Re: thisUpdate? (as opposed to lastUpdate)

Posted: Tuesday 02 June 2020 16:17
by waaren
rrozema wrote: Tuesday 02 June 2020 13:55 A question: inside dzvents' execute( dz, item) where item is a device, the value for device.lastUpdate seems to be that of the previous change to the device. Is it possible to retrieve from inside this trigger the value that lastUpdate will have after the device has changed? i.e. sort of a "thisUpdate"?

The last line in the log shows that my customEvent has the value for the 'Off'-event at "2020-06-02 13:41:02.760". I am looking for a way to get the "2020-06-02 13:41:04.057" value for the 'On'-event when the customEvent gets emitted.
Probably the closest you can get is with:

Code: Select all

domoticz.emitEvent(name, { idx = object.idx, bState = object.bState, lastUpdate = domoticz.time } ).afterSec(10)

Re: thisUpdate? (as opposed to lastUpdate)

Posted: Tuesday 02 June 2020 16:40
by rrozema
waaren wrote: Tuesday 02 June 2020 16:17 Probably the closest you can get is with:

Code: Select all

domoticz.emitEvent(name, { idx = object.idx, bState = object.bState, lastUpdate = domoticz.time } ).afterSec(10)
Yeah, but as you can see in the code, that's not close enough for the purpose I intend to use it for. I was hoping to use it to determine exactly if the device was updated since the customEvent was emitted. If it was updated since then, I don't want the code -that isn't in there yet- to activate. Just checking for the value of bState being the same isn't enough, because even if the device is On, it may still have been switched Off and then On again. If it was switched Off and later On again, I will get another customEvent for that 2nd time the switched was switched On. This way I was hoping to ensure that the code could be activated exactly the specified number of seconds after the device was switched On and only if the device is still On at that time.

I intend to use this for example to send a notification if a door is left open for too long: to alert my family when the fridge door is left ajar and to disable the heating if a door is left open to let some fresh air in. But I also want it for determining how long the fan in my bathroom must be on: for a short bathroom visit I switch the fan off a few seconds after you've left the bathroom. After a long visit however I leave the fan running for a few more minutes.

I don't want you to change behavior of the lastUpdate property as I know that will break many scripts. But would it be possible to expose from the domoticz object a new thisUpdate property that during the call to the device trigger, holds the value that is going to be put into lastUpdate after that call?

Re: thisUpdate? (as opposed to lastUpdate)

Posted: Wednesday 03 June 2020 2:21
by waaren
rrozema wrote: Tuesday 02 June 2020 16:40 I don't want you to change behavior of the lastUpdate property as I know that will break many scripts. But would it be possible to expose from the domoticz object a new thisUpdate property that during the call to the device trigger, holds the value that is going to be put into lastUpdate after that call?
Can you test with this one?

Code: Select all

return {
    on = {
        devices = {
            "myTest"
        },
        customEvents = {
            "myTestEvent*"
        }
    },

    logging =
    {
        level = domoticz.LOG_ERROR,
    },

    execute = function(dz, item)
        if item.isDevice and item.lastUpdate.secondsAgo < 10 then
            return
        end

        if item.isDevice then
            local name = 'myTestEvent_' .. tostring(item.idx) .. '_' .. item.lastUpdate.raw
            dz.emitEvent(name, { idx = item.idx, bState = item.bState,  thisUpdate = item.lastUpdate.current } ).afterSec(10)
            return
        end

        local lastUpdate = dz.devices('myTest').lastUpdate

        local Time = require('Time')
        local thisUpdate = Time(os.date("%Y-%m-%d %H:%M:%S", os.time(item.json.thisUpdate)))

        dz.log('lastUpdate: ' .. lastUpdate.raw, dz.LOG_FORCE )
        dz.log('thisUpdate: ' .. thisUpdate.raw, dz.LOG_FORCE )

        dz.log('Times Equal? ' ..  tostring(lastUpdate.compare(thisUpdate).compare == 0 ) ,dz.LOG_FORCE)

    end
}

Re: thisUpdate? (as opposed to lastUpdate)

Posted: Wednesday 03 June 2020 4:38
by rrozema
waaren wrote: Wednesday 03 June 2020 2:21 Can you test with this one?

Code: Select all

2020-06-03 04:33:49.974 (dummy) Light/Switch (myTest)
2020-06-03 04:33:49.956 Status: User: Admin initiated a switch command (552/myTest/Off)

2020-06-03 04:33:53.128 (dummy) Light/Switch (myTest)
2020-06-03 04:33:53.112 Status: User: Admin initiated a switch command (552/myTest/On)

2020-06-03 04:34:00.398 Status: dzVents: !Info: lastUpdate: 2020-06-03 04:33:53
2020-06-03 04:34:00.398 Status: dzVents: !Info: thisUpdate: 2020-06-03 04:33:50
2020-06-03 04:34:00.398 Status: dzVents: !Info: Times Equal? false

Re: thisUpdate? (as opposed to lastUpdate)

Posted: Wednesday 03 June 2020 9:57
by waaren
rrozema wrote: Wednesday 03 June 2020 4:38

Code: Select all

2020-06-03 04:34:00.398 Status: dzVents: !Info: Times Equal? false
And does this help you ?

Re: thisUpdate? (as opposed to lastUpdate)

Posted: Wednesday 03 June 2020 15:57
by rrozema
waaren wrote: Wednesday 03 June 2020 9:57
rrozema wrote: Wednesday 03 June 2020 4:38

Code: Select all

2020-06-03 04:34:00.398 Status: dzVents: !Info: Times Equal? false
And does this help you ?
No, it doesn't. I need the value in the [extra data] to be exactly the same as the lastUpdate value if the switch hasn't changed between the moment the event got emitted and when the 10 seconds have passed. If I could I would also want to include the microseconds, but I don't know how to get that much precision from lastUpdate's value.

This is the scenario that I want to test for:

I want the customEvent to fire 10 seconds after the switch was switched 'On'. But only if the switch was not switched again since it was switched 'On' I want to take some follow up action.

So what I need to test for is:
1 - switch is off after 10 seconds:
bstate ~= [extra data].bState
NO ACTION

2 - switch is on, but has (at least once) been switched off and then on again:
bState == [extra data].bState but lastUpdate ~= [extra data].lastUpdate
NO ACTION

3 - switch is still on after 10 seconds:
bState == [extra data].bState and lastUpdate == [extra data].lastUpdate
NOW DO THE ACTION.

Scenario 1 is of course simple: just compare the device's bState with that which is in the json (which is filled from emitEvent's [extra data]) and it's easy to conclude that the switch has been changed at least once since the customEvent was emitted. In both scenarios 2 and 3 however, bState is going to be true. But, in scenario 2 the switch was switched off and then on again and thus the switch has not been on for 10 consecutive seconds. The only way to determine the difference between 2 and 3 is by looking at the lastUpdate as far as I know. I am looking for a way to put in the [extra data] for emitEvent, the value that lastUpdate will have in scenario 3, so I can successfully distinguish between scenarios 2 and 3.

Re: thisUpdate? (as opposed to lastUpdate)

Posted: Wednesday 03 June 2020 16:30
by waaren
rrozema wrote: Wednesday 03 June 2020 15:57 No, it doesn't.
In my tests (build 12106, dzVents 3.0.8), this script does work as you describe.
I know of no way to get milliseconds precision but the time object passed with emitEvent in thisUpdate is the time object used by domoticz to create the new lastUpdate value.

If it does not work on your system I am very much interested in the situation where it goes wrong. Could well be I am overlooking something.

Code: Select all

return {
    on = {
        devices = {
            "myTest"
        },
        customEvents = {
            "myTestEvent*"
        }
    },

    logging =
    {
        level = domoticz.LOG_ERROR,
    },

    execute = function(dz, item)
        if item.isDevice and item.lastUpdate.secondsAgo < 10 then
            return
        end

        if item.isDevice then
            local name = 'myTestEvent_' .. tostring(item.idx) .. '_' .. item.lastUpdate.raw
            dz.emitEvent(name, { idx = item.idx, bState = item.bState,  thisUpdate = item.lastUpdate.current } ).afterSec(10)
            return
        end

        local myDevice = dz.devices('myTest')
        local lastUpdate = myDevice.lastUpdate
        local bState = myDevice.bState

        local Time = require('Time')
        local thisUpdate = Time(os.date("%Y-%m-%d %H:%M:%S", os.time(item.json.thisUpdate)))

        dz.log('lastUpdate: ' .. lastUpdate.raw, dz.LOG_FORCE )
        dz.log('thisUpdate: ' .. thisUpdate.raw, dz.LOG_FORCE )

        dz.log('Times Equal? ' ..  tostring(lastUpdate.compare(thisUpdate).compare == 0 ) ,dz.LOG_FORCE)


        if bState == item.json.bState and lastUpdate.compare(thisUpdate).compare == 0  then
            dz.log('No updates occurred since emitEvent was given' ,dz.LOG_FORCE)
        else
            dz.log('One or more updates occurred since emitEvent was given' ,dz.LOG_FORCE)
        end
    end
}


Re: thisUpdate? (as opposed to lastUpdate)

Posted: Wednesday 03 June 2020 18:01
by rrozema
rrozema wrote: Wednesday 03 June 2020 4:38

Code: Select all

2020-06-03 04:34:00.398 Status: dzVents: !Info: Times Equal? false
To make it work your test code should have returned true: I did not change the switch after it was set to On, so the device's lastUpdate value should have been equal to that in the [extra data].lastUpdate when the customEvent got executed.

Re: thisUpdate? (as opposed to lastUpdate)

Posted: Wednesday 03 June 2020 18:29
by waaren
rrozema wrote: Wednesday 03 June 2020 18:01 To make it work your test code should have returned true: I did not change the switch after it was set to On, so the device's lastUpdate value should have been equal to that in the [extra data].lastUpdate when the customEvent got executed.
There must be something quite different in your setup compared to mine. I tested this many times and every test the times compared to equal when I did not touch the device after the first time and every time I touched it 1 or more times after the first time it compared to unequal.

Code: Select all

2020-06-03 16:20:10.396  Status: dzVents: Info: Handling Domoticz custom event for: "myTestEvent_3082_2020-06-03 16:19:10"
2020-06-03 16:20:10.403  Status: dzVents: !Info: lastUpdate: 2020-06-03 16:20:00
2020-06-03 16:20:10.403  Status: dzVents: !Info: thisUpdate: 2020-06-03 16:20:00
2020-06-03 16:20:10.403  Status: dzVents: !Info: Times Equal? true
2020-06-03 16:20:10.403  Status: dzVents: !Info: No updates occurred since emitEvent was given  -- Not touched

2020-06-03 16:20:48.246  Status: dzVents: Info: Handling Domoticz custom event for: "myTestEvent_3082_2020-06-03 16:20:00"
2020-06-03 16:20:48.253  Status: dzVents: !Info: lastUpdate: 2020-06-03 16:20:38
2020-06-03 16:20:48.253  Status: dzVents: !Info: thisUpdate: 2020-06-03 16:20:38
2020-06-03 16:20:48.253  Status: dzVents: !Info: Times Equal? true
2020-06-03 16:20:48.253  Status: dzVents: !Info: No updates occurred since emitEvent was given -- Not touched

2020-06-03 16:21:45.129  Status: dzVents: Info: Handling Domoticz custom event for: "myTestEvent_3082_2020-06-03 16:20:38"
2020-06-03 16:21:45.136  Status: dzVents: !Info: lastUpdate: 2020-06-03 16:21:40
2020-06-03 16:21:45.136  Status: dzVents: !Info: thisUpdate: 2020-06-03 16:21:34
2020-06-03 16:21:45.136  Status: dzVents: !Info: Times Equal? false
2020-06-03 16:21:45.136  Status: dzVents: !Info: One or more updates occurred since emitEvent was given -- switched twice

Re: thisUpdate? (as opposed to lastUpdate)

Posted: Wednesday 03 June 2020 19:20
by rrozema
I have adapted your test code so that it serves my purpose below. This works most of the times, but there are 2 things I don't like about this solution:
  • the "guessed" lastUpdate can differ from the actual lastUpdate value set by Domoticz if you're unlucky enough to trigger the switch a few milliseconds before the second changes. This can only be solved if dzVents were to expose to the triggered script the value that is going to be put into lastUpdate.
  • because device.lastUpdate does not contain any milliseconds information, clicking the switch fast results in multiple events all having the same thisUpdate value (rounded to a second), i.e. the script will incorrectly conclude that no change was made to the switch if you succeed to switch the device on and then off within one and the same second. Can we please get milliseconds in the lastUpdate value?

Code: Select all

return {
    on = {
        devices = {
            "myTest"
        },
        customEvents = {
            "myTestEvent*"
        }
    },

    logging =
    {
        level = domoticz.LOG_ERROR,
    },

    execute = function(dz, item)
        ---- rrozema: For my functionality I don't want to suppress any 
        ---- events, so I don't need following 3 lines of code.
        --if item.isDevice and item.lastUpdate.secondsAgo < 10 then
        --    return
        --end

        if item.isDevice then
            -- If the device state changes to 'On', we will emit a customEvent, carrying 
            -- extra data identifying the device, the state it reached and the exact 
            -- timestamp when it happened.
        
            -- Following is a work-around: I would like to retrieve the value from 
            -- item.lastUpdate here. However, lastUpdate is only set AFTER the device
            -- trigger gets executed. For this reason We are going to "guess" the time
            -- that will be put into lastUpdate, hoping that it is accurate enough to
            -- be equal to the lastUpdate value we find on the device X (X = 10 in 
            -- this example) seconds from now.
            -- A better solution would be if dzVents were to provide the actual value 
            -- that is going to be put into lastUpdate after this trigger fires in some 
            -- way to us (for example via dz.thisUpdate). This would avoid the risk 
            -- that we "guess" a time that is a few ms before hh:mm:ss.000 and the 
            -- actual value put into lastUpdate is just a few ms later, resulting in 
            -- the seconds value in lastUpdate being 1 higher than our "guessed" value.
            local Time = require('Time')
            local thisUpdate = Time(os.date("%Y-%m-%d %H:%M:%S", os.time()))
           
            dz.log('"guessed" thisUpdate: ' .. thisUpdate.raw, dz.LOG_FORCE )
            
            local name = 'myTestEvent_' .. tostring(item.idx) .. '_' .. thisUpdate.raw
            local extraData = { ["idx"] = item.idx, ["bState"] = item.bState,  ["thisUpdate"] = thisUpdate }
            
            dz.emitEvent(name,  extraData).afterSec(10)
            return
        end

        -- If we get here, the customEvent must have been triggered. 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 I know the device is still unchanged after the 10 second delay.

        local myDevice = dz.devices('myTest')
	
        local extraData = item.json
        local thisUpdate = extraData.thisUpdate
	
        local lastUpdate = myDevice.lastUpdate
        local bState = myDevice.bState

        dz.log('device bState: ' .. tostring(bState), dz.LOG_FORCE )
        dz.log('extraData bState: ' .. tostring(extraData.bState), dz.LOG_FORCE )
        dz.log('bState Equal? ' ..  tostring(bState == extraData.bState) ,dz.LOG_FORCE)

        dz.log('device lastUpdate: ' .. lastUpdate.raw, dz.LOG_FORCE )
        dz.log('extraData thisUpdate: ' .. thisUpdate.raw, dz.LOG_FORCE )
        dz.log('Times Equal? ' ..  tostring(lastUpdate.compare(thisUpdate).compare == 0 ) ,dz.LOG_FORCE)

        if bState == extraData.bState and lastUpdate.compare(thisUpdate).compare == 0  then
            dz.log('No updates occurred since emitEvent was given', dz.LOG_FORCE)
        else
            dz.log('One or more updates occurred since emitEvent was given', dz.LOG_FORCE)
        end
    end
}
Here is some log output that demonstrates that the "guessed" thisUpdate can be different than the actual lastUpdate value set by Domoticz. I've toggled the myTest switch once and then waited 10 seconds. The script should say the switch was not changed, but it thiks it changed anyway:

Code: Select all

2020-06-03 19:14:24.954 (dummy) Light/Switch (myTest)
2020-06-03 19:14:24.936 Status: User: Admin initiated a switch command (552/myTest/Off)
2020-06-03 19:14:25.215 Status: dzVents: !Info: "guessed" thisUpdate: 2020-06-03 19:14:25


2020-06-03 19:14:35.528 Status: dzVents: !Info: device bState: false
2020-06-03 19:14:35.528 Status: dzVents: !Info: extraData bState: false
2020-06-03 19:14:35.528 Status: dzVents: !Info: bState Equal? true
2020-06-03 19:14:35.528 Status: dzVents: !Info: device lastUpdate: 2020-06-03 19:14:24
2020-06-03 19:14:35.528 Status: dzVents: !Info: extraData thisUpdate: 2020-06-03 19:14:25
2020-06-03 19:14:35.528 Status: dzVents: !Info: Times Equal? false
2020-06-03 19:14:35.528 Status: dzVents: !Info: One or more updates occurred since emitEvent was given
My version info is:
Version: 2020.2 (build 12067)
Build Hash: 0fc3c7b70
Compile Date: 2020-05-17 13:15:45
dzVents Version: 3.0.5
Python Version: 3.7.3 (default, Dec 20 2019, 18:57:59) [GCC 8.3.0]

Re: thisUpdate? (as opposed to lastUpdate)

Posted: Wednesday 03 June 2020 20:15
by waaren
rrozema wrote: Wednesday 03 June 2020 19:20 I have adapted your test code so that it serves my purpose below.
Sorry but I don't see that you use item.lastUpdate.current in your script. item.lastUpdate.current is the time object domoticz use for the lastupdated value after the event is triggered by the device. Therefore it is the essential part of the script.

Is there a reason why you don't use that one ?

Re: thisUpdate? (as opposed to lastUpdate)

Posted: Wednesday 03 June 2020 20:29
by rrozema
waaren wrote: Wednesday 03 June 2020 20:15
rrozema wrote: Wednesday 03 June 2020 19:20 I have adapted your test code so that it serves my purpose below.
Sorry but I don't see that you use item.lastUpdate.current in your script. item.lastUpdate.current is the time object domoticz use for the lastupdated value after the event is triggered by the device. Therefore it is the essential part of the script.

Is there a reason why you don't use that one ?
Nope. I didn't realise the importance of it :-) Let me try again!

Re: thisUpdate? (as opposed to lastUpdate)  [Solved]

Posted: Thursday 04 June 2020 8:12
by rrozema
That indeed does the trick! If we could have milliseconds in the lastUpdate in an upcoming release that would be awesome, as without millis you can flip the switch a few times quickly and the script won't detect it... With milliseconds in lastUpdate it would also be possible to implement double- or triple-click, etc functionality using the same logic. I will try to integrate the logic into my auto-on script and then publish a complete version with my other scripts. But for anyone looking for a similar solution, here's my completed test version. Thank you very much Waaren!

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
}