Page 1 of 1

How to handle duplicate events

Posted: Tuesday 01 August 2017 21:30
by PatrickM
Sometimes I get duplicate events from my Fibaro Motion Sensor (and other devices as well). I'll get two updates with the same value, but for both events the device changed flag is true. How is the value of this boolean determined? From what I could tell from the raw data table, all attributes are identical for both events.

I could introduce a persistent variable to store the 'last value' and for each event compare the value and only run the script if it is changed. Is there a better way to handle this (that doesn't require persistent data)?

Re: How to handle duplicate events

Posted: Wednesday 02 August 2017 10:06
by dannybloe
The changed attribute is determined by Domoticz. When the event is passed to the event system for that device it will trigger the event sub systems like dzVents. I'm afraid you indeed have to create some debounce code yourself for this. What I'd do is create a historical persistent data with maxItems = 1. (All values in such a variable are automatically time-stamped)

Code: Select all

return {
	on = { .. }
	data = {
		last = {history = true, maxItems = 1}
	}
	execute = function(domotitcz, device)
		local last = domoticz.data.last.get()
		if ( (last == nil or (last ~= nil and last.time.secondsAgo > 1)) then
			-- do your thing
			last.add('something') -- doesn't matter what you add, it's the time-stamp that matters
		end			
	end
}
Totally untested but you get the idea. There are probably lots of other solutions.

Re: How to handle duplicate events

Posted: Thursday 03 August 2017 7:46
by BakSeeDaa
That's very useful and should be among the examples scripts.

I already do this for my door bell. Now, The postman only rings once. :D

Cheers!

Re: How to handle duplicate events

Posted: Thursday 03 August 2017 14:08
by Doler
I experimented a bit to see how I could save a timestamp and tried the following:

Code: Select all

local testData = { 
	['value'] = 0,
	['lastupdate'] = 0
	}
	
return {
	active = true,
	on = {
		devices = { 'Testlamp1' }
	},
		data = {
			devstate = { initial = {} }
	},
		logging = {
			level = domoticz.LOG_INFO
	},
	execute = function(domoticz, device, triggerInfo)
	
	domoticz.log('Just testing...')
	testData.value = device.state
	testData.lastupdate = Time().sDateTime
	domoticz.data.devstate = testData
To my surprise this works and gives the following result:

Code: Select all

-- Persistent Data
local multiRefObjects = {

} -- multiRefObjects
local obj1 = {
	["devstate"] = {
		["lastupdate"] = "2017-08-03 13:59:53";
		["value"] = "On";
	};
}
return obj1
This is just a simple example but it proves that arrays can be used for persistent data. Probably this works for globalData as well. I would like to know if there are easier (shorter) ways to accomplish the same, e.g. define the array in the on-section.
Mark

NB. I use my own Time object to get the actual timestamp (Time().sDateTime) since device.lastUpdate gives me the previous update in stead of the update now. This has been changed in one of the latest betas.

Re: How to handle duplicate events

Posted: Friday 04 August 2017 12:28
by dannybloe
Mm, the on-section should be only declarative to keep things simple. And of course arrays can be persisted as well, you can put anything in there except for functions as they will not be serialized to the persistence-data file.
But.. my point earlier.. guess you missed my point: if you use an historical persistent variable you don't have to deal with time-stamping yourself as each time you add something to that variable it will automatically get the timestamp of that moment.

And of course, lastUpdate should be the previous update. Earlier this was always the current time which didn't allow you to compare stuff. Only for the triggered device though!! (the device in the on-section). But in your case you want to compare the timestamp in the history data with the current time I think (domoticz.time).
But it's all up to you :)

Re: How to handle duplicate events

Posted: Friday 04 August 2017 15:52
by Doler
The timestamp I get using an historical persistent variable is 2 hours earlier then my local (Netherlands) time (UTC time?) and thus not easy to compare with UI. That's the main reason I have my 'own' way. Correct me if I'm wrong on UTC time though.
Mark

Re: How to handle duplicate events

Posted: Friday 04 August 2017 16:00
by dannybloe
Mm... internally it is indeed utc time but when you query the time stamp (e.g. last.time.hour) it should be your local time as the utc info is in a subattribute (e.g. last.time.utcTime.hour and last.time.utcSystemTime is the current time in utc format). See It's all about time. At least that is how it should work.

Re: How to handle duplicate events

Posted: Friday 04 August 2017 22:14
by Doler
Test:

Code: Select all

return {
	active = true,
	on = {
		devices = { 'Testlamp1' }
	},
		data = {
			devstate = {history = true, maxItems = 1}
	},
		logging = {
			level = domoticz.LOG_INFO
	},
	execute = function(domoticz, device, triggerInfo)
	
	domoticz.log('Just testing...')
	domoticz.data.devstate.add(device.state)
	domoticz.log(Time().sDateTime)
The log:

Code: Select all

2017-08-04 22:09:40.581 dzVents: Info: ------ Start external script: just testing.lua: Device: "Testlamp1 (DummyHW)", Index: 181
2017-08-04 22:09:40.587 dzVents: Info: Just testing...
2017-08-04 22:09:40.588 dzVents: Info: 2017-08-04 22:09:40
2017-08-04 22:09:40.589 dzVents: Info: ------ Finished just testing.lua
The contents of the data file:

Code: Select all

-- Persistent Data
local multiRefObjects = {

} -- multiRefObjects
local obj1 = {
	["devstate"] = {
		[1] = {
			["data"] = "Off";
			["time"] = "2017-08-04 20:09:40";
		};
	};
}
return obj1
So 2 hours off

Re: How to handle duplicate events

Posted: Friday 04 August 2017 22:22
by dannybloe
Well. You don't get it ;)
You should not look into the data file. Maybe for troubleshooting but not like you do now. Like I said earlier: internally the timestamp is utc as you can see but in your script when you ask dzvents for the value of the timestamp you get it in local time. Just try the example I gave you.

Re: How to handle duplicate events

Posted: Monday 07 August 2017 15:02
by PatrickM
Thanks for the tip about using persistent data with history, however the timestamp doesn't provide enough resolution (no milliseconds)

Re: How to handle duplicate events

Posted: Monday 07 August 2017 15:06
by dannybloe
Milliseconds??? What do you expect?

Re: How to handle duplicate events

Posted: Monday 07 August 2017 15:25
by dannybloe
Ah. Nevermind. I'll see if I can add millis.

Re: How to handle duplicate events

Posted: Monday 07 August 2017 18:06
by dannybloe
Mm.. seems like there is no way in Lua to get the current system time in milliseconds. There is os.clock() but that's the amount of seconds since the Lua interpreter was started. But that's not the same. Every event that is triggered from Domoticz starts the Lua interpreter so if you have switch that creates to consecutive events right after each other then the interpreter is launched twice.
Maybe we could send the current time in milliseconds from domoticz and use that as the offset for os.clock()...

Re: How to handle duplicate events

Posted: Monday 07 August 2017 18:24
by dannybloe
Now that I'm thinking about it some more.. I must say that indeed I don't know what you mean by 'not enough resolution'. Actually for this debouncer to work you don't need millisecond resolution. You just want to know if the second event is too fast following the first event. Why is one second not enough to detect this? If the second event is within the same second (or even within 2 seconds) then you can consider it as the same event and you can ignore the second.

Re: How to handle duplicate events

Posted: Monday 07 August 2017 20:28
by PatrickM
I didn't know Lua doesn't support milliseconds, log records of domoticz have milliseconds but that would be C code. I have a solution by comparing the value, I just thought it would be neat if you could get a more precise time diff ;-)

Re: How to handle duplicate events

Posted: Monday 07 August 2017 22:59
by dannybloe
I agree and I have some idea on how to do that.