Super basic Z-Wave parameter tool

No paired non-secure as recommended

Ok, I give up. :smile:

1 Like

Read a couple of posts here, maybe @srwhite can help you.

When pairing the G5 you need to press the inclusion button 3 times. If you do not, it will pair securely. If the OP can post a screenshot of the device details we can start look at that.

I would also suggest looking in the live logs errors too. I didn’t have to do this on mine wth 1.31, but its possible 1.35 needs to have encapsulation disabled in order to communicate with the hub.

Definitely not secure paired.

Yes, I did have errors, had to disable the encapsulation which did work using the z-wave parameter tool.

Device Details

Create Time 2019-02-06 11:16:13 PM AKST
Last Update Time 2019-02-07 10:29:53 AM AKST
Last Activity At 2019-02-07 2:59:18 PM AKST
Data * deviceType: 258
  • inClusters: 0x5E,0x86,0x72,0x32,0x56,0x60,0x8E,0x70,0x59,0x85,0x7A,0x73,0x98
  • outClusters: 0x5A
  • deviceId: 95
  • manufacturer: 134|

This a stripped down, modified HEM driver that I am using. It spits out an error now and then which I have not taken the time to track down. This should get your HEM reporting wattage at least.

/**
 *  Aeon HEMv2+
 *
 *  Copyright 2014 Barry A. Burke, modified for Hubitat by Steve W.
 *
 *  Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
 *  in compliance with the License. You may obtain a copy of the License at:
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
 *  on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
 *  for the specific language governing permissions and limitations under the License.
 *
 *
 *  Aeon Home Energy Meter v2 (US)
 *
 *  Author: Barry A. Burke
 *  Contributors: Brock Haymond: UI updates
 *
 *  Genesys: Based off of Aeon Smart Meter Code sample provided by SmartThings (2013-05-30). Built on US model
 *			 may also work on international versions (currently reports total values only)
 *
 * 				- 
 */
metadata {
	// Automatically generated. Make future change here.
	definition (
		name: 		"Aeon HEMv2+", 
		namespace: 	"Green Living",
		category: 	"Green Living",
		author: 	"Barry A. Burke"
	) 
	{
    	capability "Energy Meter"
		capability "Power Meter"
		capability "Configuration"
		capability "Sensor"
        capability "Refresh"
        capability "Polling"
        
        attribute "volts", "string"
        attribute "voltage", "string"		// We'll deliver both, since the correct one is not defined anywhere
        attribute "amps", "string"

		attribute "lastPoll", "string"


		command "reset"
        command "configure"
        command "refresh"
        command "poll"
        command "toggleDisplay"
        command "disableReporting"

        
// v1		fingerprint deviceId: "0x2101", inClusters: " 0x70,0x31,0x72,0x86,0x32,0x80,0x85,0x60"

		fingerprint deviceId: "0x3101", inClusters: "0x70,0x32,0x60,0x85,0x56,0x72,0x86"
	}

    preferences {
		section {
			image(name: 'educationalcontent', multiple: true, images: [
				"http://cdn.device-gse.smartthings.com/Outlet/US/OutletUS1.jpg",
				"http://cdn.device-gse.smartthings.com/Outlet/US/OutletUS2.jpg"
				])
		}
    	section {
    	input "kWhCost", "string", title: "\$/kWh (0.16)", description: "0.16", defaultValue: "0.16" as String
    	input "kWhDelay", "number", title: "kWh report seconds (60)", /* description: "120", */ defaultValue: 120
    	input "detailDelay", "number", title: "Detail report seconds (30)", /* description: "30", */ defaultValue: 30
        }
    }
}

def installed() {
	state.display = 1
	reset()						// The order here is important
	configure()					// Since reports can start coming in even before we finish configure()
	refresh()
}

def updated() {
	log.info "Updated"
	configure()
	resetDisplay()
	refresh()
}

def parse(String description) {
//	log.debug "Parse received ${description}"
	def result = null
	def cmd = zwave.parse(description, [0x31: 1, 0x32: 1, 0x60: 3])
	if (cmd) {
		result = createEvent(zwaveEvent(cmd))
	}
	if (result) { 
		log.debug "Parse returned ${result?.descriptionText}"
		return result
	} else {
	}
}

def zwaveEvent(hubitat.zwave.commands.meterv1.MeterReport cmd) {
    def dispValue
    def newValue
    def formattedValue
    def MAX_AMPS = 220
    def MAX_WATTS = 24000
    
	def timeString = new Date().format("h:mm a", location.timeZone)
    
    if (cmd.meterType == 33) {
		if (cmd.scale == 0) {
        	newValue = Math.round(cmd.scaledMeterValue * 100) / 100
        	if (newValue != state.energyValue) {
        		dispValue = String.format("%5.2f", newValue)

                state.energyValue = newValue
                BigDecimal costDecimal = newValue * ( kWhCost as BigDecimal )
                def costDisplay = String.format("%5.2f",costDecimal)
                state.costDisp = "Cost\n\$"+costDisplay
                [name: "energy", value: newValue, unit: "kWh", descriptionText: "Total Energy: ${formattedValue} kWh"]
            }
		} 
		else if (cmd.scale == 1) {
            newValue = Math.round( cmd.scaledMeterValue * 100) / 100
            if (newValue != state.energyValue) {
            	formattedValue = String.format("%5.2f", newValue)
    			dispValue = "${formattedValue}\nkVAh"
                state.energyValue = newValue
				[name: "energy", value: newValue, unit: "kVAh", descriptionText: "Total Energy: ${formattedValue} kVAh"]
            }
		}
		else if (cmd.scale==2) {				
        	newValue = Math.round(cmd.scaledMeterValue)		// really not worth the hassle to show decimals for Watts
            if (newValue > MAX_WATTS) { return }				// Ignore ridiculous values (a 200Amp supply @ 120volts is roughly 24000 watts)
        	if (newValue != state.powerValue) {
    			dispValue = newValue

                state.powerValue = newValue
                [name: "power", value: newValue, unit: "W", descriptionText: "Total Power: ${newValue} Watts"]
            }
		}
 	}
    else if (cmd.meterType == 161) {
    	if (cmd.scale == 0) {
        	newValue = Math.round( cmd.scaledMeterValue * 100) / 100
        	if (newValue != state.voltsValue) {
        		formattedValue = String.format("%5.2f", newValue)
    			dispValue = "${formattedValue}\nVolts"

                if (newValue < state.voltsLow) {
                	dispValue = formattedValue+"\n"+timeString                	
                    state.voltsLow = newValue
                    state.voltsLowDisp = dispValue
                }
                if (newValue > state.voltsHigh) {
                    dispValue = formattedValue+"\n"+timeString
                    state.voltsHigh = newValue
                    state.voltsHighDisp = dispValue
                } 
                state.voltsValue = newValue
                sendEvent( name: "voltage", value: newValue, unit: "V", descriptionText: "Total Voltage: ${formattedValue} Volts")
				[name: "volts", value: newValue, unit: "V", descriptionText: "Total Volts: ${formattedValue} Volts"]
            }
        }
        else if (cmd.scale==1) {
        	newValue = Math.round( cmd.scaledMeterValue * 100) / 100
            if ( newValue > MAX_AMPS) { return }								// Ignore silly values for 200Amp service
        	if (newValue != state.ampsValue) {
        		formattedValue = String.format("%5.2f", newValue)
    			dispValue = "${formattedValue}\nAmps"
                
                if (newValue < state.ampsLow) {
                	dispValue = formattedValue+"\n"+timeString
                    state.ampsLow = newValue
                    state.ampsLowDisp = dispValue
                }
                if (newValue > state.ampsHigh) {
                	dispValue = formattedValue+"\n"+timeString
                    state.ampsHigh = newValue
                    state.ampsHighDisp = dispValue
                }                
                state.ampsValue = newValue
				[name: "amps", value: newValue, unit: "A", descriptionText: "Total Current: ${formattedValue} Amps"]
            }
        }
    }           
}

def zwaveEvent(hubitat.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) {
	def dispValue
	def newValue
	def formattedValue
    def MAX_AMPS = 220
    def MAX_WATTS = 24000

   	if (cmd.commandClass == 50) {    
   		def encapsulatedCommand = cmd.encapsulatedCommand([0x30: 1, 0x31: 1]) // can specify command class versions here like in zwave.parse
		if (encapsulatedCommand) {
			if (cmd.sourceEndPoint == 1) {
				if (encapsulatedCommand.scale == 2 ) {

					newValue = Math.round(encapsulatedCommand.scaledMeterValue)
                    if (newValue > MAX_WATTS ) { return }
					formattedValue = newValue as String
					dispValue = newValue as String
					if (dispValue != state.powerL1Disp) {
						state.powerL1Disp = dispValue
					}
				} 
				else if (encapsulatedCommand.scale == 0 ){
					newValue = Math.round(encapsulatedCommand.scaledMeterValue * 100) / 100
					formattedValue = String.format("%5.2f", newValue)
					dispValue = "${formattedValue}\nkWh"
					if (dispValue != state.energyL1Disp) {
						state.energyL1Disp = dispValue
					}
				}
				else if (encapsulatedCommand.scale == 1 ){
					newValue = Math.round(encapsulatedCommand.scaledMeterValue * 100) / 100
					formattedValue = String.format("%5.2f", newValue)
					dispValue = "${formattedValue}\nkVAh"
					if (dispValue != state.energyL1Disp) {
						state.energyL1Disp = dispValue
					}
				}
				else if (encapsulatedCommand.scale == 5 ) {
					newValue = Math.round(encapsulatedCommand.scaledMeterValue * 100) / 100
                    if (newValue > MAX_AMPS) { return }
					formattedValue = String.format("%5.2f", newValue)
					dispValue = "${formattedValue}\nAmps"
					if (dispValue != state.ampsL1Disp) {
						state.ampsL1Disp = dispValuee {
						}
					}
               	}               	
			} 
			else if (cmd.sourceEndPoint == 2) {
				if (encapsulatedCommand.scale == 2 ){
					newValue = Math.round(encapsulatedCommand.scaledMeterValue)
                    if (newValue > MAX_WATTS ) { return }
					formattedValue = newValue as String
					dispValue = newValue as String
					if (dispValue != state.powerL2Disp) {
						state.powerL2Disp = dispValue
					}
				} 
				else if (encapsulatedCommand.scale == 0 ){
					newValue = Math.round(encapsulatedCommand.scaledMeterValue * 100) / 100
					formattedValue = String.format("%5.2f", newValue)
					dispValue = "${formattedValue}\nkWh"
					if (dispValue != state.energyL2Disp) {
						state.energyL2Disp = dispValue
					}
				} 
				else if (encapsulatedCommand.scale == 1 ){
					newValue = Math.round(encapsulatedCommand.scaledMeterValue * 100) / 100
					formattedValue = String.format("%5.2f", newValue)
					dispValue = "${formattedValue}\nkVAh"
					if (dispValue != state.energyL2Disp) {
						state.energyL2Disp = dispValue
					}
				}				
				else if (encapsulatedCommand.scale == 5 ){
               		newValue = Math.round(encapsulatedCommand.scaledMeterValue * 100) / 100
                    if (newValue > MAX_AMPS) { return } 
					formattedValue = String.format("%5.2f", newValue)
					dispValue = "${formattedValue}\nAmps"
					if (dispValue != state.ampsL2Disp) {
						state.ampsL2Disp = dispValue
					}
				}           	
			}
		}
	}
}

def zwaveEvent(hubitat.zwave.commands.batteryv1.BatteryReport cmd) {
	def map = [:]
	map.name = "battery"
	map.unit = "%"
	
	if (cmd.batteryLevel == 0xFF) {
		map.value = 1
		map.descriptionText = "${device.displayName} battery is low"
		map.isStateChange = true
	} 
	else {
		map.value = cmd.batteryLevel
	}
	log.debug map
	return map
}

def zwaveEvent(hubitat.zwave.Command cmd) {
	// Handles all Z-Wave commands we aren't interested in
    log.debug "Unhandled event ${cmd}"
	[:]
}

def refresh() {			// Request HEMv2 to send us the latest values for the 4 we are tracking
	log.debug "refresh()"
    
	delayBetween([
		zwave.meterV2.meterGet(scale: 0).format(),		// Change 0 to 1 if international version
		zwave.meterV2.meterGet(scale: 2).format(),
		zwave.meterV2.meterGet(scale: 4).format(),
		zwave.meterV2.meterGet(scale: 5).format()
	])
    resetDisplay()
}

def poll() {
	log.debug "poll()"
	refresh()
}

def toggleDisplay() {
	log.debug "toggleDisplay()"
    
	if (state.display == 1) { 
		state.display = 2 
	}
	else { 
		state.display = 1
	}
	resetDisplay()
}

def resetDisplay() {
	log.debug "resetDisplay() - energyL1Disp: ${state.energyL1Disp}"
}

def reset() {
	log.debug "reset()"

	state.energyValue = -1
	state.powerValue = -1
	state.ampsValue = -1
	state.voltsValue = -1
	
    state.powerHigh = 0
    state.powerHighDisp = ""
    state.powerLow = 99999
    state.powerLowDisp = ""
    state.ampsHigh = 0
    state.ampsHighDisp = ""
    state.ampsLow = 999
    state.ampsLowDisp = ""
    state.voltsHigh = 0
    state.voltsHighDisp = ""
    state.voltsLow = 999
    state.voltsLowDisp = ""
    
    state.energyL1Disp = ""
    state.energyL2Disp = ""
    state.powerL1Disp = ""
    state.powerL2Disp = ""
    state.ampsL1Disp = ""
    state.ampsL2Disp = ""
    state.voltsL1Disp = ""
    state.voltsL2Disp = ""
    
    if (!state.display) { state.display = 1 }	// Sometimes it appears that installed() isn't called

    def dateString = new Date().format("M/d/YY", location.timeZone)
    def timeString = new Date().format("h:mm a", location.timeZone)    
	state.lastResetTime = "Since\n"+dateString+"\n"+timeString
	state.costDisp = "Cost\n--"
	
    resetDisplay()

// No V1 available
	def cmd = delayBetween( [
		zwave.meterV2.meterReset().format(),			// Reset all values
		zwave.meterV2.meterGet(scale: 0).format(),		// Request the values we are interested in (0-->1 for kVAh)
		zwave.meterV2.meterGet(scale: 2).format(),
		zwave.meterV2.meterGet(scale: 4).format(),
		zwave.meterV2.meterGet(scale: 5).format()
	], 1000)
    cmd
    
    configure()
}

def configure() {
	log.debug "configure()"
    
	Long kDelay = settings.kWhDelay as Long
    Long dDelay = settings.detailDelay as Long
    
    if (kDelay == null) {		// Shouldn't have to do this, but there seem to be initialization errors
		kDelay = 15
	}

	if (dDelay == null) {
		dDelay = 15
	}
    
	def cmd = delayBetween([
		zwave.configurationV1.configurationSet(parameterNumber: 3, size: 1, scaledConfigurationValue: 0).format(),			// Disable (=0) selective reporting

		zwave.configurationV1.configurationSet(parameterNumber: 100, size: 1, scaledConfigurationValue: 0).format(),		// reset to defaults
		zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, scaledConfigurationValue: 2).format(),   // combined power in watts
		zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: 10).format(), // every 10 sec
		zwave.configurationV1.configurationSet(parameterNumber: 102, size: 4, scaledConfigurationValue: 1).format(),   // combined energy in kWh
		zwave.configurationV1.configurationSet(parameterNumber: 112, size: 4, scaledConfigurationValue: 300).format(), // every 5 min
		zwave.configurationV1.configurationSet(parameterNumber: 103, size: 4, scaledConfigurationValue: 0).format(),    // no third report
		zwave.configurationV1.configurationSet(parameterNumber: 113, size: 4, scaledConfigurationValue: 300).format() // every 5 min


	], 2000)

	cmd
}



def disableReporting()
{
	def cmd = delayBetween([
		zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, scaledConfigurationValue: 0).format(), // no first report
		zwave.configurationV1.configurationSet(parameterNumber: 102, size: 4, scaledConfigurationValue: 0).format(), // no second report
		zwave.configurationV1.configurationSet(parameterNumber: 103, size: 4, scaledConfigurationValue: 0).format()  // no third report
	], 2000)

	cmd
}
1 Like

I'm having the exact same issue with my Z-Wave Plus Aeotec Multisensor 6:

If I "set" a parameter like so:

Screenshot_2019-02-08%20Garage%20Motion%20and%20Temperature

I see this in the logs: Notice that I tried "setting" the same value multiple times, and each time the actual value reported is different:

If I "get" the value multiple times, it always returns the same value for each "get":

It sure looks like the "set" is mucking up the value somewhere along the way, and it doesn't even muck it up the same way each time.

-Jeremy

What firmware are your Multisensors on?

Whatever they shipped with. I have no idea. How do you find out?

Not sure. I just updated mine all to 1.10 yesterday though, as I hadn't updated them in a few years. lol.

Ok, I can get it to do weird values too... For instance if I write 10 to it (the lower bound of acceptable values), I get back 2567...

@mike.maxwell Do you think that is something goofy the device is doing, or something odd happening with the driver set command?

Here is what is published as the parameter config values:

1 Like

Oh, this is interesting:

If I enter a value above 255 (The maximum value for a 1 byte integer... coincidence?), it works. Anything 255 or under fails... And if you go small enough (Looks like anything under 14) it starts doing the random number non-sense.

-Jeremy

Oh, and to see your multisensor version, you can do the Version Report on the basic zwave tool. It will be the "applicationVersion" in the log.

dev:1512019-02-08 04:14:10.609 pm infoVersionReport- applicationVersion:1.10

dev:1512019-02-08 04:14:10.605 pm infoVersionReport- zWaveProtocolVersion:4.54

dev:1512019-02-08 04:14:10.601 pm infoVersionReport- zWaveLibraryType:Enhanced Slave

Same on mine. >255 works, <255 does not.

yes

no, if that were the case the tool flat out wouldn't work, nor would any options we configure in the drivers.

Screenshot_2019-02-08%20Logs-version

@mike.maxwell Any idea how I can get this to work? the default value was 240 (4 minutes) which is way too long for much of what I need to do. And now I'm stuck with 256 or more which is even less than ideal.

-Jeremy

LOL, we gave you the tool, I can't control a device that won't respect its own parameter settings...

1 Like

Nevermind...

ok, update, and I get to be wrong, which is always awesome!

We aren't returning two bytes as expected when the value fits in one byte, so its a platform issue that we'll get sorted. Happy Friday!

3 Likes

OK, that's interesting. I was assuming it was the device, as I took code I KNOW works in other drivers and made as quick test driver, and sure enough - it didn't work...

I never thought that the platform was screwing me... :smile:

Nice find! Thanks.

So as a workaround, you can change line 96 in the tool which is currenlty:

secureCmd(zwave.configurationV1.configurationSet(scaledConfigurationValue: value, parameterNumber: parameterNumber, size: size)),

and hard code the value you want, ie set paramter number 3 to 10 (000A is 10 in hex with 2 bytes) :

secureCmd(zwave.configurationV1.configurationSet(configurationValue: [0x00,0x0A], parameterNumber: 3, size: 2)),

Then of course change it back :slight_smile:

2 Likes