Picking up where this took off.
THIS DOES NOT WORK YET!!! It's In progress
CURRENT CODE PARENT:
/**
* SmartThings Device Type for Aeon Home Energy Monitor v1 (HEM v1)
* (Goal of project is to) Displays individual values for each clamp (L1, L2) for granular monitoring
* Example: Individual circuits (breakers) of high-load devices, such as HVAC or clothes dryer
*
* Original Author: Copyright 2014 Barry A. Burke
*
**/
metadata {
// Automatically generated. Make future change here.
definition (
name: "AEON HEM v1 Separate Clamp",
namespace: "jrfarrar",
category: "HEM",
author: "J.R. Farrar"
)
{
capability "Energy Meter"
capability "Power Meter"
capability "Configuration"
capability "Sensor"
capability "Refresh"
capability "Polling"
// capability "Battery"
attribute "energy", "string"
attribute "energyOne", "string"
attribute "energyTwo", "string"
attribute "power", "string"
attribute "powerOne", "string"
attribute "powerTwo", "string"
attribute "volts", "string"
attribute "voltage", "string" // We'll deliver both, since the correct one is not defined anywhere
attribute "energyDisp", "string"
attribute "energy1Disp", "string"
attribute "energy2Disp", "string"
attribute "powerDisp", "string"
attribute "power1Disp", "string"
attribute "power2Disp", "string"
command "reset"
command "configure"
command "refresh"
command "poll"
command "recreateChildDevices"
command "deleteChildren"
fingerprint deviceId: "0x2101", inClusters: " 0x70,0x31,0x72,0x86,0x32,0x80,0x85,0x60"
// fingerprint deviceId: "0x3101", inClusters: "0x70,0x32,0x60,0x85,0x56,0x72,0x86"
}
preferences {
input "voltageValue", "number",
title: "Voltage being monitored",
defaultValue: 120,
range: "110..240",
required: false,
displayDuringSetup: true
input "c1Name", "string",
title: "Clamp 1 Name",
defaultValue: "Clamp 1" as String,
required: false,
displayDuringSetup: true
input "c2Name", "string",
title: "Clamp 2 Name",
defaultValue: "Clamp 2" as String,
required: false,
displayDuringSetup: true
input "kWhCost", "string",
title: "Enter your cost per kWh (or just use the default, or use 0 to not calculate):",
defaultValue: 0.06,
required: false,
displayDuringSetup: true
input "reportType", "number",
title: "ReportType: Send watt/kWh data on a time interval (0), or on a change in wattage (1)? Enter a 0 or 1:",
defaultValue: 1,
range: "0..1",
required: false,
displayDuringSetup: true
input "wattsChangedWhole", "number",
title: "For ReportType = 1, Don't send unless watts have changed by this many watts Whole Meter (range 0 - 32,000W)",
defaultValue: 50,
range: "0..32000",
required: false,
displayDuringSetup: true
input "wattsChangedOne", "number",
title: "For ReportType = 1, Don't send unless watts have changed by this many watts Clamp 1: (range 0 - 32,000W)",
defaultValue: 50,
range: "0..32000",
required: false,
displayDuringSetup: true
input "wattsChangedTwo", "number",
title: "For ReportType = 1, Don't send unless watts have changed by this many watts Clamp 2: (range 0 - 32,000W)",
defaultValue: 50,
range: "0..32000",
required: false,
displayDuringSetup: true
input "wattsPercent", "number",
title: "For ReportType = 1, Don't send unless watts have changed by this percent(whole meter): (range 0 - 99%)",
defaultValue: 10,
range: "0..99",
required: false,
displayDuringSetup: true
input "wattsPercent1", "number",
title: "For ReportType = 1, Don't send unless watts have changed by this percent(Clamp1): (range 0 - 99%)",
defaultValue: 10,
range: "0..99",
required: false,
displayDuringSetup: true
input "wattsPercent2", "number",
title: "For ReportType = 1, Don't send unless watts have changed by this percent(Clamp2): (range 0 - 99%)",
defaultValue: 10,
range: "0..99",
required: false,
displayDuringSetup: true
input "secondsWatts", "number",
title: "For ReportType = 0, Send Watts data every how many seconds? (range 0 - 65,000 seconds)",
defaultValue: 15,
range: "0..65000",
required: false,
displayDuringSetup: true
input "secondsKwh", "number",
title: "For ReportType = 0, Send kWh data every how many seconds? (range 0 - 65,000 seconds)",
defaultValue: 60,
range: "0..65000",
required: false,
displayDuringSetup: true
input "secondsBattery", "number",
title: "If the HEM has batteries installed, send battery data every how many seconds? (range 0 - 65,000 seconds)",
defaultValue: 900,
range: "0..65000",
required: false,
displayDuringSetup: true
}
}
def installed() {
reset() // The order here is important
createChildDevices()
configure() // Since reports can start coming in even before we finish configure()
refresh()
}
def updated() {
log.debug "updated"
if (!childDevices) {
createChildDevices()
}
else if (device.label != state.oldLabel) {
childDevices.each {
def newLabel = "$device.displayName (CH${channelNumber(it.deviceNetworkId)})"
it.setLabel(newLabel)
}
state.oldLabel = device.label
}
configure()
resetDisplay()
refresh()
}
def parse(String description) {
def result = null
def cmd = zwave.parse(description, [0x31: 1, 0x32: 1, 0x60: 3])
if (cmd) {
result = createEvent(zwaveEvent(cmd))
}
if (result) {
//log.debug "Parse returned ${result?.descriptionText}"
return result
} else {
}
}
def zwaveEvent(hubitat.zwave.commands.meterv1.MeterReport cmd) {
def dispValue
def newValue
def formattedValue
//def 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 = "Total\n${formattedValue}\nkWh" // total kWh label
sendEvent(name: "energyDisp", value: dispValue as String, unit: "", descriptionText: "Display Energy: ${newValue} kWh", displayed: false)
state.energyValue = newValue
[name: "energy", value: newValue, unit: "kWh", descriptionText: "Total Energy: ${formattedValue} kWh"]
}
}
else if (cmd.scale==2) {
newValue = Math.round(cmd.scaledMeterValue*10)/10
formattedValue = String.format("%5.1f", newValue)
//newValue = Math.round(cmd.scaledMeterValue) // really not worth the hassle to show decimals for Watts
if (newValue != state.powerValue) {
dispValue = "Total\n"+newValue+"\nWatts" // Total watts label
sendEvent(name: "powerDisp", value: dispValue as String, unit: "", descriptionText: "Display Power: ${newValue} Watts", displayed: false)
state.powerValue = newValue
[name: "power", value: newValue, unit: "W", descriptionText: "Total Power: ${formattedValue} Watts"]
}
}
}
}
def zwaveEvent(hubitat.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*10)/10
formattedValue = String.format("%5.1f", newValue)
//dispValue = "${c1Name}\n${formattedValue}\nWatts" // L1 Watts Label
dispValue = "${formattedValue}" // L1 Watts Label
if (newValue != state.powerL1) {
state.powerL1 = newValue
[name: "powerOne", value: dispValue, unit: "", descriptionText: "L1 Power: ${formattedValue} Watts"]
}
}
else if (encapsulatedCommand.scale == 0 ){
newValue = Math.round(encapsulatedCommand.scaledMeterValue * 100) / 100
formattedValue = String.format("%5.2f", newValue)
//dispValue = "${c1Name}\n${formattedValue}\nkWh" // L1 kWh label
dispValue = "${formattedValue}"
if (newValue != state.energyL1) {
state.energyL1 = newValue
[name: "energyOne", value: dispValue, unit: "", descriptionText: "L1 Energy: ${formattedValue} kWh"]
}
}
}
else if (cmd.sourceEndPoint == 2) {
if (encapsulatedCommand.scale == 2 ){
newValue = Math.round(encapsulatedCommand.scaledMeterValue*10)/10
formattedValue = String.format("%5.1f", newValue)
//dispValue = "${c2Name}\n${formattedValue}\nWatts" // L2 Watts Label
dispValue = "${formattedValue}" // L2 Watts Label
if (newValue != state.powerL1) {
state.powerL2 = newValue
[name: "powerTwo", value: dispValue, unit: "", descriptionText: "L2 Power: ${formattedValue} Watts"]
}
}
else if (encapsulatedCommand.scale == 0 ){
newValue = Math.round(encapsulatedCommand.scaledMeterValue * 100) / 100
formattedValue = String.format("%5.2f", newValue)
// dispValue = "${c2Name}\n${formattedValue}\nkWh" // L2 kWh label
dispValue = "${formattedValue}"
if (newValue != state.energyL2) {
state.energyL2 = newValue
[name: "energyTwo", value: dispValue, unit: "", descriptionText: "L2 Energy: ${formattedValue} kWh"]
}
}
}
}
}
}
def zwaveEvent(hubitat.zwave.commands.batteryv1.BatteryReport cmd) {
def map = [:]
map.name = "battery"
map.unit = "%"
if (cmd.batteryLevel == 0xFF) {
map.value = 1
map.descriptionText = "${device.displayName} battery is low"
map.isStateChange = true
}
else {
map.value = cmd.batteryLevel
}
log.debug map
return map
}
def zwaveEvent(hubitat.zwave.Command cmd) {
// Handles all Z-Wave commands we aren't interested in
log.debug "Unhandled event ${cmd}"
[:]
}
def refresh() { // Request HEMv2 to send us the latest values for the 4 we are tracking
log.debug "refresh()"
delayBetween([
zwave.meterV2.meterGet(scale: 0).format(), // Change 0 to 1 if international version
zwave.meterV2.meterGet(scale: 2).format(),
])
resetDisplay()
}
def poll() {
log.debug "poll()"
refresh()
}
def resetDisplay() {
log.debug "resetDisplay()"
sendEvent(name: "powerDisp", value: "Total\n" + state.powerValue + "\nWatts", unit: "W")
sendEvent(name: "energyDisp", value: "Total\n" + state.energyValue + "\nkWh", unit: "kWh")
sendEvent(name: "power1Disp", value: c1Name + "\n" + state.powerL1 + "\nWatts", unit: "W")
sendEvent(name: "energy1Disp", value: c1Name + "\n" + state.energyL1 + "\nkWh", unit: "kWh")
sendEvent(name: "power2Disp", value: c2Name + "\n" + state.powerL2 + "\nWatts", unit: "W")
sendEvent(name: "energy2Disp", value: c2Name + "\n" + state.energyL2 + "\nkWh", unit: "kWh")
}
def reset() {
log.debug "reset()"
state.energyValue = ""
state.powerValue = ""
state.energyL1 = ""
state.energyL2 = ""
state.powerL1 = ""
state.powerL2 = ""
resetDisplay()
return [
zwave.meterV2.meterReset().format(),
zwave.meterV2.meterGet(scale: 0).format()
]
configure()
}
def configure() {
log.debug "configure()"
Long kwhDelay = settings.kWhDelay as Long
Long wDelay = settings.wDelay as Long
if (kwhDelay == null) { // Shouldn't have to do this, but there seem to be initialization errors
kwhDelay = 15
}
if (wDelay == null) {
wDelay = 15
}
def cmd = delayBetween([
// Perform a complete factory reset. Use this all by itself and comment out all others below.
// Once reset, comment this line out and uncomment the others to go back to normal
// zwave.configurationV1.configurationSet(parameterNumber: 255, size: 4, scaledConfigurationValue: 1).format()
zwave.configurationV1.configurationSet(parameterNumber: 1, size: 2, scaledConfigurationValue: voltageValue).format(), // assumed voltage
zwave.configurationV1.configurationSet(parameterNumber: 3, size: 1, scaledConfigurationValue: reportType).format(), // Disable (=0) selective reporting
zwave.configurationV1.configurationSet(parameterNumber: 4, size: 2, scaledConfigurationValue: wattsChangedWhole).format(), // Don't send whole HEM unless watts have changed by 1
zwave.configurationV1.configurationSet(parameterNumber: 5, size: 2, scaledConfigurationValue: wattsChangedOne).format(), // Don't send L1 Data unless watts have changed by 1
zwave.configurationV1.configurationSet(parameterNumber: 6, size: 2, scaledConfigurationValue: wattsChangedTwo).format(), // Don't send L2 Data unless watts have changed by 1
zwave.configurationV1.configurationSet(parameterNumber: 8, size: 1, scaledConfigurationValue: wattsPercent).format(), // Or by 5% (whole HEM)
zwave.configurationV1.configurationSet(parameterNumber: 9, size: 1, scaledConfigurationValue: wattsPercent1).format(), // Or by 5% (L1)
zwave.configurationV1.configurationSet(parameterNumber: 10, size: 1, scaledConfigurationValue: wattsPercent2).format(), // Or by 5% (L2)
zwave.configurationV1.configurationSet(parameterNumber: 100, size: 4, scaledConfigurationValue: 1).format(), // reset to defaults
zwave.configurationV1.configurationSet(parameterNumber: 110, size: 4, scaledConfigurationValue: 1).format(), // reset to defaults
zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, scaledConfigurationValue: 772).format(), // watt (don't change)
zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: secondsWatts).format(), // every %Delay% seconds
zwave.configurationV1.configurationSet(parameterNumber: 102, size: 4, scaledConfigurationValue: 6152).format(), // kwh (don't change)
zwave.configurationV1.configurationSet(parameterNumber: 112, size: 4, scaledConfigurationValue: secondsKwh).format(), // Every %Delay% seconds
zwave.configurationV1.configurationSet(parameterNumber: 103, size: 4, scaledConfigurationValue: 1).format(), // battery (don't change)
zwave.configurationV1.configurationSet(parameterNumber: 113, size: 4, scaledConfigurationValue: secondsBattery).format() // every hour
], 2000)
log.debug cmd
cmd
}
def recreateChildDevices() {
log.debug "recreateChildDevices"
deleteChildren()
createChildDevices()
}
def deleteChildren() {
log.debug "deleteChildren"
def children = getChildDevices()
children.each {child->
deleteChildDevice(child.deviceNetworkId)
}
}
private void createChildDevices() {
log.debug "createChildDevices"
for (i in 1..2) {
addChildDevice("jrfarrar", "AEON HEM V1 (Child)", "$device.deviceNetworkId-$i", [name: "ch$i", label: "$device.displayName $i", isComponent: true])
}
}
CURRENT CODE CHILD:
/*
* AEON HEM V1 Child Device Driver
*/
metadata {
definition (name: "AEON HEM V1 (Child)", namespace: "jrfarrar", author: "jrfarrar") {
capability "Energy Meter"
capability "Power Meter"
capability "Refresh"
capability "Sensor"
attribute "power", "string"
attribute "energy", "string"
}
}