Aeon Home Energy Meter v1 -- Read Clamps Separately

01/14/2017 – Status Update #5
This Device Handler no longer works correctly. Multiple members have experienced the same issue with incorrect data being generated into the GUI. However, you may want to look at Omyn’s post where they posted an update to the code with new options and features. Might be worth a look!

01/12/2017 – Status Update #4
Informational Update: For those interested in using this code to monitor 120v line sources instead of 240v, please see post #21. If no changes are made to the code, then the HEM will assume a voltage of 240v for each line.

10/24/2015 – Status Update #3
Layout finalized, code published to github. Currently setup for 240v with ‘HVAC’ on L1 and ‘Dryer’ on L2. Example layout:

10/12/2015 – Status Update #2
With everyone’s help, the baseline code from Barry’s GitHub @storageanarchy has been slightly modified and forked as a work in progress. Direct link here. The only real changes at this point are commented out lines to support v1 and to disable all color changing code to support (read: not break) Android devices. Everything else is the same.

10/08/2015 – Status Update #1
Original post as shown below, asking the community for help.


Original Post:

Another owner of the Aeon HEM v1 here, trying to figure out how to separate the combined wattage/kWh from the two clamps into two individual wattage/kWh measurements (more on this below). I’ve searched and read through other posts (here, here, here) but could not find an answer. Please let me know if this has been asked solved already and I maybe missed it? :blush:

The HEM is great for measuring the whole house energy usage, however my goal is to use each of the clamps individually on two circuit breakers. This is to allow the monitoring of two individual “high consumption” devices, like an AC unit or a clothes dryer. Unfortunately, all of the code I’ve found combines the reading of each clamp into a single value.

From my research so far, I believe the code that needs to be changed is parameter number 101 and 102 (for combined energy). But I’m certainly no programmer and could be going in the wrong direction here.

zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, scaledConfigurationValue: 4).format(),   // Combined energy in Watts
zwave.configurationV1.configurationSet(parameterNumber: 102, size: 4, scaledConfigurationValue: 8).format(),    // Combined energy in kWh

.

However, I did figure out (or, rather, saw in someone else’s code) parameter number 1 which sets the ‘assumed’ voltage value that the HEM uses to calculate the wattage using Ohm’s law. (Remember, the clamps are actually measuring amperage via induction, and then making a wattage calculation based on the ‘assumed’ voltage). The devices I’m measuring are using 240v (AC unit, clothes dryer) so the value has to be adjusted accordingly.

zwave.configurationV1.configurationSet(parameterNumber: 1, size: 2, scaledConfigurationValue: 240).format(),   // assumed voltage

.
The only documentation I found was this random PDF (from this thread) which goes into detail on the parameters, however it’s somewhat over my head. I created a new device type using the ‘Aeon Home Energy Meter’ template and modified these two parameter values, but it simply generated errors under the ‘Live Logging’ for that device.

Any ideas, thoughts or feedback on how to accomplish this would be greatly appreciated! Thank you! :smile:

Edit #1: Highlighted in yellow below, I think this the ticket for the configuration flags, but again I can’t make heads or tails of what value is actually required. I’ve tried 0-7 in my custom device type, but anything other than the default values created an error. This table is from the PDF referenced above.

5 Likes

pretty good yeoman’s work so far. I’m eager to see this pan out. HEMv1 seems like a good value.

It’s a bitmap single byte right? NO it’s 4 bytes eh?

so 0x00001B0F = 6927 should report kWH and watts for clamp1 and clamp2, and auto-send all reports. Or something like that.

I guess 0 thru 7 should do something anyway. What does the error say? What is the default value?

I use a modified version of Aeon HEM v2+ device type that has a toggle button that will show the wattage from the individual clamps. I don’t remember the post where I got the code but here it is, if you want to try it.

Edit: I re-pasted the code properly down below.

1 Like

Thank you for your reply! :smile:
Not sure I completely understand, but the conversion between a base16 and base10 makes sense. Could you elaborate on how that was calculated? (The 0x00001B0F figure)
.

Thank you for your reply! :smile:
EXCELLENT! I’ll give this a go and start tinkering. Thank you for sharing!

When/if this gets figured out, I’ll update the original post with the code so it’s available to others looking for a similar solution.

Thanks again :smiley:
.
.
Update #1: Tried the code and things didn’t go well. The phone shows a ‘Sorry, but there was an unexpected error’ and the below is what shows up in the live logging for this device:

8:52:32 PM: error groovy.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] @ line 392

.
Line 392 is as follows:

BigDecimal costDecimal = newValue * ( kWhCost as BigDecimal )

While I certainly don’t understand it all, I’m going to go through the code and see if I can figure out what is providing the two different clamp energy values.

@Jimxenus – Do you have the v1 or v2 of the HEM device?
.
.
Update #2: I think the code comes from Barry’s GitHub @storageanarchy
(Or at least the majority of the code base)

I have v1 even though this one says v2+. I think it is designed to work for both versions. You did put this in as a device type? The code may not work well on an Android device because of the color tiles. I remember reading that color tiles would mess up on Androids. You might want to comment that code out.

Maybe I shouldn’t have just pasted the code in the forum? Perhaps some spacing got messed up? I will look for a better way to upload it.

1 Like

When “pasting code” you have two good options:

  1. Link from GitHub (GitHub is worth learning, even just the very basics, since SmartThings now integrates with it). The Forum software automatically recognizes GitHub based links and formats appropriately, and you can then point to dynamic code instead of editing your post(s).

  2. Paste the raw code into the Forum editor and surround with three back quotes – this can be done by selecting the pasted code and pressing the </> symbol in the editor format header bar.

OK, thanks for tip @tgauchat, I’m going to try re-pasting the code again:

/**
* Aeon HEMv2+
*
* Copyright 2014 Barry A. Burke
*
* 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)
*
* History:
*
* 2014-06-13: Massive OverHaul
* - Fixed Configuration (original had byte order of bitstrings backwards
* - Increased reporting frequency to 10s - note that values won't report unless they change
* (they will also report if they exceed limits defined in the settings - currently just using
* the defaults).
* - Added support for Volts & Amps monitoring (was only Power and Energy)
* - Added flexible tile display. Currently only used to show High and Low values since last
* reset (with time stamps).
* - All tiles are attributes, so that their values are preserved when you're not 'watching' the
* meter display
* - Values are formatted to Strings in zwaveEvent parser so that we don't lose decimal values
* in the tile label display conversion
* - Updated fingerprint to match Aeon Home Energy Monitor v2 deviceId & clusters
* - Added colors for Watts and Amps display
* - Changed time format to 24 hour
* 2014-06-17: Tile Tweaks
* - Reworked "decorations:" - current values are no longer "flat"
* - Added colors to current Watts (0-18000) & Amps (0-150)
* - Changed all colors to use same blue-green-orange-red as standard ST temperature guages
* 2014-06-18: Cost calculations
* - Added $/kWh preference
* 2014-09-07: Bug fix & Cleanup
* - Fixed "Unexpected Error" on Refresh tile - (added Refresh Capability)
* - Cleaned up low values - reset to ridiculously high value instead of null
* - Added poll() command/capability (just does a refresh)
* 2014-09-19: GUI Tweaks, HEM v1 alterations (from Brock Haymond)
* - Reworked all tiles for look, color, text formatting, & readability
* 2014-09-20: Added HEMv1 Battery reporting (from Brock Haymond)
* 2014-11-06: Added alternate display of L2 and L2 values instead of Low/High, based on version by Jayant Jhamb
* 2014-11-11: Massive overhaul completed (see GitHub comments for specifics)
* -
*/
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"
capability "Battery"
attribute "energy", "string"
attribute "power", "string"
attribute "volts", "string"
attribute "voltage", "string"    // We'll deliver both, since the correct one is not defined anywhere
attribute "amps", "string"
attribute "energyDisp", "string"
attribute "energyOne", "string"
attribute "energyTwo", "string"
attribute "powerDisp", "string"
attribute "powerOne", "string"
attribute "powerTwo", "string"
attribute "voltsDisp", "string"
attribute "voltsOne", "string"
attribute "voltsTwo", "string"
attribute "ampsDisp", "string"
attribute "ampsOne", "string"
attribute "ampsTwo", "string"
command "reset"
command "configure"
command "refresh"
command "poll"
command "toggleDisplay"
// v1 fingerprint deviceId: "0x2101", inClusters: " 0x70,0x31,0x72,0x86,0x32,0x80,0x85,0x60"
fingerprint deviceId: "0x3101", inClusters: "0x70,0x32,0x60,0x85,0x56,0x72,0x86"
}
// simulator metadata
simulator {
for (int i = 0; i <= 10000; i += 1000) {
status "power ${i} W": new physicalgraph.zwave.Zwave().meterV1.meterReport(
scaledMeterValue: i, precision: 3, meterType: 33, scale: 2, size: 4).incomingMessage()
}
for (int i = 0; i <= 100; i += 10) {
status "energy ${i} kWh": new physicalgraph.zwave.Zwave().meterV1.meterReport(
scaledMeterValue: i, precision: 3, meterType: 33, scale: 0, size: 4).incomingMessage()
}
// TODO: Add data feeds for Volts and Amps
}
// tile definitions
tiles {
// Watts row
valueTile("powerDisp", "device.powerDisp") {
state (
"default",
label:'${currentValue}',
foregroundColors:[
[value: 1, color: "#000000"],
[value: 10000, color: "#ffffff"]
],
foregroundColor: "#000000",
backgroundColors:[
[value: "0 Watts", color: "#153591"],
[value: "500 Watts", color: "#1e9cbb"],
[value: "1000 Watts", color: "#90d2a7"],
[value: "1500 Watts", color: "#44b621"],
[value: "2000 Watts", color: "#f1d801"],
[value: "2500 Watts", color: "#d04e00"],
[value: "3000 Watts", color: "#bc2323"]
/* For low-wattage homes, use these values
[value: "0 Watts", color: "#153591"],
[value: "500 Watts", color: "#1e9cbb"],
[value: "1000 Watts", color: "#90d2a7"],
[value: "1500 Watts", color: "#44b621"],
[value: "2000 Watts", color: "#f1d801"],
[value: "2500 Watts", color: "#d04e00"],
[value: "3000 Watts", color: "#bc2323"]
*/
]
)
}
valueTile("powerOne", "device.powerOne") {
state(
"default",
label:'${currentValue}',
foregroundColors:[
[value: 1, color: "#000000"],
[value: 10000, color: "#ffffff"]
],
foregroundColor: "#000000",
backgroundColors:[
[value: "0 Watts", color: "#153591"],
[value: "500 Watts", color: "#1e9cbb"],
[value: "1000 Watts", color: "#90d2a7"],
[value: "1500 Watts", color: "#44b621"],
[value: "2000 Watts", color: "#f1d801"],
[value: "2500 Watts", color: "#d04e00"],
[value: "3000 Watts", color: "#bc2323"]
/* For low-wattage homes, use these values
[value: "0 Watts", color: "#153591"],
[value: "500 Watts", color: "#1e9cbb"],
[value: "1000 Watts", color: "#90d2a7"],
[value: "1500 Watts", color: "#44b621"],
[value: "2000 Watts", color: "#f1d801"],
[value: "2500 Watts", color: "#d04e00"],
[value: "3000 Watts", color: "#bc2323"]
*/
]
)
}
valueTile("powerTwo", "device.powerTwo") {
state(
"default",
label:'${currentValue}',
foregroundColors:[
[value: 1, color: "#000000"],
[value: 10000, color: "#ffffff"]
],
foregroundColor: "#000000",
backgroundColors:[
[value: "0 Watts", color: "#153591"],
[value: "500 Watts", color: "#1e9cbb"],
[value: "1000 Watts", color: "#90d2a7"],
[value: "1500 Watts", color: "#44b621"],
[value: "2000 Watts", color: "#f1d801"],
[value: "2500 Watts", color: "#d04e00"],
[value: "3000 Watts", color: "#bc2323"]
/* For low-wattage homes, use these values
[value: "0 Watts", color: "#153591"],
[value: "500 Watts", color: "#1e9cbb"],
[value: "1000 Watts", color: "#90d2a7"],
[value: "1500 Watts", color: "#44b621"],
[value: "2000 Watts", color: "#f1d801"],
[value: "2500 Watts", color: "#d04e00"],
[value: "3000 Watts", color: "#bc2323"]
*/
]
)
}
// Power row
valueTile("energyDisp", "device.energyDisp") {
state(
"default",
label: '${currentValue}',
foregroundColor: "#000000",
backgroundColor: "#ffffff")
}
valueTile("energyOne", "device.energyOne") {
state(
"default",
label: '${currentValue}',
foregroundColor: "#000000",
backgroundColor: "#ffffff")
}
valueTile("energyTwo", "device.energyTwo") {
state(
"default",
label: '${currentValue}',
foregroundColor: "#000000",
backgroundColor: "#ffffff")
}
// Volts row
/* valueTile("voltsDisp", "device.voltsDisp") {
state(
"default",
label: '${currentValue}',
backgroundColors:[
[value: "115.6 Volts", color: "#bc2323"],
[value: "117.8 Volts", color: "#D04E00"],
[value: "120.0 Volts", color: "#44B621"],
[value: "122.2 Volts", color: "#D04E00"],
[value: "124.4 Volts", color: "#bc2323"]
]
)
}
valueTile("voltsOne", "device.voltsOne") {
state(
"default",
label:'${currentValue}',
backgroundColors:[
[value: "L1", color: "#ffffff"],
[value: "115.6 Volts", color: "#bc2323"],
[value: "117.8 Volts", color: "#D04E00"],
[value: "120.0 Volts", color: "#44B621"],
[value: "122.2 Volts", color: "#D04E00"],
[value: "124.4 Volts", color: "#bc2323"]
]
)
}
valueTile("voltsTwo", "device.voltsTwo") {
state(
"default",
label:'${currentValue}',
backgroundColors:[
[value: "L2", color: "#ffffff"],
[value: "115.6 Volts", color: "#bc2323"],
[value: "117.8 Volts", color: "#D04E00"],
[value: "120.0 Volts", color: "#44B621"],
[value: "122.2 Volts", color: "#D04E00"],
[value: "124.4 Volts", color: "#bc2323"]
]
)
}
// Amps row
valueTile("ampsDisp", "device.ampsDisp") {
state (
"default",
label: '${currentValue}' ,
foregroundColor: "#000000",
color: "#000000",
backgroundColors:[
[value: "0 Amps", color: "#153591"],
[value: "25 Amps", color: "#1e9cbb"],
[value: "50 Amps", color: "#90d2a7"],
[value: "75 Amps", color: "#44b621"],
[value: "100 Amps", color: "#f1d801"],
[value: "125 Amps", color: "#d04e00"],
[value: "150 Amps", color: "#bc2323"]
]
)
}
valueTile("ampsOne", "device.ampsOne") {
state(
"default",
label:'${currentValue}',
foregroundColor: "#000000",
color: "#000000",
backgroundColors:[
[value: "0 Amps", color: "#153591"],
[value: "25 Amps", color: "#1e9cbb"],
[value: "50 Amps", color: "#90d2a7"],
[value: "75 Amps", color: "#44b621"],
[value: "100 Amps", color: "#f1d801"],
[value: "125 Amps", color: "#d04e00"],
[value: "150 Amps", color: "#bc2323"]
]
)
}
valueTile("ampsTwo", "device.ampsTwo") {
state(
"default",
label:'${currentValue}',
foregroundColor: "#000000",
color: "#000000",
backgroundColors:[
[value: "0 Amps", color: "#153591"],
[value: "25 Amps", color: "#1e9cbb"],
[value: "50 Amps", color: "#90d2a7"],
[value: "75 Amps", color: "#44b621"],
[value: "100 Amps", color: "#f1d801"],
[value: "125 Amps", color: "#d04e00"],
[value: "150 Amps", color: "#bc2323"]
]
)
}
*/ // Controls row
standardTile("reset", "command.reset", inactiveLabel: false) {
state "default", label:'reset', action:"reset", icon: "st.Health & Wellness.health7"
}
standardTile("refresh", "command.refresh", inactiveLabel: false) {
state "default", label:'refresh', action:"refresh.refresh", icon:"st.secondary.refresh-icon"
}
standardTile("configure", "command.configure", inactiveLabel: false) {
state "configure", label:'', action: "configure", icon:"st.secondary.configure"
}
standardTile("toggle", "command.toggleDisplay", inactiveLabel: false) {
state "default", label: "toggle", action: "toggleDisplay", icon: "st.motion.motion.inactive"
}
/* HEMv1 has a battery; v2 is line-powered */
valueTile("battery", "device.battery", decoration: "flat") {
state "battery", label:'${currentValue}% battery', unit:""
}
// HEM Version Configuration only needs to be done here - comments to choose what gets displayed
main (["energyDisp","energyTwo",
// "ampsDisp","voltsDisp", // Comment out this one for HEMv1
"powerDisp"
])
details([
"energyOne","energyDisp","energyTwo",
"powerOne","powerDisp","powerTwo",
// "ampsOne","ampsDisp","ampsTwo", // Comment out these two lines for HEMv1
// "voltsOne","voltsDisp","voltsTwo", // Comment out these two lines for HEMv1
"reset","refresh","toggle",
// "battery", // Include this for HEMv1
"configure"
])
}
preferences {
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() {
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(physicalgraph.zwave.commands.meterv1.MeterReport cmd) {
def dispValue
def newValue
def formattedValue
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) {
formattedValue = String.format("%5.2f", newValue)
dispValue = "${formattedValue}\nkWh"
sendEvent(name: "energyDisp", value: dispValue as String, unit: "", descriptionText: "Display Energy: ${newValue} kVh")
state.energyValue = newValue
BigDecimal costDecimal = newValue * ( kWhCost as BigDecimal )
def costDisplay = String.format("%5.2f",costDecimal)
state.costDisp = "Cost\n\$"+costDisplay
if (state.display == 1) { sendEvent(name: "energyTwo", value: state.costDisp, unit: "", descriptionText: "Display Cost: \$${costDisp}") }
[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"
sendEvent(name: "energyDisp", value: dispValue as String, unit: "", descriptionText: "Display Energy: ${formattedValue} kVAh")
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 != state.powerValue) {
dispValue = newValue+"\nWatts"
sendEvent(name: "powerDisp", value: dispValue as String, unit: "", descriptionText: "Display Power: ${newValue} Watts")
if (newValue < state.powerLow) {
dispValue = newValue+"\n"+timeString
if (state.display == 1) { sendEvent(name: "powerOne", value: dispValue as String, unit: "", descriptionText: "Lowest Power: ${newValue} Watts") }
state.powerLow = newValue
state.powerLowDisp = dispValue
}
if (newValue > state.powerHigh) {
dispValue = newValue+"\n"+timeString
if (state.display == 1) { sendEvent(name: "powerTwo", value: dispValue as String, unit: "", descriptionText: "Highest Power: ${newValue} Watts") }
state.powerHigh = newValue
state.powerHighDisp = dispValue
}
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"
sendEvent(name: "voltsDisp", value: dispValue as String, unit: "", descriptionText: "Display Voltage: ${formattedValue} Volts")
if (newValue < state.voltsLow) {
dispValue = formattedValue+"\n"+timeString
if (state.display == 1) { sendEvent(name: "voltsOne", value: dispValue as String, unit: "", descriptionText: "Lowest Voltage: ${formattedValue} Volts") }
state.voltsLow = newValue
state.voltsLowDisp = dispValue
}
if (newValue > state.voltsHigh) {
dispValue = formattedValue+"\n"+timeString
if (state.display == 1) { sendEvent(name: "voltsTwo", value: dispValue as String, unit: "", descriptionText: "Highest Voltage: ${formattedValue} Volts") }
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 != state.ampsValue) {
formattedValue = String.format("%5.2f", newValue)
dispValue = "${formattedValue}\nAmps"
sendEvent(name: "ampsDisp", value: dispValue as String, unit: "", descriptionText: "Display Current: ${formattedValue} Amps")
if (newValue < state.ampsLow) {
dispValue = formattedValue+"\n"+timeString
if (state.display == 1) { sendEvent(name: "ampsOne", value: dispValue as String, unit: "", descriptionText: "Lowest Current: ${formattedValue} Amps") }
state.ampsLow = newValue
state.ampsLowDisp = dispValue
}
if (newValue > state.ampsHigh) {
dispValue = formattedValue+"\n"+timeString
if (state.display == 1) { sendEvent(name: "ampsTwo", value: dispValue as String, unit: "", descriptionText: "Highest Current: ${formattedValue} Amps") }
state.ampsHigh = newValue
state.ampsHighDisp = dispValue
}
state.ampsValue = newValue
[name: "amps", value: newValue, unit: "A", descriptionText: "Total Current: ${formattedValue} Amps"]
}
}
}
}
def zwaveEvent(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) {
def dispValue
def newValue
def formattedValue
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)
formattedValue = newValue as String
dispValue = "${formattedValue}\nWatts"
if (dispValue != state.powerL1Disp) {
state.powerL1Disp = dispValue
if (state.display == 2) {
[name: "powerOne", value: dispValue, unit: "", descriptionText: "L1 Power: ${formattedValue} Watts"]
}
else {
}
}
}
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
if (state.display == 2) {
[name: "energyOne", value: dispValue, unit: "", descriptionText: "L1 Energy: ${formattedValue} kWh"]
}
else {
}
}
}
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
if (state.display == 2) {
[name: "energyOne", value: dispValue, unit: "", descriptionText: "L1 Energy: ${formattedValue} kVAh"]
}
else {
}
}
}
else if (encapsulatedCommand.scale == 5 ) {
newValue = Math.round(encapsulatedCommand.scaledMeterValue * 100) / 100
formattedValue = String.format("%5.2f", newValue)
dispValue = "${formattedValue}\nAmps"
if (dispValue != state.ampsL1Disp) {
state.ampsL1Disp = dispValue
if (state.display == 2) {
[name: "ampsOne", value: dispValue, unit: "", descriptionText: "L1 Current: ${formattedValue} Amps"]
}
else {
}
}
}
/* Ignore voltage updates, because they always match the current Total Voltage
else if (encapsulatedCommand.scale == 4 ){
newValue = Math.round(encapsulatedCommand.scaledMeterValue * 100) / 100
formattedValue = String.format("%5.2f", newValue)
dispValue = "${formattedValue}\nVolts"
if (dispValue != statevoltsL1Disp) {
state.voltsL1Disp = dispValue
if (state.display == 2) {
[name: "voltsOne", value:dispValue, unit: "", descriptionText: "L1 Voltage: ${formattedValue} Volts"]
}
else {
}
}
}
*/
}
else if (cmd.sourceEndPoint == 2) {
if (encapsulatedCommand.scale == 2 ){
newValue = Math.round(encapsulatedCommand.scaledMeterValue)
formattedValue = newValue as String
dispValue = "${formattedValue}\nWatts"
if (dispValue != state.powerL2Disp) {
state.powerL2Disp = dispValue
if (state.display == 2) {
[name: "powerTwo", value: dispValue, unit: "", descriptionText: "L2 Power: ${formattedValue} Watts"]
}
else {
}
}
}
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
if (state.display == 2) {
[name: "energyTwo", value: dispValue, unit: "", descriptionText: "L2 Energy: ${formattedValue} kWh"]
}
else {
}
}
}
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
if (state.display == 2) {
[name: "energyTwo", value: dispValue, unit: "", descriptionText: "L2 Energy: ${formattedValue} kVAh"]
}
else {
}
}
}
else if (encapsulatedCommand.scale == 5 ){
newValue = Math.round(encapsulatedCommand.scaledMeterValue * 100) / 100
formattedValue = String.format("%5.2f", newValue)
dispValue = "${formattedValue}\nAmps"
if (dispValue != state.ampsL2Disp) {
state.ampsL2Disp = dispValue
if (state.display == 2) {
[name: "ampsTwo", value: dispValue, unit: "", descriptionText: "L2 Current: ${formattedValue} Amps"]
}
else {
}
}
}
/* Ignore voltage updates, because they always match the current Total Voltage
else if (encapsulatedCommand.scale == 4 ){
newValue = Math.round(encapsulatedCommand.scaledMeterValue * 100) / 100
formattedValue = String.format("%5.2f", newValue)
dispValue = "${formattedValue}\nVolts"
if (dispValue != statevoltsL2Disp) {
state.voltsL2Disp = dispValue
if (state.display == 2) {
[name: "voltsTwo", value:dispValue, unit: "", descriptionText: "L2 Voltage: ${formattedValue} Volts"]
}
else {
}
}
}
*/
}
}
}
}
def zwaveEvent(physicalgraph.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(physicalgraph.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}"
if ( state.display == 1 ) {
sendEvent(name: "voltsOne", value: state.voltsLowDisp, unit: "")
sendEvent(name: "ampsOne", value: state.ampsLowDisp, unit: "")
sendEvent(name: "powerOne", value: state.powerLowDisp, unit: "")
sendEvent(name: "energyOne", value: state.lastResetTime, unit: "")
sendEvent(name: "voltsTwo", value: state.voltsHighDisp, unit: "")
sendEvent(name: "ampsTwo", value: state.ampsHighDisp, unit: "")
sendEvent(name: "powerTwo", value: state.powerHighDisp, unit: "")
sendEvent(name: "energyTwo", value: state.costDisp, unit: "")
}
else {
sendEvent(name: "voltsOne", value: "L1", unit: "")
sendEvent(name: "ampsOne", value: state.ampsL1Disp, unit: "")
sendEvent(name: "powerOne", value: state.powerL1Disp, unit: "")
sendEvent(name: "energyOne", value: state.energyL1Disp, unit: "")
sendEvent(name: "voltsTwo", value: "L2", unit: "")
sendEvent(name: "ampsTwo", value: state.ampsL2Disp, unit: "")
sendEvent(name: "powerTwo", value: state.powerL2Disp, unit: "")
sendEvent(name: "energyTwo", value: state.energyL2Disp, unit: "")
}
}
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()
sendEvent(name: "energyDisp", value: "", unit: "")
sendEvent(name: "powerDisp", value: "", unit: "")
sendEvent(name: "ampsDisp", value: "", unit: "")
sendEvent(name: "voltsDisp", value: "", unit: "")
// 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()
])
cmd
}
def configure() {
log.debug "configure()"
def kDelay = settings.kWhDelay as Integer
def dDelay = settings.detailDelay as Integer
if (kDelay == null) { // Shouldn't have to do this, but there seem to be initialization errors
kDelay = 120
}
if (dDelay == null) {
dDelay = 30
}
def cmd = delayBetween([
zwave.configurationV1.configurationSet(parameterNumber: 3, size: 1, scaledConfigurationValue: 0).format(), // Disable (=0) selective reporting
zwave.configurationV1.configurationSet(parameterNumber: 4, size: 2, scaledConfigurationValue: 50).format(), // Don't send whole HEM unless watts have changed by 30
zwave.configurationV1.configurationSet(parameterNumber: 5, size: 2, scaledConfigurationValue: 50).format(), // Don't send L1 Data unless watts have changed by 15
zwave.configurationV1.configurationSet(parameterNumber: 6, size: 2, scaledConfigurationValue: 50).format(), // Don't send L2 Data unless watts have changed by 15
zwave.configurationV1.configurationSet(parameterNumber: 8, size: 1, scaledConfigurationValue: 5).format(), // Or by 5% (whole HEM)
zwave.configurationV1.configurationSet(parameterNumber: 9, size: 1, scaledConfigurationValue: 5).format(), // Or by 5% (L1)
zwave.configurationV1.configurationSet(parameterNumber: 10, size: 1, scaledConfigurationValue: 5).format(), // Or by 5% (L2)
zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, scaledConfigurationValue: 6145).format(), // Whole HEM and L1/L2 power in kWh
zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: kDelay).format(), // Default every 120 Seconds
zwave.configurationV1.configurationSet(parameterNumber: 102, size: 4, scaledConfigurationValue: 1573646).format(), // L1/L2 for Amps & Watts, Whole HEM for Amps, Watts, & Volts
zwave.configurationV1.configurationSet(parameterNumber: 112, size: 4, scaledConfigurationValue: dDelay).format(), // Defaul every 30 seconds
zwave.configurationV1.configurationSet(parameterNumber: 103, size: 4, scaledConfigurationValue: 0).format(), // Disable Report 3
zwave.configurationV1.configurationSet(parameterNumber: 113, size: 4, scaledConfigurationValue: 0).format() // eDesable Report 3
])
log.debug cmd
cmd
}

Thank you Eric, I’ll try that value and see what happens. The error is in this post under update #1, not sure what it means though.
.

Thank you!!! I’ll re-try this with the updated code and see how it goes.
.

Thank you for confirming. That’s interesting! OK, then my device needs to be reset or something.

here is an example that resolves error “Ambiguous method overload”

The bitmap explanation: OOPS SLOPPY BINARY VALUES FIXED:
MSB = most significant byte
0b00000000 = “00”

then 2nd byte
0b00000000 = “00”

then 3rd byte
0b00011011 = “1B”

then LSB = least significant byte
0b00001111 = “0F”

glue it all together (assuming LITTLEendian?) = hex 0x00001B0F = decimal 6927 .

My apologies, I missed this part for some reason. Correct, I went into the IDE and added it under ‘My Device Types’ and then assigned it to the HEM under ‘My Devices’.

Yes, I am using an Android device. I’ll comment that out and try it again, maybe that’s part of the issue.

I believe I’ve found the original code on github and they do mention how color seems to cause problems on android devices although I don’t know if that issue has been resolved by now. This code specifically has the separate code for each clamp. It also commented fairly well to see what’s going on.

“2014-11-06: Added alternate display of L2 and L2 values instead of Low/High, based on version by Jayant Jhamb”

Thank you Eric, this is good info and helps me understand the error message as well as the bitmap calculation.
.

I agree, that appears to be the original code. Including in the original post to give credit to the original author.

.
We’re making progress! :smiley: Commenting out the color-changing code as well as a few other items (as indicated in the code comments; volts, amps, etc) did the trick. Now the device type works without any errors (hurray!) and the ‘toggle’ will correctly show the two line wattages. Here is a baseline copy of the code with the proper items commented out to be compatible with v1 and with an Android device.

<I’ve now found that posts are limited to 32k characters, so…I can’t paste the code here. I’ll update the original thread or make a new reply.>
I attempted to fork the original code and include the v1 changes discussed above:

Now the fun part, retro-fitting the layout and code to show only the two clamps (L1/L2) ummm…actually I haven’t decided how I would like the layout to be configured. But that’s OK! The hard part is done. Once I make some progress on that front I’ll update this thread.

Thank you: @storageanarchy, @Jimxenus, @ero4444 for your help/code/effort figuring this out. I would still be running in circles without you! :wink:

Have a good week everyone,
-Jmtyra

I’m glad it’s working out for you. Give us some screenshots once you have finalized your layout. :smile:

Perfect timing, Mailman has my V1 for delivery today. Not sure why he’s almost 3 hours late today. Yes I do, he has new toys for me. LOL

No updates to report. Work/life has gotten busy lately and I have not been able to work on this project, my apologies.

Once I get time and make some progress I’ll reply back with updates.

(Original post updated)

OK, had some time this weekend and was able to finish the code and layout. There are a few tweaks that I am considering, but this is the pretty much done.

Thank you again to everyone for their help, I really appreciate it! :smile:

@Jmtyra
Is there any chance you’d be willing to assist me with troubleshooting one of these v1 devices?
I have two of them, and I’d like to utilize your device type in order to cover two machines at same time on each one.

The problem is that, even though it paired just fine immediately as the correct device type, it never reports anything.
Then, I unpaired/removed it, and re-paired, and same thing.
Then removed again and paired again and then changed it to your device type via copy/paste in the IDE, but still no love.

Am I missing something about how these are supposed to work?
Power cord connected
No batteries installed
Clamps are each respectively around power cords leading to each of two different devices.
Nothing reported…ever.

Am I doing it wrong? lol

EDIT: I started a support ticket to get some help troubleshooting this v1 HEM not reporting.

Hi sgnihttrams! :smile:

Sorry for the delay in my response, I was offline last week and still catching up on email.

That’s very odd! It sounds like there is a definite issue there. From my experience, after a device is paired, I simply change the device type in the ST IDE and after ~10 seconds or so the UI updates within my ST mobile app. I also am not using batteries.

It sounds like you’re doing it correctly. It’s good that you opened up a support ticket, because I don’t know what else to try based on your experience.

Are you using an Android or iOS mobile device?

1 Like

@Jmtyra

Android.

I will just wait to hear from them then, and see what comes of it.
If they can’t figure it out, I will just return the two I got.

Thanks, and I do appreciate your assistance on this. i.e. the feedback regarding my state of doing it is invaluable lol :slight_smile:

I am looking for a DTH to allow me to use each clamp on my Aeon home energy meter to monitor a washer and dryer.

Both are 110, I believe this DTH defaults to 220 on each line.

Is it possible to use this DTH for my purposes or not?

Thanks!