Premise Zwave sensors

Motorola Premise

mhilbush

Member
I picked up a couple Z-wave sensors with the thought of adding support to the Zwave driver posted on this forum.

I have three devices:
- HomeManageables HM-DW001 Door/Window Sensor (also known as Everspring SM103)
- ACT ZIR000 PIR motion Motion Sensor
- HomeManageables HM-FS001 Flood Sensor

First Question:
All three of these devices are classified as Binary Sensors, yet the device class in the "Leviton" Zwave module is called MotionDetector. I believe this class should be renamed BinarySensor. Is this agreeable? It seems logical to me, since the actual connection to a MotionDetector, WindowSensor, DoorSensor, WaterSensor, etc. happens when the Zwave device is bound to an object in the "Home".

Second Question:
The Leviton MotionDetector class (the one that I propose renaming to BinarySensor) inherits from a class called MotionDetector, but I can't seem to locate where that class is defined. Any guidance here?

I've already modified the following methods to support the discovery of the DW001 and ZIR000:
ViziaRF.OnChangeOnNewData
Devices.UpdateDevices
Devices.AddDevice

I've also added the following methods to process commands from the DW001 and ZIR000:
Devices.SetMotionDetected - detects state changes (motion on/off, contact open/closed, water detected, etc.) set from the device
Devices.SetLastNotificationTime - handles wakeup notifications sent from the device every 4 hours
Devices.SetTamperAlarm - handles tamper alarm sent from device

I've added the following properties to the MotionDetector class:
LastWakeupNotificationTime (DateTime: readonly / bindable) - gets set to the time when the wakeup notification is received
TamperAlarm (Boolean: readonly / bindable / momentary) - gets set to true when the tamper alarm is received
LastTamperAlarmTime (DateTime: readonly / bindable) - gets set to the time when the tamper alarm is received

Everything seems to be working fine. The devices are discovered correctly, and I can receive and process state changes, wakeup notifications, and tamper alarms. In a logic diagram, I wired the TamperAlarm to my email sender, and it worked great!

I haven't added support for low battery notifications yet, and I'm not sure how to test that without tracking down some old batteries and just waiting days, weeks, or months for something to happen. I've instrumented OnChangeOnNewData with debugout to log unknown events so I can see them in debugview, so I should be ok there.

Anyway, does all this make sense? I'm a Premise noob, so I need to know if I'm on the right track? If all this is agreeable, I'll add the final sensor, then post a work in progress so someone with more Premise knowledge can check my work...

Mark
 
Good to hear you are getting some use out of the Leviton module too.

It appears we are both modifying the same file, doh :) I've found that there are 10x less failed jobs if the module doesn't append an ",UP" for one at a time lighting commands. Failed jobs are important to reduce because retrying the job up to three times can delay any user commands in the mean time. This can impact the user if the jobtimeout timer is set to something high like 5 seconds; EDIT: but a high jobtimeout timer is needed since receipt of X000 may take a second or two. I've added a hardware reset that I think clears the VRC0P/RZC0P's cache (not documented very well in the programming manual) and I've added the ability to get device names individually.

code added to "reset" the VRC0P
Code:
	'tell the VRC0P to abort commands
	this.SendCommand ">AB", true
	
	'reset the VRC0P in an attempt to fix the issue	
	this.SendCommand ">DE", true

I plan to post my code in the next week (been busy installing an Elk M1G), and maybe then we can combine our work?

To answer your question, it depends on how the sensors are modeled in the VRC0P protocol and the Zensys protocol (I think there is an open zwave protocol wiki if you do a google search). I don't have any binary sensors to test, but from what you're saying, it appears that a door sensor looks the same as a motion sensor to the VRC0P (or any zwave controller) during discovery and polling; maybe we should use a generic class that inherits from the "DigitalInput" class (sys://Schema/Device/DigitalInput) which is what it sounds like you did... The DigitalInput class uses a boolean property called "State" that will automatically bind to the "DoorOpen" and "MotionDetected" properties found on door sensor and motion sensor objects.

Your findings sound similar to what I've found when using a vizia rf+ fan controller. The fan controller appears as a dimmer to the VRC0P, so I left it that way and just bound it to a fan speed controller under home. What ascii text are you sending to discover each type of device?

EDIT: Any chance you have figured out how to improve ImportDeviceName reliability? I have a 30+ node network, and I always receive some X002 errors if I let the script send the name requests and some names will fail to ever be received before reaching the 3 failed job limit. The only work around I could figure out is to have a 5 second buffer between device name requests which greatly improves reliability and always results in all names being imported...

Changes to ImportDeviceNames method:
Code:
'
' The SYS Device object name will inherit the physical Z-Wave Device name.
' SYS Device Name <--- Z-Wave Device name 

dim oDevice
dim iInterval
iInterval = 0
for each oDevice in this.GetObjectsByType(Schema.Modules.Leviton.Classes.Device.Path)
	
	'the timer is necessary to improve name import reliability; without a time buffer, many X002
	'transmission packets are received.
	system.addTimer iInterval, "on error resume next: this.Parent.SendCommand '>N' & " & oDevice.NodeID & " & '?NN', true, 995", 1, oDevice.NodeID & "_" & oDevice.ObjectID
	iInterval = iInterval + 5
next
 
I plan to post my code in the next week (been busy installing an Elk M1G), and maybe then we can combine our work?
Combining the code would be excellent!. Just let me know how you would like to do this. Most of my changes are well contained to a few areas, so I expect the merge will be straightforward.


To answer your question, it depends on how the sensors are modeled in the VRC0P protocol and the Zensys protocol (I think there is an open zwave protocol wiki if you do a google search). I don't have any binary sensors to test, but from what you're saying, it appears that a door sensor looks the same as a motion sensor to the VRC0P (or any zwave controller) during discovery and polling; maybe we should use a generic class that inherits from the "DigitalInput" class (sys://Schema/Device/DigitalInput) which is what it sounds like you did... The DigitalInput class uses a boolean property called "State" that will automatically bind to the "DoorOpen" and "MotionDetected" properties found on door sensor and motion sensor objects.
I referenced the open-zwave project on code.google.com -- just google for "zwave open source". It defines all the Zwave command types, which includes BinarySensor (DW001 Door/Window Sensor and ZIR000 Motion Sensor), AlarmSensor (FS001 Flood Sensor), MultilevelSensor, etc. What I would like to do is create a Sensor virtual base class, then have Binary Sensor and Alarm Sensor inherit from the base class. Does this make sense? The DigitalInput class is what I need Sensor to inherit from, but I cannot find it when I try to "right-click New->Relationship->InheritedClass" in expert mode. How do I make my Sensor class inherit from DigitalInput instead of MotionDetector?


Your findings sound similar to what I've found when using a vizia rf+ fan controller. The fan controller appears as a dimmer to the VRC0P, so I left it that way and just bound it to a fan speed controller under home. What ascii text are you sending to discover each type of device?
This is how I modified the discovery section of OnChangeOnNewData. Does this make sense?
Code:
							select case this.Devices.DiscoveryType
								case 16: ' Switches
									' No more Switches. Move on to discovering Dimmers.
									this.Devices.DiscoveryType = 17
									this.Devices.DiscoveryStatus = "Discovering Dimmers ..."
									debugout "Discovering Dimmers ..."
									this.SendCommand ">?FI0,17,0,1", false, 996

								case 17: ' Dimmers	
									' No more Dimmers or Switches. Move on to discovering Thermostats.
									this.Devices.DiscoveryType = 8
									this.Devices.DiscoveryStatus = "Discovering Thermostats ..."
									debugout "Discovering Thermostats ..."
									this.SendCommand ">?FI0,8,0,1", false, 996

								case 8: ' Thermostats
									' No more Thermostats. Move on to discovering Binary Sensors.
									this.Devices.DiscoveryType = 161
									this.Devices.DiscoveryStatus = "Discovering Alarm Sensors ..."
									debugout "Discovering Alarm Sensors ..."
									this.SendCommand ">?FI0,161,0,1", false, 996

								case 161: ' Alarm Sensors
									' No more Alarm Sensors. Move on to discovering Binary Sensors.
									this.Devices.DiscoveryType = 32
									this.Devices.DiscoveryStatus = "Discovering Binary Sensors ..."
									debugout "Discovering Binary Sensors ..."
									this.SendCommand ">?FI0,32,0,1", false, 996

								case 32: ' Binary Sensors
									' No more Binary Sensors. Quit and reset.
									this.Devices.DeleteOrphanDevices
									this.Devices.ImportDeviceNames
									this.Devices.ResetDiscovery

									' Poll all Devices unless Polling is already enabled
									if this.Devices.PollingInterval = 0 then 
										this.Devices.PollDevices
									end if
							end select
UpdateDevices just becomes:
Code:
if this.InDiscoveryMode = true then 
	select case this.DiscoveryType
		case 16: ' Switch
			this.AddDevice "Switch", method.NodeID
			iNodeID = method.NodeID
	
		case 17: ' Dimmer
			this.AddDevice "Dimmer", method.NodeID
			iNodeID = method.NodeID
			
		case 8: ' Thermostat
			this.AddDevice "Thermostat", method.NodeID
			iNodeID = method.NodeID
			
		case 32: ' Binary Sensor
			this.AddDevice "BinarySensor", method.NodeID
			iNodeID = method.NodeID
			
		case 161: ' Alarm Sensor
			this.AddDevice "AlarmSensor", method.NodeID
			iNodeID = method.NodeID
			
		case else: ' Unknown
			debugout "UpdateDevices(): Unknown device type: " & this.DiscoveryType & ", Node: " & method.NodeID
	end select


EDIT: Any chance you have figured out how to improve ImportDeviceName reliability? I have a 30+ node network, and I always receive some X002 errors if I let the script send the name requests and some names will fail to ever be received before reaching the 3 failed job limit. The only work around I could figure out is to have a 5 second buffer between device name requests which greatly improves reliability and always results in all names being imported...
I have not looked at this part of the code yet. From what I can see in my own installation, it doesn't appear that I'm receiving any of the device names during device discovery.
 
It sounds like you already know to enable expert mode, hold down: ctrl + shift + a.

The other secret is some items don't show up when you try to browse to them from the new -> relationship menu. The secret is that you have to manually browse to the object and enable the "virtual" property (see attached). Once virtual is enabled, you can access the object from the relationship menu. To manually browse, hold control and left click on the "type" icon found under a random object's "Properties" window. Next, use the tree to navigate to Digital Input. Remember to change the virtual property back when you are done, but I think it will automatically change back if you restart the SYS service.

EDIT: Side note on how to structure things...
The RZC0P programming guide states the following:
For the generic and specific classes refer to the Zensys device class specification. For example switch device will have ggg=16, dimmer ggg=17, thermostat ggg=8.

I think that things should follow the Zensys device class typology; i.e. one virtual class for each Zensys device type. If motion sensor has its own Zensys device class, it should be a separate device that inherits from the relevant SYS class (sys://Schema/Device/MotionDetector). If all alarm sensors use the same Zensys device class, then I would stick with the DigitInput idea to make more generic alarm device objects that will bind to specific home objects. There are many SYS device classes to think about (see attached)...

It sounds like it will take me some research on the open zwave site to determine the device classes... Unless you want to paste them here :)
 

Attachments

  • virtual.jpg
    virtual.jpg
    47.5 KB · Views: 6
  • inheritance choices.JPG
    inheritance choices.JPG
    19.9 KB · Views: 5
The other secret is some items don't show up when you try to browse to them from the new -> relationship menu. The secret is that you have to manually browse to the object and enable the "virtual" property (see attached). Once virtual is enabled, you can access the object from the relationship menu. To manually browse, hold control and left click on the "type" icon found under a random object's "Properties" window. Next, use the tree to navigate to Digital Input. Remember to change the virtual property back when you are done, but I think it will automatically change back if you restart the SYS service.
Don't you just love the secret handshakes and trapdoors in this app....


EDIT: Side note on how to structure things...
The RZC0P programming guide states the following:
For the generic and specific classes refer to the Zensys device class specification. For example switch device will have ggg=16, dimmer ggg=17, thermostat ggg=8.

I think that things should follow the Zensys device class typology; i.e. one virtual class for each Zensys device type. If motion sensor has its own Zensys device class, it should be a separate device that inherits from the relevant SYS class (sys://Schema/Device/MotionDetector). If all alarm sensors use the same Zensys device class, then I would stick with the DigitInput idea to make more generic alarm device objects that will bind to specific home objects. There are many SYS device classes to think about (see attached)...
I understand your point about one virtual class for each device type. OTOH, the BinarySensor and AlarmSensor devices seem to share many of the same characteristics, such as State Change, Wakeup Notification, Battery Level Notification, Tamper Notification, etc. I'll defer to your judgement on whether there should be a BinarySensor virtual class and an AlarmSensor virtual class, or just a single Sensor virtual class. Right now, I have a Sensor virtual class, along with a BinarySensor class and an AlarmSensor class, both of which inherit from Sensor (see attached).


It sounds like it will take me some research on the open zwave site to determine the device classes... Unless you want to paste them here :)
Here's a link to the zwave open source project document I referenced.
Open Zwave Device Classes
 

Attachments

  • Capture.JPG
    Capture.JPG
    31.2 KB · Views: 10
What you have looks very logical if there are some properties that are different; however, if both BinarySensor and AlarmSensor have the same exact properties, I would make a single sensor class. The sensor class would inherit from the DigitalInput class and have a property called "State" for sensor states. I would leave the tamper boolean since you can bind it to a "RelayDevice" under "Home" in order to trigger an alert (email, voice notification etc...) through a scriptMacro. This works because you can bind multiple home objects to a single device object luckily...

I'm curious how the motion sensors work... Do they require polling or will they instantly send a state change to the VRC0P?
 
What you have looks very logical if there are some properties that are different; however, if both BinarySensor and AlarmSensor have the same exact properties, I would make a single sensor class. The sensor class would inherit from the DigitalInput class and have a property called "State" for sensor states. I would leave the tamper boolean since you can bind it to a "RelayDevice" under "Home" in order to trigger an alert (email, voice notification etc...) through a scriptMacro. This works because you can bind multiple home objects to a single device object luckily...

I'm curious how the motion sensors work... Do they require polling or will they instantly send a state change to the VRC0P?
After inclusion in the network, the sensor must be associated with the VRCOP in order for the VRCOP to be able to receive commands from the device. All commands (including state changes) are sent asynchronously (i.e. at the time the event occurs). Polling is not required.

It appears that AlarmSensor properties are a superset of BinarySensor.

All sensors of type BinarySensor and AlarmSensor send these commands:
32 -- Basic Command to set and unset the state (i.e. motion detected, contact closure opened/closed, water detected, etc.). This command is sent asynchronously by the device when the event occurs (i.e. without being polled)
113 -- Tamper Alarm Command is sent asynchronously when the device is "disturbed" (e.g. in the case of the door/window sensor, the tamper alarm is sent when you lift the device in a way that triggers the spring loaded switch on the bottom of the device).
132 -- Wakeup Notification Command is sent asynchronously by the device typically every 4 hours (although the interval can be changed)
128 -- Battery Level/Alarm Command is sent asynchronously by some of the devices (interval is still unclear to me). A low battery alarm condition also appears to be sent when the battery level gets "low" (not sure how they define "low").

In addition to the above, the flood sensor (AlarmSensor) also sends:
156 -- Sensor Alarm Command is sent asynchronously when it detects the presence or absence of water
145 -- Manufacturer Proprietary Command is sent periodically (I haven't figured out why or what this does yet)

Based on the above, it feels like there should be a base Sensor class, from which BinarySensor and AlarmSensor both inherit. There also is a MultilevelSensor defined in the doc I included in my previous reply. That also might inherit from Sensor. Alternatively, AlarmSensor could just inherit from BinarySensor, but I think that might take away some flexibility. What do you think?

From what I've seen in just a couple days, I'm pretty impressed with how the devices work.

Would you like me to post the Leviton module with my changes/edits?
 
Having several classes that inherit from an overall sensor class makes the most sense and would be the most versatile given the number of zensys device classes; it'd also make future editions easier. As far as how to package things, I've made several changes to the way the driver handles lighting in effort to lower the number of failed jobs. I've included my "final" version in the attached zip file for you to add your code to if you choose. The attached image is a result of 25000+ jobs resulting in only 25 transmission failures (receipt X002 etc) and only 11 job failures; I think this driver is darn reliable. From my experience if an X000 is received after a command transmission the switch/dimmer will actuate.

These numbers represent a 10+ fold failure decrease from the old vizia rf xdo, so I'd like to publish this version along with your work. If you could post a similar image of failed jobs and transmission failures you're encountering that'd be great :)

To get the transmission numbers low I had to sacrifice the ",UP" that would result in an update being sent back to the controller for single switch and dimmer operations. Groups and scenes still rely on an update to change the state of the switch/dimmer in Premise after a group or scene command is sent (i.e. ",UP" is still appended to scene or group commands). I thought about coding a state change to match what is being sent to the dimmer/switch (that way the controller doesn't rely on an update being received from each switch/dimmer), but wasn't sure if it was worth the effort as I don't use scene or group commands enough and any updates do eventually come in (but can take a few seconds). This may be worth doing before we release a final version under the downloads section, what do you think?

As far as fixing your naming issue, I can't think of an elegant way to handle names. >Nxxx" should be received when a name is request is initiated, but there is no guarantee >Nxxx" will be received; thus, I don't think it's a good idea to use a flag like InNamingRequestMode. This new version uses a simple 5 second timer instead, but works very well on my 39 node vizia rf+ network.
 

Attachments

  • failure rates.JPG
    failure rates.JPG
    25.6 KB · Views: 10
  • Vizia final v8.zip
    40.1 KB · Views: 2
I added BinarySensor and AlarmSensor support to the module you posted above.

I made the following modifications. As I'm still a Premise noob, please review my changes carefully and provide any constructive feedback. <wink> Feel free to modify as necessary.

Classes Deleted
- MotionDetector class

Classes Added
- Sensor virtual class
- BinarySensor class
- AlarmSensor class

Added the following methods to the Devices class
- SetSensorState
- SetLastWakeupNotificationTime
- SetTamperAlarm
- SetSensorAlarm
- SetBatteryLevel

Modified the following methods
- Devices.UpdateDevices
- Devices.AddDevice
- ViziaRF.OnChangeOnNewData

I've not had a chance to look at the naming process, and I may not be able to get to that for about a week or so.

Best regards,
Mark
 

Attachments

  • Vizia final v9.zip
    41.1 KB · Views: 7
I had chance to take a look at your code; nice work!

Here's three notes I have:
1. The SetTamperAlarm only has one parameter, nodeID, but you pass two parameters from OnChangeOnNewData.
2. The default value property defines the defualt value for a device when it's constructed. You don't need the class constructor methods for each device type...
3. For cleanliness, I should have put the boolean PowerStateChanging and BrightnessChanging under Switch and Dimmer respectively not under the Device class. Sorry about that. I promise to remember to move them once we are done. ;)

Pretty nice editions to the driver. Thanks :)
 

Attachments

  • default value.jpg
    default value.jpg
    31.7 KB · Views: 2
1. The SetTamperAlarm only has one parameter, nodeID, but you pass two parameters from OnChangeOnNewData.
I'll take another look at what the tamper alarm command includes, then decide what to do about this.


2. The default value property defines the defualt value for a device when it's constructed. You don't need the class constructor methods for each device type...
If that's the case, then the constructors can be deleted.


3. For cleanliness, I should have put the boolean PowerStateChanging and BrightnessChanging under Switch and Dimmer respectively not under the Device class. Sorry about that. I promise to remember to move them once we are done. ;)
Makes sense.


Unfortunately, I won't be able to look #1 for about a week or so.

Going forward, how would like to handle the edits to the module in order to avoid complicated code merges?
 
One other thing I'm wondering about... Since these sensor devices send a Wakeup Notification event every 4 hours, there is an opportunity to detect if a device has stopped sending Wakeup Notifications, possibly due to a dead battery (not all devices appear to send battery level events) or some other reason.

The Sensor class has a property for tracking the last Wakeup Notification time; however, it's not clear to me how I would detect the absence of a Wakeup Notification event. By any chance, does the module have the ability to periodically (every 30 or 60 minutes, for example) iterate through the list of sensor devices looking for Wakeup Notifications that have not occurred? If detected, it could set a property that could be used to alert the user. Normally, this would be done by a watchdog thread, but I don't know if Premise supports such a thing inside a module.
 
Good idea! The only way I know to do this using a module is to use timers, but as an FYI there are probably a lot better ways to do such a thing if you use .net or c++ along with the Premise SDK (and not event based vbscript).

Since all modules execute in the same thread, what you could do is have a timer that is added when the date changes (to be conservative maybe we should use an 9 hour timer?). Since the date will be set every four hours, the timer we add will never execute. If the timer does execute, it will execute code to set an "Event" to alert the user by calling a method called something like WakeUpNotificationNotReceived or ChangeBatteries. I think I did something similar in this module to monitor battery status of X10 motion and door sensors: http://www.cocoontech.com/forums/index.php?app=downloads&showfile=159
 
Mark, I know you probably haven't had time to play with the module this week, but I'd noticed a bug in how I'm handeling lights.

It turns out if you change from the default fade rate of a dimmer (by holding the paddle down and the left button at the same time), the module will not honor the new fade rate, doh! FadeRate is a feature of Leviton Vizia RF and RF+ dimmers, not sure if it applies to your dimmers or not. FadeRate not only defines how long a light takes to turn off, but there is also a FadeRate for turning on a lamp. Fade rates are set locally at the dimmer, except for scenes which can use fade rates set by Premise.

I've found there's a small bug in Leviton's protocol or firmware. If you turn on a light by sending a level command, (i.e. N23L50), the node will always use the default factory fade rate!?! If you send a power on command, the light will come on with the correct fade rate. Not a big change, so I can make it once your done testing the sensor classes. I don't think there's a work around; if you initiate a brightness change to turn on a light that Premise thinks is Off, NxxxOn must be sent before NxxxLxx in order to honor the fade rate set by the user.
 
Back
Top