1
2
3
4
5**Note**: This document is maintained on [github](https://github.com/domoticz/domoticz/blob/development/dzVents/documentation/README.md), and the wiki version is automatically generated. Edits should be performed on github, or they may be suggested on the wiki article's [Discussion page](https://www.domoticz.com/wiki/Talk:DzVents:_next_generation_LUA_scripting).
6Editing can be done by any editor but if you are looking for a specialized markDown editor; [stackedit.io](https://stackedit.io/app#) would be a good choice.
7
8**Breaking change warning!!**: For people using with dzVents prior to version 2.4: Please read the [change log](#Change_log) below as there is an easy-to-fix breaking change regarding the second parameter passed to the execute function (it is no longer `nil` for timer/security triggers).
9
10Documentation for dzVents 2.3.0 (Domoticz v3.8153) can be found [here](https://github.com/domoticz/domoticz/blob/2f6ba5c5a8978a010d6867228ad84eab762c5936/dzVents/documentation/README.md).
11
12Documentation for dzVents 2.2.0 (Domoticz v3.5876) can be found [here](https://github.com/domoticz/domoticz/blob/9f75e45f994f87c8d8ce9cb39eaab85886df0be4/scripts/dzVents/documentation/README.md).
13
14# About dzVents
15dzVents /diː ziː vɛnts/, short for Domoticz Easy Events, brings Lua scripting in Domoticz to a whole new level. Writing scripts for Domoticz has never been so easy. Not only can you define triggers more easily, and have full control over timer-based scripts with extensive scheduling support, dzVents presents you with an easy to use API to all necessary information in Domoticz. No longer do you have to combine all kinds of information given to you by Domoticz in many different data tables. You don't have to construct complex commandArrays anymore. dzVents encapsulates all the Domoticz peculiarities regarding controlling and querying your devices. And on top of that, script performance has increased a lot if you have many scripts because Domoticz will fetch all device information only once for all your device scripts and timer scripts. And ... **it is 100% Lua**! So if you already have a bunch of event scripts for Domoticz, upgrading should be fairly easy.
16
17Let's start with an example. Say you have a switch that when activated, it should activate another switch but only if the room temperature is above a certain level. And when done, it should send a notification. This is how it looks in dzVents:
18
19```Lua
20return
21{
22	on =
23	{
24		devices = { 'Room switch'}
25	},
26
27	execute = function(domoticz, roomSwitch)
28		if (roomSwitch.active and domoticz.devices('Living room').temperature > 18) then
29		domoticz.devices('Another switch').switchOn()
30		domoticz.notify('This rocks!',
31						'Turns out that it is getting warm here',
32						domoticz.PRIORITY_LOW)
33		end
34
35}
36```
37
38Or you have a timer script that should be executed every 10 minutes, but only on weekdays, and have it do something with some user variables and only during daytime:
39
40```Lua
41return
42{
43	on =
44	{
45		timer = {'Every 10 minutes on mon,tue,wed,thu,fri'}
46	},
47
48	execute = function(domoticz)
49		-- check time of the day
50		if (domoticz.time.isDayTime and domoticz.variables('myVar').value == 10) then
51			domoticz.variables('anotherVar').set(15)
52			--activate my scene
53			domoticz.scenes('Evening lights').switchOn()
54			if (domoticz.devices('My PIR').lastUpdate.minutesAgo > 5) then
55				domoticz.devices('Bathroom lights').switchOff()
56			end
57		end
58	end
59}
60```
61
62Or you want to detect a humidity rise within the past 5 minutes:
63
64```Lua
65return
66{
67	on =
68	{
69		timer = {'every 5 minutes'}
70	},
71	data =
72	{
73		previousHumidity = { initial = 100 }
74	},
75	execute = function(domoticz)
76		local bathroomSensor = domoticz.devices('BathroomSensor')
77		if (bathroomSensor.humidity - domoticz.data.previousHumidity) >= 5) then
78			-- there was a significant rise
79			domoticz.devices('Ventilator').switchOn()
80		end
81		-- store current value for next cycle
82		domoticz.data.previousHumidity = bathroomSensor.humidity
83	nd
84}
85```
86
87Just to give you an idea! Everything in your Domoticz system is now logically available in the domoticz object structure. With this domoticz object, you can get to all the information in your system and manipulate your devices.
88
89# Using dzVents with Domoticz
90In Domoticz go to **Setup > Settings > Other**  and in the section EventSystem make sure the check-box 'dzVents disabled' is not checked.
91Also make sure that in the Security section in the settings **(Setup > Settings > System > Local Networks (no username/password)** you allow 127.0.0.1 to not need a password. dzVents uses that port to send certain commands to Domoticz. Finally make sure you have set your current location in **Setup > Settings > System > Location**, otherwise there is no way to determine nighttime/daytime state.
92
93There are two ways of creating dzVents event scripts in Domoticz:
94
95 1. By creating scripts in your domoticz instance on your domoticz server: `/path/to/domoticz/scripts/dzVents/scripts`. Make sure that each script has the extension `.lua` and follows the guidelines as described below.
96 2. By creating scripts inside Domoticz using the internal Domoticz event editor: Go to **Setup > More Options > Events**. Press the + button and choose dzVents. You must then choose a template. They are there just for convenience during writing the script; the actual trigger for the script is determined by what you entered in the on = section. The internal event editor have a help button <sup>2.4.23</sup> when writing dzVents scripts, next to Save and Delete. This button opens this wiki in a separate browser tab when clicked. Name your script to your liking but leave out the extension .lua
97
98**Note: scripts that you write on the file-system and inside Domoticz using the internal web-editor all share the same name-space. That means that if you have two scripts with the same name, only the one of the file-system will be used. The log will tell you when this happens.**
99
100**Note: Scripts created in the internal editor are stored in the domoticz database and are all written to `/path/to/domoticz/scripts/dzVents/generated_scripts` on every domoticz restart and every "EventSystem: reset all events...". Scripts in `/path/to/domoticz/scripts/dzVents/scripts` are not stored in the database and should be backed-up separately. **
101
102## Quickstart
103If you made sure that dzVents system is active, we can do a quick test if everything works:
104
105 - Pick a switch in your Domoticz system. Write down the exact name of the switch. If you don't have a switch then you can create a Dummy switch and use that one.
106 - Create a new file in the `/path/to/domoticz/scripts/dzVents/scripts/` folder (or using the web-editor in Domoticz, switch to dzVents mode first.). Call the file `test.lua`. *Note: when you create a script in the web-editor you do **not** add the .lua extension!* Also, valid script names follow the same rules as [filesystem names](https://en.wikipedia.org/wiki/Filename#Reserved_characters_and_words ).
107 - Open `test.lua` in an editor and fill it with this code and change `<exact name of the switch>` with the .. you guessed it... exact name of the switch device:
108```Lua
109	 return {
110		on = {
111		  devices = {
112			 '<exact name of the switch>'
113		  }
114		},
115		execute = function(domoticz, switch)
116		  if (switch.state == 'On') then
117			 domoticz.log('Hey! I am on!')
118		  else
119			 domoticz.log('Hey! I am off!')
120		  end
121		end
122	}
123```
124 - Save the script
125 - Open the Domoticz log in the browser
126 - In Domoticz  GUI (perhaps in another browser tab) press the switch.
127 - You can watch the log in Domoticz and it should show you that indeed it triggered your script and you should see the log messages.
128
129See the examples folder `/path/to/domoticz/scripts/dzVents/examples` for more examples. This folder includes templates you can use to get started as well. And, if you use the GUI web editor to write your script, you will find boilerplate examples in the drop-down below the script type setting.
130
131# Writing scripts
132In order for your scripts to work with dzVents, they have to be turned into a Lua module with a specific structure. Basically you make sure it returns a Lua table (object) with predefined keys like `on` and `execute`. Here is an example:
133
134```Lua
135return
136{
137	on =
138	{
139		devices = { 'My switch' }
140	},
141
142	execute = function(domoticz, switch)
143		-- your script logic goes here, something like this:
144		if (switch.state == 'On') then
145			domoticz.log('I am on!', domoticz.LOG_INFO)
146		end
147	end
148}
149```
150
151Simply said, the `on`-part defines the trigger and the `execute` part is what should be done if the trigger matches with the current Domoticz event. So all your logic is inside the `execute` function.
152
153## Sections in the script
154Each dzVents event script has this structure:
155```Lua
156return
157{
158	active = true, -- optional
159	on =
160	{
161		-- at least one of these:
162		customEvents = { ... },
163		devices = { ... },
164		groups = { ... },
165		httpResponses = { ... },
166		scenes = { ... },
167		security = { ... },
168		system = { ... },
169		timer = { ... },
170		variables = { ... },
171
172	},
173	data = { ... }, -- optional
174	logging = { ... }, -- optional
175	execute = function(domoticz, item, triggerInfo)
176	-- your code here
177	end
178}
179```
180
181### active = true/false (optional)
182If `active = false`, then the script is not activated: *dzVents will ignore the script completely*. If you don't have `active` specified, `true` is assumed (default value). If you write scripts with Domoticz' internal script editor then you don't need this part as the editor has its own way of enabling and disabling scripts.
183
184So, `active` can either be:
185
186 - **true**: (default) the script file will be processed.
187 - **false**: the script file is ignored.
188 - **function(domoticz) ... end**: A function returning `true` or `false`. The function will receive the domoticz object with all the information about your domoticz instance: `active = function(domoticz) .... end`. For example you could check for a Domoticz variable or switch and prevent the script from being executed. **However, be aware that for *every script* in your scripts folder, this active function will be called, every cycle!! Therefore, it is better to put all your logic in the execute function instead of in the active function.**
189
190### on = { ... }
191The `on` section tells dzVents *when* the execute function has to be executed. It holds all the events/**triggers** that are monitored by dzVents. If any of the events or triggers match with the current event coming from Domoticz, then the `execute` part of the script is executed by dzVents.
192The `on` section has many kinds of subsections that *can all be used simultaneously* :
193
194#### customEvents = { ... } <sup>3.0.0</sup>
195A list of one or more custom event triggers. This eventTrigger can be activate by a json/api call, a MQTT message (when domoticz is setup to listen to such messages on the hardware tab) or by the dzVents internal command domoticz.emitEvent
196 - The name of the custom-event
197 - The name of the custom-event followed by a time constraint, such as:
198	`['start']  = { 'at 15:*', 'at 22:* on sat, sun' }` The script will be executed if domoticz is started, **and** it is either between 15:00 and 16:00 or between 22:00 and 23:00 in the weekend. See [See time trigger rules](#timer_trigger_rules).
199
200	- JSON: **< domoticzIP : domoticz port >**/json.htm?type=command&param=customevent&event=MyEvent&data=myData
201	- MQTT simple:  {"command":"customevent", "event":"MyEvent","data":"myData"}
202	- MQTT complex: {"command":"customevent","event":"MyEvent","data":"{\"idx\":29,\"test\":\"ok\"}" }
203	- emitEvent: domoticz.emitEvent('myCustomEvent' [,])
204		`domoticz.emitEvent('myEvent') -- no data`
205		`domoticz.emitEvent('another event', 'some data')`
206		`domoticz.emitEvent('hugeEvent', { a = 10, b = 20, some = 'text', sub = { x = 10, y = 20 } })`
207
208#### devices = { ... }
209A list of device-names or indexes. If a device in your system was updated (e.g. switch was triggered or a new temperature was received) and it is listed in this section then the execute function is executed. **Note**: update does not necessarily means the device state or value has changed. Each device can be:
210
211 - The name of your device between string quotes. **You can use the asterisk (\*) wild-card here e.g. `PIR_*` or `*_PIR`**.  E.g.: `devices = { 'myDevice', 'anotherDevice', 123, 'pir*' }`
212 - The index (idx) of your device (as the name may change, the index will usually stay the same, the index can be found in the devices section in Domoticz). **Note that idx is a number;**
213 - The name or idx of your device followed by a time constraint, such as:
214	`['myDevice']  = { 'at 15:*', 'at 22:* on sat, sun' }` The script will be executed if `myDevice` was changed, **and** it is either between 15:00 and 16:00 or between 22:00 and 23:00 in the weekend. See [time trigger rules](#timer_trigger_rules).
215
216#### groups = { ...}
217A list of one or more group-names or indexes. The same rules as devices apply.
218
219#### httpResponses = { ...}
220A list of  one or more http callback triggers. Use this in conjunction with `domoticz.openURL()` where you will provide Domoticz with the callback trigger.  See [asynchronous http requests](#Asynchronous_HTTP_requests) for more information.
221
222#### scenes = { ... }
223 A list of one or more scene-names or indexes. The same rules as devices apply. So if your scene is listed in this table then the executed function will be triggered, e.g.: `on = { scenes = { 'myScene', 'anotherScene' } },`.
224
225#### security = { ... }
226A list of one or more of these security states:
227
228 - `domoticz.SECURITY_ARMEDAWAY`,
229 - `domoticz.SECURITY_ARMEDHOME`,
230 - `domoticz.SECURITY_DISARMED`
231
232If the security state in Domoticz changes and it matches with any of the states listed here, the script will be executed. See `/path/to/domoticz/scripts/dzVents/examples/templates/security.lua` for an example see [Security Panel](#Security_Panel) for information about how to create a security panel device.
233
234#### system = { ...} <sup>3.0.0</sup>
235A list of  one or more system triggers.
236
237- `stop`,
238`start`,
239`manualBackupFinished`,
240`dailyBackupFinished`,
241`hourlyBackupFinished`,
242`monthlyBackupFinished`,
243
244 - The name of the system-event followed by a time constraint, such as:
245	`['start']  = { 'at 15:*', 'at 22:* on sat, sun' }` The script will be executed if domoticz is  started, **and** it is either between 15:00 and 16:00 or between 22:00 and 23:00 in the weekend. See [time trigger rules](#timer_trigger_rules).
246	-   **start**  - fired when Domoticz has started.
247	-   **stop**  - fired when Domoticz is shutting down. As you probably can imagine you have only a limited amount of time - also depending on the load on your system -  to have Domoticz do stuff when your script has been completed. Some commands will probably not be executed. Just give it a try.
248	-  **Backups** - the trigger item (2nd parameter of the execute function) is a table that holds information about the newly created backup (location,  duration in seconds and type).  You could use this information to copy the file to some other location or for another purpose.
249		-   **dailyBackupFinished**    - automatic backup when set in domoticz
250		-   **hourlyBackupFinished** 	 -						    " "
251		-   **monthlyBackupFinished** - " "
252		-   **manualBackupFinished**  - fired when you start a backup using the Domoticz GUI or via **< domoticz IP:domoticz port >**/backupdatabase.php
253
254
255#### timer = { ... }
256A list of one ore more time 'rules' like `every minute` or `at 17:*`. See [*timer* trigger rules](#timer_trigger_rules). If any or the rules matches with the current time/date then your execute function is called. E.g.: `on = { timer = { 'between 30 minutes before sunset and 30 minutes after sunrise' } }`.
257
258#### variables = { ... }
259A list of one or more user variable-names as defined in Domoticz ( *Setup > More options > User variables*). If any of the variables listed here is updated, ( **Note**: update does not necessarily means the variable value or type changed ).the script is executed. **Note**: Script will only execute when this variable is updated directly by dzVents or by a JSON. If updated with a standard Lua script (using commandArray) or in combination with a time option like afterAAA no event will be triggered.
260
261### execute = function(**domoticz, item, triggerInfo**) ... end
262When all the above conditions are met (active == true and the on section has at least one matching rule), then this `execute` function is called. This is the heart of your script. The function has three parameters:
263
264#### 1. (**domoticz**, item, triggerInfo)
265 The [domoticz object](#Domoticz_object_API_.28Application_Programming_Interface.29). This object gives you access to almost everything in your Domoticz system, including all methods to manipulate them—like modifying switches or sending notifications. More about the [domoticz object](#Domoticz_object_API_.28Application_Programming_Interface.29) below.
266
267#### 2. (domoticz, **item**, triggerInfo)
268 Depending on what actually triggered the script, `item` is either a:
269
270 - [customEvent](#Custom_event_API) <sup>3.0.0</sup>
271 - [device](#Device_object_API),
272 - [variable](#Variable_object_API_.28user_variables.29),
273 - [scene](#Scene),
274 - [group](#Group),
275 - [timer](#timer_=_{_..._} ),
276 - [system](#System_event_API), <sup>3.0.0</sup>
277 - [security](#Security_Panel) or
278 - [httpResponse](#Asynchronous_HTTP_requests)
279
280Since you can define multiple on-triggers in your script, it is not always clear what the type is of this second parameter. In your code you need to know this in order to properly respond to the different events. To help you inspect the object you can use these attributes like `if (item.isDevice) then ... end`:
281
282 - **isCustomEvent**: <sup>3.0.0</sup>. returns `true` if the item is a customEvent.
283 - **isDevice**: . returns `true` if the item is a Device object.
284 - **isGroup**: . returns `true` if the item is a Group object.
285 - **isHTTPResponse**: .  returns `true` if the item is an HTTPResponse object.
286 - **isScene**: . returns `true` if the item is a Scene object.
287 - **isSecurity**: .  returns `true` if the item is a Security object.
288 - **isSystem**: <sup>3.0.0</sup>.  returns `true` if the item is a system object.
289 - **isTimer**: .  returns `true` if the item is a Timer object.
290-  **isVariable**: .  returns `true` if the item is a Variable object.
291
292 - **trigger**: .  *string*. the timer rule, the security state, the customEvent or the http response callback string that actually triggered your script. E.g. if you have multiple timer rules can inspect `trigger` which exact timer rule was fired.
293
294#### 3. (domoticz, item, **triggerInfo**)
295**Note**: as of version 2.4.0, `triggerInfo` has become more or less obsolete and is left in here for backward compatibility. All information is now available on the `item` parameter (second parameter of the execute function, see point 2 above).
296
297`triggerInfo` holds information about what triggered the script. The object has two attributes:
298
299 1. **type**:  the type of the the event that triggered the execute function, either:
300	  - domoticz.EVENT_TYPE_CUSTOM,<sup>3.0.0</sup>
301	  - domoticz.EVENT_TYPE_DEVICE,
302	  - domoticz.EVENT_TYPE_GROUP
303	  - domoticz.EVENT_TYPE_HTTPRESPONSE
304	  - domoticz.EVENT_TYPE_SCENE,
305	  - domoticz.EVENT_TYPE_SECURITY,
306	  - domoticz.EVENT_TYPE_SYSTEM,<sup>3.0.0</sup>
307	  - domoticz.EVENT_TYPE_TIMER,
308	  - domoticz.EVENT_TYPE_VARIABLE)
309
310 2. **trigger**: the timer rule that triggered the script if the script was called due to a timer event, or the security state that triggered the security trigger rule. See [below](#timer_trigger_rules) for the possible timer trigger rules.
311 3. **scriptName**: the name of the current script.
312
313#### Tip: rename the parameters to better fit your needs
314The names of the execute parameters are actually something you can change to your convenience. For instance, if you only have one trigger for a specific switch device, you can rename `item` it to `switch`. Or if you think `domoticz` is too long you can rename it to `d` or `dz` (might save you a lot of typing and may make your code more readable):
315```Lua
316return
317{
318	on =
319	{
320		devices = 'mySwitch'
321	},
322	execute = function(dz, mySwitch)
323		dz.log(mySwitch.state, dz.LOG_INFO)
324	end
325}
326```
327
328### data = { ... } (optional)
329The optional data section allows you to define local variables that will hold their values *between* script runs. These variables can get a value in your execute function and the next time the script is executed these variables will have their previous state restored. For more information see the section [Persistent data](#Persistent_data).
330
331### logging = { ... } (optional)
332The optional logging section allows you to override the global logging setting of dzVents as set in *Setup > Settings > Other > EventSystem > dzVents Log Level*. This can be handy when you only want this script to have extensive debug logging while the rest of your script executes silently. You have these options:
333
334 - **level**: This is the log level you want for this script. Can be domoticz.LOG_INFO, domoticz.LOG_MODULE_EXEC_INFO, domoticz.LOG_DEBUG or domoticz.LOG_ERROR
335 - **marker**: A string that is prefixed before each log message. That way you can easily create a filter in the Domoticz log to see just these messages.
336
337Example:
338```Lua
339logging = {
340	level = domoticz.LOG_DEBUG,
341	marker = "Hey you"
342	},
343```
344
345## Some trigger examples
346### Custom events
347Suppose you want to trigger a script not on the minute but 30 seconds later.
348
349```Lua
350return
351{
352	on =
353	{
354		timer =
355		{
356			'every minute',
357		},
358
359		customEvents =
360		{
361			'delayed',
362		},
363},
364	execute = function(domoticz, item)
365		if item.isTimer then
366			domoticz.emitEvent('delayed', domoticz.time.rawTime ).afterSec(30)
367		else
368			domoticz.notify('Delayed', 'Event was emitted at ' .. item.data, domoticz.PRIORITY_LOW)
369		end
370	end
371}
372```
373
374### Device changes
375Suppose you have two devices—a smoke detector 'myDetector' and a room temperature sensor 'roomTemp', and you want to send a notification when either the detector detects smoke or the temperature is too high:
376
377```Lua
378return
379{
380	on =
381	{
382		devices = {
383			'myDetector',
384			'roomTemp'
385	}
386},
387	execute = function(domoticz, device)
388		if ((device.name == 'myDetector' and device.active) or
389			(device.name == 'roomTemp' and device.temperature >= 45)) then
390			domoticz.notify('Fire', 'The room is on fire', domoticz.PRIORITY_EMERGENCY)
391		end
392	end
393}
394```
395
396### Scene / group changes
397Suppose you have a scene 'myScene' and a group 'myGroup', and you want to turn on the group as soon as myScene is activated:
398```Lua
399return {
400	on = {
401	  scenes = { 'myScene' }
402	},
403	execute = function(domoticz, scene)
404	  if (scene.state == 'On') then
405		 domoticz.groups('myGroup').switchOn()
406	  end
407	end
408}
409```
410Or, if you want to send an email when a group is activated at night:
411```Lua
412return {
413	on = {
414	  groups = { ['myGroup'] = {'at nighttime'} }
415	},
416	execute = function(domoticz, group)
417	  if (group.state == 'On') then
418		 domoticz.email('Hey', 'The group is on', 'someone@the.world.org')
419	  end
420	end
421}
422```
423### Timer events
424Suppose you want to check the soil humidity every 30 minutes during the day and every hour during the night:
425```Lua
426return {
427	on = {
428	  timer = {
429		 'every 30 minutes at daytime',
430		 'every 60 minutes at nighttime'
431	  }
432	},
433	execute = function(domoticz, timer)
434	  domoticz.log('The rule that triggered the event was: ' .. timer.trigger')
435	  if (domoticz.devices('soil').moisture > 100) then
436		 domoticz.devices('irrigation').switchOn().forMin(60)
437	  end
438	end
439}
440```
441### Variable changes
442Suppose you have a script that updates a variable 'myAmountOfMoney', and if that variable reaches a certain level you want to be notified:
443```Lua
444return
445{
446	on =
447	{
448	  variables = { 'myAmountOfMoney' }
449	},
450	execute = function(domoticz, variable)
451		-- variable is the variable that's triggered
452		if (variable.value > 1000000) then
453			domoticz.notify('Rich', 'You can stop working now', domoticz.PRIORITY_HIGH)
454		end
455	end
456}
457```
458
459### Security changes
460Suppose you have a group holding all the lights in your house, and you want to switch it off as soon as the alarm is activated:
461```Lua
462return
463{
464	on =
465	{
466		security = { domoticz.SECURITY_ARMEDAWAY }
467	},
468	execute = function(domoticz, security)
469		domoticz.groups('All lights').switchOff()
470	end
471}
472```
473
474### Asynchronous HTTP Request and handling
475Suppose you have some external web service that will tell you what the current energy consumption is and you want that information in Domoticz:
476```Lua
477return {
478	on = {
479	  timer = { 'every 5 minutes' },
480	  httpResponses = { 'energyRetrieved' }
481	},
482	execute = function(domoticz, item)
483	  if (item.isTimer) then
484		 domoticz.openURL({
485			url = 'http://url/to/service',
486			method = 'GET',
487			callback = 'energyRetrieved'
488		 })
489	  elseif (item.isHTTPResponse) then
490		 if (item.ok) then -- statusCode == 2xx
491			local current = item.json.consumption
492			domoticz.devices('myCurrentUsage').updateEnergy(current)
493		 end
494	  end
495	end
496}
497```
498See[ asynchronous http requests](#Asynchronous_HTTP_requests) for more information.
499
500### System changes
501Do some initial work when domoticz starts
502
503```Lua
504return
505{
506	on =
507	{
508		system =
509		{
510			'start',
511			'backupDoneDaily',
512		},
513
514	},
515
516	execute = function(domoticz, system)
517		domoticz.log('Domoticz sends ' ..  system.type, domoticz.LOG_INFO)
518
519		if system.type == 'start' then
520			domoticz.device('initial device').switchOff().silent
521			domoticz.variables('special startVar').set('domoticz started at ' .. domoticz.time.rawDateTime )
522		elseif system.type == 'backupDoneDaily' then
523			domoticz.notify('Domoticz backup', 'Ended. Backupfile ' .. system.data.location , domoticz.PRIORITY_LOW)
524		end
525	end
526}
527```
528
529### Combined rules
530Let's say you have a script that checks the status of a lamp and is triggered by motion detector:
531```Lua
532return {
533	on = {
534	  timer = { 'every 5 minutes' },
535	  devices = { 'myDetector' }
536	},
537	execute = function(domoticz, item)
538	  if (item.isTimer) then
539		 -- the timer was triggered
540		 domoticz.devices('myLamp').switchOff()
541	  elseif (item.isDevice and item.active) then
542		 -- it must be the detector
543		 domoticz.devices('myLamp').switchOn()
544	  end
545	end
546}
547```
548
549## *timer* trigger rules
550There are several options for time triggers. It is important to know that Domoticz timer events only trigger once every minute, so one minute is the smallest interval for your timer scripts. However, dzVents gives you many options to have full control over when and how often your timer scripts are called (all times are in 24hr format and all dates in dd/mm):
551
552```Lua
553	on = {
554		timer = {
555			'every minute',				-- causes the script to be called every minute
556			'every other minute',		-- minutes: xx:00, xx:02, xx:04, ..., xx:58
557			'every <xx> minutes',		-- starting from xx:00 triggers every xx minutes
558										-- (0 > xx < 60)
559			'every hour',				-- 00:00, 01:00, ..., 23:00  (24x per 24hrs)
560			'every other hour',		  	-- 00:00, 02:00, ..., 22:00  (12x per 24hrs)
561			'every <xx> hours',			-- starting from 00:00, triggers every xx
562										-- hours (0 > xx < 24)
563			'at 13:45',					-- specific time
564			'at *:45',					-- every 45th minute in the hour
565			'at 15:*',					-- every minute between 15:00 and 16:00
566			'at 12:45-21:15',			-- between 12:45 and 21:15. You cannot use '*'!
567			'at 19:30-08:20',			-- between 19:30 and 8:20 then next day
568			'at 13:45 on mon,tue',		-- at 13:45 only on Mondays and Tuesdays (english)
569			'on mon,tue',				-- on Mondays and Tuesdays
570			'every hour on sat',		-- you guessed it correctly
571			'at sunset',				-- uses sunset/sunrise info from Domoticz
572			'at sunrise',
573			'at civiltwilightstart',	-- uses civil twilight start/end info from Domoticz
574			'at civiltwilightend',
575			'at sunset on sat,sun',
576			'xx minutes before civiltwilightstart',
577			'xx minutes after civiltwilightstart',
578			'xx minutes before civiltwilightend',
579			'xx minutes after civiltwilightend',
580			'xx minutes before sunset',
581			'xx minutes after sunset',
582			'xx minutes before sunrise',
583			'xx minutes after sunrise'	-- guess ;-)
584			'between aa and bb'			-- aa/bb can be a time stamp like 15:44
585										-- aa/bb can be sunrise/sunset
586										-- aa/bb can be 'xx minutes before/after sunrise/sunset'
587			'at civildaytime',			-- between civil twilight start and civil twilight end
588			'at civilnighttime',		-- between civil twilight end and civil twilight start
589			'at nighttime',				-- between sunset and sunrise
590			'at daytime',				-- between sunrise and sunset
591			'at daytime on mon,tue',	-- between sunrise and sunset only on Mondays and Tuesdays
592			'in week 12,44'				-- in week 12 or 44
593			'in week 20-25,33-47'		-- between week 20 and 25 or week 33 and 47
594			'in week -12, 33-'			-- week <= 12 or week >= 33
595			'every odd week',
596			'every even week',			-- odd or even numbered weeks
597			'on 23/11',					-- on 23rd of november (dd/mm)
598			'on 23/11-25/12',			-- between 23/11 and 25/12
599			'on 2/3-18/3',11/8,10/10-14/10',
600			'on */2,15/*',				-- every day in February or
601										-- every 15th day of the month
602			'on -3/4,4/7-',				-- before 3/4 or after 4/7
603
604			-- or if you want to go really wild and combine them:
605				'at nighttime at 21:32-05:44 every 5 minutes on sat, sun',
606				'every 10 minutes between 20 minutes before sunset and 30 minutes after sunrise on mon,fri,tue on 20/5-18/8'
607
608			-- or just do it yourself:
609				function(domoticz)
610				-- you can use domoticz.time to get the current time
611				-- note that this function is called every minute!
612				-- custom code that either returns true or false
613				...
614			end
615	  },
616	}
617```
618
619The timer events are triggered every minute. If such a trigger occurs, dzVents will scan all timer-based events and will evaluate the timer rules. So, if you have a rule `on mon` then the script will be executed *every minute* but only on Monday.
620
621Be mindful of the logic if using multiple types of timer triggers. It may not make sense to combine a trigger for a specific or instantaneous time with a trigger for a span or sequence of times (like 'at sunset' with 'every 6 minutes') in the same construct. Similarly, `'between aa and bb'` only makes sense with instantaneous times for `aa` and `bb`.
622
623**One important note: if Domoticz, for whatever reason, skips a timer event then you may miss the trigger! Therefore, you should build in some fail-safe checks or some redundancy if you have critical time-based stuff to control. There is nothing dzVents can do about it**
624
625Another important issue: the way it is implemented right now, the `every xx minutes` and `every xx hours` is a bit limited. The interval resets at every \*:00  (for minutes) or 00:* for hours. You need an interval that is an integer divider of 60 (or 24 for the hours). So you can do every 1, 2, 3, 4, 5, 6, 10, 12, 15, 20 and 30 minutes only.
626
627# The domoticz object
628The domoticz object passed as the first parameter to the `execute` function contains everything you need to interact with your domotica system. It provides all the information about your devices, scenes, groups, variables and has all the methods needed to inspect and manipulate them. Getting this information is easy:
629
630`domoticz.time.isDayTime` or `domoticz.devices('My sensor').temperature` or `domoticz.devices('My sensor').lastUpdate.minutesAgo`.
631
632The domoticz object consists of a logically arranges structure. It harbors all methods to manipulate Domoticz. dzVents will take care to notify Domoticz with all your intended changes and actions. Earlier you had to fill a commandArray with obscure commands. That's no longer the case.
633
634Some more examples:
635 `domoticz.devices(123).switchOn().forMin(5).afterSec(10)` or
636 `domoticz.devices('My dummy sensor').updateBarometer(1034, domoticz.BARO_THUNDERSTORM)`.
637
638One tip before you get started:
639**Make sure that all your devices have unique names. dzVents will give you warnings in the logs if device names are not unique.**
640
641##  Domoticz object API (Application Programming Interface)
642The domoticz object holds all information about your Domoticz system. It has global attributes and methods to query and manipulate your system. It also has a collection of **devices**, **variables** (user variables in Domoticz), **scenes**, **groups**. Each of these collections has three iterator functions: `forEach()`, `filter()` and `reduce()` to make searching for devices easier. See [Looping through the collections: iterators](#Looping_through_the_collections:_iterators).
643
644### Domoticz attributes and methods
645 - **devices(idx/name)**: *Function*. A function returning a device by idx or name: `domoticz.devices(123)` or `domoticz.devices('My switch')`. For the device API see [Device object API](#Device_object_API). To iterate over all devices do: `domoticz.devices().forEach(..)`. See [Looping through the collections: iterators](#Looping_through_the_collections:_iterators). Note that you cannot do `for i, j in pairs(domoticz.devices()) do .. end`.
646 - **dump([osfile]<sup>3.0.0</sup>)**: *Function*. <sup>2.4.16</sup> Dump all domoticz.settings attributes to the Domoticz log. This ignores the log level setting.
647 - **email(subject, message, mailTo)**: *Function*. Send email.
648 - **emitEvent(name,[extra data ])**:*Function*. <sup>3.0.0</sup> Have Domoticz 'call' a customEvent. If you just pass a name then Domoticz will execute the script(s) that subscribed to the named customEvent after your script has finished. You can optionally pass extra information as a string or table. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
649 - **groups(idx/name)**: *Function*: A function returning a group by name or idx. Each group has the same interface as a device. To iterate over all groups do: `domoticz.groups().forEach(..)`. See [Looping through the collections: iterators](#Looping_through_the_collections:_iterators). Note that you cannot do `for i, j in pairs(domoticz.groups()) do .. end`. Read more about [Groups](#Group).
650 - **helpers**: *Table*. Collection of shared helper functions available to all your dzVents scripts. See [Shared helper functions](#Shared_helper_functions).
651 - **log(message, [level])**: *Function*. Creates a logging entry in the Domoticz log but respects the log level settings. You can provide the loglevel: `domoticz.LOG_INFO`, `domoticz.LOG_DEBUG`, `domoticz.LOG_ERROR` or `domoticz.LOG_FORCE`. In Domoticz settings you can set the log level for dzVents.
652- **moduleLabel**: <sup>3.0.3</sup> Module (script) name without extension.
653 - **notify(subject, message, priority, sound, extra, subsystem)**: *Function*. Send a notification (like Prowl). Priority can be like `domoticz.PRIORITY_LOW, PRIORITY_MODERATE, PRIORITY_NORMAL, PRIORITY_HIGH, PRIORITY_EMERGENCY`. For sound see the SOUND constants below. `subsystem` can be a table containing one or more notification subsystems. See `domoticz.NSS_subsystem` types.
654 - **openURL(url/options)**: *Function*. Have Domoticz 'call' a URL. If you just pass a url then Domoticz will execute the url after your script has finished but you will not get notified.  If you pass a table with options then you have to possibility to receive the results of the request in a dzVents script. Read more about [asynchronous http requests](#Asynchronous_HTTP_requests) with dzVents. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
655 - **scenes(idx/name)**: *Function*: A function returning a scene by name or id. Each scene has the same interface as a device. See [Device object API](#Device_object_API). To iterate over all scenes do: `domoticz.scenes().forEach(..)`. See [Looping through the collections: iterators]. (#Looping_through_the_collections:_iterators). Note that you cannot do `for i, j in pairs(domoticz.scenes()) do .. end`. Read more about [Scenes](#Scene).
656 - **security**: Holds the state of the security system e.g. `Armed Home` or `Armed Away`.
657 - **sendCommand(command, value)**: Generic (low-level)command method (adds it to the commandArray) to the list of commands that are being sent back to domoticz. *There is likely no need to use this directly. Use any of the device methods instead (see below).*
658 - **settings**:
659	- **domoticzVersion**:<sup>2.4.15</sup> domoticz version string.
660	- **dzVentsVersion**:<sup>2.4.15</sup> dzVents version string.
661	- **location**
662		- **latitude**:<sup>2.4.14</sup> domoticz settings locations latitude.
663		- **longitude**:<sup>2.4.14</sup> domoticz settings locations longitude.
664		- **name**:<sup>2.4.14</sup> domoticz settings location Name.
665	- **serverPort**: webserver listening port.
666	- **url**: internal url to access the API service.
667	- **webRoot**: `webroot` value as specified when starting the Domoticz service.
668 - **sms(message)**: *Function*. Sends an sms if it is configured in Domoticz.
669 - **snapshot(cameraID or camera Name<sup>2.4.15</sup>,subject)**:<sup>2.4.11</sup> *Function*. Sends email with a camera snapshot if email is configured and set for attachments in Domoticz.
670 - **startTime**: *[Time Object](#Time_object)*. Returns the startup time of the Domoticz service.
671 - **systemUptime**: *Number*. Number of seconds the system is up.
672 - **time**: *[Time Object](#Time_object)*: Current system time. Additional to Time object attributes:
673	- **isDayTime**: *Boolean*
674	- **isNightTime**: *Boolean*
675	- **isCivilDayTime**: *Boolean*. <sup>2.4.7</sup>
676	- **isCivilNightTime**: *Boolean*. <sup>2.4.7</sup>
677	- **isToday**: *Boolean*. Indicates if the device was updated today
678	- **sunriseInMinutes**: *Number*. Number of minutes since midnight when the sun will rise.
679	- **sunsetInMinutes**: *Number*. Number of minutes since midnight when the sun will set.
680	- **civTwilightStartInMinutes**: *Number*. <sup>2.4.7</sup> Number of minutes since midnight when the civil twilight will start.
681	- **civTwilightEndInMinutes**: *Number*. <sup>2.4.7</sup> Number of minutes since midnight when the civil twilight will end.
682 - **triggerHTTPResponse([httpResponse], [delay], [message])**: <sup>2.5.3</sup> *Function*. Creates a callback by sending a logmessage. httpResponse defaults to scriptname, delay defaults to 0 (immediate), message defaults to httpResponse.
683 - **triggerIFTTT(makerName [,sValue1, sValue2, sValue3])**: *Function*. <sup>2.4.18</sup> Have Domoticz 'call' an IFTTT maker event. makerName is required, 0-3 sValue's are optional. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
684 - **utils**: . A subset of handy utilities:
685		Note that these functions must be preceded by domoticz.utils. If you use more then a few declare something like local _u = domoticz.utils at the beginning of your script and use _u.functionName in the remainder. Example:
686
687	  ```{.lua}
688		_u = domoticz.utils
689		print(_u.rightPad('test',10) .. '|||') -- =>  test	  |||
690	```
691
692	- **\_.lodash**: This is an entire collection with very handy
693		Lua functions. Read more about
694		[lodash](#lodash_for_Lua "wikilink").  E.g.:
695		``` {.lua}
696		domoticz.utils._.size({'abc', 'def'}))` Returns 2.
697		```
698
699	- **cameraExists(parm)**: *Function*: <sup>2.4.28</sup> returns name when entered with valid cameraID or ID when entered with valid cameraName or false when not a cameraID or cameraName of an existing camera
700	- **deviceExists(parm)**: *Function*: ^2.4.28^ returns name when
701		entered with valid deviceID or ID when entered with valid
702		deviceName or false when not a deviceID or deviceName of an
703		existing device.
704		example:
705
706		``` {.lua}
707		local dz = domoticz
708		local _u = dz.utils
709		if _u.deviceExists('myDevice') then
710			dz.devices('myDevice').switchOn()
711		else
712			dz.log('Device myDevice does not exist!', dz.LOG_ERROR)
713		end
714
715		local myName = _u.deviceExists(123)
716		if myName then
717			dz.log('Device 123 is ' .. myName, dz.LOG_INFO)
718		else
719			dz.log('Device 123 does not exist', dz.LOG_ERROR)
720		end
721		```
722
723	- **dumpTable(table,[levelIndicator],[osfile]<sup>3.0.0</sup>))**: *Function*: <sup>2.4.19</sup> print table structure and contents to log
724	- **fileExists(path)**: *Function*:  Returns `true` if the file (with full path) exists.
725	- **fromBase64(string)**: *Function*: <sup>2.5.2</sup>) Decode a base64 string
726	- **fromJSON(json, fallback <sup>2.4.16</sup>)**: *Function*. Turns a json string to a Lua table. Example: `local t = domoticz.utils.fromJSON('{ "a": 1 }')`. Followed by: `print( t.a )` will print 1. Optional 2nd param fallback will be returned if json is nil or invalid.
727	- **fromXML(xml, fallback )**: *Function*: <sup>2.5.1</sup>. Turns a xml string to a Lua table. Example: `local t = domoticz.utils.fromXML('<testtag>What a nice feature!</testtag>') Followed by: `print( t.texttag)` will print What a nice feature! Optional 2nd param fallback will be returned if xml is nil or invalid.
728	 - **groupExists(parm)**: *Function*: <sup>2.4.28</sup> returns name when entered with valid groupID or ID when entered with valid groupName or false when not a groupID or groupName of an existing group
729	- **inTable(table, searchString)**: *Function*: <sup>2.4.21</sup> Returns `"key"` if table has searchString as a key, `"value"` if table has searchString as value and `false` otherwise.
730	- **leftPad(string, length [, character])**: *Function*: <sup>2.4.27</sup> Precede string with given character(s) (default = space) to given length.
731	- **centerPad(string, length [, character])**: *Function*: <sup>2.4.27</sup> Center string by preceding and succeeding with given character(s) (default = space) to given length.
732	- **numDecimals(number [, integer [, decimals ]])**: *Function*: <sup>2.4.27</sup> Format number to float representation
733	  Examples:
734 ```Lua
735			domoticz.utils.numDecimals(12.23, 4, 4) -- => 12.2300,
736			domoticz.utils.numDecimals (12.23,1,1) -- => 12.2,
737			domoticz.utils.leadingZeros(domoticz.utils.numDecimals (12.23,4,4),9) -- => 0012.2300
738 ```
739
740   - **osExecute(cmd)**: *Function*:  Execute an os command.
741	- **rightPad(string, length [, character])**: *Function*: <sup>2.4.27</sup> Succeed string with given character(s) (default = space) to given length.
742	- **round(number, [decimalPlaces])**: *Function*. Helper function to round numbers. Default decimalPlaces is 0.
743	- **sceneExists(parm)**: *Function*: <sup>2.4.28</sup> returns name when entered with valid sceneID or ID when entered with valid sceneName or false when not a sceneID or sceneName of an existing scene
744	- **setLogMarker([marker])**: *Function*: <sup>2.5.2</sup> set logMarker to 'marker'. Defaults to scriptname. Can be used to change logMarker based on flow in script
745	- **stringSplit(string, [separator ])**:<sup>2.4.19</sup> *Function*. Helper function to split a line in separate words. Default separator is space. Return is a table with separate words.
746	- **toBase64(string)**: *Function*: <sup>2.5.2</sup>) Encode a string to base64
747	- **toCelsius(f, relative)**: *Function*. Converts temperature from Fahrenheit to Celsius along the temperature scale or when relative == true it uses the fact that 1F = 0.56C. So `toCelsius(5, true)` returns 5F*(1/1.8) = 2.78C.
748	- **toJSON(luaTable)**: *Function*.  Converts a Lua table to a json string.
749	- **toXML(luaTable, [header])**: *Function*. <sup>2.5.1</sup> Converts a Lua table to a xml string.
750	- **urlDecode(s)**: <sup>2.4.13</sup> *Function*. Simple deCoder to convert a string with escaped chars (%20, %3A and the likes) to human readable format.
751	- **urlEncode(s, [strSub])**: *Function*. Simple url encoder for string so you can use them in `openURL()`. `strSub` is optional and defaults to + but you can also pass %20 if you like/need.
752	- **variableExists(parm)**: *Function*: <sup>2.4.28</sup> returns name when entered with valid variableID or ID when entered with valid variableName or false when not a variableID or variableName of an existing variable
753	- **leadingZeros(number, length)**: *Function*: <sup>2.4.27</sup> Precede number with given zeros to given length.
754	- **variables(idx/name)**: *Function*. A function returning a variable by it's name or idx. See  [Variable object API]
755(#Variable_object_API_.28user_variables.29) for the attributes. To iterate over all variables do: `domoticz.variables().forEach(..)`. See [Looping through the collections: iterators](#Looping_through_the_collections:_iterators). **Note that you cannot do `for i, j in pairs(domoticz.variables()) do .. end`**.
756
757### Looping through the collections: iterators
758The domoticz object has these collections (tables): devices, scenes, groups, variables, changedDevices and changedVariables. You cannot use the `pairs()` or `ipairs()` functions. Therefore dzVents has three iterator methods:
759
760 1. **find(function)**: Returns the item in the collection for which `function` returns true. When no item is found `find` returns nil.
761 2. **forEach(function)**: Executes function once per array element. The function receives the item in the collection (device or variable). If the function returns *false*, the loop is aborted.
762 3. **filter(function / table)**: returns items in the collection for which the function returns true. You can also provide a table with names and/or ids.
763 4. **reduce(function, initial)**: Loop over all items in the collection and do some calculation with it. You call it with the function and the initial value. Each iteration the function is called with the accumulator and the item in the collection. The function does something with the accumulator and returns a new value for it.
764
765#### Examples:
766
767find():
768```Lua
769	local myDevice = domoticz.devices().find(function(device)
770	  return device.name == 'myDevice'
771	end)
772	domoticz.log('Id: ' .. myDevice.id)
773```
774forEach():
775```Lua
776	domoticz.devices().forEach(function(device)
777		if (device.batteryLevel < 20) then
778		  -- do something
779		end
780	end)
781```
782filter():
783```Lua
784	local deadDevices = domoticz.devices().filter(function(device)
785	  return (device.lastUpdate.minutesAgo > 60)
786	end)
787	deadDevices.forEach(function(zombie)
788	  -- do something
789	end)
790```
791or
792```Lua
793	local livingLights = {
794	  'window',
795	  'couch',
796	  33, -- kitchen light id
797	}
798	local lights = domoticz.devices().filter(livingLights)
799	lights.forEach(function(light)
800	  -- do something
801	  light.switchOn()
802	end)
803```
804
805Of course you can chain:
806```Lua
807	domoticz.devices().filter(function(device)
808	  return (device.lastUpdate.minutesAgo > 60)
809	end).forEach(function(zombie)
810	  -- do something with the zombie
811	end)
812```
813Using a reducer to count all devices that are switched on:
814```Lua
815	local count = domoticz.devices().reduce(function(acc, device)
816		if (device.state == 'On') then
817		  acc = acc + 1 -- increase the accumulator
818		end
819		return acc -- always return the accumulator
820	end, 0) -- 0 is the initial value for the accumulator
821```
822
823### Constants
824The domoticz object has these constants available for use in your code e.g. `domoticz.LOG_INFO`.
825
826**IMPORTANT:  you have to prefix these constants with the name of your domoticz object. Example: `domoticz.ALERTLEVEL_RED`**:
827
828 - **ALERTLEVEL_GREY**, **ALERTLEVEL_GREEN**, **ALERTLEVEL_ORANGE**, **ALERTLEVEL_RED**, **ALERTLEVEL_YELLOW**: for updating text sensors.
829 - **BASETYPE_CUSTOM_EVENT** <sup>3.0.0</sup>,**BASETYPE_DEVICE**, **BASETYPE_SCENE**, **BASETYPE_GROUP**, **BASETYPE_VARIABLE**, **BASETYPE_SECURITY**, **BASETYPE_TIMER**, **BASETYPE_HTTP_RESPONSE**, **BASETYPE_SYSTEM**<sup>3.0.0</sup>: indicators for the various object types that are passed as the second parameter to the execute function. E.g. you can check if an object is a device object:
830	```Lua
831	if (item.baseType == domoticz.BASETYPE_DEVICE) then ... end
832	```
833
834 - **BARO_CLOUDY, BARO_CLOUDY_RAIN, BARO_STABLE, BARO_SUNNY, BARO_THUNDERSTORM, BARO_NOINFO, BARO_UNSTABLE**: for updating barometric values.
835 - **EVENT_TYPE_DEVICE**, **EVENT_TYPE_VARIABLE**, **EVENT_TYPE_CUSTOM**<sup>3.0.0</sup>**EVENT_TYPE_SECURITY**,  **EVENT_TYPE_HTTPRESPONSE**, **EVENT_TYPE_SYSTEM**<sup>3.0.0</sup> **EVENT_TYPE_TIMER**: triggerInfo types passed to the execute function in your scripts.
836 - **EVOHOME_MODE_AUTO**, **EVOHOME_MODE_TEMPORARY_OVERRIDE**, **EVOHOME_MODE_PERMANENT_OVERRIDE**, **EVOHOME_MODE_FOLLOW_SCHEDULE** <sup>2.4.9</sup>: mode for EvoHome system.
837 - **EVOHOME_MODE_AUTO**, **EVOHOME_MODE_AUTOWITHRESET**, **EVOHOME_MODE_AUTOWITHECO**, **EVOHOME_MODE_AWAY**, **EVOHOME_MODE_DAYOFF**, **EVOHOME_MODE_CUSTOM**, **EVOHOME_MODE_HEATINGOFF** <sup>2.4.23</sup>: mode for EvoHome controller
838 - **HUM_COMFORTABLE**, **HUM_DRY**, **HUM_NORMAL**, **HUM_WET**: constant for humidity status.
839 - **INTEGER**, **FLOAT**, **STRING**, **DATE**, **TIME**: variable types.
840 - **LOG_DEBUG**, **LOG_ERROR**, **LOG_INFO**, **LOG_FORCE**: for logging messages. LOG_FORCE is at the same level as LOG_ERROR.
841 - **NSS_FIREBASE**, **NSS_FIREBASE_CLOUD_MESSAGING**, **NSS_HTTP**, **NSS_KODI**, **NSS_LOGITECH_MEDIASERVER**, **NSS_NMA**,**NSS_PROWL**, **NSS_PUSHALOT**, **NSS_PUSHBULLET**, **NSS_PUSHOVER**, **NSS_PUSHSAFER**, **NSS_TELEGRAM** <sup>2.4.8</sup>, **NSS_GOOGLE_CLOUD_MESSAGING** <sup>deprecated by Google and replaced by firebase</sup>: for notification subsystem
842 - **PRIORITY_LOW**, **PRIORITY_MODERATE**, **PRIORITY_NORMAL**, **PRIORITY_HIGH**, **PRIORITY_EMERGENCY**: for notification priority.
843 - **SECURITY_ARMEDAWAY**, **SECURITY_ARMEDHOME**, **SECURITY_DISARMED**: for security state.
844 - **SOUND_ALIEN** , **SOUND_BIKE**, **SOUND_BUGLE**, **SOUND_CASH_REGISTER**, **SOUND_CLASSICAL**, **SOUND_CLIMB** , **SOUND_COSMIC**, **SOUND_DEFAULT** , **SOUND_ECHO**, **SOUND_FALLING**  , **SOUND_GAMELAN**, **SOUND_INCOMING**, **SOUND_INTERMISSION**, **SOUND_MAGIC** , **SOUND_MECHANICAL**, **SOUND_NONE**, **SOUND_PERSISTENT**, **SOUND_PIANOBAR** , **SOUND_SIREN** , **SOUND_SPACEALARM**, **SOUND_TUGBOAT**  , **SOUND_UPDOWN**: for notification sounds.
845
846## Custom event API
847If you have a dzVents script that is triggered by a customEvent in Domoticz then the second parameter passed to the execute function will be a *notification* object. The object.type = customEvent (isCustomEvent: true) and object.data contains the passed data to this script. object.trigger is the name of the customEvent that triggered the script.## Device object API
848If you have a dzVents script that is triggered by switching a device in Domoticz then the second parameter passed to the execute function will be a *device* object. Also, each device in Domoticz can be found in the `domoticz.devices()` collection (see above). The device object has a set of fixed attributes like *name* and *idx*. Many devices, however, have different attributes and methods depending on their (hardware)type, subtype and other device specific identifiers. It is possible that you will get an error if you call a method on a device that doesn't support it, so please check the device properties for your specific hardware to see which are supported (can also be done in your script code!).
849
850dzVents recognizes most of the different device types in Domoticz and creates the proper attributes and methods. It is possible that your device type has attributes that are not recognized; if that's the case, please create a ticket in the Domoticz [issue tracker on GitHub](https://github.com/domoticz/domoticz/issues), and an adapter for that device will be added.
851
852If for some reason you miss a specific attribute or data for a device, then likely the `rawData` attribute will have that information.
853
854### Device attributes and methods for all devices
855 - **active**: *Boolean*. Is true for some common states like 'On' or 'Open' or 'Motion'. Same as bState.
856 - **batteryLevel**: *Number* If applicable for that device then it will be from 0-100.
857 - **bState**: *Boolean*. Is true for some common states like 'On' or 'Open' or 'Motion'. Better to use active.
858 - **changed**: *Boolean*. True if the device was updated. **Note**: This does not necessarily means the device state or value changed.
859 - **description**: *String*. Description of the device.
860 - **deviceId**: *String*. Another identifier of devices in Domoticz. dzVents uses the id(x) attribute. See device list in Domoticz' settings table.
861 - **deviceSubType**: *String*. See Domoticz devices table in Domoticz GUI.
862 - **deviceType**: *String*. See Domoticz devices table in Domoticz GUI.
863 - **dump()**: *Function*. Dump all attributes to the Domoticz log. This ignores the log level setting.
864 - **hardwareName**: *String*. See Domoticz devices table in Domoticz GUI.
865 - **hardwareId**: *Number*. See Domoticz devices table in Domoticz GUI.
866 - **hardwareType**: *String*. See Domoticz devices table in Domoticz GUI.
867 - **hardwareTypeValue**: *Number*. See Domoticz devices table in Domoticz GUI.
868 - **icon**: *String*. Name of the icon in Domoticz GUI.
869 - **id**: *Number*. Index of the device. You can find the index in the device list (idx column) in Domoticz settings. It's not truly an index but is unique enough for dzVents to be treated as an id.
870 - **idx**: *Number*. Same as id: index of the device
871 - **lastUpdate**: *[Time Object](#Time_object)*: Time when the device was updated.
872 - **name**: *String*. Name of the device.
873 - **nValue**: *Number*. Numerical representation of the state.
874 - **protected**: *Boolean*. <sup>2.4.27</sup> True when device / scene / group is protected. False otherwise.
875 - **protectionOff()**: *Function*. <sup>2.4.27</sup> switch protection to off. Supports some [command options]
876 - **protectionOn()**: *Function*. <sup>2.4.27</sup> switch protection to on. Supports some [command options] !! **Note: domoticz protects against GUI and API access only. switchOn / switchOff type Blockly / Lua / dzVents commands are not influenced (because they are executed as admin user)
877 - **rawData**: *Table*: All values are *String* types and hold the raw data received from Domoticz.
878 - **rename(newName)**: *Function*. <sup>2.4.24</sup> Change current devicename to new devicename Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
879 - **setDescription(description)**: *Function*. <sup>2.4.16</sup> Generic method to update the description for all devices, groups and scenes. E.g.: device.setDescription(device.description .. '/nChanged by '.. item.trigger .. 'at ' .. domoticz.time.raw). Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
880 - **setIcon(iconNumber)**: *Function*. <sup>2.4.17</sup> method to update the icon for devices. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
881 - **setState(newState)**: *Function*. Generic update method for switch-like devices. E.g.: device.setState('On'). Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
882 - **setValues(nValue,[ sValue1, sValue2, ...])**: *Function*. <sup>2.4.17</sup> Generic alternative method to update device nValue, sValue. Uses domoticz JSON API to force subsequent events like pushing to influxdb. nValue required but when set to nil it will use current nValue. sValue parms are optional and can be many.
883 - **state**: *String*. For switches, holds the state like 'On' or 'Off'. For dimmers that are on, it is also 'On' but there is a level attribute holding the dimming level. **For selector switches** (Dummy switch) the state holds the *name* of the currently selected level. The corresponding numeric level of this state can be found in the **rawData** attribute: `device.rawData[1]`.
884 - **signalLevel**: *Number* If applicable for that device then it will be from 0-100.
885 - **switchType**: *String*. See Domoticz devices table in Domoticz GUI(Switches tab). E.g. 'On/Off', 'Door Contact', 'Motion Sensor' or 'Blinds'
886 - **sValue**: *String*. <sup>2.4.21</sup> Returns the sValue (string Value) of a device.
887 - **switchTypeValue**: *Number*. See Domoticz devices table in Domoticz GUI.
888 - **timedOut**: *Boolean*. Is true when the device couldn't be reached.
889 - **unit**: *Number*. Device unit. See device list in Domoticz' settings for the unit.
890 - **update(< params >)**: *Function*. Generic update method. Accepts any number of parameters that will be sent back to Domoticz. There is no need to pass the device.id here. It will be passed for you. Example to update a temperature: `device.update(0,12)`. This will eventually result in a commandArray entry `['UpdateDevice']='<idx>|0|12'`. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
891
892### Device attributes and methods for specific devices
893Note that if you do not find your specific device type here you can always inspect what is in the `rawData` attribute. Please let us know that it is missing so we can write an adapter for it (or you can write your own and submit it). Calling `myDevice.dump()` will dump all attributes and values for myDevice to the Domoticz log.
894
895#### Air quality
896 - **co2**: *Number*. PPM
897 - **quality**: *String*. Air quality string.
898 - **updateAirQuality(ppm)**: Pass the CO<sub>2</sub> concentration. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
899
900#### Alert sensor
901 - **color**: *Number*. Color of the alert. See domoticz color constants for possible values.
902 - **text**: *String*
903 - **updateAlertSensor(level, text)**: *Function*. Level can be domoticz.ALERTLEVEL_GREY, ALERTLEVEL_GREEN, ALERTLEVEL_YELLOW, ALERTLEVEL_ORANGE, ALERTLEVEL_RED. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
904
905#### Ampère, 1-phase
906 - **current**: *Number*. Ampère.
907 - **updateCurrent(current)**: *Function*. Current in Ampère. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
908
909#### Ampère, 3-phase
910 - **current1**, **current2**, **current3** : *Number*. Ampère.
911 - **updateCurrent(current1, current2, current3)**: *Function*. Currents in Ampère. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
912
913#### Barometer sensor
914 - **barometer**. *Number*. Barometric pressure.
915 - **forecast**: *Number*.
916 - **forecastString**: *String*.
917 - **updateBarometer(pressure, forecast)**: *Function*. Update barometric pressure. Forecast can be domoticz.BARO_STABLE, BARO_SUNNY, BARO_CLOUDY, BARO_UNSTABLE, BARO_THUNDERSTORM. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
918
919#### Counter, managed Counter <sup>2.4.12</sup>,counter incremental
920 - **counter**: *Number*
921 - **counterToday**: *Number*. Today's counter value.
922 - **updateCounter(value)**: *Function*. **This will overwrite; and not increment !**. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
923 - **incrementCounter(value)**: <sup>2.4.23</sup>*Function*. (counter incremental) Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
924 - **valueQuantity**: *String*. For counters.
925 - **valueUnits**: *String*.
926
927#### Custom sensor
928 - **sensorType**: *Number*.
929 - **sensorUnit**: *String*:
930 - **updateCustomSensor(value)**: *Function*. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
931
932#### Distance sensor
933 - **distance**: *Number*.
934 - **updateDistance(distance)**: *Function*. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
935
936#### Electric usage
937 - **actualWatt**: *Number*. <sup>2.5.2 </sup> Current Watt usage.
938 - **WhActual**: *Number*. Current Watt usage. (please use actualWatt)
939 - **updateEnergy(energy)**: *Function*. In Watt. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
940
941#### Evohome (zones)
942 - **setPoint**: *Number*.
943 - **mode**: *string* <sup>2.4.9</sup>.
944 - **untilDate**: *string in ISO 8601 format* or n/a <sup>2.4.9</sup>.
945 - **updateSetPoint(setPoint, mode, until)**: *Function*. Update set point. Mode can be domoticz.EVOHOME_MODE_AUTO, domoticz.EVOHOME_MODE_TEMPORARY_OVERRIDE, domoticz.EVOHOME_MODE_FOLLOW_SCHEDULE <sup>2.4.9</sup> or domoticz.EVOHOME_MODE_PERMANENT_OVERRIDE. You can provide an until date (in ISO 8601 format e.g.: `os.date("!%Y-%m-%dT%TZ")`). Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
946
947#### Evohome (controller) <sup>2.4.23</sup>
948 - **mode**: *string* <sup>3.0.0</sup>.
949 - **setMode(mode, dparm, action, ooc )**: *Function*. set mode for controller. Mode can be domoticz.EVOHOME_MODE_AUTO, domoticz.EVOHOME_MODE_AUTOWITHRESET, domoticz.EVOHOME_MODE_AUTOWITHECO, domoticz.EVOHOME_MODE_AWAY, domoticz.EVOHOME_MODE_DAYOFF, domoticz.EVOHOME_MODE_CUSTOM or domoticz.EVOHOME_MODE_HEATINGOFF. dParm <optional> can be a future time string (in ISO 8601 format e.g.: `os.date("!%Y-%m-%dT%TZ")`), a future time object, a future time as number of seconds since epoch or a number representing a positive offset in minutes (max 1 year). action <optional> (1 = run on action script, 0 = disable), ooc <optional> (1 = only trigger the event & log on change, 0 = always trigger & log)
950
951#### Evohome (hotWater) <sup>2.4.9</sup>.
952 - **state**: *string*  ('On' or 'Off')
953 - **mode**: *string*
954 - **untilDate**: *string in ISO 8601 format* or n/a.
955 - **setHotWater(state, mode, until)**: *Function*. set HotWater Mode can be domoticz.EVOHOME_MODE_AUTO, domoticz.EVOHOME_MODE_TEMPORARY_OVERRIDE, domoticz.EVOHOME_MODE_FOLLOW_SCHEDULE or domoticz.EVOHOME_MODE_PERMANENT_OVERRIDE You can provide an until date (in ISO 8601 format for domoticz.EVOHOME_MODE_TEMPORARY_OVERRIDE e.g.: `os.date("!%Y-%m-%dT%TZ")`).
956
957#### Gas
958 - **counter**: *Number*. Value in m<sup>3</sup>
959 - **counterToday**: *Number*. Value in m<sup>3</sup>
960 - **updateGas(usage)**: *Function*. Usage in **dm<sup>3</sup>** (liters). Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
961
962#### Group
963 - **devices()**: *Function*. Returns the collection of associated devices. Supports the same iterators as for `domoticz.devices()`: `forEach()`, `filter()`, `find()`, `reduce()`. See [Looping through the collections: iterators](#Looping_through_the_collections:_iterators). Note that the function doesn't allow you to get a device by its name or id. Use `domoticz.devices()` for that.
964 - **protectionOff()**: *Function*. <sup>2.4.27</sup> switch protection to off. Supports some [command options]
965 - **protectionOn()**: *Function*. <sup>2.4.27</sup> switch protection to on. Supports some [command options]
966 - **rename(newName)**: *Function*. <sup>2.4.24</sup> Change current group-name to new group-name Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
967 - **switchOff()**: *Function*. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
968 - **switchOn()**: Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
969 - **toggleGroup()**: Toggles the state of a group. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
970
971#### Humidity sensor
972 - **humidity**: *Number*
973 - **humidityStatus**: *String*
974 - **humidityStatusValue**: *Number*. Value matches with domoticz.HUM_NORMAL, -HUM_DRY, HUM_COMFORTABLE, -HUM_WET.
975 - **updateHumidity(humidity, status)**: Update humidity. status can be domoticz.HUM_NORMAL, HUM_COMFORTABLE, HUM_DRY, HUM_WET. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
976
977#### Kodi
978 - **kodiExecuteAddOn(addonId)**: *Function*. Will send an Execute Addon command sending no parameters. Addon IDs are embedded in the addon configuration and are not to be confused with the Addon Name. For example: http://forums.homeseer.com/showthread.php?p=1213403.
979 - **kodiPause()**: *Function*. Will send a Pause command, only effective if the device is streaming.
980 - **kodiPlay()**: *Function*. Will send a Play command, only effective if the device was streaming and has been paused.
981 - **kodiPlayFavorites([position])**: *Function*. Will play an item from the Kodi's Favorites list optionally starting at *position*. Favorite positions start from 0 which is the default.
982 - **kodiPlayPlaylist(name, [position])**: *Function*. Will play a music or video Smart Playlist with *name* optionally starting at *position*. Playlist positions start from 0 which is the default.
983 - **kodiSetVolume(level)**: *Function*. Set the volume for a Kodi device, 0 <= level <= 100.
984 - **kodiStop()**: *Function*. Will send a Stop command, only effective if the device is streaming.
985 - **kodiSwitchOff()**: *Function*. Will turn the device off if this is supported in settings on the device.
986
987#### kWh, Electricity (instant and counter)
988 - **actualWatt**: *Number*.  <sup>2.5.2 </sup>Actual usage in Watt.
989 - **counterToday**: *Number*.
990 - **updateElectricity(power, energy)**: *Function*. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
991 - **usage**: *Number*.
992 - **WhToday**: *Number*. Total Wh usage of the day. Note the unit is Wh and not kWh!
993 - **WhTotal**: *Number*. Total Wh usage.
994 - **WhActual**: *Number*. Actual reading in Watt. Please use actualWatt
995
996#### Leaf wetness
997 - **wetness**: *Number*. Wetness value
998 - **updateWetness(wetness)**: *Function*. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
999
1000#### Logitech Media Server
1001 - **pause()**: *Function*.  Will pause the device if it was streaming. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1002 - **play()**: *Function*.  If the device was off, it will turn on and start streaming. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1003 - **playFavorites([position])**: *Function*.	Will start the favorites playlist. `position` is optional (0 = default). Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1004 - **playlistID**: *Nubmer*.
1005 - **setVolume(level)**: *Function*.  Sets the volume (0 <= level <= 100). Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1006 - **startPlaylist(name)**: *Function*.  Will start the playlist by its `name`. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1007 - **stop()**: *Function*.  Will stop the device (only effective if the device is streaming). Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1008 - **volumeUp()**: *Function*. <sup>2.4.16</sup> Will turn the device volume up with 2 points. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1009 - **volumeDown()**: *Function*. <sup>2.4.16</sup> Will turn the device volume down with 2 points. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1010
1011#### Lux sensor
1012 - **lux**: *Number*. Lux level for light sensors.
1013 - **updateLux(lux)**: *Function*. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1014
1015#### Onkyo receiver
1016 - **onkyoEISCPCommand(command)**. *Function*.  Sends an EISP command to the Onkyo receiver.
1017
1018#### OpenTherm gateway
1019 - **setPoint**: *Number*.
1020 - **updateSetPoint(setPoint)**: *Function*. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1021
1022#### P1 Smart meter
1023 - **counterDeliveredToday**: *Number*.
1024 - **counterToday**: *Number*.
1025 - **usage1**, **usage2**: *Number*.
1026 - **return1**, **return2**: *Number*.
1027 - **updateP1(usage1, usage2, return1, return2, cons, prod)**: *Function*. Updates the device. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1028 - **usage**: *Number*.
1029 - **usageDelivered**: *Number*.
1030
1031#### Percentage
1032 - **percentage**: *Number*.
1033 - **updatePercentage(percentage)**: *Function*. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1034
1035#### Philips Hue Light
1036See switch below.
1037
1038#### Pressure
1039 - **pressure**: *Number*.
1040 - **updatePressure(pressure)**: *Function*. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1041
1042#### Rain meter
1043 - **rain**: *Number*
1044 - **rainRate**: *Number*
1045 - **updateRain(rate, counter)**: *Function*. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1046
1047#### RGBW(W) / Lighting Limitless/Applamp
1048 - **decreaseBrightness()**: deprecated because only very limited supported and will be removed from API
1049 - **getColor()**; *Function*. <sup>2.4.17</sup> Returns table with color attributes or nil when color field of device is not set.
1050 - **increaseBrightness()**: deprecated because only very limited supported and will be removed from API
1051 - **setColor(r, g, b, br, cw, ww, m, t)**: *Function*. <sup>2.4.16</sup> Sets the light to requested color.  r, g, b required, others optional. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29). Meaning and limits of parms can be found [here](https://www.domoticz.com/wiki/Domoticz_API/JSON_URL's#Set_a_light_to_a_certain_color_or_color_temperature).
1052 - **setColorBrightness()**: same as setColor
1053 - **setDiscoMode(modeNum)**: deprecated because only very limited supported and will be removed from API
1054- **setHex(r, g, b)**: *Function*. <sup>2.4.16</sup> Sets the light to requested color.  r, g, b required (decimal Values 0-255). Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1055- **setHue(hue, brightness, isWhite)**: *Function*. <sup>2.4.16</sup> Sets the light to requested Hue. Hue and brightness required. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1056 - **setKelvin(Kelvin)**: *Function*.  Sets Kelvin level of the light (For RGBWW devices only). Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1057 - **setNightMode()**: *Function*.  Sets the lamp to night mode. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1058 - **setRGB(red, green, blue)**: *Function*.  Set the lamps RGB color. Values are from 0-255. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1059 - **setWhiteMode()**: *Function*.  Sets the lamp to white mode. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1060
1061#### Scale weight
1062 - **weight**: *Number*
1063 - **udateWeight()**: *Function*. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1064
1065#### Scene
1066 - **devices()**: *Function*. Returns the collection of associated devices. Supports the same iterators as for `domoticz.devices()`: `forEach()`, `filter()`, `find()`, `reduce()`. See [Looping through the collections: iterators](#Looping_through_the_collections:_iterators). Note that the function doesn't allow you to get a device by its name or id. Use `domoticz.devices()` for that.
1067 - **protectionOff()**: *Function*. <sup>2.4.27</sup> switch protection to off. Supports some [command options]
1068 - **protectionOn()**: *Function*. <sup>2.4.27</sup> switch protection to on. Supports some [command options]
1069 - **rename(newName)**: *Function*. <sup>2.4.24</sup> Change current scene-name to new scene-name Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1070 - **switchOn()**: *Function*. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1071 - **switchOff()**: *Function*. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1072
1073#### Security Panel
1074Create a security device:
1075
1076 1. Set a security panel password in Domoticz settings.
1077 2. Activate the security panel (**Setup > More Options > Security Panel** and set it to **Disarm** (using your password)).
1078 3. Go to the device list in (**Setup > Devices**) where it should show the security panel device under 'Not used'.
1079 4. Add the device and give it a name.
1080
1081Methods/attributes:
1082
1083 - **armAway()**: Sets a security device to Armed Away. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1084 - **armHome()**: Sets a security device to Armed Home. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1085 - **disarm()**: Disarms a security device. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1086 - **state**: *String*: Same values as domoticz.security value.
1087
1088#### Smoke detection <sup>2.4.26</sup>.
1089 - **activate()**: *Function*. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1090 - **reset()**: *Function*. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1091
1092#### Solar radiation
1093 - **radiation**. *Number*. In Watt/m<sup>2</sup>.
1094 - **updateRadiation(radiation)**: *Function*. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1095
1096#### Soil moisture
1097 - **moisture**. *Number*. In centibars (cB).
1098 - **updateSoilMoisture(moisture)**: *Function*. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1099
1100#### Sound level
1101 - **level**. *Number*. In dB.
1102 - **updateSoundLevel(level)**: *Function*. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1103
1104#### Switch (dimmer, selector etc.)
1105There are many switch-like devices. Not all methods are applicable for all switch-like devices. You can always use the generic `setState(newState)` method.
1106
1107 - **close()**: *Function*. Set device to Close if it supports it. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1108 - **dimTo(percentage)**: *Function*. Switch a dimming device on and/or dim to the specified level. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1109 - **lastLevel**: Number. The level of a dimmer just before it was switched off. **Note: lastLevel only shows you the previous level if you have a trigger for the device itself. So for instance you have a on-trigger for 'myDimmer' and the dimmer is set from 20% to 30%, in your script `myDimmer.level == 30` and `myDimmer.lastLevel == 20`. **
1110 - **level**: *Number*. For dimmers and other 'Set Level..%' devices this holds the level like selector switches.
1111 - **levelActions**: *String*. |-separated list of url actions for selector switches.
1112 - **levelName**: *String*. Current level name for selector switches.
1113 - **levelNames**: *Table*. Table holding the level names for selector switch devices.
1114 - **maxDimLevel**: *Number*.
1115 - **open()**: *Function*. Set device to Open if it supports it. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1116 - **quietOn()**: *Function*. <sup>2.4.20</sup> Set deviceStatus to on without physically switching it. Subsequent Events are triggered. Supports some [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1117 - **quietOff()**: *Function*. <sup>2.4.20</sup> set deviceStatus to off without physically switching it. Subsequent Events are triggered. Supports some [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1118 - **setLevel(percentage)**: *Function*. <sup>2.4.29</sup> Set device to a given level if it supports it (e.g. blinds percentage). Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1119 - **stop()**: *Function*. Set device to Stop if it supports it (e.g. blinds). Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1120 - **switchOff()**: *Function*. Switch device off it is supports it. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1121 - **switchOn()**: *Function*. Switch device on if it supports it. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1122 * '''switchSelector(&lt;[level]|[levelname] &gt;) '''  :
1123 - **switchSelector(<[level]|[levelname] >)** <sup>levelname >= 2.4.22</sup> : *Function*. Switches a selector switch to a specific level ( levelname or level(numeric) required ) levelname must be exact, for level the closest fit will be picked. See the edit page in Domoticz for such a switch to get a list of the values). Levelname is only supported when level 0 ("Off") is not removed Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1124 - **toggleSwitch()**: *Function*. Toggles the state of the switch (if it is togglable) like On/Off, Open/Close etc.
1125
1126#### Temperature sensor
1127 - **temperature**: *Number*
1128 - **updateTemperature(temperature)**: *Function*. Note: temperature must be in Celsius. Use `domoticz.toCelsius()` to convert a Fahrenheit temperature to Celsius. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1129
1130#### Temperature, Barometer sensor
1131 - **barometer**: *Number*
1132 - **forecast**: *Number*.
1133 - **forecastString**: *String*.
1134 - **temperature**: *Number*
1135 - **updateTempBaro(temperature, pressure, forecast)**: *Function*. Forecast can be domoticz.BARO_STABLE, BARO_SUNNY, BARO_CLOUDY, BARO_UNSTABLE, BARO_THUNDERSTORM. Note: temperature must be in Celsius. Use `domoticz.toCelsius()` to convert a Fahrenheit temperature to Celsius. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1136
1137#### Temperature, Humidity, Barometer sensor
1138 - **barometer**: *Number*
1139 - **dewPoint**: *Number*
1140 - **forecast**: *Number*.
1141 - **forecastString**: *String*.
1142 - **humidity**: *Number*
1143 - **humidityStatus**: *String*
1144 - **humidityStatusValue**: *Number*. Value matches with domoticz.HUM_NORMAL, -HUM_DRY, HUM_COMFORTABLE, -HUM_WET.
1145 - **temperature**: *Number*
1146 - **updateTempHumBaro(temperature, humidity, status, pressure, forecast)**: *Function*. forecast can be domoticz.BARO_NOINFO, BARO_SUNNY, BARO_PARTLY_CLOUDY, BARO_CLOUDY, BARO_RAIN. status can be domoticz.HUM_NORMAL, HUM_COMFORTABLE, HUM_DRY, HUM_WET. Note: temperature must be in Celsius. Use `domoticz.toCelsius()` to convert a Fahrenheit temperature to Celsius. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1147
1148#### Temperature, Humidity
1149 - **dewPoint**: *Number*
1150 - **humidity**: *Number*
1151 - **humidityStatus**: *String*
1152 - **humidityStatusValue**: *Number*. Value matches with domoticz.HUM_NORMAL, -HUM_DRY, HUM_COMFORTABLE, -HUM_WET.
1153 - **temperature**: *Number*
1154 - **updateTempHum(temperature, humidity, status)**: *Function*. status can be domoticz.HUM_NORMAL, HUM_COMFORTABLE, HUM_DRY, HUM_WET. Note: temperature must be in Celsius. Use `domoticz.toCelsius()` to convert a Fahrenheit temperature to Celsius. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1155
1156#### Text
1157 - **text**: *String*
1158 - **updateText(text)**: Function*. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1159
1160#### Thermostat set point
1161 - **setPoint**: *Number*.
1162 - **updateSetPoint(setPoint)**:*Function*. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1163
1164#### UV sensor
1165 - **uv**: *Number*. UV index.
1166 - **updateUV(uv)**: *Function*. UV index. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1167
1168#### Visibility
1169 - **visibility**: *Number*. In km.
1170 - **updateVisibility(distance)**:Function*. In km. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1171
1172#### Voltage
1173 - **voltage**: *Number*.
1174 - **updateVoltage(voltage)**:Function*. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1175
1176#### Waterflow
1177 - **flow**: *Number*. In L/m.
1178 - **updateWaterflow(flow)**:Function*. In L/m. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1179
1180#### Wind
1181 - **chill**: *Number*.
1182 - **direction**: *Number*. Degrees.
1183 - **directionString**: *String*. Formatted wind direction like N, SE.
1184 - **gust**: *Number*. ( in meters / second, might change in future releases to Meters/Counters settings for Wind Meter )
1185 - **gustMs**: *Number*. Gust ( in meters / second ) <sup>2.4.9</sup>
1186 - **temperature**: *Number*
1187 - **speed**: *Number*. Windspeed ( in the unit set in Meters/Counters settings for Wind Meter )
1188 - **speedMs**: *Number*. Windspeed ( in meters / second ) <sup>2.4.9</sup>
1189 - **updateWind(bearing, direction, speed, gust, temperature, chill)**: *Function*. Bearing in degrees, direction in N, S, NNW etc, speed in m/s, gust in m/s, temperature and chill in Celsius. Use `domoticz.toCelsius()` to convert a Fahrenheit temperature to Celsius. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1190
1191#### Youless meter <sup>2.4.6</sup>
1192 - **counterDeliveredToday**: *Number*.
1193 - **counterDeliveredTotal**: *Number*.
1194 - **powerYield**: *String*.
1195 - **updateYouless(total, actual)**: *Function*.
1196
1197#### Zone heating
1198 - **setPoint**: *Number*.
1199 - **heatingMode**: *String*.
1200
1201#### Z-Wave Fan mode <sup>2.5.5</sup>
1202 - **mode**: *Number*. Current mode number.
1203 - **modeString**: *String*. Mode name.
1204 - **modes**: *Table*. Lists all available modes.
1205 - **updateMode(modeString)**: *Function*. Set new mode. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1206
1207#### Z-Wave Thermostat mode
1208 - **mode**: *Number*. Current mode number.
1209 - **modeString**: *String*. Mode name.
1210 - **modes**: *Table*. Lists all available modes.
1211 - **updateMode(modeString)**: *Function*. Set new mode. Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1212
1213### Command options (delay, duration, event triggering)
1214Many dzVents device methods support extra options, like controlling a delay or a duration:
1215```Lua
1216
1217	-- switch on for 2 minutes after 10 seconds
1218	device.switchOn().afterSec(10).forMin(2)
1219
1220	-- switch on at a specic time / day
1221	device.switchOn().at('09:00')                 -- earliest moment it will be 09:00 hr.
1222	device.switchOn().at('08:53:30 on fri')       -- earliest moment it will be Friday at 08:53:30
1223	device.switchOn().at('08:53:30 on sat, sun')  -- earliest moment it will be Saturday or Sunday at 08:53:30 (whatever comes first)
1224
1225	-- switch on for 2 minutes after a randomized delay of 1-10 minutes
1226	device.switchOff().withinMin(10).forMin(2)
1227	device.close().forMin(15)
1228	device.open().afterSec(20)
1229	device.open().afterMin(2)
1230
1231	-- switch on but do not trigger follow up events
1232	device.switchOn().silent()
1233
1234	-- flash a light for 3 times
1235	device.switchOn().forSec(2).repeatAfterSec(1, 3)
1236
1237	-- switch the device on but only if the current state isn't already on:
1238	device.switchOn().checkFirst()
1239	-- this is a short for:
1240	if (device.state == 'Off') then
1241	  devices.switchOn()
1242	end
1243```
1244
1245#### Options
1246 - **at(hh:mm[:ss][ on [ ddd|dddd ] )**: *Function*.<sup>3.0.1</sup> Activates the command at a certain time [ on a certain day]
1247 - **afterHour(hours), afterMin(minutes), afterSec(seconds)**: *Function*. Activates the command after a certain number of hours, minutes or seconds.
1248 - **cancelQueuedCommands()**: *Function*.  Cancels queued commands. E.g. you switch on a device after 10 minutes:  `myDevice.switchOn().afterMin(10)`. Within those 10 minutes you can cancel that command by calling:  `myDevice.cancelQueuedCommands()`.
1249 - **checkFirst()**: *Function*. Checks if the **current** state of the device is different than the desired new state. If the target state is the same, no command is sent. If you do `mySwitch.switchOn().checkFirst()`, then no switch command is sent if the switch is already on. This command only works with switch-like devices. It is not available for toggle and dim commands, either.
1250 - **forHour(hours), forMin(minutes), forSec(seconds)**: *Function*. Activates the command for the duration of hours, minutes or seconds. See table below for applicability and the warning on unexpected behavior of these functions.
1251 - **withinHour(hours), withinMin(minutes), withinSec(seconds)**: *Function*. Activates the command within a certain period (specified in hours, minutes or seconds) *randomly*. See table below for applicability.
1252 - **silent()**: *Function*. No follow-up events will be triggered: `mySwitch.switchOff().silent()`.
1253 - **repeatAfterHour(hours, [number]), repeatAfterMin(minutes, [number]), repeatAfterSec(seconds, [number])**: *Function*. Repeats the sequence *number* times after the specified duration (specified in hours, minutes, or seconds).  If no *number* is provided, 1 is used. **Note that `afterAAA()` and `withinAAA()` are only applied at the beginning of the sequence and not between the repeats!**
1254
1255Note that the actual switching or changing of the device is done by Domoticz and not by dzVents. dzVents only tells Domoticz what to do; if the options are not carried out as expected, this is likely a Domoticz or hardware issue.
1256
1257**Important note when using forAAA()**: Let's say you have a light that is triggered by a motion detector.  Currently the light is `Off` and you do this: `light.switchOn().forMin(5)`. What happens inside Domoticz is this:  at t<sub>0</sub> Domoticz issues the `switchOn()` command and schedules a command to restore the **current** state at t<sub>5</sub> which is `Off`. So at t<sub>5</sub> it will switch the light off.
1258
1259If, however, *before the scheduled `switchOff()` happens at t<sub>5</sub>*, new motion is detected and you send this command again at t<sub>2</sub> then something unpredictable may seem to happen: *the light is never turned off!* This is what happens:
1260
1261At t<sub>2</sub> Domoticz receives the `switchOn().forMin(5)` command again. It sees a scheduled command at t<sub>5</sub> and deletes that command (it is within the new interval). Then Domoticz performs the (unnecessary, it's already on) `switchOn()` command. Then it checks the current state of the light which is `On`!! and schedules a command to return to that state at t<sub>2+5</sub>=t<sub>7</sub>. So, at t<sub>7</sub> the light is switched on again. And there you have it: the light is not switched off and never will be because future commands will always be checked against the current on-state.
1262
1263That's just how it works and you will have to deal with it in your script. So, instead of simply re-issuing `switchOn().forMin(5)` you have to check the switch's state first:
1264```Lua
1265if (light.active) then
1266	light.switchOff().afterMin(5)
1267else
1268	light.switchOn().forMin(5)
1269end
1270```
1271or issue these two commands *both* as they are mutually exclusive:
1272```Lua
1273light.switchOff().checkFirst().afterMin(5)
1274light.switchOn().checkFirst().forMin(5)
1275```
1276
1277#### Availability
1278Some options are not available to all commands. All the options are available to device switch-like commands like `myDevice.switchOff()`, `myGroup.switchOn()` or `myBlinds.open()`.  For updating (usually Dummy ) devices like a text device `myTextDevice.updateText('zork')` you can only use `silent()`. For thermostat setpoint devices and snapshot command silent() is not available.  For commands for which dzVents must use openURL, only  `at()` and  `afterAAA()` methods are available. These commands are mainly the setAaaaa() commands for RGBW type devices.
1279
1280
1281See table below
1282
1283```{=mediawiki}
1284
1285{| class="wikitable"
1286!width="17%"| option
1287!align="center" width="12%"| state changes
1288!align="center" width="12%"| update commands
1289!align="center" width="12%"| user variables
1290!align="center" width="12%"| updateSetpoint
1291!align="center" width="12%"| snapshot
1292!align="center" width="12%"| triggerIFTTT
1293!align="center" width="12%"| emitEvent
1294|-
1295| <code>afterAAA()</code><sup>1</sup>
1296|align="center"| •
1297|align="center"| •
1298|align="center"| •
1299|align="center"| •
1300|align="center"| •
1301|align="center"| •
1302|align="center"| •
1303|-
1304| <code>at()</code>
1305|align="center"| •
1306|align="center"| •
1307|align="center"| •
1308|align="center"| •
1309|align="center"| •
1310|align="center"| •
1311|align="center"| •
1312|-
1313| <code>forAAA()</code>
1314|align="center"| •
1315|align="center"| n/a
1316|align="center"| n/a
1317|align="center"| n/a
1318|align="center"| n/a
1319|align="center"| n/a
1320|align="center"| n/a
1321|-
1322| <code>withinAAA()</code>
1323|align="center"| •
1324|align="center"| •
1325|align="center"| •
1326|align="center"| •
1327|align="center"| •
1328|align="center"| n/a
1329|align="center"| •
1330|-
1331| <code>silent()</code>
1332|align="center"| •
1333|align="center"| •
1334|align="center"| •
1335|align="center"| n/a
1336|align="center"| n/a
1337|align="center"| n/a
1338|align="center"| n/a
1339|-
1340| <code>repeatAfterAAA()</code>
1341|align="center"| •
1342|align="center"| n/a
1343|align="center"| n/a
1344|align="center"| n/a
1345|align="center"| n/a
1346|align="center"| n/a
1347|align="center"| n/a
1348|-
1349| <code>checkFirst()</code>
1350|align="center"| • <sup>2</sup>
1351|align="center"| n/a
1352|align="center"| n/a
1353|align="center"| n/a
1354|align="center"| n/a
1355|align="center"| n/a
1356|align="center"| n/a
1357|-
1358| <code>cancelQueuedCommands()</code>
1359|align="center"| •
1360|align="center"| •
1361|align="center"| •
1362|align="center"| n/a
1363|align="center"| n/a
1364|align="center"| n/a
1365|align="center"| n/a
1366
1367|}
1368```
1369
1370#### Notes on table
1371 - **Note 1**: AAA is a placeholder for `Min/Sec/Hour` affix e.g. `afterMin()`.
1372 - **Note 2**: for `domoticz.openURL()` only `at()`, `afterAAA()` and `withinAAA()` is available.
1373 - **Note 3**: Note 2 also applies for all commands depending on openURL (like rgbwwDevice.setAaa() commands).
1374
1375#### Follow-up event triggers
1376Normally if you issue a command, Domoticz will immediately trigger follow-up events, and dzVents will automatically trigger defined event scripts. If you trigger a scene, all devices in that scene will issue a change event. If you have event triggers for these devices, they will be executed by dzVents. If you don't want this to happen, add `.silent()` to your commands (exception is updateSetPoint).
1377
1378### Create your own device adapter
1379If your device is not recognized by dzVents, you can still operate it using the generic device attributes and methods. It is much nicer, however, to have device specific attributes and methods. Existing recognized adapters are in `/path/to/domoticz/dzVents/runtime/device-adapters`.  Copy an existing adapter and adapt it to your needs. You can turn debug logging on and inspect the file `domoticzData.lua` in the dzVents folder. There you will find the unique signature for your device type. Usually it is a combination of deviceType and deviceSubType, but you can use any of the device attributes in the `matches` function. The matches function checks if the device type is suitable for your adapter and the `process` function actually creates your specific attributes and methods.
1380Also, if you call `myDevice.dump()` you will see all attributes and methods and the attribute `_adapters` shows you a list of applied adapters for that device.
1381Finally, register your adapter in `Adapters.lua`. Please share your adapter when it is ready and working.
1382
1383## Variable object API (user variables)
1384User variables created in Domoticz have these attributes and methods:
1385
1386### Variable attributes and methods
1387 - **changed**: *Boolean*. Was the variable updated. **Note**: update does not necessarily means the variable value or type changed.
1388 - **date**: *Date*. If type is domoticz.DATE. See lastUpdate for the sub-attributes.
1389 - **id**: *Number*. Index of the variable.
1390 - **lastUpdate**: *[Time Object](#Time_object)*
1391 - **name**: *String*. Name of the variable
1392 - **rename(newName)**: *Function*. <sup>2.4.24</sup> Change current variable name to new variable name. (does not support timing options)
1393 - **set(value)**: Tells Domoticz to update the variable. Supports timing options. See [above](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
1394 - **time**: *Date*. If type is domoticz.TIME. See lastUpdate for the sub-attributes.
1395 - **type**: *String*. Can be domoticz.INTEGER, domoticz.FLOAT, domoticz.STRING, domoticz.DATE, domoticz.TIME.
1396 - **value**: *String|Number|Date|Time*. Value of the variable.
1397
1398## Time object
1399Many attributes represent a moment in time, like `myDevice.lastUpdate`  or `domoticz.time`. In dzVents, a time-like attribute is an object with properties and methods which make your life easier.
1400
1401```Lua
1402	print(myDevice.lastUpdate.minutesAgo)
1403	print(myDevice.lastUpdate.daysAgo)
1404
1405	-- compare two times
1406	print(domoticz.time.compare(myDevice.lastUpdate).secs))
1407```
1408
1409You can also create your own:
1410```Lua
1411	local Time = require('Time')
1412	local t = Time('2016-12-12 07:35:00') -- must be this format!!
1413```
1414If you don't pass a time string:
1415```Lua
1416	local Time = require('Time')
1417	local currentTime = Time()
1418```
1419
1420Use this in combination with the various dzVents time attributes:
1421
1422```Lua
1423	local Time = require('Time')
1424	local t = Time('2016-12-12 07:35:00')
1425
1426	local tonight = Time(domoticz.time.rawDate .. ' 20:00:00')
1427	print (tonight.getISO())
1428	-- will print something like: 2016-12-12T20:00:00Z
1429	print(t.minutesAgo) -- difference from 'now' in minutes
1430
1431	-- and you can feed it with all same rules as you use
1432	-- for the timer = { .. } section:
1433	if (t.matchesRule('at 16:00-21:00')) then
1434	  -- t is in between 16:00 and 21:00
1435	end
1436
1437	-- very powerful if you want to compare two time instances:
1438	local anotherTime = Time('...') -- fill-in some time here
1439	print(t.compare(anotherTime).secs) -- diff in seconds between t and anotherTime.
1440```
1441
1442### System event API
1443If you have a dzVents script that is triggered by a system-event in Domoticz then the second parameter passed to the execute function will be a *system* object. The object.type = system-event that triggered the script. ( object.isSystemEvent: true) For backups the object also contains location and durationin seconds.
1444
1445### Time properties and methods
1446
1447Creation:
1448```Lua
1449local Time = require('Time')
1450local now = Time() -- current time
1451local someTime = Time('2017-12-31 22:19:15')
1452local utcTime = Time('2017-12-31 22:19:15', true)
1453```
1454
1455Creation:<sup>2.5.4</sup>
1456```Lua
1457local someTime = domoticz.time.addMinutes(30) -- someTime = domoticz time object for now + 30 minutes
1458local someTime = domoticz.time.makeTime() -- someTime = new domoticz time object.
1459```
1460
1461 - **addAAA(offset)**: *time object*. <sup>2.5.4</sup> time object with given offset (positive or negativ. AAA is a placeholder for `Seconds, Minutes, Hours or Days` affix e.g. `addHours(-2)
1462 - **civTwilightEndInMinutes**: *Number*. Minutes from midnight until civTwilightEnd.
1463 - **civTwilightStartInMinutes**:*Number*. Minutes from midnight until civTwilightStart.
1464 - **compare(time)**: *Function*. Compares the current time object with another time object. *Make sure you pass a Time object!* Returns a table (all values are *positive*, use the compare property to see if *time* is in the past or future):
1465	- **milliseconds**: Total difference in milliseconds.
1466	- **seconds**: Total difference in whole seconds.
1467	- **minutes**: Total difference in whole minutes.
1468	- **hours**: Total difference in whole hours.
1469	- **days**: Total difference in whole days.
1470	- **compare**: 0 = both are equal, 1 = *time* is in the future, -1 = *time* is in the past.
1471 - **day**: *Number*
1472 - **dayAbbrOfWeek**: *String*. sun,mon,tue,wed,thu,fri or sat
1473 - **daysAgo**: *Number*
1474 - **dayName**: *String*.<sup>2.5.6</sup>  complete name Sunday, Monday, etc
1475 - **dDate**: *Number*. timestamp (seconds since 01/01/1970 00:00)
1476 - **getISO**: *Function*. Returns the ISO 8601 formatted date.
1477 - **hour**: *Number*
1478 - **hoursAgo**: *Number*. Number of hours since the last update.
1479 - **isToday**: *Boolean*. Indicates if the device was updated today
1480 - **isUTC**: *Boolean*.
1481 - **makeTime(timeString,[isUTC])**: *time object*. <sup>2.5.4</sup> time object based on parameter format must 'yyyy-mm-dd hh:mm:ss'. isUTC defaults to false
1482 - **matchesRule(rule) **: *Function*. Returns true if the rule matches with the time. See [time trigger rules](#timer_trigger_rules) for rule examples.
1483 - **millisecondsAgo**: *Number*. Number of milliseconds since the last update.
1484 - **minutes**: *Number*
1485 - **minutesAgo**: *Number*. Number of minutes since the last update.
1486 - **minutesSinceMidnight**: *Number* <sup>2.5.4</sup>
1487 - **month**: *Number*
1488 - **monthAbbrName**: String. <sup>2.5.6</sup> jan, feb, mar, etc
1489 - **monthName**: *String*. <sup>2.5.6</sup>  January, February, etc
1490 - **msAgo**: *Number*. Number of milliseconds since the last update.
1491 - **raw**: *String*. Generated by Domoticz
1492 - **rawDate**: *String*. Returns the date part of the raw data.
1493 - **rawDateTime**: *String*. <sup>2.4.25</sup> Combined date / time formatted as domoticz does in API / JSON returns (rawDate .. ' '.. rawTime )
1494 - **rawTime**: *String*. Returns the time part of the raw data as HH:MM:SS
1495 - **seconds**: *Number*
1496 - **secondsSinceMidnight**: *Number*
1497 - **secondsAgo**: *Number*. Number of seconds since the last update.
1498 - **sunsetInMinutes**: *Number*. Minutes from midnight until sunset.
1499 - **sunriseInMinutes**: *Number*. Minutes from midnight until sunrise.
1500 - **time**: *String*. <sup>2.5.6</sup> Returns the time part of the raw data as HH:MM
1501 - **utcSystemTime**: *Table*. UTC system time (only when in UTC mode):
1502	- **day**: *Number*
1503	- **hour**: *Number*
1504	- **month**: *Number*
1505	- **minutes**: *Number*
1506	- **seconds**: *Number*
1507	- **year**: *Number*
1508 - **utcTime**: *Table*. Time stamp in UTC time:
1509	- **day**: *Number*
1510	- **hour**: *Number*
1511	- **month**: *Number*
1512	- **minutes**: *Number*
1513	- **seconds**: *Number*
1514	- **year**: *Number*
1515 - **year**: *Number*
1516 - **wday**: *Number* day of the week. Sunday = 1, Saturday = 7
1517 - **week**: *Number* week of the year
1518
1519**Note: it is currently not possible to change the domoticz.time object instance.** ( but you can create a new one )
1520
1521## Shared helper functions
1522It is not unlikely that at some point you want to share Lua code among your scripts. Normally in Lua you would have to create a module and require that module in all you scripts. But dzVents makes that easier for you:
1523Inside your scripts folder or in Domoticz' GUI web editor, create a `global_data.lua` script (same as for global persistent data) and feed it with this code:
1524```Lua
1525return {
1526	helpers = {
1527	  myHandyFunction = function(param1, param2)
1528		 -- do your stuff
1529	  end,
1530	  MY_CONSTANT = 100 -- doesn't have to be a function
1531	}
1532}
1533```
1534Save the file and then you can use myHandyFunction everywhere in your event scripts:
1535```Lua
1536return {
1537	...
1538	execute = function(domoticz, device)
1539	  local results = domoticz.helpers.myHandyFunction('bla', 'boo')
1540	  print(domoticz.helpers.MY_CONSTANT)
1541	end
1542}
1543```
1544No `require` or `dofile` is needed.
1545
1546**Important note: if you need to access the domoticz object in your helper function you have to pass it as a parameter:**
1547
1548Example:
1549```Lua
1550return {
1551	helpers = {
1552	  myHandyFunction = function(domoticz, param1, param2)
1553		 -- do your stuff
1554		 domoticz.log('Hey')
1555	  end
1556	}
1557}
1558```
1559And pass it along:
1560```Lua
1561return {
1562	...
1563	execute = function(domoticz, device)
1564	  local results = domoticz.helpers.myHandyFunction(domoticz, 'bla', 'boo')
1565	end
1566}
1567```
1568**Note**: there can be only **one** `global_data.lua` on your system. Either in `/path/to/domoticz/scripts/dzVents/script` or in Domoticz' internal GUI web editor.
1569
1570## Requiring your own modules
1571If you don't want to use the helpers support, but you want to require your own modules, place them either in `/path/to/domoticz/scripts/dzVents/modules` or `/path/to/domoticz/scripts/dzVents/scripts/modules` as these folders are already added to the Lua package path. You can just require those modules: `local myModule = require('myModule')`
1572
1573# Persistent data
1574
1575In many situations you need to store a device state or other information in your scripts for later use. Like knowing what the state was of a device the previous time the script was executed or what the temperature in a room was 10 minutes ago. Without dzVents, you had to resort to user variables. These are global variables that you create in the Domoticz GUI and that you can access in your scripts like: domoticz.variables('previousTemperature').
1576
1577Now, for some this is rather inconvenient and they want to control this state information in the event scripts themselves or want to use all of Lua's variable types. dzVents has a solution for that: **persistent script data**. This can either be on the script level or on a global level.
1578
1579## Script level persistent variables
1580
1581The values in persistent script variables persist and can be retrieved in the next script run.
1582
1583For example, send a notification if a switch has been activated 5 times:
1584```Lua
1585	return {
1586		on = {
1587		 devices = { 'MySwitch' }
1588		},
1589		data = {
1590			counter = { initial = 0 }
1591		},
1592		execute = function(domoticz, switch)
1593		  if (domoticz.data.counter == 5) then
1594			 domoticz.notify('The switch was pressed 5 times!')
1595			 domoticz.data.counter = 0 -- reset the counter
1596		  else
1597			 domoticz.data.counter = domoticz.data.counter + 1
1598		  end
1599		end
1600	}
1601```
1602The `data` section defines a persistent variable called `counter`. It also defines an initial value.  From then on you can read and set the variable in your script.
1603
1604You do not have to provide an initial value though. In that case the initial value is *nil*:
1605
1606```Lua
1607	return {
1608		--
1609		data = {
1610			'x', 'y', 'z' -- note the quotes
1611		},
1612		execute = function(domoticz, item)
1613		  print(tostring(domoticz.data.x)) -- prints nil
1614		end
1615	}
1616```
1617
1618You can define as many variables as you like and put whatever value in there that you like. It doesn't have to be just a number. Just don't put something in there with functions (well, they are filtered out actually).
1619
1620### Size matters and watch your speed!!
1621If you include tables (or arrays) in the persistent data, beware to not let them grow. It will definitely slow down script execution because dzVents has to serialize and deserialize the data. It is better to use the historical option as described below.
1622
1623### Re-initializing a variable
1624You can re-initialize a persistent variable and re-apply the initial value as defined in the data section:
1625
1626```Lua
1627return {
1628	on = { .. },
1629	data = {
1630	  x = { initial = 'initial value' }
1631	},
1632	execute = function(domoticz, item)
1633	  if (domoticz.data.x ~= 'initial value') then
1634		 domoticz.data.initialize('x')
1635		 print(domoticz.data.x) -- will print 'initial value'
1636	  end
1637	end
1638}
1639```
1640Note that `domoticz.data.initialize('<varname>')` is just a convenience method. You can of course create a local variable in your module holding the initial value and use it in your data section and your execute function.
1641
1642## Global persistent variables
1643
1644Script level variables are only available in the scripts that define them, but global variables can be accessed and changed in every script. To utilize global persistent variables, create a script file called `global_data.lua` in your scripts folder with this content (same file where you can also put your shared helper functions):
1645
1646```Lua
1647	return {
1648		helpers = {},
1649		data = {
1650		  peopleAtHome = { initial = false },
1651		  heatingProgramActive = { initial = false }
1652		}
1653	}
1654```
1655
1656Just define the variables that you need and access them in your scripts:
1657```Lua
1658	return {
1659		on = {
1660			devices = {'WindowSensor'}
1661		},
1662		execute = function(domoticz, windowSensor)
1663		  if (domoticz.globalData.heatingProgramActive
1664			  and windowSensor.state == 'Open') then
1665			 domoticz.notify("Hey don't open the window when the heating is on!")
1666		  end
1667		end
1668	}
1669```
1670**Note**: there can be only one `global_data.lua` on your system. Either in `/path/to/domoticz/scripts/dzVents/script` or in Domoticz' internal GUI web editor.
1671
1672You can use `domoticz.globalData.initialize('<varname>')` just as like `domoticz.data.initialize('<varname>')`.
1673
1674## A special kind of persistent variables: *history = true* (Historical variables API)
1675
1676In some situations, storing a previous value for a sensor is not enough, and you would like to have more previous values. For example, you want to calculate an average over several readings. Of course you can define a persistent variable holding a table:
1677
1678```Lua
1679	return {
1680		active = true,
1681		on = {
1682			devices = {'MyTempSensor'}
1683		},
1684		data = {
1685		  previousData = { initial = {} }
1686		},
1687		execute = function(domoticz, sensor)
1688		  -- add new data
1689		  table.insert(domoticz.data.previousData, sensor.temperature)
1690
1691		  -- calculate the average
1692		  local sum = 0, count = 0
1693		  for i, temp in pairs(domoticz.data.previousData) do
1694			 sum = sum + temp
1695			 count = count + 1
1696		  end
1697		  local average = sum / count
1698		end
1699	}
1700```
1701
1702The problem with this is that you have to do a lot of bookkeeping to make sure that there isn't too much data to store (see [below for how it works](#How_does_the_storage_stuff_work.3F)) . Fortunately, dzVents has done this for you:
1703```Lua
1704	return {
1705		active = true,
1706		on = {
1707			devices = {'MyTempSensor'}
1708		},
1709		data = {
1710		  temperatures = { history = true, maxItems = 10 }
1711		},
1712		execute = function(domoticz, sensor)
1713		  -- add new data
1714		  domoticz.data.temperatures.add(sensor.temperature)
1715
1716		  -- average
1717		  local average = domoticz.data.temperatures.avg()
1718
1719		  -- maximum value in the past hour:
1720		  local max = domoticz.data.temperatures.maxSince('01:00:00')
1721		end
1722	}
1723```
1724
1725### Defining
1726Define a script variable or global variable in the data section and set `history = true`:
1727
17281729	data = {
1730	  var1 = { history = true, maxItems = 10, maxHours = 1, maxMinutes = 5 }
1731	}
1732
1733 - **maxItems**: *Number*. Controls how many items are stored in the variable. maxItems has precedence over maxHours and maxMinutes.
1734 - **maxHours**: *Number*. Data older than `maxHours` from now will be discarded.  E.g., if set to 2, then data older than 2 hours will be removed at the beginning of the script.
1735 - **maxMinutes**: *Number*. Same as maxHours but, you guessed it: for minutes this time..
1736 All these options can be combined. **Reminder: don't store too much data. Only put in what you really need!**
1737
1738### Adding data
1739Add new values to a historical variable:
1740
1741	domoticz.data.myVar.add(value)
1742
1743As soon as this new value is put on top of the list, the older values shift one place down the line. If `maxItems` is reached, then the oldest value will be discarded.  *All methods, like calculating averages or sums, will immediately use this new value!* If you don't want this to happen, set the new value at the end of your script or after you have done your analysis.
1744
1745Any kind of data may be stored in the historical variable: numbers, strings, but also more complex data like tables. However, in order to use the [statistical methods](#Statistical_functions), numeric values are required.
1746
1747### Accessing values in historical variables
1748Values in a historical variable are indexed, where index 1 is the newest value, 2 is the second newest, and so on:
1749
1750	local item = domoticz.data.myVar.get(5)
1751	print(item.data)
1752
1753However, all data in the storage are time-stamped:
1754
1755	local item = domoticz.data.myVar.getLatest()
1756	print(item.time.secondsAgo) -- access the time stamp
1757	print(item.data) -- access the data
1758
1759The time attribute by itself is a table with many properties that help you inspect the data points more easily. See [Time Object](#Time_object) for all attributes and methods.
1760
1761#### Index
1762All data in the set can be addressed using an index. The item with index = 1 is the youngest, and the item with the highest index is the oldest. Beware, if you have called `add()` first, then the first item is that new value! You can always check the size of the set by inspecting `myVar.size`.
1763
1764#### Time specification (*timeAgo*)
1765Every data point in the set has a timestamp and the set is ordered so that the youngest item is the first and the oldest item the last. Many functions require a moment in the past to be specified by passing a string in the format **`hh:mm:ss`**, where *hh* is the number of hours ago, *mm* the number of minutes and *ss* the number of seconds. The times are added together, so you don't have to consider 60 minute boundaries, etc. A time specification of `12:88:03` is valid, and points to the data point at or around `12*3600 + 88*60 + 3 = 48.483 seconds` in the past.
1766
1767Example:
1768
1769	-- get average for the past 30 minutes:
1770	local avg = myVar.avgSince('00:30:00')
1771
1772#### Getting data points
1773
1774 - **get(idx)**: Returns the idx-th item in the set. Same as `myVar.storage[idx]`.
1775 - **getAtTime([timeAgo](#Time_specification_.28timeAgo.29))**: Returns the data point *closest* to the moment as specified by `timeAgo` and the index in the set. So, `myVar.getAtTime('1:00:00')` returns the item that is closest to one hour old. It may be a bit younger or a bit older than 1 hour. The second return value is the index in the set: `local item, index = myVar.getAtTime('1:00:00')`
1776 - **getLatest( )**: Returns the youngest item in the set. Same as `print(myVar.get(1).data)`.
1777 - **getOldest( )**: Returns the oldest item in the set and the index. Same as `print(myVar.get(myVar.size).data)`. Note that the index is always the same as the total size. `local item, index = myVar.getOldest()`.
1778 - **size**: Return the number of data points in the set.
1779 - **subset( [fromIdx], [toIdx] )**: Returns a subset of the stored data. Default value, if omitted, of `fromIdx` is 1. Omitting `toIdx` takes all items until the end of the set (oldest). E.g., `myVar.subset()` returns all data. The result set supports [iterators](#Looping_through_the_data:_iterators) `forEach`, `filter`, `find` and `reduce`.
1780 - **subsetSince( [timeAgo](#Time_specification_.28timeAgo.29) )**: Returns a subset of the stored data since the relative time specified by timeAgo. So calling `myVar.subsetSince('00:60:00')` returns all items that have been added to the list in the past 60 minutes. The result set supports [iterators](#Looping_through_the_data:_iterators) `forEach`, `filter`, `find` and `reduce`.
1781 - **reset( )**: Removes all the items from the set. It could be a good practice to do this often when you know you don't need older data. For instance, when you turn on a heater and you just want to monitor rising temperatures starting from this moment when the heater is activated. If you don't need data points from before, then you may call reset.
1782
1783#### Looping through the data: iterators
1784Similar to the iterators as described [above](#Looping_through_the_collections:_iterators), there are convenience methods to make looping through the data set easier.
1785
1786 - **forEach(function)**: Loop over all items in the set: E.g.: `myVar.forEach( function( item, index, collection) ... end )`
1787 - **filter(function)**: Create a filtered set of items. The function receives the item and returns true if the item is in the result set. E.g. get a set with item values larger than 20: `subset = myVar.filter( function (item) return (item.data > 20) end )`.
1788 - **find(function)**: Search for a specific item in the set: E.g. find the first item with a value higher than 20: `local item = myVar.find( function (item) return (item.data > 20) end )`.
1789 - **reduce(function, initial)**: Loop over all items in the set and do some calculation with it. You call reduce with the function and the initial value. Each iteration the function is called with the accumulator. The function does something with the accumulator and returns a new value for it. Once you get the hang of it, it is very powerful. Best to give an example. To sum all values:
1790
1791		local sum = myVar.reduce(function(acc, item)
1792		 local value = item.data
1793		 return acc + value
1794	  end, 0)
1795
1796Suppose you want to get data points older than 45 minutes and count the values that are higher than 20 (of course there are more ways to do this):
1797
1798	local myVar = domoticz.data.myVar
1799
1800	local olderItems = myVar.filter(function (item)
1801	  return (item.time.minutesAgo > 45)
1802	end)
1803
1804	local count = olderItems.reduce(function(acc, item)
1805	  if (item.data > 20) then
1806		 acc = acc + 1
1807	  end
1808	  return acc
1809	end, 0)
1810
1811	print('Found ' .. tostring(count) .. ' items')
1812
1813#### Statistical functions
1814Statistical functions require *numerical* data in the set. If the set is just numbers you can do this:
1815
1816	myVar.add(myDevice.temperature) -- adds a number to the set
1817	myVar.avg() -- returns the average
1818
1819If, however, you add more complex data or you want to do a computation first, then you have to *tell dzVents how to get a numeric value from these data*. So let's say you do this to add data to the set:
1820
1821	myVar.add( { 'person' = 'John', waterUsage = u })
1822
1823Where `u` is a variable that got its value earlier. If you want to calculate the average water usage, then dzVents will not be able to do this because it doesn't know the value is actually in the `waterUsage` attribute! You will get `nil`.
1824
1825To make this work you have to provide a **getValue function** in the data section when you define the historical variable:
1826
1827	return {
1828		active = true,
1829		on = {...},
1830		data = {
1831		 myVar = {
1832			history = true,
1833			maxItems = 10,
1834			getValue = function(item)
1835				return item.data.waterUsage -- return number!!
1836			end
1837		 }
1838		},
1839		execute = function()...end
1840	}
1841
1842This function tells dzVents how to get the numeric value for a data item. **Note: the `getValue` function has to return a number!**.
1843
1844Of course, if you don't intend to use any of these statistical functions you can put whatever you want in the set.
1845
1846 - **avg( [fromIdx], [toIdx], [default] )**: Calculates the average of all item values within the range `fromIdx` to `toIdx`. If no data are in the set, the value `default` will be returned instead of `0`.
1847 - **avgSince([timeAgo](#Time_specification_.28timeAgo.29), default )**: Calculates the average of all data points since `timeAgo`. Returns `default` if there are no data, otherwise 0. E.g.: `local avg = myVar.avgSince('00:30:00')` returns the average over the past 30 minutes.
1848 - **min( [fromIdx], [toIdx] )**: Returns the lowest value in the range defined by fromIdx and toIdx.
1849 - **minSince([timeAgo](#Time_specification_.28timeAgo.29))**: Same as **min** but now within the `timeAgo` interval.
1850 - **max( [fromIdx], [toIdx] )**: Returns the highest value in the range defined by fromIdx and toIdx.
1851 - **maxSince([timeAgo](#Time_specification_.28timeAgo.29))**: Same as **max** but within the `timeAgo` interval.
1852 - **sum( [fromIdx], [toIdx] )**: Returns the summation of all values in the range defined by fromIdx and toIdx. It will return 0 when there are no data.
1853 - **sumSince([timeAgo](#Time_specification_.28timeAgo.29))**: Same as **sum** but within the `timeAgo` interval.  It will return 0 when there are no data in the interval.
1854 - ** delta(fromIdx, toIdx, [smoothRange], [default] )**: Returns the delta (difference) between items specified by `fromIdx` and `toIdx`. Provide a valid range (no `nil` values). [Supports data smoothing]. (#Data_smoothing) when providing a `smoothRange` value. Returns `default` if there is not enough data. The function also returns the fromItem and the toItem that is used to calculate the delta with: `local delta, from, to = delta(2, 5, 3)`.
1855 - **delta2( fromIdx, toIdx, [smoothRangeFrom], [smoothRangeTo], [default] )**:	Same as **delta** but now you can control if the smooth values for the *from-item* and the *to-item* separately. The function also returns the fromItem and the toItem that is used to calculate the delta with: `local delta, from, to = delta2(2, 5, 3, 3)`.
1856 - **deltaSince([timeAgo](#Time_specification_.28timeAgo.29),  [smoothRange], [default] )**: Same as **delta** but within the `timeAgo` interval. The function also returns the fromItem and the toItem that is used to calculate the delta with: `local delta, from, to = deltaSince('00:00:10', 3)`.
1857 - **deltaSinceOrOldest([timeAgo](#Time_specification_.28timeAgo.29),  [smoothRangeFrom], [smoothRangeTo], [default] )**:	Same as **deltaSince** but it will take the oldest value in the set if *timeAgo* is older than the age of the entire set. The function also returns the fromItem and the toItem that is used to calculate the delta with: `local delta, from, to = deltaSinceOrOldest('00:00:10', 3, 3)`.
1858 - **localMin( [smoothRange], default )**:
1859 - **localMin( [smoothRange], default )**: Returns the first minimum value (and the item holding the minimal value) in the past. [Supports data smoothing](#Data_smoothing) when providing a `smoothRange` value. For example, given this range of values in the data set (from new to old): `10 8 7 5 3 4 5 6`, it will return `3` because older values *and* newer values are higher: a local minimum. Use this if you want to know at what time a temperature started to rise after it had been dropping. E.g.:
1860
1861	  local value, item = myVar.localMin()
1862	  print(' minimum was : ' .. value .. ': ' .. item.time.secondsAgo .. ' seconds ago' )
1863 - **localMax([smoothRange], default)**: Same as **localMin** but for the maximum value. [Supports data smoothing](#Data_smoothing) when providing a `smoothRange` value.
1864 - **smoothItem(itemIdx, [smoothRange])**: Returns a the value of `itemIdx` in the set but smoothed by averaging with its neighbors. The number of neighbors is set by `smoothRange`. See [Data smoothing](#Data_smoothing).
1865
1866#### Data smoothing
1867
1868Example:
1869Suppose you store temperatures in the historical variable. These temperatures may have extremes. Perhaps these extremes could be due to sensor reading errors. In order to reduce the effect of these so-called spikes, you could smooth out values. It is like blurring the data. The Raw column is your temperatures. The other columns are calculated by averaging the neighbors. For item 10 the calculations are:
1870
1871	Range=1 for time10 = (25 + 31 + 29) / 3 = 28,3
1872	Range=2 for time10 = (16 + 25 + 31 + 29 + 26) / 5 = 25,4
1873
1874```{=mediawiki}
1875
1876{| class="wikitable" style="text-align: center; align="center" width="30% height:10px;"
1877! style="text-align: center; background:darkblue; color:white" align="center" width="12%"| time
1878! style="text-align: center; background:darkblue; color:white" align="center" width="12%"align="center" width="12%"| raw
1879! style="text-align: center; background:darkblue; color:white" align="center" width="12%"align="center" width="12%"| range=1
1880! style="text-align: center; background:darkblue; color:white" align="center" width="12%"align="center" width="12%"| range=2
1881|-
1882| '''1'''
1883| 18
1884| 20,0
1885| 21,7
1886|-
1887| '''2'''
1888| 22
1889| 21,7
1890| 25,0
1891|-
1892| '''3'''
1893| 25
1894| 27,3
1895| 24,6
1896|-
1897| '''4'''
1898| 35
1899| 27,7
1900| 26,6
1901|-
1902| '''5'''
1903| 23
1904| 28,7
1905| 27,6
1906|-
1907| '''6'''
1908| 28
1909| 26,0
1910| 25,8
1911|-
1912| '''7'''
1913| 27
1914| 23,7
1915| 23,8
1916|-
1917| '''8'''
1918| 16
1919| 22,7
1920| 25,4
1921|-
1922| '''9'''
1923| 25
1924| 24,0
1925| 25,6
1926|-
1927| '''10'''
1928| 31
1929| 28,3
1930| 25,4
1931|-
1932| '''11'''
1933| 29
1934| 28,7
1935| 29,2
1936|-
1937| '''12'''
1938| 26
1939| 30,0
1940| 30,2
1941|-
1942| '''13'''
1943| 35
1944| 30,3
1945| 30,2
1946|-
1947| '''14'''
1948| 30
1949| 32,0
1950| 30,4
1951|-
1952| '''15'''
1953| 31
1954| 30,3
1955| 30,8
1956|-
1957| '''16'''
1958| 30
1959| 29,7
1960| 28,2
1961|-
1962| '''17'''
1963| 28
1964| 26,7
1965| 28,6
1966|-
1967| '''18'''
1968| 22
1969| 27,3
1970| 26,2
1971|-
1972| '''19'''
1973| 32
1974| 24,3
1975| 25,3
1976|-
1977| '''20'''
1978| 19
1979| 25,5
1980| 24,3
1981|}
1982
1983```
1984
1985A chart illustrates it more clearly. The red line is not smoothed and has more spikes than the others:
1986
1987[[File:dzvents-smoothing.png|frame|none|alt=|Smoothing]]
1988
1989Usually a range of 1 or 2 is sufficient when providing a smoothing range to statistical functions. I suggest smoothing when checking deltas, local minimums and maximums.
1990
1991## How does the storage stuff work?
1992For every script file that defines persisted variables (using the `data={ … }` section), dzVents will create storage file with the name `__data_scriptname.lua` in a subfolder called `data`. You can always delete these data files or the entire storage folder if there is a problem with it:
1993
1994	domoticz/
1995		scripts/
1996 		dzVents/
1997			data/
1998				__data_yourscript1.lua
1999				__data_yourscript2.lua
2000				__data_global_data.lua
2001			examples/
2002			generated_scripts/
2003			scripts/
2004				yourscript1.lua
2005				yourscript2.lua
2006				global_data.lua
2007
2008If you dare to, you can watch inside these files. Every time some data are changed, dzVents will stream the changes back into the data files.
2009**Again, make sure you don't put too much stuff in your persisted data as it may slow things down too much.**
2010
2011# Asynchronous HTTP requests
2012dzVents allows you to make asynchronous HTTP request and handle the results. Asynchronous means that you don't block the system while waiting for the response. Earlier you had to use os functions like `curl` or `wget` and some magic to make sure that you didn't block the system for too long after which Domoticz will terminate the script with a message that it took more than 10 seconds.
2013
2014dzVents to the rescue. With dzVents there are two ways to make an http call and it is determined by how you use the `domoticz.openURL()` command. The simplest form simply calls `openURL` on the domoticz object with only the url as the parameter (a string value):
2015
2016```Lua
2017domoticz.openURL('http://domain/path/to/something?withparameters=1')
2018```
2019
2020After your script is finished, Domoticz will make the request that's where it ends. No callback. Nothing.
2021
2022The second way is different. Instead of passing a url you pass in a table with all the parameters to make the request **and** your provide a *callback trigger* which is just a string or a name:
2023```Lua
2024return {
2025	on = { ... }, -- some trigger
2026	execute = function(domoticz)
2027  	domoticz.openURL({
2028 		url = 'http://domain/path/to/something',
2029 		method = 'POST',
2030 		callback = 'mycallbackstring',
2031 		postData = {
2032			paramA = 'something',
2033			paramB = 'something else'
2034 		}
2035  	})
2036	end
2037}
2038```
2039In this case, Domoticz will make the request (a POST in this case), and when done it will trigger an event. dzVents will capture that event and will execute all scripts listening for this callback trigger (*mycallbackstring*):
2040
2041```Lua
2042return {
2043	on = {
2044  	httpResponses = { 'mycallbackstring' }
2045	},
2046	execute = function(domoticz, response)
2047  	if (response.ok) then -- success
2048 		if (response.isJSON) then
2049			domoticz.log(response.json.some.value)
2050 		end
2051  	else
2052 		domoticz.log('There was an error', domoticz.LOG_ERROR)
2053  	end
2054	end
2055}
2056```
2057Of course you can combine the script that issues the request and handles the response in one script:
2058```Lua
2059return {
2060	on = {
2061  	timer = {'every 5 seconds'},
2062  	httpResponses = { 'trigger' }
2063	},
2064	execute = function(domoticz, item)
2065  	if (item.isTimer) then
2066 		domoticz.openURL({
2067			url = '...',
2068			callback = 'trigger'
2069 		})
2070  	end
2071  	if (item.isHTTPResponse) then
2072 		if (item.ok) then
2073			...
2074 		end
2075  	end
2076	end
2077}
2078```
2079## API
2080
2081### Making the request:
2082
2083 **domoticz.openURL(options)**: *options*	is a Lua table:
2084
2085 - **url**: *String*.
2086 - **method**: *String*. Optional. Either `'GET'` (default), `'POST'`, `'PUT'`<sup>3.0.2</sup>  or `'DELETE'`<sup>3.0.2</sup> .
2087 - **callback**: *String*. Optional. A custom string that will be used by dzVents to find a the callback handler script.
2088 - **headers**: *Table*. Optional. A Lua table with additions http request-headers.
2089 - **postData**: Optional. When doing a `POST`, `PUT` <sup>3.0.2</sup> or `DELETE`<sup>3.0.2</sup> this data will be the payload of the request (body). If you provide a Lua table then this will automatically be converted to json and the request-header `application/json` is set. So no need to do that manually.
2090
2091Supports [command options](#Command_options_.28delay.2C_duration.2C_event_triggering.29).
2092
2093### The response object
2094The response object  (second parameter in your execute function) has these attributes:
2095
2096 - **data**: Raw response data.
2097 - **headers**: *Table*. Response headers.
2098 - **isJSON**: *Boolean*. Short for `response.headers['Content-Type'] == 'application/json'`. When true, the data is automatically converted to a Lua table.
2099 - **isXML**: *Boolean*. <sup>2.5.1</sup> Short for `response.headers['Content-Type'] == 'text/xml'`. When true, the data is automatically converted to a Lua table.
2100 - **json**. *Table*. When the response data is `application/json` then the response data is automatically converted to a Lua table for quick and easy access.
2101 - **ok**: *Boolean*. `True` when the request was successful. It checks for statusCode to be in range of 200-299.
2102 - **statusCode**: *Number*. HTTP status codes. See [HTTP response status codes](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes ).
2103 - **statusText**: *String*. <sup>2.4.19</sup> HTTP status message. See [HTTP response status codes]( https://en.wikipedia.org/wiki/List_of_HTTP_status_codes ).
2104 - **protocol**: *String*. <sup>2.4.19</sup> HTTP protocol. See [HTTP response status codes]( https://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol ).
2105 - **trigger**, **callback**: *String*. The callback string that triggered this response instance. This is useful if you have a script that is triggered by multiple different callback strings.
2106 - **xml**. *Table*. <sup>2.5.1</sup> When the response data is `text/xml` , the response data is automatically converted to a Lua table for quick and easy access.
2107 - **xmlEncoding**. *String*. <sup>2.5.1</sup> When the response data is `text/xml` See [ xml encoding] ( https://en.wikipedia.org/wiki/XML ).
2108 - **xmlVersion**. *String*. <sup>2.5.1</sup> When the response data is `text/xml` See [ xml versions ] ( https://en.wikipedia.org/wiki/XML ).
2109
2110### More about request and response headers
2111Whenever you do an http request it is not just some data that is sent. Along with the request a bunch of so-called headers are sent along with it. HTTP headers allow the client and the server to pass additional information with the request or the response. Also, in the response there are also headers (response header). These response headers usually tell you what kind of data is returned, if it is compressed, if the request was successful etc.
2112
2113#### request headers
2114dzVents allow you to set custom request headers that will accompany the data in the request. Sometimes it is necessary to set these headers like for instance when a API or webservice require a security token or key or when the service needs to know what the format of the response data is. Check the documentation of the web service.
2115
2116So, let's say you need to call a web service that requires an api key in the headers and the documentation states it needs to be passed in an x-access-token header. Your openURL command then may look like this:
2117```Lua
2118domoticz.openURL({
2119	url = 'https://somedomain.com/service/getInfo',
2120	headers = { ['x-access-token'] = '<api-key>' },
2121	method = 'GET',
2122	callback = 'info'
2123})
2124```
2125Check google for more information about request headers. All you need to know here is that dzVents allow you to set these headers.
2126
2127#### response headers
2128As said earlier, the response also contains a bunch of headers. You can inspect those headers with dzVents but ususally you don't have to. For starters, dzVents already checks the `Content-Type` header which usually states what kind of data format the response is. If it is `application/json` then it automatically converts the json data to a Lua table. Also, it checks the `Status` header to see if the request was successful. If so, then it sets the `ok` attribute on the response object. So normally you don't have to inspect the headers. However, sometimes the web service puts a session token in the response header that you have to use in follow-up requests.
2129
2130So here an example where we have to log in before we can fetch data. It uses two requests: the first performs the log-in and the second grabs the session token from the login response data and uses that token in the second request to get the data we need. In this example we do this every hour.
2131
2132That would look like this:
2133
2134```Lua
2135return {
2136	on = {
2137		timer = {'every hour'},
2138		httpResponses = { 'loggedin', 'data' }
2139	},
2140	execute = function(domoticz, item)
2141		if (item.isTimer) then
2142			-- login
2143			domoticz.openURL({
2144				url = 'https://somedomain.com/login',
2145				method = 'POST',
2146				postData = { ['username'] = 'Luke Skywalker', ['password'] = 'theforce' }
2147				callback = 'loggedin'
2148			})
2149		end
2150		if (item.isHTTPResponse and item.ok) then
2151			-- check to which request this response was the result
2152			if (item.trigger == 'loggedin') then
2153				-- we are logged in, now grab the session token from the header and
2154				-- fetch our data
2155				local token = item.headers['x-session-token']
2156				-- now we have the token, put it in the headers:
2157				domoticz.openURL({
2158					url = 'https://somedomain.com/getData',
2159					method = 'GET',
2160					headers = { ['x-session-token'] = token },
2161					callback = 'data'
2162				})
2163			else
2164				-- it must the data we requested
2165				local data = item.data
2166				-- do something with it
2167			end
2168		end
2169	end
2170}
2171```
2172
2173Some remarks about the response header `Content-Type`. If a service is a good web-citizen then it tells you what the format of the data is in this header. So, if the data is a json object then the header should be `application/json`. Unfortunately, there are lot of lazy programmers out there who don't set this header properly. If that is the case, dzVents cannot detect the format and will not turn it into a Lua table for you automatically. So, if you know it is json but the header is not properly set, then you can easily convert it into a Lua table in your code:
2174
2175```Lua
2176return {
2177	on = {
2178		timer = {'every hour'},
2179		httpResponses = { 'trigger' }
2180	},
2181	execute = function(domoticz, item)
2182		if (item.isTimer) then
2183			-- login
2184			domoticz.openURL({
2185				url = 'https://somedomain.com/getData',
2186				callback = 'trigger'
2187			})
2188		end
2189		if (item.isHTTPResponse and item.ok) then
2190			-- we know it is json but dzVents cannot detect this
2191			-- convert to Lua
2192			local json = domoticz.utils.fromJSON(item.data)
2193			-- json is now a Lua table
2194			print(json.result.title) -- just an example
2195		end
2196	end
2197}
2198```
2199
2200### Fetching data from Domoticz itself
2201Most of the things you need to do in your dzVents script is already exposed somewhere in the dzVents object hierarchy. Sometimes however you need some data that is not available in dzVents. Just to give an example, let's assume you have some zwave hardware and you want to know the `last seen` information of zwave devices or the status. This information is available in the node overview on the hardware page in Domoticz GUI. So, here is an example of how you can get that information into dzVents:
2202
2203```Lua
2204return {
2205	on = {
2206		timer = { 'every hour' },
2207		httpResponses = {
2208			'zwaveInfo'
2209		}
2210	},
2211	execute = function(domoticz, item)
2212
2213		if (item.isTimer) then
2214			-- check the index of your zwave hardware in the GUI
2215			-- in this example it is 2
2216			-- we assume you can access your Domoticz using the 1.0.0.127 ip
2217			-- on port 8080
2218			domoticz.openURL({
2219				url = 'http://1.0.0.127:8080/json.htm?type=openzwavenodes&idx=2',
2220				method = 'GET',
2221				callback = 'zwaveInfo',
2222			})
2223		end
2224
2225		if (item.isHTTPResponse and item.ok) then
2226			local Time = require('Time')
2227			local results = item.json.result
2228			-- loop through the nodes and print some info
2229			for i, node in pairs(results) do
2230				-- convert the time stamp in the raw data into a
2231				-- dzVents Time object
2232				local lastUpdate = Time(node.LastUpdate)
2233				print(node.Name)
2234				print('Hours ago: ' .. lastUpdate.hoursAgo)
2235				print('State: ' .. node.State')
2236			end
2237		end
2238	end
2239}
2240
2241```
2242
2243# Settings
2244
2245Settings for dzVents are found in the Domoticz GUI: **Setup > Settings > Other > EventSystem**:
2246
2247 - **dzVents disabled**: Tick this if you don't want any dzVents script to be executed.
2248 - **Log level**: (Note that you can override this setting in the logging section of your script)
2249	- *Errors*,
2250	- *Errors + minimal execution info*: Errors and some minimal information about which script is being executed and why,
2251	- *Errors + minimal execution info + generic info*. Even more information about script execution and a bit more log formatting.
2252	- *Debug*. Shows everything and dzVents will create a file `domoticzData.lua` in the dzVents folder. This is a dump of all the data received by dzVents from Domoticz.. These data are used to create the entire dzVents data structure.
2253	- *No logging*. As silent as possible.
2254
2255# Troubleshooting
2256So, you think if you have done everything correctly but things do not work (in some way) as you expected. Here are a couple steps you can do to find the cause.
2257
2258### Is dzVents enabled?
2259Check the settings (see above) and make sure the checkbox **dzVents disabled** is not checked.
2260
2261### Is your script enabled?
2262Make sure the active section in your script is set to `true`:  `active = true`. And, on top of that, if you are using the internal web editor to write your script, make sure that your script is active there and you have clicked Save! "Event active" is a separate checkbox that must be ticked for every active script. When not active, the script name will be red in the list on the right.
2263
2264### Turn on debug logging
2265Activate debug logging in the settings (see above). This will produce a lot of extra messages in the Domoticz log (don't forget to turn it off when you are done troubleshooting!). It is best to monitor the log through the command line, as the log in the browser sometimes tends to not always show all log messages. See the Domoticz manual for how to do that.
2266
2267When debug logging is enabled, every time dzVents kicks into action (Domoticz throws an event) it will log it, and it will create a file `/path/to/domoticz/scripts/dzVents/domoticzData.lua` with a dump of the data sent to dzVents. These data lie at the core of the dzVents object model. You can open this file in an editor to see if your device/variable/scene/group is in there. Note that the data in the file are not exactly the same as what you will get when you interact with dzVents, but it is a good start. If your device is not in the data file, then you will not have access to it in dzVents and dzVents will not be able to match triggers with that device. Something's wrong if you expect your device to be in there but it is not (is the device active/used?).
2268
2269Every time Domoticz starts dzVents and debug logging is enabled you should see these lines:
2270```
2271dzVents version: x.y.z
2272Event trigger type: aaaa
2273```
2274Where aaaa can be time, device, uservariable, security or scenegroup. That should give you a clue what kind of event is active. If you don't see this information then dzVents is not active (or debug logging is not active).
2275
2276### Script is still not executed
2277If for some reason your script is not executed while all of the above is done, it is possible that your triggers are not correct. Either the time rule is not matching with the current time (try to set the rule to `every minute` or something simple), or the device name is not correct (check casing), or you use an id that doesn't exist. Note that in the `on` section, you cannot use the dzVents domoticz object!
2278
2279Make sure that if you use an id in the `on` section that this id is correct. Go to the device list in Domoticz and find the device and make sure the device is in the 'used' list!. Unused devices will not create an event. Find the idx for the device and use that as the id.
2280
2281Also, make sure that your device names are unique! dzVents will throw a warning in the log if multiple device names match. It's best practice to have unique names for your devices. Use some clever naming like prefixing like 'Temperature: living room' or 'Lights: living room'. That also makes using wild cards on your `on` section easier.
2282
2283If your script is still not triggered, you can try to create a classic Lua event script and see if that does work.
2284
2285### Debugging your script
2286A simple way to inspect a device in your script is to dump it to the log: `myDevice.dump()`. This will dump all the attributes (and more) of the device so you can inspect what its state is.
2287Use print statements or domoticz.log() statements in your script at cricital locations to see if the Lua interpreter reaches that line.
2288Don't try to print a device object though; use the `myDevice.dump()` method for that. It wil log all attributes of the device in the Domoticz log.
2289
2290If you place a print statement all the way at the top of your script file it will be printed every time dzVents loads your script (that is done at the beginning of each event cycle). Sometimes that is handy to see if your script gets loaded in the first place. If you don't see your print statement in the log, then likely dzVents didn't load it and it will not work.
2291
2292### Get help
2293The Domoticz forum is a great resource for help and solutions. Check the [dzVents forum](https://www.domoticz.com/forum/viewforum.php?f=59).
2294
2295# Other interesting stuff
2296
2297## lodash for Lua
2298
2299lodash is a well known and very popular Javascript library filled with dozens of handy helper functions that really make you life a lot easier. Fortunately there is also a Lua version. This is directly available through the domoticz object:
2300
2301```Lua
2302local _ = domoticz.utils._
2303_.print(_.indexOf({2, 3, 'x', 4}, 'x'))
2304```
2305
2306<!--- (Removed because link is dead. Hopefully only temporarily  ) Check out the great documentation [here](http://axmat.github.io/lodash.lua/).  --->
2307Check out the documentation [here](https://htmlpreview.github.io/?https://github.com/rwaaren/lodash.lua/blob/master/doc/index.html).
2308
2309# Migrating from version 1.x.x
2310As you can read in the change log below there are a couple of changes in 2.0 that will break older scripts.
2311
2312## The 'on={..}' section.
2313The on-section needs the items to be grouped based on their type. Prior to 2.0 you had
2314```Lua
2315	on = {
2316	  'myDevice',
2317	  'anotherDevice'
2318	}
2319```
2320In 2.x you have:
2321```Lua
2322	on = {
2323	  devices = {
2324		 'myDevice',
2325		 'anotherDevice'
2326	  }
2327	}
2328```
2329The same for timer options, in 1.x.x:
2330```Lua
2331	on = {
2332	  ['timer'] = 'every 10 minutes on mon,tue'
2333	}
2334```
23352.x:
2336```Lua
2337	on = {
2338	  timer = {
2339		 'every 10 minutes on mon,tue'
2340	  }
2341	}
2342```
2343Or when you have a combination, in 1.x.x
2344```Lua
2345	on = {
2346		 'myDevice',
2347		 ['timer'] = 'every 10 minutes on mon,tue'
2348	  }
2349	}
2350
2351```
23522.x:
2353```Lua
2354	on = {
2355	  devices = {
2356		 'myDevice'
2357	  }
2358	  timer = {
2359		 'every 10 minutes on mon,tue'
2360	  }
2361	}
2362
2363```
2364## Getting devices, groups, scenes etc.
2365Prior to 2.x you did this to get a device:
2366```Lua
2367	domoticz.devices['myDevice']
2368	domoticz.groups['myGroup']
2369	domoticz.scenes['myScene']
2370	domoticz.variables['myVariable']
2371	domoticz.changedDevices['myDevices']
2372	domoticz.changeVariables['myVariable']
2373```
2374Change that to:
2375```Lua
2376	domoticz.devices('myDevice') -- a function call
2377	domoticz.groups('myGroup')
2378	domoticz.scenes('myScene')
2379	domoticz.variables('myVariable')
2380	domoticz.changedDevices('myDevices')
2381	domoticz.changeVariables('myVariable')
2382```
2383## Looping through the devices (and other dzVents collections), iterators
2384Earlier you could do this:
2385```Lua
2386	for i, device in pairs(domoticz.devices) do
2387	  domoticz.log(device.name)
2388	end
2389```
2390In 2.x that is no longer possible. You now have to do this:
2391```Lua
2392	domoticz.devices().forEach(function(device)
2393	  domoticz.log(device.name)
2394	end)
2395```
2396The same applies for the other collections like groups, scenes, variables, changedDevices and changedVariables.
2397Note that you can easily search for a device using iterators as well:
2398```Lua
2399	local myDevice = domoticz.devices().find(function(device)
2400	  return device.name == 'deviceImLookingFor'
2401	end)
2402```
2403For more information about these iterators see: [Looping through the collections: iterators](#Looping_through_the_collections:_iterators).
2404
2405## Timed commands
2406Prior to 2.0, to turn a switch off after 10 seconds:
2407```Lua
2408	domoticz.devices['mySwitch'].switchOff().after_sec(10)
2409```
2410In 2.x:
2411```Lua
2412	domoticz.devices('mySwitch').switchOff().afterSec(10)
2413```
2414The same applies for for_min and with_min.
2415
2416## Device attributes
2417Some device attributes are no longer formatted strings with units in there like WhToday. It is possible that you have some scripts that deal with strings instead of values.
2418
2419## Changed attributes
2420In 1.x.x you had a changedAttributes collection on a device. That is no longer there. Just remove it and just check for the device to be changed instead.
2421
2422## Using rawData
2423Prior to 2.x you likely used the rawData attribute to get to certain device values. With 2.x this is likely not needed anymore. Check the various device types above and check if there isn't a named attribute for you device type. dzVents 2.x uses so called device adapters which should take care of interpreting raw values and put them in named attributes for you. If you miss your device you can file a ticket or create an adapter yourself. See ![Create your own device adapter](#Create_your_own_device_adapter).
2424
2425## What happened to fetch http data?
2426In 2.x it is no longer needed to make timed json calls to Domoticz to get extra device information into your scripts. Very handy.
2427On the other hand, you have to make sure that dzVents can access the json without the need for a password because some commands are issued using json calls by dzVents. Make sure that in Domoticz settings under **Local Networks (no username/password)** you add `127.0.0.1` and you're good to go.
2428
2429# History
2430
2431## [3.0.2]
2432- Add `PUT` and `DELETE` support to `openURL`
2433- Ensure sending integer in nValue in update function
2434- Fix sValue for custom sensor
2435
2436## [3.0.1]
2437- Add option `at()` to the various commands/methods
2438
2439## [3.0.0]
2440 - Add system-events triggers as option to the on = { ... } section. Scripts can now be triggered based on these system-events:
2441	 - start
2442	 - stop
2443	 - manualBackupFinished,
2444	 - dailyBackupFinished
2445	 - hourlyBackupFinished
2446	 - monthlyBackupFinished
2447
2448 - Add custom-events triggers as option to the on = { ... } section. You can now send an event trigger to start subscribed dzVents scripts. customEvents can be triggered by:
2449	 - dzVents domoticz.emitEvent(name, data )  --  command  (data = optional)
2450	 - JSON: json.htm?type=command&param=customevent&event=MyEvent&data=myData ( data = optional )
2451	 - MQTT: {"command" : "customevent", "event" :    "MyEvent" , "data" : "myData" } ( data = opt ional )
2452 - Add method  domoticz.emitEvent()
2453 - Add attribute `mode` to Evohome controller
2454 - Add option to dumpTable() and ([device][uservariable][scene][group].dump() to os file
2455
2456## [2.5.7]
2457- Add option checkFirst to switchSelector method
2458
2459## [2.5.6]
2460- Add dayName, monthName, monthAbbrName and time as time attributes
2461- Add \_.round, \_.isEqual functions to lodash.lua
2462- Add testLodash.lua as testModule for lodash
2463
2464## [2.5.5]
2465- Add Zwave fan to Zwave mode device adapter
2466
2467## [2.5.4]
2468- Add minutesSinceMidnight to domoticz Time object
2469- Add domoticz.time.addSeconds(), -.addMinutes(), -.addHours(), -.addDays(), -.makeTime()
2470- Add string.sMatch to utils
2471- Made wildcard handling more resilient when magic chars are part of script triggers
2472
2473## [2.5.3]
2474- Add timealert / errors for long running scripts
2475- Add triggerHTTPResponse()
2476
2477## [2.5.2]
2478- Add actualWatt to replace WhActual (left in WhActual for compatibility reasons)
2479- Add toBase64 and fromBase64 function in utils
2480- Add setLogMarker function in utils
2481- Deprecated increaseBrightness(), decreaseBrightness(), discomode methods (only available for Yeelight and left devices stateless)
2482
2483## [2.5.1]
2484- Added `toXML` and `fromXML` methods to domoticz.utils.
2485- Add attributes isXML, xmlVersion, xmlEncoding
2486
2487## [2.5.0]
2488- Prepared for Lua 5.3
2489
2490## [2.4.29]
2491- Add error message including affected module when module got corrupted on disk.
2492- Add setLevel method for switchTypes.
2493- Increased resilience against badly formatted type Time user-variables.
2494- Use native domoticz command for increaseCounter method.
2495- Set inverse of "set color" to Off to enable use of toggleSwitch for RGB type of devices.
2496
2497## [2.4.28]
2498- Add deviceExists(), groupExists(), sceneExists(), variableExists(), cameraExists() methods in utils
2499- increased httpResponse resilience against different use of Upper-, Lowercase in headers['content-type'] to ensure JSON conversion to Lua table
2500
2501## [2.4.27]
2502- Add attribute protected for devices / scenes and groups
2503- Add methods protectionOn and protectionOff for devices / scenes and groups
2504- Add functions rightPad, leftPad, centerPad, leadingZeros, numDecimals in utils
2505
2506## [2.4.26]
2507- Add Smoke Detector device (activate and reset functions )
2508
2509## [2.4.25]
2510- Add rawDateTime
2511- fix for combined device / civil[day|night]time trigger rule
2512- fix for checkFirst on stopped status
2513
2514## [2.4.24]
2515- Add method rename for devices, user-variables , scenes and groups
2516
2517## [2.4.23]
2518- Add method setMode for evohome device
2519- Add method incrementCounter for incremental counter
2520- Prepared for Firebase notifications. Firebase (fcm) is the replacement for Google Cloud Messaging gcm)
2521- fix wildcard device
2522
2523## [2.4.22]
2524- selector.switchSelector method accepts levelNames
2525- increased selector.switchSelector resilience
2526- fix wildcard timerule
2527
2528## [2.4.21]
2529- fixed wrong direction for open() and close() for some types of blinds
2530- Add inTable function to domoticz.utils
2531- Add sValue attribute to devices
2532
2533## [2.4.20]
2534- Add quietOn() and quietOff() method to switchType devices
2535
2536## [2.4.19]
2537- Add stringSplit function to domoticz.utils.
2538- Add statusText and protocol to HTTPResponse
2539
2540## [2.4.18]
2541- Add triggerIFTTT() to domoticz
2542
2543## [2.4.17]
2544- Add dumpTable() to domoticz.utils
2545- Add setValues for devices
2546- Add setIcon for devices
2547
2548## [2.4.16]
2549- Add method dump() to domoticz (dumps settings)
2550- Add setHue, setColor, setHex, getColor for RGBW(W) devices
2551- Add setDescription for devices, groups and scenes
2552- Add volumeUp / volumeDown for Logitech Media Server (LMS)
2553- Changed domoticz.utils.fromJSON (add optional fallback param)
2554
2555## [2.4.15]
2556- Add option to use camera name in snapshot command
2557- Add domoticz.settings.domoticzVersion
2558- Add domoticz.settings.dzVentsVersion
2559
2560## [2.4.14]
2561- Added domoticz.settings.location.longitude and domoticz.settings.location.latitude
2562- Added check for- and message when call to openURL cannot open local (127.0.0.1)
2563- **BREAKING CHANGE** :Changed domoticz.settings.location to domoticz.settings.location.name (domoticz settings location Name)
2564- prevent call to updateCounter with table
2565
2566## [2.4.13]
2567- Added domoticz.settings.location (domoticz settings location Name)
2568- Added domoticz.utils.urlDecode method to convert a string with escaped chars (%20, %3A and the likes) to human readable format
2569
2570## [2.4.12]
2571- Added managed Counter (to counter)
2572
2573## [2.4.11]
2574- Added snapshot command to send Email with camera snapshot ( afterAAA() and withinAAA() options available)
2575
2576## [2.4.10]
2577- Added option to use afterAAA() and withinAAA() functions to updateSetPoint() <sup>needs domoticz V4.10360 or newer</sup>
2578- Changed function updateMode to display mode as string in domoticz log
2579
2580## [2.4.9]
2581- Added evohome hotwater device (state, mode, untilDate and setHotWater function)
2582- Added mode and untilDate for evohome zone devices
2583- Added EVOHOME_MODE_FOLLOW_SCHEDULE as mode for evohome devices
2584- Add speedMs and gustMs from wind devices
2585- bugfix for youless device (0 handling)
2586- bugfix for time ( twilightstart and twilightend handling)
2587- Fixed some date-range rule checking
2588
2589## [2.4.8]
2590- Added telegram as option for domoticz.notify
2591
2592## [2.4.7]
2593- Added support for civil twilight in rules
2594
2595## [2.4.6]
2596- Added Youless device
2597- Added more to the documentation section for http requests
2598- Made sure global_data is the first module to process. This fixes some unexpected issues if you need some globals initialized before the other scripts are loaded.
2599
2600## [2.4.5]
2601- Fixed a bug in date ranges for timer triggers (http://domoticz.com/forum/viewtopic.php?f=59&t=23109).
2602
2603## [2.4.4]
2604- Fixed rawTime and rawData so it shows leading zeros when values are below 10.
2605- Fixed one wildcard issue. Should now work as expected.
2606- Fixed a problem in Domoticz where you couldn't change the state of some door contact-like switches using the API or dzVents. That seems to work now.
2607
2608## [2.4.3]
2609- Fixed trigger wildcards. Now you can do `*aa*bb*cc` or `a*` which will require the target to start with an `a`
2610- Added more EvoHome device types to the EvoHome device adapter.
2611
2612## [2.4.2]
2613- Fixed RGBW device adapter
2614- Fixed EvoHome device adapter
2615- Changed param ordering opentherm gateway command (https://www.domoticz.com/forum/viewtopic.php?f=59&t=21620&p=170469#p170469)
2616
2617## [2.4.1]
2618- Fixed week number problems on Windows
2619- Fixed 'on date' rules to support dd/mm format (e.g. 01/02)
2620
2621## [2.4.0]
2622
2623- **BREAKING CHANGE**: The second parameter passed to the execute function is no longer `nil` when the script was triggered by a timer or a security event. Please check your scripts. The second parameter has checks to determine the type. E.g. `execute = function(domoticz, item) .. end`. You can inspect `item` using: `item.isDevice`, `item.isTimer`, `item.isVariable`, `item.isScene`, `item.isGroup`, `item.isSecurity`, `item.isHTTPResponse`. Please read the documentation about the execute function.
2624- Added ``.cancelQueuedCommands()`` to devices, groups, scenes and variables. Calling this method will cancel any scheduled future commands issued using for instance `.afterMin(10)` or `.repeatAfterMin(1, 4)`
2625- Added `.devices()` collection to scenes and groups to iterate (`forEach`, `filter`, `reduce`, `find`) over the associated devices.
2626- Added http response event triggers to be used in combination with `openURL`. You can now do `GET` and `POST` request and handle the response in your dzVents scripts **ASYNCHRONICALLY**. See the documentation. No more json parsing needed or complex `curl` shizzle.
2627- Added a more consistent second parameter sent to the execute function. When a timer is triggered then the second parameter is a Timer object instead of nil. This way you can check the baseType of the second parameter and makes third parameter (triggerInfo) kind of obsolete. Every object bound to the second parameter now has a baseType.
2628- Added locked/unlocked support for door-locks (locked == active).
2629- Moved utility functions from the domoticz object to `domoticz.utils` object. You will see a deprecation warning when using the old function like `round()`, `toCelsius()` etc.
2630- Added `lodash` as a method to `domoticz.utils`: `domoticz.utils._`
2631- Added `toJSON` and `fromJSON` methods to domoticz.utils.
2632- Added `afterAAA()` and `withinAAA()` support for device-update commands. E.g.: `myTextDevice.updateText('Zork').afterMin(2)`.
2633- Added support for Logitech Media Server devices (thanks to Eoreh).
2634- Added new timer rules: date rules: `on 13/07`, `on */03`, `on 12/*`, `on 12/04-22/09`, `on -24/03`, `on 19/11-`, week rules: `in week 12,15,19-23,-48,53-`, `every even week`, `every odd week`. See documentation.
2635- Added historical data helper `delta2(fromIndex, toIndex, smoothRangeFrom, smoothRangeTo, default)` to have a bit more control over smoothing. You can specify if want to smooth either the start value (reference) and/or the to value (compared value).
2636- Added historical data helper `deltaSinceOrOldest(timeAgo, smoothRangeFrom, smoothRangeTo, default)`. This will use the oldest data value when the data set is shorter than timeAgo.
2637- Added support for Lighting Limitless/Applamp RGBW devices. You can now set Kelvin and RGB values, NightMode, WhiteMode and increase and decrease the brightness and discoMode. See the documentation.
2638- Added device adapter for Onkyo receiver hardware.
2639- Added `scriptName` to the triggerInfo object passed as the third parameter to the execute function. This holds the name of the script being executed.
2640- Fixed bug in Domoticz where using forAAA() with selector switches didn't always work.
2641- Fixed bug in Domoticz where improper states were passed to the event scripts. This may happen on slower machines where several devices may have been updated before the event-system had a change to operate on them. In that case the event scripts received the current final state instead of the state at the moment of the actual event.
2642- Added support for webroot. dzVents will now use the proper API url when domoticz is started with the -webroot switch.
2643- Added support for event-bursts. If (on slower machines) events get queued up in Domoticz, they will be sent to dzVents in one-package. This makes event processing significantly faster.
2644- Added `domoticz.data.initialize(varName)`. This will re-initialize non-historical variables to the initial value as defined in the data section.
2645- You now no longer have to provide an initial value for a persistent variable when you declare it. So you can do `data = { 'a', 'b', 'c'}` instead of `data = {a={initial = nil}, b={initial=nil}, c={initial=nil} }`. You have to quote the names though.
2646- A filter can now accept a table with names/id's instead of only functions. You can now do `domoticz.devices().filter({ 'mySwitch', 'myPIR', 34, 35, 'livingLights'})` which will give you a collection of devices with these names and ids.
2647- Added and documented `domoticz.settings.url`, `domoticz.settings.webRoot` and `domoticz.settings.serverPort`.
2648- Removed fixed limit on historical variables if there is a limit specified.
2649
2650## [2.3.0]
2651
2652 - Added `active` attribute to devices (more logical naming than the attribute 'bState'). `myDevice.active` is true or false depending on a set of known state values (like On, Off, Open, Closed etc). Use like `if mySwitch.active then .. end`
2653 - Added `domoticz.urlEncode` method on the `domoticz` object so you can prepare a string before using it with `openURL()`.
2654 - Updating devices, user variables, scenes and groups now always trigger the event system for follow-up events.
2655 - Added support for groups and scenes change-event scripts. Use `on = { scenes = { 'myScene1', 'myScene2' }, groups = {'myGroup1'} }`
2656 - Added adapter for the new Temperature+Barometer device.
2657 - Added `domoticz.startTime` giving you the time at which the Domoticz service was started. Returns a Time object.
2658 - Added `domoticz.systemUptime` (in seconds) indicating the number of seconds the machine is running. Returns a Time object.
2659 - Added more options to the various commands/methods: e.g. `myDevice.switchOff().silent()`, `.forSec()`, `.forHour()`, `.afterHour()`, `.repeatAfterSec()`, `.repeatAfterMin()`, `.repeatAfterHour()`, `.withinHour()` and `.checkFirst()`. This now works not only for devices but also scenes, groups and user variables. See documentation about command options.
2660 - Added `.silent()` option to commands like `switchOn().afterSec(4).silent()` causing no follow-up events to be triggered. This also works when updating non-switch-like devices, scenes, groups and user variables. If you do not call `silent()``, a follow-up event is *always* triggered (for devices, scenes, groups and user variables).
2661 - Added time rule `between xx and yy`. You can now do things like: `between 16:34 and sunset` or `between 10 minutes before sunset and sunrise`. See the doc.
2662 - Added support for milliseconds in `Time` object. This also give a ms part in the time-stamp for historical persistent data. You can now do `msAgo()` on time stamp when you inspect a data point from an history variable.
2663 - Added `daysAgo()` to `Time` object.
2664 - Added `compare(time)` method to `Time` object to calculate the difference between them. Returns a table. See documentation.
2665 - Added `domoticz.round()` method to `domoticz` object.
2666 - Added `text` property to alert sensor.
2667 - `active` section is now optional in your dzVents script. If you don't specify an `active = true/false` then true is assumed (script is active). Handy for when you use Domoticz' GUI script editor as it has its own way of activating and deactivating scripts.
2668 - Added `humidityStatusValue` for humidity devices. This value matches with the values used for setting the humidity status.
2669 - `Time` object will initialize to current time if nothing is passed: `local current = Time()`.
2670 - Added the lua lodash library,	<!--  removed because of dead link http://axmat.github.io/lodash.lua/ , MIT license ).	-->
2671 - Fixed documentation about levelNames for selector switches and added the missing levelName.
2672 - Moved dzVents runtime code away from the `/path/to/domoticz/scripts/dzVents` folder as this scripts folder contains user stuff.
2673 - Added more trigger examples in the documentation.
2674 - You can now put your own non-dzVents modules in your scripts folder or write them with the Domoticz GUI editor. dzVents is no longer bothered by it. You can require your modules in Lua's standard way.
2675 - Added `/path/to/domoticz/scripts/dzVents/scripts/modules` and `/path/to/domoticz/scripts/dzVents/modules` to the Lua package path for custom modules. You can now place your modules in there and require them from anywhere in your scripts.
2676 - Added dzVents-specific boilerplate/templates for internal web editor.
2677 - Fixed the confusing setting for enabling/disabling dzVents event system in Domoticz settings.
2678 - Fixed a problem where if you have two scripts for a device and one script uses the name and the other uses the id as trigger, the id-based script wasn't executed.
2679
2680## [2.2.0]
2681
2682 - Fixed typo in the doc WActual > WhActual.
2683 - Updated switch adapter to match more switch-like devices.
2684 - Added Z-Wave Thermostat mode device adapter.
2685 - Fixed a problem with thermostat setpoint devices to issue the proper url when updating.
2686 - Added secondsSinceMidnight to time attributes (e.g. lastUpdate.secondsSinceMidnight)
2687 - Added 4 new time-rules: xx minutes before/after sunset/sunrise.
2688 - Added example script to fake user presence.
2689 - Fixed support for uservariables with spaces in their names.
2690 - Show a warning when an item's name isn't unique in the collection.
2691 - Added timing options for security methods armAway, armHome and disarm like device.armAway().afterSec(10).
2692 - Added idx, deviceId and unit to device objects. Don't confuse deviceId with device.id(x) which is actually the index of the device.
2693 - Added instructions on how to create a security panel device in Domoticz. This device now has a state that has the same value as domoticz.security.
2694 - Fixed bug in check battery levels example.
2695 - Fixed some irregularities with dimmer levels.
2696
2697## [2.1.1]
2698
2699 - Fixed typo in the doc WActual > WhActual.
2700 - Updated switch adapter to match more switch-like devices.
2701 - Added Z-Wave Thermostat mode device adapter.
2702 - Fixed a problem with thermostat setpoint devices to issue the proper url when updating.
2703
2704## [2.1.0]
2705
2706 - Added support for switching RGB(W) devices (including Philips/Hue) to have toggleSwitch(), switchOn() and switchOff() and a proper level attribute.
2707 - Added support for Ampère 1 and 3-phase devices
2708 - Added support for leaf wetness devices
2709 - Added support for scale weight devices
2710 - Added support for soil moisture devices
2711 - Added support for sound level devices
2712 - Added support for visibility devices
2713 - Added support for waterflow devices
2714 - Added missing color attribute to alert sensor devices
2715 - Added updateEnergy() to electric usage devices
2716 - Fixed casing for WhTotal, WhActual methods on kWh devices (Watt's in a name?)
2717 - Added toCelsius() helper method to domoticz object as the various update temperature methods all need Celsius.
2718 - Added lastLevel for dimmers so you can see the level of the dimmer just before it was switched off (and while is it still on).
2719 - Added integration tests for full round-trip Domoticz > dzVents > Domoticz > dzVents tests (100 tests). Total tests (unit+integration) now counts 395!
2720 - Fixed setting uservariables. It still uses json calls to update the variable in Domoticz otherwise you won't get uservariable event scripts triggered in dzVents.
2721 - Added dzVents version information in the Domoticz settings page for easy checking what dzVents version is being used in your Domoticz built. Eventhough it is integrated with Domoticz, it is handy for dzVents to have it's own heartbeat.
2722 - avg(), avgSince(), sum() and sumSince() now return 0 instead of nil for empty history sets. Makes more sense.
2723 - Fixed boiler example to fallback to the current temperature when there is no history data yet when it calculates the average temperature.
2724 - Use different api command for setting setPoints in the Thermostat setpoint device adapter.
2725
2726## [2.0.0] Domoticz integration
2727
2728 - Almost a complete rewrite.
2729 - **BREAKING CHANGE**: Accessing a device, scene, group, variable, changedDevice, or changedVariable has been changed: instead of doing `domoticz.devices['myDevice']` you now have to call a function: `domoticz.devices('myDevice')`. This applies also for the other collections: `domoticz.scenes(), domoticz.groups(), domoticz.changedDevices(), domoticz.changedVariables()`. If you want to loop over these collection **you can no longer use the standard Lua for..pairs or for..ipairs construct**. You have to use the iterators like forEach, filter and reduce: `domoticz.devices().forEach(function() .. end)` (see [Looping through the collections: iterators](#Looping_through_the_collections:_iterators)). This was a necessary change to make dzVents a whole lot faster in processing your event scripts. **So please change your existing dzVents scripts!**
2730 - **BREAKING CHANGE**: after_sec, for_min, after_min, within_min methods have been renamed to the camel-cased variants afterSec, forMin, afterMin, withinMin. Please rename the calls in your script.
2731 - **BREAKING CHANGE**: There is no longer an option to check if an attribute was changed as this was quite useless. The device has a changed flag. You can use that. Please change your existing scripts.
2732 - **BREAKING CHANGE**: Many device attributes are now in the appropriate type (Number instead of Strings) so you can easily make calculations with them. Units are stripped from the values as much as possible. **Check your scripts as this may break stuff.**
2733 - **BREAKING CHANGE**: on-section now requires subsections for `devices`, `timer`, `variables`, and `security`. The old way no longer works! Please convert your existing scripts!
2734 - **BREAKING CHANGE**: Make sure that in Domoticz settings under **Local Networks (no username/password)** you add `127.0.0.1` so dzVents can use Domoticz api when needed.
2735 - dzVents now works on Windows machines!
2736 - dzVents is no longer a separate library that you have to get from GitHub. All integrated into Domoticz.
2737 - Added option to create shared utility/helper functions and have them available in all your scripts. Simply add a `helpers = { myFunction = function() ... end }` to the `global_data.lua` file in your scripts folder and you can access the function everywhere: `domoticz.helpers.myFunction()`.
2738 - Created a pluggable system for device adapters so people can easily contribute by creating specific adapters for specific devices. An adapter makes sure that you get the proper methods and attributes for that device. See `/path/to/domoticz/scripts/dzVents/runtime/device-adapters`.
2739 - Added a `reduce()` iterator to the collections in the domoticz object so you can now easily collect data about all your devices. See  [Looping through the collections: iterators](#Looping_through_the_collections:_iterators).
2740 - Added a `find()` iterator so you can easily find an item in one of the collection (devices, scenes, groups etc.). See  [Looping through the collections: iterators](#Looping_through_the_collections:_iterators).
2741 - Variables (uservariables) have more attributes. The `value` is now the same type as it is defined in Domoticz. So no more need for a converted nValue attribute. You can inspect the type using `myVar.type`. If it is a time variable or date variable you an extra `date` or `time` attribute with the same methods as with all other date/time related attributes like `lastUpdate`. .E.g. `myVar.date.minutesAgo`.
2742 - Settings are now moved to the Domoticz GUI (**Setup > Settings > Other**) and no longer in a settings file.
2743 - You can now override the log settings per script. So you can turn-off logging globally (see log level in the settings) and still have debug-level logging for that one script you are working on. You can even add a prefix string to the log messages for easy filtering in the Domoticz log. See the documentation about the `logging = { .. }` section.
2744 - No more need to do http-calls to get extended data from Domoticz. All relevant internal Domoticz state-data is now available inside your dzVents scripts. Thanks Scotty!!
2745 - Support for many many more device types and their specific methods. See the documentation for the list of attributes and events that are available. Note that device-type specific attributes are only available for those type of devices. You will receive an error in the log if you try to access an attribute that doesn't exist for that particular device. Hopefully you don't have to use the rawData table anymore. If you still do please file a report or create a device adapter yourself.
2746 - You can now write dzVents scripts using the internal editor in Domoticz. These scripts will be automatically exported to the filesystem (one-way only) so dzVents can execute them (generated_scripts folder).  Thanks again Scotty!
2747 - Support for variable change events (`on = { variables = { 'varA', 'varB'} }`)
2748 - Support for security change events (`on = { security = { domoticz.SECURITY_ARMEDAWAY } }`)
2749 - The triggerInfo passed to the execute function now includes information about which security state triggered the script if it was a security event.
2750 - Extended the timer-rule with time range e.g. `at 16:45-21:00` and `at nighttime` and `at daytime` and you can provide a custom function. See documentation for examples. The timer rules can be combined as well.
2751 - Timer rules for `every xx minutes` or `every xx hours` are now limited to intervals that will reach *:00 minutes or hours. So for minutes you can only do these intervals: 1, 2, 3, 4, 5, 6, 10, 12, 15, 20 and 30. Likewise for hours.
2752 - The Time object (e.g. domoticz.time) now has a method `matchesRule(rule)`. `rule` is a string same as you use for timer options: `if (domoticz.time.matchesRule('at 16:32-21:33 on mon,tue,wed')) then ... end`. The rule matches if the current system time matches with the rule.
2753 - A device trigger can have a time-rule constraint: ` on = { devices = { ['myDevice'] = { 'at nighttime' } }`. This only triggers the script when myDevice was changed **and** the time is after sunset and before sunrise.
2754 - Add support for subsystem selection for domoticz.notify function.
2755 - Fixed a bug where a new persistent variable wasn't picked up when that variable was added to an already existing data section.
2756
2757## [1.1.2]
2758
2759 - More robust way of updating devices.lua
2760 - Added device level information for non-dimmer-like devices
2761
2762## [1.1.1]
2763
2764 - Added support for a devices table in the 'on' section.
2765 - Added extra log level for only showing information about the execution of a script module.
2766 - Added example script for System-alive checker notifications (preventing false negatives).
2767
2768## [1.1]
2769
2770 - Added example script for controlling the temperature in a room with hysteresis control.
2771 - Fixed updateLux (thanks to neutrino)
2772 - Added Kodi commands to the device methods.
2773 - Fixed updateCounter
2774 - Added counterToday and counterTotal attributes for counter devices. Only available when http fetching is enabled. See [Using dzVents with Domoticz](#Using_dzVents_with_Domoticz).
2775
2776## [1.0.2]
2777
2778 - Added device description attribute.
2779 - Added support for setting the setpoint for opentherm gateway.
2780 - Added timedOut boolean attribute to devices. Requires http data fetching to be enabled. See [Using dzVents with Domoticz](#Using_dzVents_with_Domoticz).
2781 - Properly detects usage devices and their Wattage.
2782
2783## [1.0.1]
2784
2785 - Added updateCustomSensor(value) method.
2786 - Fixed reset() for historical data.
2787
2788## [1.0][1.0-beta2]
2789
2790 - Deprecated setNew(). Use add() instead. You can now add multiple values at once in a script by calling multiple add()s in succession.
2791 - Fixed printing device logs when a value was boolean or nil
2792 - Fixed WActual/total/today for energy devices.
2793 - Added updateSetPoint method on devices for dummy thermostat devices and EvoHome setpoint devices
2794 - Added couple of helper properties on Time object. See README.
2795 - Renamed the file dzVents_settings.lua to dzVents_settings_example.lua so you don't overwrite your settings when you copy over a new version of dzVents to your system.
2796
2797## [1.0-beta1]
2798
2799 - Added data persistence for scripts between script runs (see readme for more info)
2800 - Added a time-line based data type for you scripts with historical information and many statistical functions for retreiving information like average, minumum, maximum, delta, data smoothing (averaging values over neighbours) etc. See readme for more information.
2801 - Added SMS method to the domoticz object.
2802 - Added toggleSwitch() method to devices that support it.
2803 - Added more switch states that control device.bState (e.g. on == true, open == true 'all on' == true)
2804 - Added secondsAgo to the lastUpdate attribute
2805 - Added tests (test code coverage is above 96%!)
2806 - Refactored code significantly.
2807 - Made sure differently formulated but equal triggers in one script only execute the script only once (like MySensor and MySensor_Temperature).
2808 - Added trigger info as a third parameter (Lua table) that is passed to the execute method of a script containing information about what exactly triggered the script (type = EVENT_TYPE_TIMER/EVENT_TYPE_DEVICE, trigger=<timer rule>). See readme.
2809 - Added Lua time properties to domoticz.time property with all information about the current time (hours, minutes, seconds, etc.)
2810 - Added option to return false in a forEach iteratee function which will abort the forEach loop.
2811 - All devices not delivered by Domoticz to the event scripts are now added to domoticz.devices using the http data that is fetched every 30 minutes (by default).
2812 - Added scenes and groups collections to the domoticz object
2813 - Added Quick Reference Guide.
2814
2815## [0.9.13]
2816
2817 - Fixed some timer functions
2818
2819## [0.9.12]
2820
2821 - Fixed a bug with log level printing. Now errors are printed.
2822 - Added setPoint, heatingMode, lux, WhTotal, WhToday, WActual attributes to devices that support it. No need to access rawData for these anymore.
2823
2824## [0.9.11]
2825
2826 - Added log method to domoticz object. Using this to log message in the Domoticz log will respect the log level setting in the settings file. [dannybloe]
2827 - Updated readme. Better overview, more attributes described.
2828 - Added iterator functions (forEach and filter) to domoticz.devices, domoticz.changedDevices and domoticz.variables to iterate or filter more easily over these collections.
2829 - Added a couple of example scripts.
2830
2831## [0.9.10]
2832
2833 - A little less verbose debug logging. Domoticz seems not to print all message in the log. If there are too many they may get lost. [dannybloe]
2834 - Added method fetchHttpDomoticzData to domoticz object so you can manually trigger getting device information from Domoticz through http. [dannybloe]
2835 - Added support for sounds in domoticz.notify(). [WebStarVenlo]
2836
2837## [0.9.9]
2838
2839 - Fixed a bug where every trigger name was treated as a wild-carded name. Oopsidayzy...
2840
2841## [0.9.8]
2842
2843 - Fixed a bug where a device can have underscores in its name.
2844 - Added dimTo(percentage) method to control dimmers.
2845 - Modified the switch-like commands to allow for timing options: .for_min(), .within_min(), after_sec() and after_min() methods to control delays and durations. Removed the options argument to the switch functions. See readme.
2846 - Added switchSelector method on a device to set a selector switch.
2847 - Added wild-card option for triggers
2848 - Added http request data from Domoticz to devices. Now you can check the battery level and switch type and more. Make sure to edit dzVents_settings.lua file first and check the readme for install instructions!!!
2849 - Added log level setting in dzVents_settings.lua
2850
2851## [0.9.7]
2852
2853 - Added domoticz object resource structure. Updated readme accordingly. No more (or hardly any) need for juggling with all the Domoticz Lua tables and commandArrays.
2854
2855