Page 1 of 3

[userMODULE] eaZy Logic for starters

Posted: 06 Apr 2015 18:34
by dolpheen
The RaZberry platform has a great number of functions for developers and is very flexible.
So flexible :) that it's not easy to start to do cool automation things for RaZberry newbies.
You can do a lot of automation tasks in different ways and manner - via different HTTP APIs, modules or scripts(need some learning) or you can do simple logic with some modules (too basic and not well documented though).
I'd like to present an intermediate solution(between full featured scripts and simple module rules) - eaZyLogic module :D. You can start writing your logic rules in a couple of minutes (you need just basic knowlege of JavaScript).
I also plan to use it for my simple automation scenes.
it's still in developement, so comments are welcome.
Tested on - 2.0.1rc-24 Current version 1.0.2

Update 1.0.2
Chain logic rewritten
Added support for IR remote controls - onRemote()
Update 1.0.21
Added support for IR remote controls - remoteSendKey()

Basic Usage
Device basic control
The name for device for _z function can be ID or title of device from your HomeAutomation UI
You can use any javascript code to program logic inside functions.

Code: Select all

//Set dimmer light level

// Switch dimmer on/off

//Switch wall plug off

//Get Temperature 
var temp = _z('motion sensor temp').getLevel(); 

//select two dimmers from different fooms and set level to 50
_z('lamp on desk in cabinet, dimmer2 in kitchen').setLevel(50) 

// switch 'lamp at entrance' device in room 'hall'
_z('lamp at entrance in hall').on()

//select all devices with 'lights' tag
_z('all lights') 

//select all devices with 'lights' tag in room 'hall'
_z('all lights in hall') 

//select all devices with 'lights' tag in room 'hall' (force tag use if you have 'all lights' device)
_z('all with tag lights in hall'') 

// Select all devices with 'always armed alarms' tag (flood seensor, etc.), arm it and send notification  
// if breached (you can use Javascript functions instead notifications
_z('all Always Armed alarms').arm().onBreach('Alarm!)   
// disarm so that you do not recieve notifications 
_z('all general alarms').disarm() 

// The next device selection patterns exist (also can be passed as array)
_z('dimmer1, 'dimmer2, dimmer3', 'wallplug at basement')
Add delays between commands in chain

Code: Select all

//Switch on dimmer after 3 sec

//Switch on and after 4 sec switch it off
Do some control on device group

Code: Select all

//Switch off all 3 devices at the same time
_z(['dimmerBedroom', 'dimmerHall', 'wallPlug']).switchOff();
Activating scenes. Before use you must create 'Dummy Device'(binary switch) from module of 'Devices' section to control scene activation.

Code: Select all

var scene1 = function(){
  _z('rgbw R').setLevel(10); _z('rgbw G').setLevel(20); _z('rgbw B').setLevel(30);
_z('scene1 dummy switch').onSwitchOn( scene1 );
Handling events from devices

Code: Select all

//Create and send notification. You can use SMS module to send notification to your phone
_z('Motion sensor').onSwitchOn('Motion!');
_z('Motion sensor').onSwitchOff('No motion!');
_z('Flood sensor').onTrigger('Flood!');
_z('Door sensor').onBreach('Breached!');
_z('Motion sensor').onIdle('Idle!');

//or do some more spohisitcated stuff
_z('Motion sensor').onSwitchOn( function() {
  if(_z('Light sensor 1').getLevel() < 400){
Handling Alarms
Create alarm zones and recieve a notifications when breached. Before use you must create 'Dummy Device'(binary switch) from module of 'Devices' section to control arm/disarm.

Code: Select all

// Create alarm zone with device list
var alarmZone1 = ['Door senosr Entrance', 'Door senosr Backyard',  'Motion Sensor1', 'Motion Sensor2'];

// Set Arm or Disarm state with dummy switch
_z('dummy arm/disarm switch')
  .onSwitchOn( function() { _z(alarmZone1).setKey({isArmed:true}); })
  .onSwitchOff( function(){ _z(alarmZone1).setKey({isArmed:false});});
// Send just notification in case of breach (you can setup SMS module to recieve SMS on your phone)

// Or more sophisticated example with some logic
_z(alarmZone1).onBreach(function() {
  _z.notify('alert', 'Hey!!!', 'core', 'eaZyLogic');
How to install
Copy and unpack the attached file to your 'userModules' directory of Razberry.
Restart z-way server form command prompt - 'sudo /etc/init.d/z-way-server restart'

How to start use
Go to 'preferences' menu in your Home Automation UI.
Select 'modules', then 'Automation' section.
Select 'EaZyLogic' module, put title and some description, got next page and enter your code in textarea.
Example (replace 'my dimmer' with your device name from HA UI)

Code: Select all

_z('my dimmer').switchOn().delay(2).switchOff().delay(3).switchOn();
Press Finish and there you go with simple on/off scenario :)
You can then edit code for your created module in Preference->Automation menu later.

Re: [userMODULE] eaZy Logic for starters

Posted: 07 Apr 2015 10:39
by pz1
Interesting module. Not only for beginners I think, but also potentially useful for system integrators.

Re: [userMODULE] eaZy Logic for starters

Posted: 07 Apr 2015 13:56
by dolpheen
Yes, I plan it to use it for my automation scenes and also i work for system integrator company I suppose it can help to optimize installation time too.
I do it with simplicity in mind and use common automation features but also use a full power of JavaScript if needed.
So you can create not simple static scenes but some smart ones for example.

Code: Select all

// Create light group
var lightGroup = _z(['dimmer1', 'dimmer2', 'switch2']);

// Describe scene logic
var scene1 = function(){
  if(_z('Lux sensor').getLevel() < 400) _z('mainLamp').switchOn();

// Activate scene on switch press
_z('scene1 dummy switch').onSwitchOn( scene1 );

Re: [userMODULE] eaZy Logic for starters

Posted: 07 Apr 2015 15:23
by pofs
Well done.

delay() stuff seems dubious though, because it will work accurate enough only for "always on" devices. It will be a bit inaccurate for FLiRS devices, and totally useless for sleeping ones. This could be solved if using command class callbacks instead of timers, but it'd require to go from HA to lower z-wave level (and address real devices instead of HA abstractions).

Also I'd used

Code: Select all

_z('dimmerBedroom', 'dimmerHall', 'wallPlug')
syntax instead, or at least make both variants acceptable.

Re: [userMODULE] eaZy Logic for starters

Posted: 07 Apr 2015 15:54
by dolpheen
Thanks for the remark pofs.
Yes, the chain logic is far from optimal. I'm going to use 'promises' instead of direct timers between calls.
And direct access to physic devices is also needed for chain mechanism as you proposed and some algorithms.
For example, I need to check how much time has passed since binarySwitch was triggered or when device was waked-up. The only good way I see is to check 'update' fields of real device.

Re: [userMODULE] eaZy Logic for starters

Posted: 07 Apr 2015 16:14
by pofs
Using promises causes other problems to be solved here.

For example, you're referencing two different devices in your chain (one always-on and one sleeping), and use delay somewhere between commands. When should commands standing after delay fire?
When both devices processed commands before delay? It could take hours because of sleeping device, so delay for several seconds won't really matter, so the whole logic gets broken.
Process both devices as separate chains, so delay works independently for both devices? Still wicked logic (you expect commands for both devices to execute before next chain command), and still no good for sleeping device, because it could go to sleep again while waiting, and instead of several seconds delay it would take much longer until next wake-up.

Speaking of promises, I'd try to start with a Task class, which is able to track when the pair "command delivered" + "response received" is completed, so the response value can be used by the next Task in chain.
"Command delivered" can be tracked by providing a success callback to the CC function (and here you should start monitoring "response received" event).
"Response received" can be tracked by binding to CC-specific data holders and wait for callback.
After both conditions are met, you should clean up (unbind data holders) and set task as completed.

But still not clear to me whether tasks for both devices should be executed as a single chain, or separately.

Re: [userMODULE] eaZy Logic for starters

Posted: 07 Apr 2015 16:28
by dolpheen
Looks like the delay() command can be used only for acuators at the moment :) (that normally always powered or FLiRS).
We need some examples from real world of applying delay to battery device (in wich situation we need to send command to battery device?) Anyway it's a good remark to think on when dealing with sleeping devices.

Regarding 'command delivered/response' - at the moment I use only virtual devices to be more consistent with future added devices that are not z-wave or we should check the physical device type to act accordingly.
At the moment we have only 'updateTime' on vDevs, so may be it can be used for command completion as reference.

Re: [userMODULE] eaZy Logic for starters

Posted: 07 Apr 2015 18:56
by dolpheen
When I started to use the module in real wordl :) I found that selecting devices can be ambiguous.
For example we can have several devices with the same name in rooms.
I thought of different solution to this (like some special signs in names or function calls to select room), but I forgot the main rule - simplicity and we have the smart system aren't we.:)
So, I propose the next solution for device selection to operate on

Normal behaviour

Code: Select all

_z('dimmer1')      // Select all devices with 'dimmer1' name
_z(['dimmer1', 'dimmer2']) // Select  several devices with 'dimmer1' and 'dimmer2' names 
_z('dimmer1', 'dimmer2')   // The same as above but without array, as proposed by pofs 
If the name of device isn't found then the next rules apply

Code: Select all

// Switch Off all devices with name 'dimmer' and 'wallplug' in room Kitchen
_z('dimmer, wallplug in kitchen') .switchOff()

// Set all devices to level 50 (or switch on switches) with Tag='lights' in whole house
_z('all lights').setLevel(50)

// Switch On all devices with Tag='lights' in room Hall
_z('all lights in hall') .switchOn()

// Selected all devices of type switchBinary in basement
_z('all switchBinary type in basement').switchOff()

Re: [userMODULE] eaZy Logic for starters

Posted: 07 Apr 2015 20:21
by pofs
And how would your parser behave if I have device named "all lights"? :)

BTW, how will .getLevel() work for multiple devices? Will it return an array of values, or just first one (like val() in jQuery)?

Re: [userMODULE] eaZy Logic for starters

Posted: 07 Apr 2015 21:04
by dolpheen
pofs wrote:And how would your parser behave if I have device named "all lights"? :)

It will select device 'all lights' in your house (It's really 'all lights' that you want to operate on isn't it? :))
But if you select 'all lights in kitchen' then it will selects all lights in kitchen, but if you have 'all lights' device also there :) it will select device 'all lights' in kitchen.
pofs wrote:BTW, how will .getLevel() work for multiple devices? Will it return an array of values, or just first one (like val() in jQuery)?
At the moment it returns the first device level in list. I don't know how to manage multiple returns.