Does the Aeotec Energy Meter Driver Work

I am able to pair with the device but, I do not see any of the configuration options I would expect based upon Aeotec documentation. Does everything have to be configured by sending Z-wave commands or is there something I am missing? Is there a better driver which makes the functionality of this meter more user friendly? When adding this device to the dashboard it simply reports "unknown" regardless of the template I choose "Energy Meter" or "Power Meter"
If I perform a "reset" and "configure" from the device screen I can get a "0.000" on the dashboard but nothing else using the "energy meter" template. Logs do not indicate the device is ever polled for information.

What driver are you using? I have a GEN2 Aeotec that has been running on HE for a couple years now, I ran it on ST and Iris several years before that. I can get power and energy readings from it.

Don't remember where I got the driver I use, but there are a few listed here in the community.

This one seems to work for a number of people.

I am using the Aeon Home Energy Meter that comes with the latest Hubitat release. I'm wondering if I simply need to send the correct z-wave commands to the device to configure it. I have a ticket open with Aeotec so that may lead to a solution. Documentation for the device that applies to Hubitat seems hard to find.

Based on this thread, I just ordered one, lol.

I have had very good luck with Aeotech products in the past. I suspect that once I get it figured out this should be good as well. Just as a warning, the literature which comes with the device is in such small print it is miserable. The online version is much easier to read. I have yet to find good examples of working with and configuring everything for this device from a Hubitat hub. I will post any solution for my issues when I find and test them.

1 Like

I'm sure it'll be a way to while away the long winter evenings.

I have used the Aeotech Gen2 meters for awhile. It took me a bit of sleuthing to get them set up correctly, but now have them working reliably in HE. I use one to monitor hottub usage for both knowing the cost as well as monitoring in case it should lose power. I use another to monitor the washer and dryer so that I get notification when they are done doing their duty. They are in the basement and we cannot hear the little jingle when they finish.

I am using a modified driver that I obtained through another post but again it is for Gen2. As terminal3 posted there is a custom driver for the GEN5 product available.

1 Like

My faith in aeon labs or Aeotech has come through. Technical support provided driver code which corrected my issues. By creating a new driver using the txt file supplied by Aeotech technical support I simply dropped the device and re-added using the driver code supplied. The code was written by Taylor Vierrether and the device worked immediately including in the standard Hubitat dashboard. Reviewing another persons code will make this an excellent learning experience for me as well. It is called "Aeotec Home Energy Monitor (Gen 5)" in the driver code they supplied.

1 Like

Aeotech provided a txt file from which I created a driver which works great.

1 Like

FYI, that's the same driver that @terminal3 linked to earlier in this thread.

1 Like

Looks like I'll have to find something else to while away the dark winter evenings, which is a good thing.

Hello, Can you share the referenced file?

See the link above.

I believe I had to make a tweak in the code to change some attributes from 'string' to 'number'. I think they're all 'number' now, for me.

1 Like

I have a 3 Clamp unit and had been using Taylor's 2 phase driver as it was twice as useful as the single phase hubitat driver.
I contacted Aeotec Support and they managed to tweak the driver to add the 3rd clamp.
I can view the 3 clamps in the Dashboard but can only use the Total in Rule Machine, so have contacted Support again to see if they can expose all 3 clamps to Rule machine.
Anyone else tried to make rules with the individual clamps?

Can you share the driver here? Someone might be able to make the necessary changes.

Ah

Just noticed velvetfoot's comment about attributes needing to be number not string.
Changed them and now all three clamp attributes are available!

1 Like

Here is the tweaked 3 phase driver, the triggers have not been added in for the 3rd clamp, but might be possible to guess what the numbers need to be from the other 2 clamps.

/*

  • Copyright 2020 Taylor Vierrether
  • This program is free software: you can redistribute it and/or modify
  • it under the terms of the GNU General Public License as published by
  • the Free Software Foundation, either version 3 of the License, or
  • (at your option) any later version.
  • This program is distributed in the hope that it will be useful,
  • but WITHOUT ANY WARRANTY; without even the implied warranty of
  • MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  • GNU General Public License for more details.
  • You should have received a copy of the GNU General Public License
  • along with this program. If not, see https://www.gnu.org/licenses/.
    */

/*
*

  • RELEASE HISTORY:
  • - 0.1.0: Initial Release
    
  • - 0.1.1: Fix typo introduced in cleanup of code
    
  • - 0.1.2: Add back in ability to enable debug messaging
    
  • - 0.1.3: Cleanup of cruft and a bit of debug logging added
    
  • - 0.1.4: Tiny bit of cleanup
    

*/

import groovy.transform.Field

//
// Driver Definition
//
metadata {
definition(
name: 'Aeotec Home Energy Monitor 3 phase (Gen 5)',
namespace: 'com.viertaxa.hubitat',
author: 'Taylor Vierrether'
) {
capability 'Configuration'
capability 'Refresh'
capability 'Initialize'

    capability 'EnergyMeter'
    capability 'PowerMeter'
    capability 'VoltageMeasurement'
    capability 'Sensor'

    command 'getConfig'
    command 'resetMeterAccumulation'

    attribute "energy", "number"
    attribute "power", "number"
    attribute "voltage", "number"
    attribute "current", "number"
    attribute "kVar", "number"
    attribute "kVarh", "number"
    attribute "energy-Clamp-1", "number"
    attribute "power-Clamp-1", "number"
    attribute "voltage-Clamp-1", "number"
    attribute "current-Clamp-1", "number"
    attribute "kVar-Clamp-1", "number"
    attribute "kVarh-Clamp-1", "number"
    attribute "energy-Clamp-2", "number"
    attribute "power-Clamp-2", "number"
    attribute "voltage-Clamp-2", "number"
    attribute "current-Clamp-2", "number"
    attribute "kVar-Clamp-2", "number"
    attribute "kVarh-Clamp-2", "number"
    attribute "energy-Clamp-3", "number"
    attribute "power-Clamp-3", "number"
    attribute "voltage-Clamp-3", "number"
    attribute "current-Clamp-3", "number"

    fingerprint deviceId: "95", inClusters: "0x5E,0x86,0x72,0x98,0x56", outClusters: "0x5A", mfr: "134", prod: "258", deviceJoinName: "Aeotec HEM Gen 5"
}

preferences {
    input name: 'enableCrc16Encap', type: 'bool', title: 'Enable CRC16 Encapsulation',
        description: 'Enable CRC16 Encapsulation. NOTE: C-7 currently is dropping CRC16 messages from this device. <em>Strongly</em> recommend leaving disabled.',
        defaultValue: false, required: true
    input name: 'enableSelectiveReport', type: 'bool', title: 'Enable Selective Reporting',
        description: 'Enable reporting only on threshold cross as defined below.',
        defaultValue: false, required: true
    input name: 'reportingMode', type: 'enum', title: 'Reporting Mode',
        description: 'Choose the type of energy reporting', defaultValue: 1,
        options: reportingModes, multiple: false, required: true

    input name: 'wattTriggerCombined', type: 'number', range: 1..60000, title: 'Wattage Report Trigger (Both Clamps Combined)',
        description: 'Enter the wattage delta that will result in a message to be sent',
        defaultValue: 50, required: true
    input name: 'wattTriggerClamp1', type: 'number', range: 1..60000, title: 'Wattage Report Trigger (Clamp 1)',
        description: 'Enter the wattage delta that will result in a message to be sent',
        defaultValue: 50, required: true
    input name: 'wattTriggerClamp2', type: 'number', range: 1..60000, title: 'Wattage Report Trigger (Clamp 2)',
       description: 'Enter the wattage delta that will result in a message to be sent',
        defaultValue: 50, required: true

    input name: 'wattPctTriggerCombined', type: 'number', range: 1..100, title: 'Wattage Percent Report Trigger (Both Clamps Combined)',
        description: 'Enter the wattage delta percentage that will result in a message to be sent',
        defaultValue: 10, required: true
    input name: 'wattPctTriggerClamp1', type: 'number', range: 1..100, title: 'Wattage Percent Report Trigger (Clamp 1)',
        description: 'Enter the wattage delta percentage that will result in a message to be sent',
        defaultValue: 10, required: true
    input name: 'wattPctTriggerClamp2', type: 'number', range: 1..100, title: 'Wattage Percent Report Trigger (Clamp 2)',
        description: 'Enter the wattage delta percentage that will result in a message to be sent',
        defaultValue: 10, required: true

    input name: 'group1ReportValues', type: 'enum', title: 'Group 1 Reports',
        description: 'Choose which values will be reported for group 1',
        defaultValue: 2, options: reportOptions, multiple: true, required: true
    input name: 'group2ReportValues', type: 'enum', title: 'Group 2 Reports',
        description: 'Choose which values will be reported for group 2',
        defaultValue: 1, options: reportOptions, multiple: true, required: true
    input name: 'group3ReportValues', type: 'enum', title: 'Group 3 Reports',
        description: 'Choose which values will be reported for group 3',
        defaultValue: 0, options: reportOptions, multiple: true, required: true

    input name: 'group1ReportInterval', type: 'number', range: 1..4294967295, title: 'Group 1 Report Interval',
        description: 'Choose how frequently values will be reported for group 1 in seconds',
        defaultValue: 5, required: true
    input name: 'group2ReportInterval', type: 'number', range: 1..4294967295, title: 'Group 2 Report Interval',
        description: 'Choose how frequently values will be reported for group 2 in seconds',
        defaultValue: 120, required: true
    input name: 'group3ReportInterval', type: 'number', range: 1..4294967295, title: 'Group 3 Report Interval',
        description: 'Choose how frequently values will be reported for group 3 in seconds',
        defaultValue: 120, required: true
    input name: 'logDebugMessages', type: 'bool', title: 'Enable Debug Logging',
        defaultValue: false, required: true
}

}
//
// STATIC DATA
//
@Field def reportingModes = [
0: 'Power & Energy Absolute Value',
1: '+/- Power & Summed Energy',
2: '+/- Power, Only Positive Energy (Consumption)',
3: '+/- Power, Only Negative Energy (Generation)'
]

@Field def reportOptions = [
0: 'None',
1: 'kWh Total',
2: 'W Total',
4: 'V Total',
8: 'A Total',
16: 'kVarh Total',
32: 'kVar Total',
//64: "", //Reserved
//128: "", //Reserved
256: 'W Clamp 1',
512: 'W Clamp 2',
1024: "W Clamp 3", //Reserved
2048: 'kWh Clamp 1',
4096: 'kWh Clamp 2',
8192: "kWh Clamp 3", //Reserved
//16384: "", //Reserved
//32768: "", //Reserved
65536: 'V Clamp 1',
131072: 'V Clamp 2',
262144: "V Clamp 3", //Reserved
524288: 'A Clamp 1',
1048576: 'A Clamp 2',
2097152: "A Clamp 3", //Reserved
//4194304: '', //Reserved
//8388608: '', //Reserved
//16777216: 'kVarh Clamp 1',
//33554432: 'kVarh Clamp 2',
//67108864: '', //Reserved
//134217728: 'kVar Clamp 1',
//268435456: 'kVar Clamp 2'

]

@Field def commandClasses = [
0x5E: 2, // COMMAND_CLASS_ZWAVEPLUS_INFO V2COMMAND_CLASS_VERSION V2
0x72: 2, // COMMAND_CLASS_MANUFACTURER_SPECIFIC V2
0x32: 4, // COMMAND_CLASS_METER V4
0x56: 1, // COMMAND_CLASS_CRC_16_ENCAP V1
0x60: 4, // COMMAND_CLASS_MULTI_CHANNEL V4
0x8E: 3, // COMMAND_CLASS_MULTI_CHANNEL_ASSOCIATION_V3
0x70: 1, // COMMAND_CLASS_CONFIGURATION V1
0x59: 1, // COMMAND_CLASS_ASSOCIATION_GRP_INFO V1
0x85: 2, // COMMAND_CLASS_ASSOCIATION V2
0x7A: 2, // COMMAND_CLASS_FIRMWARE_UPDATE_MD V2
0x73: 1, // COMMAND_CLASS_POWERLEVEL V1
0x98: 1, // COMMAND_CLASS_SECURITY V1
//0xEF: 1, // COMMAND_CLASS_MARK V1
0x5A: 1 // COMMAND_CLASS_DEVICE_RESET_LOCALLY V1
]

def getRefreshAllDataCommands(){
[
// Whole HEM
zwave.meterV4.meterGet(scale: 0), //kWh
zwave.meterV4.meterGet(scale: 1), //kVAh
zwave.meterV4.meterGet(scale: 2), //W
zwave.meterV4.meterGet(scale: 3), //Pulse count
zwave.meterV4.meterGet(scale: 4), //V
zwave.meterV4.meterGet(scale: 5), //A
zwave.meterV4.meterGet(scale: 6), //Power Factor
//zwave.meterV4.meterGet(scale: 7, scale2: 0), //kVar
//zwave.meterV4.meterGet(scale: 7, scale2: 1), //kVarh

// Clamp 1
zwave.multiChannelV4.multiChannelCmdEncap(destinationEndPoint: 1).encapsulate(zwave.meterV4.meterGet(scale: 0)), //kWh
zwave.multiChannelV4.multiChannelCmdEncap(destinationEndPoint: 1).encapsulate(zwave.meterV4.meterGet(scale: 1)), //kVAh
zwave.multiChannelV4.multiChannelCmdEncap(destinationEndPoint: 1).encapsulate(zwave.meterV4.meterGet(scale: 2)), //W
zwave.multiChannelV4.multiChannelCmdEncap(destinationEndPoint: 1).encapsulate(zwave.meterV4.meterGet(scale: 3)), //Pulse count
zwave.multiChannelV4.multiChannelCmdEncap(destinationEndPoint: 1).encapsulate(zwave.meterV4.meterGet(scale: 4)), //V
zwave.multiChannelV4.multiChannelCmdEncap(destinationEndPoint: 1).encapsulate(zwave.meterV4.meterGet(scale: 5)), //A
zwave.multiChannelV4.multiChannelCmdEncap(destinationEndPoint: 1).encapsulate(zwave.meterV4.meterGet(scale: 6)), //Power Factor
//zwave.multiChannelV4.multiChannelCmdEncap(destinationEndPoint: 1).encapsulate(zwave.meterV4.meterGet(scale: 7, scale2: 0)), //kVar
//zwave.multiChannelV4.multiChannelCmdEncap(destinationEndPoint: 1).encapsulate(zwave.meterV4.meterGet(scale: 7, scale2: 1)), //kVarh

// Clamp 2
zwave.multiChannelV4.multiChannelCmdEncap(destinationEndPoint: 2).encapsulate(zwave.meterV4.meterGet(scale: 0)), //kWh
zwave.multiChannelV4.multiChannelCmdEncap(destinationEndPoint: 2).encapsulate(zwave.meterV4.meterGet(scale: 1)), //kVAh
zwave.multiChannelV4.multiChannelCmdEncap(destinationEndPoint: 2).encapsulate(zwave.meterV4.meterGet(scale: 2)), //W
zwave.multiChannelV4.multiChannelCmdEncap(destinationEndPoint: 2).encapsulate(zwave.meterV4.meterGet(scale: 3)), //Pulse count
zwave.multiChannelV4.multiChannelCmdEncap(destinationEndPoint: 2).encapsulate(zwave.meterV4.meterGet(scale: 4)), //V
zwave.multiChannelV4.multiChannelCmdEncap(destinationEndPoint: 2).encapsulate(zwave.meterV4.meterGet(scale: 5)), //A
zwave.multiChannelV4.multiChannelCmdEncap(destinationEndPoint: 2).encapsulate(zwave.meterV4.meterGet(scale: 6)), //Power Factor
//zwave.multiChannelV4.multiChannelCmdEncap(destinationEndPoint: 2).encapsulate(zwave.meterV4.meterGet(scale: 7, scale2: 0)), //kVar
//zwave.multiChannelV4.multiChannelCmdEncap(destinationEndPoint: 2).encapsulate(zwave.meterV4.meterGet(scale: 7, scale2: 1)) //kVarh
    
// Clamp 3
zwave.multiChannelV4.multiChannelCmdEncap(destinationEndPoint: 3).encapsulate(zwave.meterV4.meterGet(scale: 0)), //kWh
zwave.multiChannelV4.multiChannelCmdEncap(destinationEndPoint: 3).encapsulate(zwave.meterV4.meterGet(scale: 1)), //kVAh
zwave.multiChannelV4.multiChannelCmdEncap(destinationEndPoint: 3).encapsulate(zwave.meterV4.meterGet(scale: 2)), //W
zwave.multiChannelV4.multiChannelCmdEncap(destinationEndPoint: 3).encapsulate(zwave.meterV4.meterGet(scale: 3)), //Pulse count
zwave.multiChannelV4.multiChannelCmdEncap(destinationEndPoint: 3).encapsulate(zwave.meterV4.meterGet(scale: 4)), //V
zwave.multiChannelV4.multiChannelCmdEncap(destinationEndPoint: 3).encapsulate(zwave.meterV4.meterGet(scale: 5)), //A
zwave.multiChannelV4.multiChannelCmdEncap(destinationEndPoint: 3).encapsulate(zwave.meterV4.meterGet(scale: 6)), //Power Factor
]

}

//
// Capability Methods
//
def updated() {
logTrace "Entering Updated"
logTrace "Calling initialze"
initialize()
logTrace "Calling configure"
configure()
logTrace "Exiting updated"
}

def initialize() {
logTrace "Entering: initialize"
state.clear()
getConfig()
logTrace "Exiting: initialize"
}

def refresh() {
logTrace "Entering refresh"
logTrace "Calling runCommandsWithInterstitialDelay"
runCommandsWithInterstitialDelay refreshAllDataCommands
logTrace "Exiting refresh"
}

def configure() {
logTrace "Entering configure"
logInfo "Sending configuration for ${device.label}"

logDebug "Generating configuration command list"
logDebug "Setting param 3, size 1, value ${enableSelectiveReport ? 1 : 0}"
logDebug "Setting param 13, size 1, value ${enableCrc16Encap ? 1 : 0}"
logDebug "Setting param 2, size 1, value ${reportingMode.toInteger()}"
logDebug "Setting param 4, size 2, value ${wattTriggerCombined.toInteger()}"
logDebug "Setting param 5, size 2, value ${wattTriggerClamp1.toInteger()}"
logDebug "Setting param 6, size 2, value ${wattTriggerClamp2.toInteger()}"
logDebug "Setting param 8, size 1, value ${wattPctTriggerCombined.toInteger()}"
logDebug "Setting param 9, size 1, value ${wattPctTriggerClamp1.toInteger()}"
logDebug "Setting param 10, size 1, value ${wattPctTriggerClamp2.toInteger()}"
logDebug "Setting param 101, size 4, value ${group1ReportValues.collect{ it.toInteger() }.sum()}"
logDebug "Setting param 102, size 4, value ${group2ReportValues.collect{ it.toInteger() }.sum()}"
logDebug "Setting param 103, size 4, value ${group3ReportValues.collect{ it.toInteger() }.sum()}"
logDebug "Setting param 111, size 4, value ${group1ReportInterval.toInteger()}"
logDebug "Setting param 112, size 4, value ${group2ReportInterval.toInteger()}"
logDebug "Setting param 113, size 4, value ${group3ReportInterval.toInteger()}"

def commands = [
   
    //General Config

    // Selective Reports
    zwave.configurationV1.configurationSet(parameterNumber: 3, size: 1, scaledConfigurationValue: enableSelectiveReport ? 1 : 0),
    //CRC16 Encapsulation
    zwave.configurationV1.configurationSet(parameterNumber: 13, size: 1, scaledConfigurationValue: enableCrc16Encap ? 1 : 0),
    //Reporting Mode
    zwave.configurationV1.configurationSet(parameterNumber: 2, size: 1, scaledConfigurationValue: reportingMode.toInteger()),

    //Threshold Configuration

    //Trigger HEM watts with change by this value
    zwave.configurationV1.configurationSet(parameterNumber: 4, size: 2, scaledConfigurationValue: wattTriggerCombined.toInteger()),
    //Trigger clamp 1 watts with change by this value
    zwave.configurationV1.configurationSet(parameterNumber: 5, size: 2, scaledConfigurationValue: wattTriggerClamp1.toInteger()),
    //Trigger clamp 2 watts with change by this value
    zwave.configurationV1.configurationSet(parameterNumber: 6, size: 2, scaledConfigurationValue: wattTriggerClamp2.toInteger()),
    //Trigger HEM watts with change by this percent
    zwave.configurationV1.configurationSet(parameterNumber: 8, size: 1, scaledConfigurationValue: wattPctTriggerCombined.toInteger()),
    //Trigger clamp 1 watts with change by this percent
   zwave.configurationV1.configurationSet(parameterNumber: 9, size: 1, scaledConfigurationValue: wattPctTriggerClamp1.toInteger()),
    //Trigger clamp 2 watts with change by this percent
    zwave.configurationV1.configurationSet(parameterNumber: 10, size: 1, scaledConfigurationValue: wattPctTriggerClamp2.toInteger()),

    // Reporting Group Configuration

    // Which reports need to send in Report group 1.
    zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, scaledConfigurationValue: group1ReportValues.collect{ it.toInteger() }.sum()),
    // Which reports need to send in Report group 2.
    zwave.configurationV1.configurationSet(parameterNumber: 102, size: 4, scaledConfigurationValue: group2ReportValues.collect{ it.toInteger() }.sum()),
    // Which reports need to send in Report group 3.
    zwave.configurationV1.configurationSet(parameterNumber: 103, size: 4, scaledConfigurationValue: group3ReportValues.collect{ it.toInteger() }.sum()),
    // Interval to send Report group 1.
    zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: group1ReportInterval.toInteger()),
    // Interval to send Report group 2.
    zwave.configurationV1.configurationSet(parameterNumber: 112, size: 4, scaledConfigurationValue: group2ReportInterval.toInteger()),
    // Interval to send Report group 3.
    zwave.configurationV1.configurationSet(parameterNumber: 113, size: 4, scaledConfigurationValue: group3ReportInterval.toInteger())
]

runCommandsWithInterstitialDelay(commands, 300)

runIn(10, 'getConfig')

runIn(25, 'setAssociations')

}

def parse(String description) {
logTrace "Entering parse()"
logTrace description
logTrace "Calling zwave.parse()"
def cmd = zwave.parse(description, commandClasses)
if (cmd) {
logTrace "cmd parsed"
return zwaveEvent(cmd)
}
else {
logErr("Command not able to be parsed: $description")
}
}

//
// Custom Command Methods
//
def getConfig() {
logTrace "Entering getConfig"
def commands = [
zwave.configurationV1.configurationGet(parameterNumber: 2), //Energy detection mode configuration for parameters 101~103
zwave.configurationV1.configurationGet(parameterNumber: 3), //enable/disable parameter selective reporting parameters 4~10
zwave.configurationV1.configurationGet(parameterNumber: 4), //Induce an automatic report of HEM by watts
zwave.configurationV1.configurationGet(parameterNumber: 5), //Induce an automatic report of Channel 1 by watts
zwave.configurationV1.configurationGet(parameterNumber: 6), //Induce an automatic report of Channel 2 by watts
zwave.configurationV1.configurationGet(parameterNumber: 8), //Induce an automatic report of HEM by percent
zwave.configurationV1.configurationGet(parameterNumber: 9), //Induce an automatic report of Channel 1 by percent
zwave.configurationV1.configurationGet(parameterNumber: 10), //Induce an automatic report of Channel 2 by percent
zwave.configurationV1.configurationGet(parameterNumber: 13), //Enable/disable CRC-16 Encapsulation
zwave.configurationV1.configurationGet(parameterNumber: 101), //Report group 1 reports
zwave.configurationV1.configurationGet(parameterNumber: 102), //Report group 2 reports
zwave.configurationV1.configurationGet(parameterNumber: 103), //Report group 3 reports
zwave.configurationV1.configurationGet(parameterNumber: 111), //Report group 1 frequency
zwave.configurationV1.configurationGet(parameterNumber: 112), //Report group 2 frequency
zwave.configurationV1.configurationGet(parameterNumber: 113), //Report group 3 frequency
zwave.configurationV1.configurationGet(parameterNumber: 200), //Is Aeon or Third-party
zwave.configurationV1.configurationGet(parameterNumber: 252), //Configuration locked?

    zwave.versionV2.versionGet(),
    zwave.manufacturerSpecificV2.manufacturerSpecificGet()
]

logTrace "Calling runCommandsWithInterstitialDelay"
runCommandsWithInterstitialDelay commands

logTrace "Scheduling refreshAssociations"
runIn 10, "refreshAssociations"
logTrace "Exiting getConfig"

}

def resetMeterAccumulation() {
logTrace "Entering resetMeterAccumulation"
def commands = [
zwave.meterV4.meterReset()
]

logTrace "Appending refreshAllData commands"
commands.addAll refreshAllDataCommands

logTrace "Calling runCommandsWithInterstitialDelay"
runCommandsWithInterstitialDelay commands
logTrace "Exiting resetMeterAccumulation"

}

def refreshAssociations() {
logTrace "Entering refreshAssociations()"

commands = [
    zwave.associationV2.associationGet(groupingIdentifier: 1),
    zwave.multiChannelAssociationV3.multiChannelAssociationGet(groupingIdentifier: 1)
]

logTrace "Calling runCommandsWithInterstitialDelay"
runCommandsWithInterstitialDelay commands

logTrace "Exiting refreshAssociations"

}

def setAssociations() {
logTrace "Entering setAssociations"

logTrace "Iterating on associatedNodes"
state.associatedNodes[1].each { node ->
    logTrace "Removing node: $node"
    runCommand(zwave.associationV2.associationRemove(groupingIdentifier: 1, nodeId: node.toInteger()))
    pauseExecution(1)
}
logTrace "Refreshing Associations"
refreshAssociations()
pauseExecution(5)
logTrace "Iterating on multiChannelAssociations"
state.multiChannelAssociations[1].each { node ->
    logTrace "Removing node: $node"
    runCommand(zwave.multiChannelAssociationV3.multiChannelAssociationRemove(groupingIdentifier: 1, nodeId: [node]))
    pauseExecution(1)
}
logTrace "Refreshing Associations"
refreshAssociations()
pauseExecution(5)
logTrace "Iterating on multiChannelAssociationsMultiChannelNodeIDs"
state.multiChannelAssociationsMultiChannelNodeIDs[1].each{ nodeAssociation ->
    logTrace "Removing node: $nodeAssociation"
    runCommand(zwave.multiChannelAssociationV3.multiChannelAssociationRemove(groupingIdentifier: 1, multiChannelNodeIds: nodeAssociation))
    pauseExecution(1)
}
logTrace "Refreshing Associations"
refreshAssociations()
logTrace "Adding Hub back in"
runCommand(zwave.associationV2.associationSet(groupingIdentifier: 1, nodeId: 1))
pauseExecution(1)
logTrace "Refreshing Associations"
refreshAssociations()

}

//
// zwaveEvent Methods
//

def zwaveEvent(hubitat.zwave.Command cmd) {
logErr "Unhandled: $cmd"
cmd.properties.each { logTrace "$it.key => $it.value"}
}

//COMMAND_CLASS_ZWAVEPLUS_INFO V2
// NOTE: Unlikely to receive one of these, as there's no Get method in Hubitat,
// but we will handle and log the information just in case.
def zwaveEvent(hubitat.zwave.commands.zwaveplusinfov2.ZwaveplusInfoReport cmd) {
logTrace 'zwaveEvent(hubitat.zwave.commands.zwaveplusinfov2.ZwaveplusInfoReport cmd)'
logTrace cmd
cmd.properties.each { p -> logTrace "${p.key} => ${p.value}"}
}
//COMMAND_CLASS_VERSION V2
def zwaveEvent(hubitat.zwave.commands.versionv2.VersionReport cmd) {
logTrace "zwaveEvent(hubitat.zwave.commands.versionv2.VersionReport cmd)"
logTrace cmd
cmd.properties.each { p -> logTrace "${p.key} => ${p.value}"}

def firmwareStr = "${cmd.firmware0Version}.${cmd.firmware0SubVersion}"
def zwaveVerStr = "${cmd.zWaveProtocolVersion}.${cmd.zWaveProtocolSubVersion}"
def hwVerStr = "$cmd.hardwareVersion"

updateDataValue("firmware", firmwareStr)
updateDataValue("zwave-version", zwaveVerStr)
updateDataValue("hardware-version", hwVerStr)
logDebug "${device.displayName} is running firmware version: $firmwareStr, Z-Wave version: $zwaveVerStr"

}
//COMMAND_CLASS_MANUFACTURER_SPECIFIC V2
def zwaveEvent(hubitat.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
logTrace 'zwaveEvent(hubitat.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd)'
logTrace cmd
cmd.properties.each { p -> logTrace "${p.key} => ${p.value}"}
}
//COMMAND_CLASS_METER V4
def zwaveEvent(hubitat.zwave.commands.meterv4.MeterReport cmd, int endpoint = 0) {
logTrace 'zwaveEvent(hubitat.zwave.commands.meterv4.MeterReport cmd, int clampNo = 0)'
logTrace cmd
cmd.properties.each { p -> logTrace "${p.key} => ${p.value}"}

def source = endpoint == 0 ? '' : "-Clamp-$endpoint"

def label = Null
switch (cmd.scale){
    case 0: //kWh
        unit = 'kWh'
        label = 'energy'
        break
    case 1: //kVAh
        unit = 'kVAh'
        label = 'kVAh'
        break
    case 2: //W
        unit = 'W'
        label = 'power'
        break
    case 3: //Pulse count
        unit = 'Hz'
        label = 'Cycles'
        break
    case 4: //V
        unit = 'V'
        label = 'voltage'
        break
    case 5: //A
        unit = 'A'
        label = 'current'
        break
    case 6: //Power Factor
        unit = ''
        label = 'PF'
        break
    case 7:
        switch (cmd.scale2){
            case 0: //kVar
                unit = 'kVar'
                label = 'kVar'
                break
            case 1: //kVarh
                unit = 'kVarh'
                label = 'kVarh'
                break
            default:
                logErr "Scale not implemented. ${cmd.scale}, ${cmd.scale2}: ${cmd.scaledMeterValue}"
                break
        }
        break
    default:
        logWarn "Scale not implemented. ${cmd.scale}, ${cmd.scale2}: ${cmd.scaledMeterValue}"
        break
}
logDebug "Got message for endpoint: $endpoint for scale: $cmd.scale, scale2: $cmd.scale2 value: $cmd.scaledMeterValue"
sendEvent(name: "$label$source", value: cmd.scaledMeterValue.toFloat(), unit: unit)

}
//COMMAND_CLASS_CRC_16_ENCAP V1
// CRC16 handled by Hubitat C-7

//COMMAND_CLASS_MULTI_CHANNEL V4
def zwaveEvent(hubitat.zwave.commands.multichannelv4.MultiChannelCmdEncap cmd) {
logTrace "Entering zwaveEvent(hubitat.zwave.commands.multichannelv4.MultiChannelCmdEncap cmd)"
logTrace "Attempting to unpack the encapsulated command"
zwaveEvent cmd.encapsulatedCommand(), cmd.sourceEndPoint.toInteger()

}
//COMMAND_CLASS_MULTI_CHANNEL_ASSOCIATION_V3
def zwaveEvent(hubitat.zwave.commands.multichannelassociationv3.MultiChannelAssociationReport cmd) {
logTrace 'hubitat.zwave.commands.multichannelassociationv3.MultiChannelAssociationReport'

cmd.properties.each{ logTrace "${it.key} => ${it.value}" }

if (!state.multiChannelAssociations) state.multiChannelAssociations = []
if (!state.multiChannelAssociationsMultiChannelNodeIDs) state.multiChannelAssociationsMultiChannelNodeIDs = []

state.multiChannelAssociations[cmd.groupingIdentifier] = cmd.nodeId
state.multiChannelAssociationsMultiChannelNodeIDs[cmd.groupingIdentifier] = cmd.multiChannelNodeIds

}
//COMMAND_CLASS_CONFIGURATION V1
def zwaveEvent(hubitat.zwave.commands.configurationv1.ConfigurationReport cmd) {
logTrace 'zwaveEvent(hubitat.zwave.commands.configurationv1.ConfigurationReport cmd)'
logTrace cmd
cmd.properties.each{ logTrace "${it.key} => ${it.value}" }

logInfo "$device.displayName has value '$cmd.scaledConfigurationValue' for property with ID '$cmd.parameterNumber'"

}
//COMMAND_CLASS_ASSOCIATION_GRP_INFO V1
//We don't need to support this one.
//COMMAND_CLASS_ASSOCIATION V2
def zwaveEvent(hubitat.zwave.commands.associationv2.AssociationReport cmd) {
logTrace 'hubitat.zwave.commands.associationv2.AssociationReport'
cmd.properties.each{ logTrace "${it.key} => ${it.value}" }
if (!state.associatedNodes) {
state.associatedNodes = []
}
state.associatedNodes[cmd.groupingIdentifier] = cmd.nodeId
}
//COMMAND_CLASS_FIRMWARE_UPDATE_MD V2
//No Need for us to do anything with this CC
//COMMAND_CLASS_POWERLEVEL V1
//Not going to handle this here, info is available on Z-Wave Settings page
//COMMAND_CLASS_SECURITY V1
// Security handled by Hubitat on C-7
//COMMAND_CLASS_DEVICE_RESET_LOCALLY V1
def zwaveEvent(hubitat.zwave.commands.deviceresetlocallyv1.DeviceResetLocallyNotification cmd) {
logTrace 'zwaveEvent(hubitat.zwave.commands.deviceresetlocallyv1.DeviceResetLocallyNotification cmd)'
logTrace cmd
cmd.properties.each{ logTrace "${it.key} => ${it.value}" }

logErr "WARNING: $device.displayName sent a DeviceResetLocallyNotification!"

}

//
// Custom Methods
//
def logErr(message) {
log.error message
}

def logWarn(message) {
log.warn message
}

def logInfo(message) {
log.info message
}

def logDebug(message) {
if (logDebugMessages) log.debug message
}

def logTrace(message) {
//VERY VERBOSE. Only enable during development!
def logTraceMessages = false
if (logTraceMessages) log.trace message
}
def runCommandsWithInterstitialDelay(commands, delay = 300) {
logTrace "Entering runCommandsWithInterstitialDelay"

logTrace "Calling delayBetween"
commandsWithDelays = delayBetween(commands.collect { command -> zwaveSecureEncap command }, delay)

commandsWithDelays.each { command -> logTrace command }

logTrace "Generating hubMultiAction"
multiAction = new hubitat.device.HubMultiAction(commandsWithDelays, hubitat.device.Protocol.ZWAVE)

logTrace "Sending multiAction"
sendHubCommand multiAction

logTrace "Returning from runCommandsWithInterstitialDelay"

}

def runCommand(command) {
logTrace "Entering runCommand"

logTrace "Generating hubAction for command ${zwaveSecureEncap(command)}"
action = new hubitat.device.HubAction(zwaveSecureEncap(command), hubitat.device.Protocol.ZWAVE)

logTrace "Sending hubAction"
sendHubCommand action
logTrace "Returning from runCommand"

}

My meter has been cranking out total house numbers every 5 seconds for 6 months now without missing a beat. I don't do much with the data. Check it at the end of the month, see if it's high when we leave the house in case we left something on, just look at it once in a while. I need to get into graphing, but I haven't yet.

image