HEM v5

Do not pair it securely or else your hub will be very laggy.

I had read that, but doesn't it need to be paired securely in order to have it's parameters set?

No you can set parameters wit the basic zwave tool.

Ah, OK, thanks for that. I have the basic Zwave tool driver already on my system.

What driver are you using?

I've been using this ported driver. I made some changes that allow for changing the parameters from the driver page.

/*
 *  Aeon HEM Gen5(zwave plus)
 *
 *  Copyright 2016 Dillon A. Miller
 *
 *  v0.8 of Aeon HEM Gen5(zwave plus) code, released 04/15/2016 for Aeotec Model zw095-a
 *  This Gen5 device handler is not backward compatible with the Aeon V1 or V2 device. If your model number is not zw095-a, don't use it.
 *
 *  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.
 *
 *  Some code used from various SmartThings device handlers created by:
 *		Brock Haymond, Barry A. Burke, and Robert Vandervoort. Portions of the metering code came from ElasticDev.
 *
 *  Link to find the latest version of the Device Handler code:
 *		https://gist.github.com/DuncanIdahoCT/deb2bafdd28af4fce3073b9d9f4ecafa
 *
 *  General notes:
 *		You may need to change the device type to this device handler after you pair it to your hub. I'm not sure why it doesn't always automatically pair using this handler even though the fingerprint matches...
 *		Also, you need to hit the button on the back of the HEM Gen5 a couple (two-three) times to get it to flash the red light on the front rapidly to ensure it's in inclusion mode. It isn't in the right mode if it's just flashing slow.
 *		Once the red light is solid, look in your things list and find it, could be just called z-wave, then change it's name and device type using the graph api to this custom handler to make it start working.
 *		The config with default intervals will send right away after you set the HEM Gen5 to this handler, please wait a few minutes before sending the config again or changing the intervals under preferences.
 *		The purpose of the config button is just really to resend the config with monitor interval prefs, as sometimes the config isn't fully applied, See the list of config items at the bottom of this code.
 *		You may need to send the config a few times, with about 2 minutes delay between to get all the properties to take. Not sure why-but if you look in the debug log in the graph api for this device you can see if they all applied.
 *		I had to unplug and replug my device after extensive testing and repeatedly setting the config over and over. Could be it works for you the first time, or you may need to pull power and re plug too in order to get all the Pole 1/2 data to show in the app.
 *
 *	Known Issues:
 *		Issue 1:
 *			Not sure if this is the device handler or just a general SmartThings IOS App issue but sometimes when you set the preferences, it just spins in the app.
 *			If you are watching the log you can see it did set the preferences. Not sure why the app gets stuck, but just reload the app and should be fine.
 *		Issue 2:
 *			Not really a problem, more like a limitation; the clamps 1/2 data packets are sent to the ST hub based on monitor intervals for reports groups 1-3 which you can set in the device preferences.
 *			What this means is that, if you are paying attention to the tile data, you'll notice the center Total values don't quite work out to be the sum of Pole 1/2 values.
 *			This is simply because the base HEM data can be "polled" whereas the clamp 1/2 data is sent. And only sent on a schedule.
 *
 *  Change log:
 *		v0.1 - released 04/04/16:
 *			Added support for secure inclusion and command encapsulation
 *		v0.2 - released 04/05/16:
 *			Added configuration settings using some preference variables that you can control from the app
 *		v0.3 - released 04/05/16:
 *			Added clamp1 and clamp2 data display, may have to hit configure a few times (wait at least 2 minute each time) to make the top left and right boxes show data from the clamps.
 *		v0.4 - released 04/06/16:
 *			Changed the "main" tile to display a clean total kWh, although the ST app seems to make everything on the main Things list all CAPS so it's actually displayed as KWH...
 *		v0.5 - released 04/07/16:
 *			Changed the main thing list device icon to st.Lighting.light14 cause it has a leaf!.
 *		v0.6 - released 04/07/16:
 *			Added a cost per kWh preference and a cost tile that is calculated on kWh.
 *			Also added a timestamp of last reset button tap to work with above cost feature.
 *		v0.7 - released 04/08/16:
 *			Removed individual value tile polling actions and polling function.
 *			Cleaned up and well-formed code
 *		v0.8 - released 04/15/16:
 *			Slightly adjusted the size of the tiles to fit all tiles into the App screen without scrolling.
 *			Further commented and cleaned up the code in preparation for submission to SmartThings as an official device handler.
 *			Submitted for consideration by SmartThings.
 * 		v0.9 - Updated to add parameter 13 to enable/disable CRC16 encapsulation.  
 *
 *	To do:
 *		Features:
 *			Color code tiles or tile values for hi/low usage conditions.
 *			Possibly integrate a second tile set page with peak/min usage of watts and/or amps values over time.
 *			Integrate PlotWatt or other online Energy tracking API based service.
 *		Fixes:
 *			Determine why app sometimes freezes when setting preferences, I have seen this with other devices, e.g. Arrival Sensor, Jasco Wall Switches, etc...
 *
 */

// metadata
metadata {
	definition (name: "Aeon HEM Gen5(zwave plus)", namespace: "DuncanIdahoCT", author: "Dillon A. Miller") {
		capability "Energy Meter"
		capability "Power Meter"
		capability "Configuration"
		capability "Refresh"
		capability "Sensor"
		
		attribute "energy", "string"
        attribute "power", "string"
        attribute "cost", "string"
		attribute "voltage", "string"
        attribute "current", "string"
		attribute "current1", "string"
		attribute "current2", "string"
		attribute "lastresettime", "string"
		
			
		command "reset"
		command "refresh"
		command "configure"
		
		
		fingerprint deviceId: "0x3101", inClusters: "0x98"
		fingerprint inClusters: "0x5E,0x86,0x72,0x32,0x56,0x60,0x70,0x59,0x85,0x7A,0x73,0xEF,0x5A", outClusters: "0x82"
	}
	preferences {
		
		input name: "logEnable", type: "bool", title: "Enable debug logging", defaultValue: true
    	input name: "txtEnable", type: "bool", title: "Enable descriptionText logging", defaultValue: true
		
		input "kWhCost", "string",
			title: "Cost in \$/kWh",
			description: "Your Electric Bill Cost Per kWh",
			defaultValue: "0.19514" as String,
			required: false,
			displayDuringSetup: true
		input "monitorInterval1", "integer",
			title: "Group 1 Reporting Interval (Total: Watt,Voltage,Amperage,kVarh,kVar)",
			description: "Interval (secs) for parameter 101",
			defaultValue: 60,
			range: "1..4294967295?",
			required: false,
			displayDuringSetup: true
		input "monitorInterval2", "integer",
			title: "Group 2 Reporting Interval (Watt, kWh for Clamp 1 and Clamp2)",
			description: "Interval (secs) for parameter 102",
			defaultValue: 30,
			range: "1..4294967295?",
			required: false,
			displayDuringSetup: true
		input "monitorInterval3", "integer",
			title: "Group 3 Reporting Interval (voltage/current for Clamp 1 and Clamp2)",
			description: "Interval (secs) for parameter 103",
			defaultValue: 6,
			range: "1..4294967295?",
			required: false,
			displayDuringSetup: true
		input "SelectiveReporting", "integer",
			title: "Enable Or Disable Selective Reporting",
			description: "This is used to reduce network traffic. (0=disable, 1=enable) ",
			defaultValue: 0,
			range: "0..1",
			required: false,
			displayDuringSetup: true
		input "percentage2Report", "integer",
			title: "Change Percentage",
			description: "Percentage change in wattage to induce a automatic report (Whole HEM). Range: 0-100. ",
			defaultValue: 5,
			range: "0..100",
			required: false,
			displayDuringSetup: true
		input "watt2Report", "integer",
			title: "Wattage Change To Report",
			description: "Threshold change in wattage to induce a automatic report (Whole HEM). Range: 0-60000 ",
			defaultValue: 50,
			range: "0..60000",
			required: false,
			displayDuringSetup: true
        input "parameter101", "integer",
			title: "Parameter 101",
			description: "<a href='https://aeotec.freshdesk.com/support/solutions/articles/6000191986-hem-gen5-parameter-101-103-and-111-113-use-'> Aeotec Info </a>",
			defaultValue: 1776399,
			range: "0..1776399",
			required: false,
			displayDuringSetup: true
        input "parameter102", "integer",
			title: "Parameter 102",
			description: "Parameter 102 Reporting Group",
			defaultValue: 0,
			range: "0..1776399",
			required: false,
			displayDuringSetup: true
        input "parameter103", "integer",
			title: "Parameter 103",
			description: "Parameter 103 Reporting Group",
			defaultValue: 0,
			range: "0..1776399",
			required: false,
			displayDuringSetup: true
	}
	

}

def logsOff(){
    log.warn "debug logging disabled..."
    device.updateSetting("logEnable",[value:"false",type:"bool"])
}

def updated(){
	if (state.sec && !isConfigured()) {
		// in case we miss the SCSR
		response(configure())
	}
	log.info "updated..."
    log.warn "debug logging is: ${logEnable == true}"
    log.warn "description logging is: ${txtEnable == true}"
    if (logEnable) runIn(1800,logsOff)   
}

def parse(String description){
	def result = null
	if (description.startsWith("Err 106")) {
		state.sec = 0
		result = createEvent( name: "secureInclusion", value: "failed", isStateChange: true,
			descriptionText: "This sensor failed to complete the network security key exchange. If you are unable to control it via SmartThings, you must remove it from your network and add it again.")
	} else if (description != "updated") {
		def cmd = zwave.parse(description, [0x32: 3, 0x56: 1, 0x59: 1, 0x5A: 1, 0x60: 3, 0x70: 1, 0x72: 2, 0x73: 1, 0x82: 1, 0x85: 2, 0x86: 2, 0x8E: 2, 0xEF: 1])
		if (cmd) {
			result = zwaveEvent(cmd)
		}
	}
    //if (logEnable) log.debug "Parsed '${description}' to ${result.inspect()}"
	return result
}

def zwaveEvent(hubitat.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
	def encapsulatedCommand = cmd.encapsulatedCommand([0x32: 3, 0x56: 1, 0x59: 1, 0x5A: 1, 0x60: 3, 0x70: 1, 0x72: 2, 0x73: 1, 0x82: 1, 0x85: 2, 0x86: 2, 0x8E: 2, 0xEF: 1])
	state.sec = 1
    //if (logEnable) log.debug "encapsulated: ${encapsulatedCommand}"
	if (encapsulatedCommand) {
		zwaveEvent(encapsulatedCommand)
	} else {
		//log.warn "Unable to extract encapsulated cmd from $cmd"
		sendEvent(descriptionText: cmd.toString())
	}
}

def zwaveEvent(hubitat.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) {
	response(configure())
}

def zwaveEvent(hubitat.zwave.commands.configurationv1.ConfigurationReport cmd) {
    if (logEnable) log.debug "---CONFIGURATION REPORT V1--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}"
}

def zwaveEvent(hubitat.zwave.commands.associationv2.AssociationReport cmd) {
    if (logEnable) log.debug "---ASSOCIATION REPORT V2--- ${device.displayName} groupingIdentifier: ${cmd.groupingIdentifier}, maxNodesSupported: ${cmd.maxNodesSupported}, nodeId: ${cmd.nodeId}, reportsToFollow: ${cmd.reportsToFollow}"
}

def zwaveEvent(hubitat.zwave.commands.meterv3.MeterReport cmd) {
    def meterTypes = ["Unknown", "Electric", "Gas", "Water"]
    def electricNames = ["energy", "energy", "power", "count",  "voltage", "current", "powerFactor",  "unknown"]
    def electricUnits = ["kWh",    "kVAh",   "W",     "pulses", "V",       "A",       "Power Factor", ""]

    //log.debug cmd
    //log.debug cmd.scaledPreviousMeterValue
    
    //NOTE ScaledPreviousMeterValue does not always contain a value
    def previousValue = cmd.scaledPreviousMeterValue ?: 0

    //Here is where all HEM polled values are defined. Scale(0-7) is in reference to the Aeon Labs HEM Gen5 data for kWh, kVAh, W, V, A, and M.S.T. respectively.
    //If scale 7 (M.S.T.) is polled, you would receive Scale2(0-1) which is kVar, and kVarh respectively. We are ignoring the Scale2 ranges in this device handler.
    def map = [ name: electricNames[cmd.scale], unit: electricUnits[cmd.scale], displayed: state.display]
    //log.debug cmd.scale
    switch(cmd.scale) {
        case 0: //kWh
						log.debug "Kilowatt Hrs Since Reset: " + cmd.scaledMeterValue 
                        previousValue = device.currentValue("energy") ?: cmd.scaledPreviousMeterValue ?: 0
						BigDecimal costDecimal = cmd.scaledMeterValue * (kWhCost as BigDecimal)
						def costDisplay = String.format("%5.2f",costDecimal)
						sendEvent(name: "cost", value: costDisplay, unit: "", descriptionText: "Display Cost: \$${costDisplay}")
                        log.debug "Total Cost Since Reset: \$" + costDisplay 
						map.value = cmd.scaledMeterValue
            break;
        case 1: //kVAh (not used in the U.S.)
            map.value = cmd.scaledMeterValue
			log.debug "kVaH: " + cmd.scaledValue 
            break;
        case 2: //Watts
            previousValue = device.currentValue("power") ?: cmd.scaledPreviousMeterValue ?: 0
            map.value = Math.round(cmd.scaledMeterValue)
			log.debug "Power: " + cmd.scaledMeterValue + " Watts"
            break;
        case 3: //pulses
						map.value = Math.round(cmd.scaledMeterValue)
            break;
        case 4: //Volts
            previousValue = device.currentValue("voltage") ?: cmd.scaledPreviousMeterValue ?: 0
            map.value = cmd.scaledMeterValue
			log.debug "Voltage: " + cmd.scaledMeterValue + " Volts"
            break;
        case 5: //Amps
            previousValue = device.currentValue("current") ?: cmd.scaledPreviousMeterValue ?: 0
            map.value = cmd.scaledMeterValue
			log.debug "Current: " + cmd.scaledMeterValue + " Amps"
            break;
        case 6: //Power Factor
        case 7: //Scale2 values (not currently implimented or needed)
            map.value = cmd.scaledMeterValue
            break;
        default:
            break;
    }
sendEvent(map)
}

def zwaveEvent(hubitat.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) {
	//This is where the HEM clamp1 and clamp2 (subdevice) report values are defined. Scale(2,5) is in reference to the Aeon Labs HEM Gen5 (subdevice) data for W, and A respectively.
	//Z-Wave Command Class 0x60 (multichannelv3) is necessary to interpret the subdevice data from the HEM clamps.
	//In addition, "cmd.commandClass == 50" and "encapsulatedCommand([0x30: 1, 0x31: 1])" below is necessary to properly receive and inturpret the encasulated subdevice data sent to the SmartThings hub by the HEM.
	//The numbered "command class" references: 50, 0x30v1, and 0x31v1 do not seem to be true Z-Wave Command Classes and any correlation is seemingly coincidental.
	//It should also be noted that without the above, the data received will not be processed here under the 0x60 (multichannelv3) command class and you will see unhandled messages from the HEM along with references to command class 50 as well as Meter Types 33, and 161.
	//sourceEndPoint 1, and 2 are the Clamps 1, and 2.
	def dispValue
	def newValue
	def formattedValue
	def MAX_AMPS = 220
    def MAX_VOLT = 240
	def MAX_WATTS = 24000
    //log.debug "command class: " + cmd.commandClass
	if (cmd.commandClass == 50) { //50 is likely a manufacturer specific code, Z-Wave specifies this as a "Basic Window Covering" so it's not a true Z-Wave Command Class.   
		def encapsulatedCommand = cmd.encapsulatedCommand([0x30: 1, 0x31: 1]) // The documentation on working with Z-Wave subdevices and the technical specs from Aeon Labs do not explain this adequately, but it's necessary.
	//if (logEnable) log.debug ("Command from endpoint ${cmd.sourceEndPoint}: ${encapsulatedCommand}")
        
       // log.debug "aldsf : " + encapsulatedCommand
		if (encapsulatedCommand) {
			if (cmd.sourceEndPoint == 1) {
				if (encapsulatedCommand.scale == 2 ) {
						newValue = Math.round(encapsulatedCommand.scaledMeterValue)
	                    if (newValue > MAX_WATTS) { return }
						formattedValue = newValue
						dispValue = "${formattedValue}"
						sendEvent(name: "power1", value: dispValue as String, unit: "", descriptionText: "L1 Power: ${formattedValue} Watts")
				}
                if (encapsulatedCommand.scale == 4 ) {
						newValue = Math.round(encapsulatedCommand.scaledMeterValue * 100) / 100
	                    if (newValue > MAX_VOLT) { return }
						formattedValue = String.format("%5.2f", newValue)
						dispValue = "${formattedValue}"
						sendEvent(name: "volt1", value: dispValue as String, unit: "", descriptionText: "L1 Voltage: ${formattedValue} Volts")
                        log.debug "Clamp 1 voltage: " + dispValue  + " Volts"
				}
				if (encapsulatedCommand.scale == 5 ) {
						newValue = Math.round(encapsulatedCommand.scaledMeterValue * 100) / 100
	                    if (newValue > MAX_AMPS) { return }
						formattedValue = String.format("%5.2f", newValue)
						dispValue = "${formattedValue}"
						sendEvent(name: "current1", value: dispValue as String, unit: "", descriptionText: "L1 Current: ${formattedValue} Amps")
                        log.debug "Clamp 1 current: " + dispValue  + " Amps"
				}
			}
			else if (cmd.sourceEndPoint == 2) {
				if (encapsulatedCommand.scale == 2 ) {
						newValue = Math.round(encapsulatedCommand.scaledMeterValue)
	                    if (newValue > MAX_WATTS) { return }
						formattedValue = newValue
						dispValue = "${formattedValue}"
						sendEvent(name: "power2", value: dispValue as String, unit: "", descriptionText: "L2 Power: ${formattedValue} Watts")
				}
                if (encapsulatedCommand.scale == 4 ) {
						newValue = Math.round(encapsulatedCommand.scaledMeterValue * 100) / 100
	                    if (newValue > MAX_VOLT) { return }
						formattedValue = String.format("%5.2f", newValue)
						dispValue = "${formattedValue}"
						sendEvent(name: "volt2", value: dispValue as String, unit: "", descriptionText: "L2 Voltage: ${formattedValue} Volts")
                        log.debug "Clamp 2 voltage: " + dispValue  + " Volts"
				}
				if (encapsulatedCommand.scale == 5 ) {
						newValue = Math.round(encapsulatedCommand.scaledMeterValue * 100) / 100
	                    if (newValue > MAX_AMPS) { return }
						formattedValue = String.format("%5.2f", newValue)
						dispValue = "${formattedValue}"
						sendEvent(name: "current2", value: dispValue as String, unit: "", descriptionText: "L2 Current: ${formattedValue} Amps")
                        log.debug "Clamp 2 current: " + dispValue + " Amps"
				}
			}
		}
	}
}

def zwaveEvent(hubitat.zwave.Command cmd) {
	//This will log any unhandled command output to the debug window.
	//if (logEnable) log.debug "Unhandled: $cmd"
    sendEvent(descriptionText: cmd.toString(), isStateChange: false)
}

def refresh() {
	def request = [
	//This is where the tile action "refresh" is defined. Refresh is very basic. It simply gets and displays the latest values from the HEM exclusive of the clamp subdevices.
		zwave.meterV3.meterGet(scale: 0),	//kWh
		zwave.meterV3.meterGet(scale: 2),	//Wattage
		zwave.meterV3.meterGet(scale: 4),	//Volts
		zwave.meterV3.meterGet(scale: 5),	//Amps
	]
	commands(request)
}

def reset() {
	//This is where the tile action "reset" is defined. Reset is only meant to be used once a month on the end/beginning of your electric utility billing cycle.
	//Tapping reset will send the meter reset command to HEM and zero out the kWh data so you can start fresh.
	//This will also clear the cost data and reset the last reset timestamp. Finally it will poll for latest values from the HEM.
	//This has no impact on Pole1 or Pole2 (clamp1 and clamp2 subdevice) tile data as that is sent via reports from the HEM.
	def dateString = new Date().format("M/d/YY", location.timeZone)
	def timeString = new Date().format("h:mm a", location.timeZone)    
	state.lastresettime = dateString+" @ "+timeString
	sendEvent(name: "lastresettime", value: state.lastresettime)	
	def request = [
		zwave.meterV3.meterReset(),
		zwave.meterV3.meterGet(scale: 0),	//kWh
		zwave.meterV3.meterGet(scale: 2),	//Wattage
		zwave.meterV3.meterGet(scale: 4),	//Volts
		zwave.meterV3.meterGet(scale: 5),	//Amps
	]
	commands(request)
}

def configure() {
    
   
	//This is where the tile action "configure" is defined. Configure resends the configuration commands below (using the variables set by the preferences section above) to the HEM Gen5 device.
	//If you're watching the debug log when you tap configure, you should see the full configuration report come back slowly over about a minute.
	//If you don't see the full configuration report (seven messages) followed by the association report, tap configure again.
	//def monitorInt1 = 60
		if (monitorInterval1) {
		monitorInt1=monitorInterval1.toInteger()
		}
	def monitorInt2 = 30
		if (monitorInterval2) {
			monitorInt2=monitorInterval2.toInteger()
		}
	def monitorInt3 = 6
		if (monitorInterval3) {
			monitorInt3=monitorInterval3.toInteger()
	}
	def SelectiveReportingInt = 0
		if (SelectiveReporting) {
			SelectiveReportingInt=SelectiveReporting.toInteger()
	}
	def  percentageInt = 5
		if (percentage2Report) {
			percentageInt=percentage2Report.toInteger()
	}	
   def  watt2ReportInt = 50
		if (watt2Report) {
			watt2ReportInt=watt2Report.toInteger()
	}	
   def  parameter101Int = 63
		if (parameter101) {
			parameter101Int=parameter101.toInteger()
	}	
       def  parameter102Int = 0
		if (parameter102) {
			parameter102Int=parameter102.toInteger()
	}	
       def  parameter103Int = 0
		if (parameter103) {
			parameter103Int=parameter103.toInteger()
	}	
	
	if (logEnable) log.debug "Sending configure commands - kWhCost '${kWhCost}', monitorInterval1 '${monitorInt1}', monitorInterval2 '${monitorInt2}', monitorInterval3 '${monitorInt3}'"
	def request = [
		// Reset switch configuration to defaults.
	    //zwave.configurationV1.configurationSet(parameterNumber: 255, size: 1, scaledConfigurationValue: 1),
		// Disable selective reporting, so always update based on schedule below <set to 1 to reduce network traffic>.
		zwave.configurationV1.configurationSet(parameterNumber: 3, size: 1, scaledConfigurationValue: SelectiveReportingInt),
		// (DISABLED by first option) Don't send unless watts have changed by 50 <default>.
		zwave.configurationV1.configurationSet(parameterNumber: 4, size: 2, scaledConfigurationValue: watt2ReportInt),
		// (DISABLED by first option) Or by 5% <default>.
		zwave.configurationV1.configurationSet(parameterNumber: 8, size: 1, scaledConfigurationValue: percentageInt),
		// (DISABLED CRC16 Encapsulaltion O = Disable 1 = Enable)
		zwave.configurationV1.configurationSet(parameterNumber: 13, size: 1, scaledConfigurationValue: 0),
		// Which reports need to send in Report group 1. Old value 6149
		//zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, scaledConfigurationValue: 6149),
        zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, scaledConfigurationValue: parameter101Int),
		// Which reports need to send in Report group 2.
		zwave.configurationV1.configurationSet(parameterNumber: 102, size: 4, scaledConfigurationValue: parameter102Int),
		// Which reports need to send in Report group 3.
		zwave.configurationV1.configurationSet(parameterNumber: 103, size: 4, scaledConfigurationValue: parameter103Int),
		// Interval to send Report group 1.
		zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: monitorInt1),
		// Interval to send Report group 2.
		zwave.configurationV1.configurationSet(parameterNumber: 112, size: 4, scaledConfigurationValue: monitorInt2),
		// Interval to send Report group 3.
		zwave.configurationV1.configurationSet(parameterNumber: 113, size: 4, scaledConfigurationValue: monitorInt3),

		// Report which configuration commands were sent to and received by the HEM Gen5 successfully.
		zwave.configurationV1.configurationGet(parameterNumber: 3),
		zwave.configurationV1.configurationGet(parameterNumber: 4),
		zwave.configurationV1.configurationGet(parameterNumber: 8),
		zwave.configurationV1.configurationGet(parameterNumber: 13),
		zwave.configurationV1.configurationGet(parameterNumber: 101),
		zwave.configurationV1.configurationGet(parameterNumber: 102),
		zwave.configurationV1.configurationGet(parameterNumber: 103),
		zwave.configurationV1.configurationGet(parameterNumber: 111),
		zwave.configurationV1.configurationGet(parameterNumber: 112),
		zwave.configurationV1.configurationGet(parameterNumber: 113),
		zwave.associationV2.associationGet(groupingIdentifier: 1)
	]
	commands(request)
}

private setConfigured() {
	updateDataValue("configured", "true")
}

private isConfigured() {
	getDataValue("configured") == "true"
}

private command(hubitat.zwave.Command cmd) {
	if (state.sec) {
		zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
	} else {
		cmd.format()
	}
}

private commands(commands, delay=500) {
	delayBetween(commands.collect{ command(it) }, delay)
}
3 Likes

This driver is working great for my UK spec 240v single phase Aeotec HEM gen5 :+1:

1 Like

Hello @cuboy29

What you have on Parameter 101? My friend got a new hem but it shows like 1776399 for 101, 0 for 102 and 103

I did use that number at one point, that will report everything for group 1. I am now only using 15 for parameter 101 since I only care about power and energy reporting. Don't really care about the individual clamp voltage and current data.

There is a link on the driver page that will take you to Aeotec's page that show how to configure parameter 101, 102 and 103.

1 Like

I just paired up my Gen5 that I had on ST. I used the driver listed above. It seems to work, but in the logs I'm seeing an error as follows:

2019-11-09 08:36:27.369 am errorgroovy.lang.GroovyRuntimeException: Ambiguous method overloading for method java.math.BigDecimal#multiply. Cannot resolve which method to invoke for [null] due to overlapping prototypes between: [class java.lang.Character] [class java.lang.Number] on line 248 (parse)

Not sure what to do about that.

Change the value for the energy cost and hit the save button. I think that should do it.

@cuboy29 Sorry to waking a dead thread.

Do you know why I cannot get "<" ">" in RM using this driver? Is there a way to be able to?

instead of

My guess is that the second driver's attribute is numeric, while the first driver's attribute is text. You might be able to modify the driver's 'attribute' definition for 'current1' to make it a number instead of a string.

1 Like

like..

image

that crashed the rule

Well, you're probably going to need to redo the rule, since you literally just pulled the rug out from underneath it. :wink:

I created a new rule and as soon as I select that as a trigger it goes blank screen.

I am wondering if the device would need to be "Removed" and then "Added" again? I am not sure what happens when a device has a certain amount of history with an attribute being one data type and then later with a different data type... :thinking:

When you look at the device, is the 'current1' attribute updating with new data? Any errors in the Live Logs? There may be other changes required in the driver to get the data in the correct format.

When I did this with a Aquara sensor, I had to go into the device, do a save to "reload" the driver or something.

Whatever saving does, it made the rule work from there on out.

Worth a try anyway.

1 Like

I just took a quick look at that driver and it definitely has some issues that need to be addressed. Custom attributes for 'power' and 'energy' not necessary since those capabilities are declared. Also, those attributes are incorrectly declared as strings as well. Also, the driver should include the capability for "Voltage Measurement" and that custom attribute for 'voltage' (again wrong data type) could be removed.

I don't have one of those devices or else I would assist in cleaning up the driver. Hopefully a developer with one will assist.

@TechMedX - I took a stab at fixing this driver to use the proper capabilities and data types for the custom attributes. If you want to give it a try, here it is...

Please let me know if this works or makes things worse. I don't want to leave a potentially bad driver in the community...

/*
 *  Aeon HEM Gen5(zwave plus)
 *
 *  Copyright 2016 Dillon A. Miller
 *
 *  v0.8 of Aeon HEM Gen5(zwave plus) code, released 04/15/2016 for Aeotec Model zw095-a
 *  This Gen5 device handler is not backward compatible with the Aeon V1 or V2 device. If your model number is not zw095-a, don't use it.
 *
 *  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.
 *
 *  Some code used from various SmartThings device handlers created by:
 *		Brock Haymond, Barry A. Burke, and Robert Vandervoort. Portions of the metering code came from ElasticDev.
 *
 *  Link to find the latest version of the Device Handler code:
 *		https://gist.github.com/DuncanIdahoCT/deb2bafdd28af4fce3073b9d9f4ecafa
 *
 *  General notes:
 *		You may need to change the device type to this device handler after you pair it to your hub. I'm not sure why it doesn't always automatically pair using this handler even though the fingerprint matches...
 *		Also, you need to hit the button on the back of the HEM Gen5 a couple (two-three) times to get it to flash the red light on the front rapidly to ensure it's in inclusion mode. It isn't in the right mode if it's just flashing slow.
 *		Once the red light is solid, look in your things list and find it, could be just called z-wave, then change it's name and device type using the graph api to this custom handler to make it start working.
 *		The config with default intervals will send right away after you set the HEM Gen5 to this handler, please wait a few minutes before sending the config again or changing the intervals under preferences.
 *		The purpose of the config button is just really to resend the config with monitor interval prefs, as sometimes the config isn't fully applied, See the list of config items at the bottom of this code.
 *		You may need to send the config a few times, with about 2 minutes delay between to get all the properties to take. Not sure why-but if you look in the debug log in the graph api for this device you can see if they all applied.
 *		I had to unplug and replug my device after extensive testing and repeatedly setting the config over and over. Could be it works for you the first time, or you may need to pull power and re plug too in order to get all the Pole 1/2 data to show in the app.
 *
 *	Known Issues:
 *		Issue 1:
 *			Not sure if this is the device handler or just a general SmartThings IOS App issue but sometimes when you set the preferences, it just spins in the app.
 *			If you are watching the log you can see it did set the preferences. Not sure why the app gets stuck, but just reload the app and should be fine.
 *		Issue 2:
 *			Not really a problem, more like a limitation; the clamps 1/2 data packets are sent to the ST hub based on monitor intervals for reports groups 1-3 which you can set in the device preferences.
 *			What this means is that, if you are paying attention to the tile data, you'll notice the center Total values don't quite work out to be the sum of Pole 1/2 values.
 *			This is simply because the base HEM data can be "polled" whereas the clamp 1/2 data is sent. And only sent on a schedule.
 *
 *  Change log:
 *		v0.1 - released 04/04/16:
 *			Added support for secure inclusion and command encapsulation
 *		v0.2 - released 04/05/16:
 *			Added configuration settings using some preference variables that you can control from the app
 *		v0.3 - released 04/05/16:
 *			Added clamp1 and clamp2 data display, may have to hit configure a few times (wait at least 2 minute each time) to make the top left and right boxes show data from the clamps.
 *		v0.4 - released 04/06/16:
 *			Changed the "main" tile to display a clean total kWh, although the ST app seems to make everything on the main Things list all CAPS so it's actually displayed as KWH...
 *		v0.5 - released 04/07/16:
 *			Changed the main thing list device icon to st.Lighting.light14 cause it has a leaf!.
 *		v0.6 - released 04/07/16:
 *			Added a cost per kWh preference and a cost tile that is calculated on kWh.
 *			Also added a timestamp of last reset button tap to work with above cost feature.
 *		v0.7 - released 04/08/16:
 *			Removed individual value tile polling actions and polling function.
 *			Cleaned up and well-formed code
 *		v0.8 - released 04/15/16:
 *			Slightly adjusted the size of the tiles to fit all tiles into the App screen without scrolling.
 *			Further commented and cleaned up the code in preparation for submission to SmartThings as an official device handler.
 *			Submitted for consideration by SmartThings.
 * 		v0.9 - Updated to add parameter 13 to enable/disable CRC16 encapsulation.  
 *
 *	To do:
 *		Features:
 *			Color code tiles or tile values for hi/low usage conditions.
 *			Possibly integrate a second tile set page with peak/min usage of watts and/or amps values over time.
 *			Integrate PlotWatt or other online Energy tracking API based service.
 *		Fixes:
 *			Determine why app sometimes freezes when setting preferences, I have seen this with other devices, e.g. Arrival Sensor, Jasco Wall Switches, etc...
 *
 */

// metadata
metadata {
	definition (name: "Aeon HEM Gen5(zwave plus)", namespace: "DuncanIdahoCT", author: "Dillon A. Miller") {
		capability "Sensor"
        capability "Energy Meter"
		capability "Power Meter"
        capability "Voltage Measurement"
		capability "Configuration"
		capability "Refresh"

		
		//attribute "energy", "string"
        //attribute "power", "string"
        attribute "cost", "string"
		//attribute "voltage", "string"
        attribute "current", "number"
		attribute "current1", "number"
		attribute "current2", "number"
		attribute "power1", "number"
		attribute "power2", "number"
        attribute "volt1", "number"
		attribute "volt2", "number"
        attribute "lastresettime", "string"
		
			
		command "reset"
		command "refresh"
		command "configure"
		
		
		fingerprint deviceId: "0x3101", inClusters: "0x98"
		fingerprint inClusters: "0x5E,0x86,0x72,0x32,0x56,0x60,0x70,0x59,0x85,0x7A,0x73,0xEF,0x5A", outClusters: "0x82"
	}
	preferences {
		
		input name: "logEnable", type: "bool", title: "Enable debug logging", defaultValue: true
    	input name: "txtEnable", type: "bool", title: "Enable descriptionText logging", defaultValue: true
		
		input "kWhCost", "string",
			title: "Cost in \$/kWh",
			description: "Your Electric Bill Cost Per kWh",
			defaultValue: "0.19514" as String,
			required: false,
			displayDuringSetup: true
		input "monitorInterval1", "integer",
			title: "Group 1 Reporting Interval (Total: Watt,Voltage,Amperage,kVarh,kVar)",
			description: "Interval (secs) for parameter 101",
			defaultValue: 60,
			range: "1..4294967295?",
			required: false,
			displayDuringSetup: true
		input "monitorInterval2", "integer",
			title: "Group 2 Reporting Interval (Watt, kWh for Clamp 1 and Clamp2)",
			description: "Interval (secs) for parameter 102",
			defaultValue: 30,
			range: "1..4294967295?",
			required: false,
			displayDuringSetup: true
		input "monitorInterval3", "integer",
			title: "Group 3 Reporting Interval (voltage/current for Clamp 1 and Clamp2)",
			description: "Interval (secs) for parameter 103",
			defaultValue: 6,
			range: "1..4294967295?",
			required: false,
			displayDuringSetup: true
		input "SelectiveReporting", "integer",
			title: "Enable Or Disable Selective Reporting",
			description: "This is used to reduce network traffic. (0=disable, 1=enable) ",
			defaultValue: 0,
			range: "0..1",
			required: false,
			displayDuringSetup: true
		input "percentage2Report", "integer",
			title: "Change Percentage",
			description: "Percentage change in wattage to induce a automatic report (Whole HEM). Range: 0-100. ",
			defaultValue: 5,
			range: "0..100",
			required: false,
			displayDuringSetup: true
		input "watt2Report", "integer",
			title: "Wattage Change To Report",
			description: "Threshold change in wattage to induce a automatic report (Whole HEM). Range: 0-60000 ",
			defaultValue: 50,
			range: "0..60000",
			required: false,
			displayDuringSetup: true
        input "parameter101", "integer",
			title: "Parameter 101",
			description: "<a href='https://aeotec.freshdesk.com/support/solutions/articles/6000191986-hem-gen5-parameter-101-103-and-111-113-use-'> Aeotec Info </a>",
			defaultValue: 1776399,
			range: "0..1776399",
			required: false,
			displayDuringSetup: true
        input "parameter102", "integer",
			title: "Parameter 102",
			description: "Parameter 102 Reporting Group",
			defaultValue: 0,
			range: "0..1776399",
			required: false,
			displayDuringSetup: true
        input "parameter103", "integer",
			title: "Parameter 103",
			description: "Parameter 103 Reporting Group",
			defaultValue: 0,
			range: "0..1776399",
			required: false,
			displayDuringSetup: true
	}
	

}

def logsOff(){
    log.warn "debug logging disabled..."
    device.updateSetting("logEnable",[value:"false",type:"bool"])
}

def updated(){
	if (state.sec && !isConfigured()) {
		// in case we miss the SCSR
		response(configure())
	}
	log.info "updated..."
    log.warn "debug logging is: ${logEnable == true}"
    log.warn "description logging is: ${txtEnable == true}"
    if (logEnable) runIn(1800,logsOff)   
}

def parse(String description){
	def result = null
	if (description.startsWith("Err 106")) {
		state.sec = 0
		result = createEvent( name: "secureInclusion", value: "failed", isStateChange: true,
			descriptionText: "This sensor failed to complete the network security key exchange. If you are unable to control it via SmartThings, you must remove it from your network and add it again.")
	} else if (description != "updated") {
		def cmd = zwave.parse(description, [0x32: 3, 0x56: 1, 0x59: 1, 0x5A: 1, 0x60: 3, 0x70: 1, 0x72: 2, 0x73: 1, 0x82: 1, 0x85: 2, 0x86: 2, 0x8E: 2, 0xEF: 1])
		if (cmd) {
			result = zwaveEvent(cmd)
		}
	}
    //if (logEnable) log.debug "Parsed '${description}' to ${result.inspect()}"
	return result
}

def zwaveEvent(hubitat.zwave.commands.securityv1.SecurityMessageEncapsulation cmd) {
	def encapsulatedCommand = cmd.encapsulatedCommand([0x32: 3, 0x56: 1, 0x59: 1, 0x5A: 1, 0x60: 3, 0x70: 1, 0x72: 2, 0x73: 1, 0x82: 1, 0x85: 2, 0x86: 2, 0x8E: 2, 0xEF: 1])
	state.sec = 1
    //if (logEnable) log.debug "encapsulated: ${encapsulatedCommand}"
	if (encapsulatedCommand) {
		zwaveEvent(encapsulatedCommand)
	} else {
		//log.warn "Unable to extract encapsulated cmd from $cmd"
		sendEvent(descriptionText: cmd.toString())
	}
}

def zwaveEvent(hubitat.zwave.commands.securityv1.SecurityCommandsSupportedReport cmd) {
	response(configure())
}

def zwaveEvent(hubitat.zwave.commands.configurationv1.ConfigurationReport cmd) {
    if (logEnable) log.debug "---CONFIGURATION REPORT V1--- ${device.displayName} parameter ${cmd.parameterNumber} with a byte size of ${cmd.size} is set to ${cmd.configurationValue}"
}

def zwaveEvent(hubitat.zwave.commands.associationv2.AssociationReport cmd) {
    if (logEnable) log.debug "---ASSOCIATION REPORT V2--- ${device.displayName} groupingIdentifier: ${cmd.groupingIdentifier}, maxNodesSupported: ${cmd.maxNodesSupported}, nodeId: ${cmd.nodeId}, reportsToFollow: ${cmd.reportsToFollow}"
}

def zwaveEvent(hubitat.zwave.commands.meterv3.MeterReport cmd) {
    def meterTypes = ["Unknown", "Electric", "Gas", "Water"]
    def electricNames = ["energy", "energy", "power", "count",  "voltage", "current", "powerFactor",  "unknown"]
    def electricUnits = ["kWh",    "kVAh",   "W",     "pulses", "V",       "A",       "Power Factor", ""]

    //log.debug cmd
    //log.debug cmd.scaledPreviousMeterValue
    
    //NOTE ScaledPreviousMeterValue does not always contain a value
    def previousValue = cmd.scaledPreviousMeterValue ?: 0

    //Here is where all HEM polled values are defined. Scale(0-7) is in reference to the Aeon Labs HEM Gen5 data for kWh, kVAh, W, V, A, and M.S.T. respectively.
    //If scale 7 (M.S.T.) is polled, you would receive Scale2(0-1) which is kVar, and kVarh respectively. We are ignoring the Scale2 ranges in this device handler.
    def map = [ name: electricNames[cmd.scale], unit: electricUnits[cmd.scale], displayed: state.display]
    //log.debug cmd.scale
    switch(cmd.scale) {
        case 0: //kWh
						log.debug "Kilowatt Hrs Since Reset: " + cmd.scaledMeterValue 
                        previousValue = device.currentValue("energy") ?: cmd.scaledPreviousMeterValue ?: 0
						BigDecimal costDecimal = cmd.scaledMeterValue * (kWhCost as BigDecimal)
						def costDisplay = String.format("%5.2f",costDecimal)
						sendEvent(name: "cost", value: costDisplay, unit: "", descriptionText: "Display Cost: \$${costDisplay}")
                        log.debug "Total Cost Since Reset: \$" + costDisplay 
						map.value = cmd.scaledMeterValue
            break;
        case 1: //kVAh (not used in the U.S.)
            map.value = cmd.scaledMeterValue
			log.debug "kVaH: " + cmd.scaledValue 
            break;
        case 2: //Watts
            previousValue = device.currentValue("power") ?: cmd.scaledPreviousMeterValue ?: 0
            map.value = Math.round(cmd.scaledMeterValue)
			log.debug "Power: " + cmd.scaledMeterValue + " Watts"
            break;
        case 3: //pulses
						map.value = Math.round(cmd.scaledMeterValue)
            break;
        case 4: //Volts
            previousValue = device.currentValue("voltage") ?: cmd.scaledPreviousMeterValue ?: 0
            map.value = cmd.scaledMeterValue
			log.debug "Voltage: " + cmd.scaledMeterValue + " Volts"
            break;
        case 5: //Amps
            previousValue = device.currentValue("current") ?: cmd.scaledPreviousMeterValue ?: 0
            map.value = cmd.scaledMeterValue
			log.debug "Current: " + cmd.scaledMeterValue + " Amps"
            break;
        case 6: //Power Factor
        case 7: //Scale2 values (not currently implimented or needed)
            map.value = cmd.scaledMeterValue
            break;
        default:
            break;
    }
sendEvent(map)
}

def zwaveEvent(hubitat.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) {
	//This is where the HEM clamp1 and clamp2 (subdevice) report values are defined. Scale(2,5) is in reference to the Aeon Labs HEM Gen5 (subdevice) data for W, and A respectively.
	//Z-Wave Command Class 0x60 (multichannelv3) is necessary to interpret the subdevice data from the HEM clamps.
	//In addition, "cmd.commandClass == 50" and "encapsulatedCommand([0x30: 1, 0x31: 1])" below is necessary to properly receive and inturpret the encasulated subdevice data sent to the SmartThings hub by the HEM.
	//The numbered "command class" references: 50, 0x30v1, and 0x31v1 do not seem to be true Z-Wave Command Classes and any correlation is seemingly coincidental.
	//It should also be noted that without the above, the data received will not be processed here under the 0x60 (multichannelv3) command class and you will see unhandled messages from the HEM along with references to command class 50 as well as Meter Types 33, and 161.
	//sourceEndPoint 1, and 2 are the Clamps 1, and 2.
	def dispValue
	def newValue
	def formattedValue
	def MAX_AMPS = 220
    def MAX_VOLT = 240
	def MAX_WATTS = 24000
    //log.debug "command class: " + cmd.commandClass
	if (cmd.commandClass == 50) { //50 is likely a manufacturer specific code, Z-Wave specifies this as a "Basic Window Covering" so it's not a true Z-Wave Command Class.   
		def encapsulatedCommand = cmd.encapsulatedCommand([0x30: 1, 0x31: 1]) // The documentation on working with Z-Wave subdevices and the technical specs from Aeon Labs do not explain this adequately, but it's necessary.
	//if (logEnable) log.debug ("Command from endpoint ${cmd.sourceEndPoint}: ${encapsulatedCommand}")
        
       // log.debug "aldsf : " + encapsulatedCommand
		if (encapsulatedCommand) {
			if (cmd.sourceEndPoint == 1) {
				if (encapsulatedCommand.scale == 2 ) {
						newValue = Math.round(encapsulatedCommand.scaledMeterValue)
	                    if (newValue > MAX_WATTS) { return }
						formattedValue = newValue
						dispValue = "${formattedValue}"
						sendEvent(name: "power1", value: dispValue, unit: "", descriptionText: "L1 Power: ${formattedValue} Watts")
				}
                if (encapsulatedCommand.scale == 4 ) {
						newValue = Math.round(encapsulatedCommand.scaledMeterValue * 100) / 100
	                    if (newValue > MAX_VOLT) { return }
						formattedValue = String.format("%5.2f", newValue)
						dispValue = "${formattedValue}"
						sendEvent(name: "volt1", value: dispValue, unit: "", descriptionText: "L1 Voltage: ${formattedValue} Volts")
                        log.debug "Clamp 1 voltage: " + dispValue  + " Volts"
				}
				if (encapsulatedCommand.scale == 5 ) {
						newValue = Math.round(encapsulatedCommand.scaledMeterValue * 100) / 100
	                    if (newValue > MAX_AMPS) { return }
						formattedValue = String.format("%5.2f", newValue)
						dispValue = "${formattedValue}"
						sendEvent(name: "current1", value: dispValue, unit: "", descriptionText: "L1 Current: ${formattedValue} Amps")
                        log.debug "Clamp 1 current: " + dispValue  + " Amps"
				}
			}
			else if (cmd.sourceEndPoint == 2) {
				if (encapsulatedCommand.scale == 2 ) {
						newValue = Math.round(encapsulatedCommand.scaledMeterValue)
	                    if (newValue > MAX_WATTS) { return }
						formattedValue = newValue
						dispValue = "${formattedValue}"
						sendEvent(name: "power2", value: dispValue, unit: "", descriptionText: "L2 Power: ${formattedValue} Watts")
				}
                if (encapsulatedCommand.scale == 4 ) {
						newValue = Math.round(encapsulatedCommand.scaledMeterValue * 100) / 100
	                    if (newValue > MAX_VOLT) { return }
						formattedValue = String.format("%5.2f", newValue)
						dispValue = "${formattedValue}"
						sendEvent(name: "volt2", value: dispValue, unit: "", descriptionText: "L2 Voltage: ${formattedValue} Volts")
                        log.debug "Clamp 2 voltage: " + dispValue  + " Volts"
				}
				if (encapsulatedCommand.scale == 5 ) {
						newValue = Math.round(encapsulatedCommand.scaledMeterValue * 100) / 100
	                    if (newValue > MAX_AMPS) { return }
						formattedValue = String.format("%5.2f", newValue)
						dispValue = "${formattedValue}"
						sendEvent(name: "current2", value: dispValue, unit: "", descriptionText: "L2 Current: ${formattedValue} Amps")
                        log.debug "Clamp 2 current: " + dispValue + " Amps"
				}
			}
		}
	}
}

def zwaveEvent(hubitat.zwave.Command cmd) {
	//This will log any unhandled command output to the debug window.
	//if (logEnable) log.debug "Unhandled: $cmd"
    sendEvent(descriptionText: cmd.toString(), isStateChange: false)
}

def refresh() {
	def request = [
	//This is where the tile action "refresh" is defined. Refresh is very basic. It simply gets and displays the latest values from the HEM exclusive of the clamp subdevices.
		zwave.meterV3.meterGet(scale: 0),	//kWh
		zwave.meterV3.meterGet(scale: 2),	//Wattage
		zwave.meterV3.meterGet(scale: 4),	//Volts
		zwave.meterV3.meterGet(scale: 5),	//Amps
	]
	commands(request)
}

def reset() {
	//This is where the tile action "reset" is defined. Reset is only meant to be used once a month on the end/beginning of your electric utility billing cycle.
	//Tapping reset will send the meter reset command to HEM and zero out the kWh data so you can start fresh.
	//This will also clear the cost data and reset the last reset timestamp. Finally it will poll for latest values from the HEM.
	//This has no impact on Pole1 or Pole2 (clamp1 and clamp2 subdevice) tile data as that is sent via reports from the HEM.
	def dateString = new Date().format("M/d/YY", location.timeZone)
	def timeString = new Date().format("h:mm a", location.timeZone)    
	state.lastresettime = dateString+" @ "+timeString
	sendEvent(name: "lastresettime", value: state.lastresettime)	
	def request = [
		zwave.meterV3.meterReset(),
		zwave.meterV3.meterGet(scale: 0),	//kWh
		zwave.meterV3.meterGet(scale: 2),	//Wattage
		zwave.meterV3.meterGet(scale: 4),	//Volts
		zwave.meterV3.meterGet(scale: 5),	//Amps
	]
	commands(request)
}

def configure() {
    
   
	//This is where the tile action "configure" is defined. Configure resends the configuration commands below (using the variables set by the preferences section above) to the HEM Gen5 device.
	//If you're watching the debug log when you tap configure, you should see the full configuration report come back slowly over about a minute.
	//If you don't see the full configuration report (seven messages) followed by the association report, tap configure again.
	//def monitorInt1 = 60
		if (monitorInterval1) {
		monitorInt1=monitorInterval1.toInteger()
		}
	def monitorInt2 = 30
		if (monitorInterval2) {
			monitorInt2=monitorInterval2.toInteger()
		}
	def monitorInt3 = 6
		if (monitorInterval3) {
			monitorInt3=monitorInterval3.toInteger()
	}
	def SelectiveReportingInt = 0
		if (SelectiveReporting) {
			SelectiveReportingInt=SelectiveReporting.toInteger()
	}
	def  percentageInt = 5
		if (percentage2Report) {
			percentageInt=percentage2Report.toInteger()
	}	
   def  watt2ReportInt = 50
		if (watt2Report) {
			watt2ReportInt=watt2Report.toInteger()
	}	
   def  parameter101Int = 63
		if (parameter101) {
			parameter101Int=parameter101.toInteger()
	}	
       def  parameter102Int = 0
		if (parameter102) {
			parameter102Int=parameter102.toInteger()
	}	
       def  parameter103Int = 0
		if (parameter103) {
			parameter103Int=parameter103.toInteger()
	}	
	
	if (logEnable) log.debug "Sending configure commands - kWhCost '${kWhCost}', monitorInterval1 '${monitorInt1}', monitorInterval2 '${monitorInt2}', monitorInterval3 '${monitorInt3}'"
	def request = [
		// Reset switch configuration to defaults.
	    //zwave.configurationV1.configurationSet(parameterNumber: 255, size: 1, scaledConfigurationValue: 1),
		// Disable selective reporting, so always update based on schedule below <set to 1 to reduce network traffic>.
		zwave.configurationV1.configurationSet(parameterNumber: 3, size: 1, scaledConfigurationValue: SelectiveReportingInt),
		// (DISABLED by first option) Don't send unless watts have changed by 50 <default>.
		zwave.configurationV1.configurationSet(parameterNumber: 4, size: 2, scaledConfigurationValue: watt2ReportInt),
		// (DISABLED by first option) Or by 5% <default>.
		zwave.configurationV1.configurationSet(parameterNumber: 8, size: 1, scaledConfigurationValue: percentageInt),
		// (DISABLED CRC16 Encapsulaltion O = Disable 1 = Enable)
		zwave.configurationV1.configurationSet(parameterNumber: 13, size: 1, scaledConfigurationValue: 0),
		// Which reports need to send in Report group 1. Old value 6149
		//zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, scaledConfigurationValue: 6149),
        zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, scaledConfigurationValue: parameter101Int),
		// Which reports need to send in Report group 2.
		zwave.configurationV1.configurationSet(parameterNumber: 102, size: 4, scaledConfigurationValue: parameter102Int),
		// Which reports need to send in Report group 3.
		zwave.configurationV1.configurationSet(parameterNumber: 103, size: 4, scaledConfigurationValue: parameter103Int),
		// Interval to send Report group 1.
		zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: monitorInt1),
		// Interval to send Report group 2.
		zwave.configurationV1.configurationSet(parameterNumber: 112, size: 4, scaledConfigurationValue: monitorInt2),
		// Interval to send Report group 3.
		zwave.configurationV1.configurationSet(parameterNumber: 113, size: 4, scaledConfigurationValue: monitorInt3),

		// Report which configuration commands were sent to and received by the HEM Gen5 successfully.
		zwave.configurationV1.configurationGet(parameterNumber: 3),
		zwave.configurationV1.configurationGet(parameterNumber: 4),
		zwave.configurationV1.configurationGet(parameterNumber: 8),
		zwave.configurationV1.configurationGet(parameterNumber: 13),
		zwave.configurationV1.configurationGet(parameterNumber: 101),
		zwave.configurationV1.configurationGet(parameterNumber: 102),
		zwave.configurationV1.configurationGet(parameterNumber: 103),
		zwave.configurationV1.configurationGet(parameterNumber: 111),
		zwave.configurationV1.configurationGet(parameterNumber: 112),
		zwave.configurationV1.configurationGet(parameterNumber: 113),
		zwave.associationV2.associationGet(groupingIdentifier: 1)
	]
	commands(request)
}

private setConfigured() {
	updateDataValue("configured", "true")
}

private isConfigured() {
	getDataValue("configured") == "true"
}

private command(hubitat.zwave.Command cmd) {
	if (state.sec) {
		zwave.securityV1.securityMessageEncapsulation().encapsulate(cmd).format()
	} else {
		cmd.format()
	}
}

private commands(commands, delay=500) {
	delayBetween(commands.collect{ command(it) }, delay)
}
2 Likes