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¶m=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(<[level]|[levelname] >) ''' : 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 1728 … 1729 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¶m=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