Premise Zwave sensors

Motorola Premise
Nice work Mark. I'll have to finish looking everything over this week.

Everything I'm using still functions as expected. Since I was testing things again, I noticed one case my code under sys://Schema/Modules/Leviton/Classes/Switch/OnChangePowerState wasn't handling correctly: when a user dims to 0 brightness, then turns a lamp back on, NxxxON was being sent instead of NxxxLxx (which is needed for the brightness in Premise to match that of the light since a dimmer will default to minimum brightness defined within the dimmer itself).

Code is below, but I'm also attaching a txt file with the code for you to paste into your version since I think the tabs will be messed up otherwise. The flow is getting a little confusing, but vbscript doesn't have a support go to statements :(

EDIT: I cleaned up the code a little more.

Code:
'
dim sCmd, iLevel

if this.ReceivingUpdate = false then
	'debugout "SourceElementName: " & sysevent.srcElement.Name & ", SourcePropertyName: " & sysevent.srcProperty.name

	' Handle dimmer type
	' Ignore requests from Brightness changes because OnChangeBrightness will handle 
	' the task of turning a dimmer on or off.
	if this.IsOfExplicitType("sys://Schema/Modules/Leviton/Classes/Dimmer") then
		this.PowerStateChanging = true
		' Use brightness changing flag to avoid using sysevent.srcproperty since "trigger" is src property for macros
		if this.BrightnessChanging = false then
			iLevel = round(this.Brightness * 100)
			sCmd = ">N" & this.NodeID
			
			' Handle special case of iLevel = 0 by defaulting brightness to 99%
			if sysevent.newVal then
				if iLevel = 0 then
					' Transfer control to brightness
					this.PowerStateChanging = false			
					this.Brightness = 1
				end if
			end if
			
			' Handle special case of iLevel = 100
			if iLevel = 100 then 
				this.Brightness = 1
			end if
			
			' If control wasn't transferred to brightness, send the powerstate command 
			if this.PowerStateChanging <> false  then
				if this.PowerState = true then
					this.Parent.Parent.SendCommand sCmd & "ON", true, this.NodeID ' High-priority
				else
					this.Parent.Parent.SendCommand sCmd & "OF", true, this.NodeID ' High-priority
				end if
			end if
		end if
		this.PowerStateChanging = false
	else
		' Handle switch type
		sCmd = ">N" & this.NodeID
		
		if this.PowerState = true then
			sCmd = sCmd & "ON"
		else
			sCmd = sCmd & "OF"
		end if
		this.Parent.Parent.SendCommand sCmd, true, this.NodeID ' High-priority
	end if
end if
 

Attachments

  • Leviton.Classes.Switch.OnChangePowerState v2.txt
    1.7 KB · Views: 6
Code is below, but I'm also attaching a txt file with the code for you to paste into your version since I think the tabs will be messed up otherwise. The flow is getting a little confusing, but vbscript doesn't have a support go to statements :(
This change is integrated into next rev.
 

Attachments

  • Vizia final v12.zip
    54.5 KB · Views: 5
Thanks Mark. I plan to study your code in more depth this weekend.
While you're at it, can you take a look at this piece of code in OnChangeOnNewData:
Code:
			case 5: ' Network Reconfiguration (<!)
				sMsg = "Network Reconfiguration: " & aParms(0)
				this.Devices.DiscoverDevices = true
When I do an Update Controller on my VRCOP, my VRCOP first responds with a MANUFACTURER_PROPRIETARY command class, then a <!016, then a <!000. Sometimes it responds with two <!016. I'm not too concerned with the MANUFACTURER_PROPRIETARY command for now. However, the <!016 kicks off the device discovery process, which in my case yields no results (perhaps because the VRCOP is still in the middle of receiving its update from my primary controller?). At the conclusion of this device discovery process, DeleteOrphanDevices is called, which deletes all the existing devices.

At the conclusion of the VRCOP update, the VRCOP issues a <!000, which kicks off yet another device discovery. This time, all the devices are properly discovered and created again.

This behavior does not seem right. Of course, I can't find any reference to this <!016 <!000 behavior in any of the VRCOP docs. Could it be that the <!016 responses should be ignored until a <!000 is received, at which point the discovery process would be kicked off? Could it be that commands to the VRCOP should be suspended completely during the period between the <!016 and <!000?

The code to ignore all but the <!000 would then look something like this:
Code:
			case 5: ' Network Reconfiguration (<!)
				sMsg = "Network Reconfiguration: " & aParms(0)
				'Do nothing with <!016; only kick off rediscovery on <!000
				if aParms(0) = 0 then
					this.Devices.DiscoverDevices = true
				end if

Let me know what you think. I made the above change to my version, and it appears to fix my problem for now. However, I'm not as familiar with the discovery code as you.
 
I'll have to test things when I get home.

I think I had the same issue you're describing last year, but I unchecked "Enable Auto-Discovery" and the module quit deleting my devices when I updated the controller. I never got around to researching the issue like you and forgot about it to be honest...

What you are saying makes sense; wait for <!0016 then <!0000. However, I would still add a 60 second timer just to be safe. The timer is kind of sloppy, so up to you if you use it. It shouldn't be needed if the documentation is accurate and the response is exactly as documented.

I would also ensure that the "Enable Auto-Discovery" boolean check still in the code and that "Enable Auto-Discovery" (or whatever it's called) is set to false for the default value.
 
What you are saying makes sense; wait for <!0016 then <!0000. However, I would still add a 60 second timer just to be safe. The timer is kind of sloppy, so up to you if you use it. It shouldn't be needed if the documentation is accurate and the response is exactly as documented.
I'll see how it works without the timer. I'll also look more closely at the exact timing of the events to see if there is a race condition that would justify a timer.

I would also ensure that the "Enable Auto-Discovery" boolean check still in the code and that "Enable Auto-Discovery" (or whatever it's called) is set to false for the default value.
EnableAutoDiscovery was set to false in my case.

It looks like the FoundNode processing in OnChangeOnNewData is wrapped with a check of EnableAutoDiscover and InDiscoveryMode. If EnableAutoDiscovery is false (and your not in DiscoveryMode), the FoundNode response will not be processed. However, it also appears that when you set DiscoverDevices to true in OnChangeOnNewData for a network reconfig, InDiscoveryMode gets set to true. By virtue of this, the FoundNode processing will execute no matter what the value of EnableAutoDiscovery is.

I'm not sure if this is what was intended.
 
This makes sense, but I'll have to look at the code when I get home.

The idea is that setting DiscoverDevices to true will always result in device discovery no matter what EnableAutoDiscovery is set to. This was 123's intent (I think). Further, EnableAutoDiscovery should prevent discovery following an update of the VRC0P from the primary controller.

PS: Did you check out the radioshack sale yet? I went to a couple radioshacks this weekend and they all had zwave stuff at 75% off. Most GE stuff is $9-$10.
 
Here's the version with completely reworked sensor functionality, as described in the other post. It's not final by any measure, but it has been very stable for me the last couple days. The ability to bind with Home objects now works like a charm!

I added a few things to the Device class -- variables to hold response from MANUFACTURER_SPECIFIC and VERSION command classes, as those apply to any device.

I also added a function to make it easier to turn on/off debugging output.

This version also include the logic to handle the <!016 and <!000 network reconfiguration behavior I described previously.

Finally, I believe the naming issue is a problem with the HSM100, not the module.

The module now supports the following sensors. Adding support for other sensors should now be very straightforward.
HSM100 - motion, temp, light
FS-001 - water
TS-001 - temp, humidity
DW-001 - door/window (or whatever you want to hook up to it)
ZIR000 - motion

I was going to add support for the CA9000 PIR, but I've not be able to find any documentation; and, from what I've read it seems that the CA9000 doesn't work well in an non-Intermatic network.
 

Attachments

  • Vizia final v13.zip
    62.1 KB · Views: 8
About once every few weeks, it appears your previous version gives this error. I can't figure out why this method is ever executing since I have no sensors installed, any ideas?!? SYS recovers and continues working, but the an event is logged below.

sys://Schema/Modules/Leviton/Classes/Devices/ProcessCmd_SensorMultilevel

A script error occured while system deployed.
SYS Server is requesting script engine to continue.
The details of the error are as follows

LineNumber = 14
Description = Subscript out of range: '[number: 4]'
SourceElement = sys://Schema/Modules/Leviton/Classes/Devices/ProcessCmd_SensorMultilevel

Your current version caused an error at the last line below.

sys://Schema/Modules/Leviton/Classes/Devices/ProcessCmd_Configuration

Code:
iParms = method.numparms
aParms = gViziaArgsUnpack( method.parms, method.numparms )

dim oDevice
set oDevice = this.GetDeviceByNodeID( aParms(0) )
if not oDevice is nothing then
	oDevice.receivingUpdate = true
	if aParms(2) = 6 then  'Report
		'If the sensor device has a reference to an object, and the object is of type Model,
		' then process the model-specific command from the device
		if Not oDevice.DeviceModelDetails is Nothing then

I think the issue is that oDevice.DeviceModelDetails will cause an error if the property DeviceModelDetails does not exist. For some reason, one of my thermostats triggered ProcessCmd_Configuration. Since thermostats do not inherit from BatteryDevice (sole class where DeviceModelDetails exists), an error occurs.

The solution for both of these issue may be simple. The methods could check for specific object types before any code is executed. Premise gives several ways to test an object such as the GetSuperClasses method (iterate through each inherited object, looking for one named "BatteryDevice"). Similarly, you could use IsOfExplicitType to fix the ProcessCmd_SensorMultilevel issue. I don't know why any of this is necessary other than my thermostats maybe giving a strange class type periodically? I couldn't catch them doing this in port spy, but I'll run debugview until the next error. However, since you can never be certain what z-wave class type a device may give to the VRC0P when polled, it may be a good idea to do checks such as these anyways...
 
As an example, here's the change I'm proposing for ProcessCmd_Configuration. On error resume next is necessary since if not oDevice is nothing then will throw an error if oDevice is null. This is due to the fact that vbscript offers no way to test whether an object exists or not!?!

Code:
iParms = method.numparms
aParms = gViziaArgsUnpack( method.parms, method.numparms )

dim oDevice, oSuperClass, bTest
set oDevice = this.GetDeviceByNodeID( aParms(0) )

bTest = false
on error resume next
if not oDevice is nothing then
	for each oSuperClass In oDevice.GetSuperClasses()
		if oSuperClass.Name = "BatteryDevice" then bTest = true
	next
end if

if bTest then
	oDevice.receivingUpdate = true
	if aParms(2) = 6 then  'Report
		'If the sensor device has a reference to an object, and the object is of type Model,
		' then process the model-specific command from the device
		if Not oDevice.DeviceModelDetails is Nothing then
			if odevice.DeviceModelDetails.IsOfExplicitType(Schema.Modules.Leviton.Classes.Model.Path) then
				parameterNumber = aParms(3)
				'Number of bytes are contained in bits 0-2
				numBytes = aParms(4) And 3
				select case numBytes
					case 1:
						parameterValue = aParms(5)
					case 2:
						parameterValue = (aParms(5)*256) + aParms(6)
					case 3:
						parameterValue = (aParms(5)*65536) + (aParms(6)*256) + aParms(7)
					case 4:
						parameterValue = (aParms(5)*16777216) + (aParms(6)*65536) + (aParms(7)*265) + aParms(8)
				end select
				if gViziaIsDebugOn(2) then debugout "ProcessCmd_Configuration(): parameterNumber=" & parameterNumber & ", parameterValue=" & parameterValue
				oDevice.DeviceModelDetails.ProcessConfigurationCommand parameterNumber, parameterValue
			end if
		end if
	end if
	oDevice.receivingUpdate = false
	set oDevice = nothing
end if
 
Thanks for catching this problem. Would it not be sufficient to wrap the code in question with oDevice.IsOfExplicitType(), such as this?

Code:
iParms = method.numparms
aParms = gViziaArgsUnpack( method.parms, method.numparms )

dim oDevice
set oDevice = this.GetDeviceByNodeID( aParms(0) )
if not oDevice is nothing then
	oDevice.receivingUpdate = true
	if oDevice.IsOfExplicitType(Schema.Modules.Leviton.Classes.BatteryDevice.Path) = true then
		...Do Stuff...
	end if
	oDevice.receivingUpdate = false
	set oDevice = nothing
end if
I believe this approach would fix both problems temporarily (see attached new version).
View attachment Vizia final v14.zip

Looking down the road a bit, we might want to be able to use Premise to set/get configuration parameters for non-battery powered devices. To do this we would move the model functionality from BatteryDevice to Device. If the device model can be determined at discovery time, then you would have the ability to tweak the config parameters from Premise. At device discovery time, we would need to issue the MANUFACTURER_SPECIFIC request in a way similar to how Node Names are requested. If/when we make this change, it would be a simple matter of removing the IsOfExplicitType check.

I would like to understand why your thermostat sends the unsolicited CONFIGURATION command class. If you can capture the rxTextLine associated with that command, I can see what's going on.

Similarly, it appears that thermostats emit the SENSOR_MULTILEVEL (and possibly even MULTI_INSTANCE) command class to inform of the temperature. Right now, OnChangeOnNewData has some special case logic under case 49: 'SENSOR_MULTILEVEL to account for this. Again, thinking a bit more long term, the Thermostat device is essentially a temperature sensor along with it's other HVAC functionality. It might make sense for Thermostat to contain a SensorType_Temperature child object. This would entail a fair bit of work, since we would need to:
- move the "model" functionality to the Device class (as described above)
- create classes for the thermostat models we want to support
- at discovery time, detect the thermostat model using the MANUFACTURER_SPECIFIC command class, then create the proper Model and SensorType child classes
- potentially other refactoring of Device, BatteryDevice, and Wakeup classes
- as an added benefit, if thermostats have config parameters, we'd also be able to use Premise to set/get those parameters

Of course, this also will break any existing Home objects that are bound to Thermostat.Temperature.

In the meantime, as with the CONFIGURATION command class, I'd like to take a look at the rxTextLine associated with the unhandled SENSOR_MULTILEVEL command that your thermostat is emitting (assuming you are able to capture it).
 
You're pretty good at programming, so please comment if my thinking is wrong as I'm still new at programming...

...
Nevermind what I said about "if not oDevice is nothing then." I think it should work provided you always call a method such as GetDeviceByNodeID that will return an object equal to nothing if no devices are found. You're code always seems to call GetDeviceByNodeID first so it's ok :)

However, I learned the hard way that if you try to see if a property or object exists in vbscript with similar code, you will throw an error since vbscript does not allow for testing if an object exists or not. "if not oDevice.SomeProp is nothing then" will cause an error if SomeProp does not exist. Checking that an object is a specific type or inherits from a specific class with the pro,,perty seems like a good strategy in these situations.
...

The problem with my thermostats seems random and this confuses me. I'll have to save many days of polling data to catch the issue and will post what's causing the issue then. IsOfExplicitType should work too as the help file says: "Determines if the object derives from a specific class." Do IsOfExplicitType check all superclasses, or just certain types? Since the method has "Type" in the name, I was thinking it only checked a device objects "Type" property, but it appears I am wrong?
 
I've started debugview and added a debugout statement to the top of the two methods in question so we'll know what and how they're interacting with the thermostats (I left your other debugout statements since mine are temporary). I'm going to let this run several days and will send you the output. Thanks for all of your work on this. The VRC0P module is truly versatile in the realm of sensors due to your additions.
 
You're pretty good at programming, so please comment if my thinking is wrong as I'm still new at programming...
I gave up writing code for a living a long time ago when I realized there were people a lot better at it than me. <_< These days, I know just enough to be dangerous. :lol:


You're code always seems to call GetDeviceByNodeID first so it's ok :)
Well, at least I'm consistent. B)


However, I learned the hard way that if you try to see if a property or object exists in vbscript with similar code, you will throw an error since vbscript does not allow for testing if an object exists or not. "if not oDevice.SomeProp is nothing then" will cause an error if SomeProp does not exist. Checking that an object is a specific type or inherits from a specific class with the pro,,perty seems like a good strategy in these situations.
I've seen this approach used all over the code I've looked at so far -- seems like a good, safe practice.


The problem with my thermostats seems random and this confuses me. I'll have to save many days of polling data to catch the issue and will post what's causing the issue then.
It will be interesting to see what's going on. I bet once you figure it out, it won't seem so random and intermittent.


IsOfExplicitType should work too as the help file says: "Determines if the object derives from a specific class." Do IsOfExplicitType check all superclasses, or just certain types? Since the method has "Type" in the name, I was thinking it only checked a device objects "Type" property, but it appears I am wrong?
I'm still learning the API myself, but it looks like IsOfExplicitType returns true for an object of that specific class, as well as any object whose class inherits from that class.

So, for example, if I use IsOfExplicitType(Scheme.Modules.Leviton.Classes.SensorType.Path), it appears to return true for an object of class SensorType, as well as any object of a class that inherits from SensorType (i.e. SensorType_Binary, SensorType_Alarm, SensorType_Temperature, SensorType_Light, SensorType_Humidity, etc.).

So, this snippet of code should iterate through all child objects whose class inherits from Scheme.Modules.Leviton.Classes.SensorType. In this case, it becomes a very handy way to determine the types of sensors supported by a specific device.

Code:
for each oChild in this.GetChildren(2)
    if oChild.IsOfExplicitType(Scheme.Modules.Leviton.Classes.SensorType.Path) = true then
	...Do Something...
    end if
next
 
Here's one of issues with the thermostat: Mode was being handled as a configuration code. Toggling through the cooling modes gives the output below. What is interesting is going from HOLD->RUN gives a different RUN code than going from ESM->RUN!?! At any rate, this explains the issue with v13 as far as the process configuration error I was getting. You may want to add some code to ProcessCmd_Configuration to handle thermostat states for: HOLD, RUN and Energy Saving Mode.

I'm still waiting for the multilevel sensor error. I lost my log as I didn't have a log file location set in debugview, doh!

PS: if you don't yet have a z-wave thermostat, call a few radioshack's and find one with the trane/schlage thermostat in stock. It's on clearance for $74.99 or less. Great deal if you can find one as they're well made and pretty versatile. These thermostats give two way feedback if someone manually changes them and I think are built by the same folks who make the $300 RCS thermostats.

HOLD:
00000000 0.00000000 [1844] OnChangeOnNewData(): <3/27/2011 1:42:53 PM> rxtextline=<N003:112,006,132,001,000
00000001 0.00203924 [1844] OnChangeOnNewData(): <3/27/2011 1:42:53 PM> Process CONFIGURATION command from node=3, rxText=<N003:112,006,132,001,000
00000002 0.00432400 [1844] BEGINNING ProcessCmd_Configuration(): parameterNumber=, parameterValue=

RUN:
00000003 9.08378696 [1844] OnChangeOnNewData(): <3/27/2011 1:43:02 PM> rxtextline=<N003:112,006,132,001,001
00000004 9.08558083 [1844] OnChangeOnNewData(): <3/27/2011 1:43:02 PM> Process CONFIGURATION command from node=3, rxText=<N003:112,006,132,001,001
00000005 9.08787918 [1844] BEGINNING ProcessCmd_Configuration(): parameterNumber=, parameterValue=

Energy Saving Mode:
00000006 22.24174690 [1844] OnChangeOnNewData(): <3/27/2011 1:43:16 PM> rxtextline=<N003:112,006,025,001,002
00000007 22.24316788 [1844] OnChangeOnNewData(): <3/27/2011 1:43:16 PM> Process CONFIGURATION command from node=3, rxText=<N003:112,006,025,001,002
00000008 22.24545860 [1844] BEGINNING ProcessCmd_Configuration(): parameterNumber=, parameterValue=


00000009 22.30141068 [1844] OnChangeOnNewData(): <3/27/2011 1:43:16 PM> rxtextline=<N003:067,003,001,009,065
00000010 22.34259987 [1844] OnChangeOnNewData(): <3/27/2011 1:43:16 PM> rxtextline=<N003:067,003,002,009,080

RUN:
00000011 34.27228165 [1844] OnChangeOnNewData(): <3/27/2011 1:43:28 PM> rxtextline=<N003:112,006,025,001,000
00000012 34.27399826 [1844] OnChangeOnNewData(): <3/27/2011 1:43:28 PM> Process CONFIGURATION command from node=3, rxText=<N003:112,006,025,001,000
00000013 34.27624512 [1844] BEGINNING ProcessCmd_Configuration(): parameterNumber=, parameterValue=


00000014 34.38577271 [1844] OnChangeOnNewData(): <3/27/2011 1:43:28 PM> rxtextline=<N003:067,003,001,009,064
00000015 34.42645645 [1844] OnChangeOnNewData(): <3/27/2011 1:43:28 PM> rxtextline=<N003:067,003,002,009,068


PS: Here's some fan data we should explore adding. The original module built by 123 was designed with the Wayne Dalton thermostat in mind and the WD did not offer fan setting status over z-wave. To figure out whether the fan is actually running or not, we would need logic that combines the Fan ON or AUTO setting and whether HeatingStatus is heating, cooling or off.

Set to FAN ON:
[1844] OnChangeOnNewData(): <3/27/2011 2:22:29 PM> rxtextline=<N003:069,003,001
[1844] OnChangeOnNewData(): <3/27/2011 2:22:29 PM> Unknown Node General command: from node=3, rxText=<N003:069,003,001
[1844] OnChangeOnNewData(): <3/27/2011 2:22:29 PM> rxtextline=<N003:068,003,001

Set to FAN AUTO:
[1844] OnChangeOnNewData(): <3/27/2011 2:23:28 PM> rxtextline=<N003:069,003,000
[1844] OnChangeOnNewData(): <3/27/2011 2:23:28 PM> Unknown Node General command: from node=3, rxText=<N003:069,003,000
[1844] OnChangeOnNewData(): <3/27/2011 2:23:29 PM> rxtextline=<N003:068,003,000
 
Back
Top