My custom laundry device handler solution for Aeon HEM version one and a Smartthings Plug

I had browsed around at different laundry solutions and ultimately couldn’t find one that worked good for me. The first I tried was a multi sensor but the washer nor dryer shook enough to trigger it unless I put it inside the dryer on the drum… Funny cause I remembered those things being way more sensitive than that so I wonder if they have decreased the sensitivity with firmware over time? Anyways for list of wants I had for this project.

  1. I wanted continuing notifications until the laundry was attended to at set intervals
  2. I wanted it to arm and disarm the continuing notifications automatically
  3. I didn’t want to open up or alter the chord or anything warranty voiding electrical manipulation on my new washer and dryer.
  4. I wanted the devices in smartthings to look like they were specific to a washer and dryer
  5. I wanted power monitoring for curiosity sake

With all that in mind I settled on the following hardware approach…

For the washer:

  1. A smarthtings outlet (any power monitoring outlet would do with some editing of the device handler)
  2. A xiaomi contact sensor again any would work these things are just like 5 bucks and super small

For the dryer:

  1. Aeon home energy monitor. (this was a good way to monitor a 240 volt appliance)
  2. Another contact sensor for the dryer door

I was able to find one device handler for the aeon that did both a washer and a dryer but it killed the accurate power monitoring and it required device modifications on the washer and dryer. Plus it was set up to do both a washer and a dryer and I wanted to just have the dryer with power monitoring. With that in mind I set out to make my own. I edited the popular device handler created by jscgs350 that has tons of good customizing options for the HEM to basically have the functionality of a dryer. I then did the same thing with stock device handler for the smartthings outlet and I just removed the plug functions since I couldn’t see a use and I just wanted to keep the plug hot all the time. The washer plugs right into the smartthings plug and they HEM for the dryer I just put out in my electrical panel where the wires leave the breaker. The door sensors on each of the washer and dryer doors to cancel the continuing alerts. The Whole schebang is then tied together with a webcore piston.

Some pics





contactsensor

The device handlers… Once installed change the trip point of the waher and dryer to a good value for your setup using the settings cog in the smartthings mobile app. I found sometimes my energy efficient washer will drop to no electrical load for a couple minutes at a time here and there which is why my webcore piston factors in some delays to start and send the notifications.

washer

/*
 *  Copyright 2016 SmartThings
 *
 *  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.
 */
metadata {
	// Automatically generated. Make future change here.
	definition(name: "WasherSTOutlet", namespace: "Brennon's Apps", author: "bscuderi", ocfDeviceType: "oic.d.smartplug") {
		capability "Power Meter"
		capability "Refresh"
		capability "Sensor"
       // removed capabilities for device health and swith and added attribute washer status 
        attribute "washerstatus", "enum"

		fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B04,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3200", deviceJoinName: "Outlet"
		fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B04,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "3200-Sgb", deviceJoinName: "Outlet"
		fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B04,0B05", outClusters: "0019", manufacturer: "CentraLite", model: "4257050-RZHAC", deviceJoinName: "Outlet"
		fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 000F, 0B04", outClusters: "0019", manufacturer: "SmartThings", model: "outletv4", deviceJoinName: "Outlet"
		fingerprint profileId: "0104", inClusters: "0000,0003,0004,0005,0006,0B04,0B05", outClusters: "0019"
	}

	// simulator metadata
	simulator {
		
	}

	preferences {
		section {
			image(name: 'educationalcontent', multiple: true, images: [
					"http://cdn.device-gse.smartthings.com/Outlet/US/OutletUS1.jpg",
					"http://cdn.device-gse.smartthings.com/Outlet/US/OutletUS2.jpg"
			])
		}
	
		// ask for desired trippoint on settings page
        input "trippoint", "number", title: "washer on trip point", defaultValue: 9, required: true, displayDuringSetup: true
    }

	// UI tile definitions
	tiles(scale: 2) {
		multiAttributeTile(name: "main", type: "lighting", width: 6, height: 4, canChangeIcon: true) {
			tileAttribute("device.washerstatus", key: "PRIMARY_CONTROL") {
				attributeState "on", label: 'Washing', icon: "st.Appliances.appliances8", backgroundColor: "#0000FF"
				attributeState "off", label: 'Off', icon: "st.Appliances.appliances8", backgroundColor: "#ffffff"
				
			}
			tileAttribute("power", key: "SECONDARY_CONTROL") {
				attributeState "power", label: '${currentValue} W'
			}
		}

		standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat", width: 2, height: 2) {
			state "default", label: '', action: "refresh.refresh", icon: "st.secondary.refresh"
		}

		main "main"
		details(["main", "refresh"])
	}
}

// Parse incoming device messages to generate events
def parse(String description) {
	log.debug "description is $description"

	def event = zigbee.getEvent(description)

	if (event) {
		if (event.name == "power") {
			def value = (event.value as Integer) / 10
			// change washer status to on if power goes > trippoint
            if (value >= trippoint){
            sendEvent(name: 'washerstatus', value: 'on')
                        }
            // change washer status to off if power goes < trippoint
            if (value <= trippoint){
            sendEvent(name: 'washerstatus', value: 'off')
                        }
            event = createEvent(name: event.name, value: value, descriptionText: '{{ device.displayName }} power is {{ value }} Watts', translatable: true)
        
        } 
	} 
	
	return event ? createEvent(event) : event
}


def refresh() {
	zigbee.electricMeasurementPowerRefresh()
}

// added to define and store data for washer status
def updated() {
    log.debug "Updated !"
    state.washerstatus = 1    
    log.debug "device.washerstatus: ${device.washerstatus}"
}

Dryer

// created as a spinoff from jscgs350's device typr for version 1 adapted to just show my dryer as a switch running or not

metadata {
	definition (name: "Dryer Energy Monitor", namespace: "Brennon's Apps", author: "bscuderi")
	{
		capability "Energy Meter"
		capability "Power Meter"
		capability "Configuration"
		capability "Sensor"
		capability "Refresh"
		capability "Polling"
		capability "Battery"
//		capability "Health Check"


		attribute "currentKWH", "string"		// Used to show current kWh since last reset
		attribute "currentWATTS", "string"		// Used to show current watts being used on the main tile
		attribute "minWATTS", "string"			// Used to store/display minimum watts used since last reset
		attribute "maxWATTS", "string"			// Used to store/display maximum watts used since last reset
		attribute "resetMessage", "string"		// Used for messages of what was reset (min, max, energy, or all values)
		attribute "kwhCosts", "string"			// Used to show energy costs since last reset
		attribute "batteryStatus", "string"
        attribute "kWhLastReset", "number"
        attribute "CostLastReset", "number"
        attribute "dryerstatus", "enum"         // added for mock dryer capability

		command "resetkwh"
		command "resetmin"
		command "resetmax"
		command "resetMeter"

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

	// tile definitions
	tiles(scale: 2) {
		multiAttributeTile(name:"main", type: "lighting", width: 6, height: 4, decoration: "flat"){
			tileAttribute ("device.dryerstatus", key: "PRIMARY_CONTROL") {
				attributeState "on", label: "Drying", icon: "st.Appliances.appliances1", backgroundColor: "#FF0000"
        		attributeState "off", label: "Off", icon: "st.Appliances.appliances1", backgroundColor: "#ffffff"
			}
            tileAttribute ("device.currentWATTS", key: "SECONDARY_CONTROL") {
				attributeState "default", label: '${currentValue}W', icon: "https://raw.githubusercontent.com/constjs/jcdevhandlers/master/img/device-activity-tile@2x.png"
		}
		}
        standardTile("iconTile", "iconTile", inactiveLabel: false, width: 1, height: 1) {
			state "default", icon:"https://raw.githubusercontent.com/constjs/jcdevhandlers/master/img/device-activity-tile@2x.png"
		}
		valueTile("statusText", "statusText", inactiveLabel: false, decoration: "flat", width: 5, height: 1) {
			state "statusText", label:'${currentValue}', backgroundColor:"#ffffff"
		}
		valueTile("resetMessage", "device.resetMessage", width: 5, height: 1, inactiveLabel: false, decoration: "flat") {
			state("default", label: '${currentValue}', backgroundColor:"#ffffff")
		}
		valueTile("currentKWH", "device.currentKWH", width: 3, height: 1, inactiveLabel: false, decoration: "flat") {
			state("default", action: "refresh", label: '${currentValue}', backgroundColor:"#ffffff")
		}
		valueTile("kwhCosts", "device.kwhCosts", width: 3, height: 1, inactiveLabel: false, decoration: "flat") {
			state("default", label: 'Cost ${currentValue}', backgroundColor:"#ffffff")
		}
		standardTile("resetmin", "device.resetmin", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
			state "default", label:'Reset Min', action:"resetmin", icon:"st.secondary.refresh-icon"
		}
		standardTile("resetmax", "device.resetmax", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
			state "default", label:'Reset Max', action:"resetmax", icon:"st.secondary.refresh-icon"
		}
		standardTile("resetkwh", "device.resetkwh", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
			state "default", label:'Reset Energy', action:"resetkwh", icon:"st.secondary.refresh-icon"
		}
		standardTile("refresh", "device.refresh", width: 3, height: 2, inactiveLabel: false, decoration: "flat") {
			state "default", label:'Refresh', action:"refresh", icon:"st.secondary.refresh-icon"
		}
		standardTile("configure", "device.configure", width: 3, height: 2, inactiveLabel: false, decoration: "flat") {
			state "configure", label:'', action:"configure", icon:"st.secondary.configure"
		}
		valueTile("history", "device.history", decoration:"flat",width: 6, height: 2) {
			state "history", label:'${currentValue}'
		}

		
		details(["main", "currentKWH", "kwhCosts", "history", "resetmin", "resetmax", "resetkwh", "refresh", "configure"])
	}

	preferences {
		// added trippoint setting
        input "trippoint", "number", title: "dryer on trip point", defaultValue: 30, required: true, displayDuringSetup: true
        input "displayEvents", "boolean", title: "Display all power and energy events in the Recently tab and the device's event log?",	defaultValue: false, required: false, displayDuringSetup: true
		input "displayBatteryLevel", "boolean", title: "Display battery level on main tile and Recently tab?", defaultValue: true, 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.16, required: false, displayDuringSetup: true
		input "wattsLimit", "number", title: "Sometimes the HEM will send a wildly large watts value. What limit should be in place so that it's not processed? (in watts)", defaultValue: 20000, 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 "wattsChanged", "number", title: "For ReportType = 1, Don't send unless watts have changed by this many watts: (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: (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
		input "decimalPositions", "number", title: "How many decimal positions do you want watts AND kWh to display? (range 0 - 3)", defaultValue: 3, range: "0..3", required: false, displayDuringSetup: true
	}
}


def updated() {
	// Device-Watch simply pings if no device events received for 32min(checkInterval)
	sendEvent(name: "checkInterval", value: 2 * 15 * 60 + 2 * 60, displayed: false, data: [protocol: "zwave", hubHardwareId: device.hub.hardwareID])
	state.displayDisabled = ("true" == displayEvents)
	state.displayBattery = ("true" == displayBatteryLevel)
	log.debug "updated (kWhCost: ${kWhCost}, wattsLimit: ${wattsLimit}, reportType: ${reportType}, wattsChanged: ${wattsChanged}, wattsPercent: ${wattsPercent}, secondsWatts: ${secondsWatts}, secondsKwh: ${secondsKwh}, secondsBattery: ${secondsBattery}, decimalPositions: ${decimalPositions})"
    // add dryer capability a place to store info
    state.dryerstatus = 1    
    log.debug "device.dryerstatus: ${device.dryerstatus}"
    //
    response(configure())
}

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

	if (state.displayBattery) {
		def batteryStatusmsg = "USB power, batteries at ${device.currentState('battery')?.value}%"
		sendEvent(name: "batteryStatus", value: batteryStatusmsg, displayed: false)
	} else {
		def batteryStatusmsg = "USB power"
		sendEvent(name: "batteryStatus", value: batteryStatusmsg, displayed: false)
	}

	return result
}

def zwaveEvent(physicalgraph.zwave.commands.meterv1.MeterReport cmd) {
	def dispValue
	def newValue
	def switchValue
    def timeString = new Date().format("MM-dd-yy h:mm a", location.timeZone)
	if (cmd.meterType == 33) {
		if (cmd.scale == 0) {
			newValue = cmd.scaledMeterValue


//            log.debug "newValue is ${newValue} and prevValue is ${state.energyValue}"
			if (newValue != state.energyValue) {
				if (decimalPositions == 2) {
					dispValue = String.format("%3.2f",newValue)
				} else if (decimalPositions == 1) {
					dispValue = String.format("%3.1f",newValue)
				} else if (decimalPositions == 0) {
					dispValue = Math.round(cmd.scaledMeterValue)
				} else {
					dispValue = String.format("%3.3f",newValue)		// default
				}

				dispValue += " kWh"
				sendEvent(name: "currentKWH", value: dispValue as String, unit: "", displayed: false)

				state.energyValue = newValue
				BigDecimal costDecimal = newValue * (kWhCost as BigDecimal)
				def costDisplay = "\$"
				costDisplay += String.format("%3.2f",costDecimal)
				sendEvent(name: "kwhCosts", value: costDisplay as String, unit: "", displayed: false)
				if (state.displayDisabled) {
					[name: "energy", value: newValue, unit: "kWh", displayed: true]
				} else {
					[name: "energy", value: newValue, unit: "kWh", displayed: false]
				}
			}
		} else if (cmd.scale == 1) {
			newValue = cmd.scaledMeterValue
			if (newValue != state.energyValue) {
				dispValue = newValue + " kVAh"
				sendEvent(name: "currentKWH", value: dispValue as String, unit: "", displayed: false)
				state.energyValue = newValue
				if (state.displayDisabled) {
					[name: "energy", value: newValue, unit: "kVAh", displayed: true]
				} else {
					[name: "energy", value: newValue, unit: "kVAh", displayed: false]
				}
			}
		}
		else if (cmd.scale==2) {
			newValue = cmd.scaledMeterValue								// Remove all rounding
			if (newValue < 0) {newValue = state.powerValue}				// Don't want to see negative numbers as a valid minimum value (something isn't right with the meter) so use the last known good meter reading
			if (newValue < wattsLimit) {								// don't handle any wildly large readings due to firmware issues
				if (newValue != state.powerValue) {						// Only process a meter reading if it isn't the same as the last one
					if (decimalPositions == 2) {
						dispValue = String.format("%3.2f",newValue)
					} else if (decimalPositions == 1) {
						dispValue = String.format("%3.1f",newValue)
					} else if (decimalPositions == 0) {
						dispValue = Math.round(cmd.scaledMeterValue)
					} else {
						dispValue = String.format("%3.3f",newValue)		// default
					}
					if (newValue < state.powerLow) {
						def dispLowValue = dispValue+"w on "+timeString
						sendEvent(name: "minWATTS", value: dispLowValue as String, unit: "", displayed: false)
						state.powerLow = newValue
                        def historyDisp = ""
					    historyDisp = "Minimum/Maximum Readings as of ${timeString}\n------------------------------------------------------\nPower Low : ${device.currentState('minWATTS')?.value}\nPower High : ${device.currentState('maxWATTS')?.value}\nMessages : ${device.currentState('resetMessage')?.value}"
					    sendEvent(name: "history", value: historyDisp, displayed: false)
					}
					if (newValue > state.powerHigh) {
						def dispHighValue = dispValue+"w on "+timeString
                        def historyDisp = ""
						sendEvent(name: "maxWATTS", value: dispHighValue as String, unit: "", displayed: false)
						state.powerHigh = newValue
					    historyDisp = "Minimum/Maximum Readings as of ${timeString}\n------------------------------------------------------\nPower Low : ${device.currentState('minWATTS')?.value}\nPower High : ${device.currentState('maxWATTS')?.value}\nMessages : ${device.currentState('resetMessage')?.value}"
					    sendEvent(name: "history", value: historyDisp, displayed: false)
					}
					//////////             //Dryer on or off
             if (newValue >= trippoint){
                    	sendEvent(name: 'dryerstatus', value: 'on')
                        }
             if (newValue <= trippoint){
                    	sendEvent(name: 'dryerstatus', value: 'off')
                        }
                    sendEvent(name: "currentWATTS", value: dispValue as String, unit: "", displayed: false)
					state.powerValue = newValue
					if (state.displayDisabled) {
						[name: "power", value: newValue, unit: "W", displayed: true]
					} else {
						[name: "power", value: newValue, unit: "W", displayed: false]
					}
				}
			}
		}
	}

}

def zwaveEvent(physicalgraph.zwave.commands.batteryv1.BatteryReport cmd) {
	if (state.displayBattery) {
		def map = [:]
		map.name = "battery"
		map.unit = "%"
        map.displayed = true
		if (cmd.batteryLevel == 0xFF) { // low battery message from device
			map.value = 1
			map.isStateChange = true
		} else {
			map.value = cmd.batteryLevel
			map.isStateChange = true
		}
	sendEvent(name: "battery", value: map.value as String, displayed: true)
	return map
	} else {
		def map = [:]
		map.name = "battery"
		map.unit = "%"
        map.value = 99
        map.displayed = false
        map.isStateChange = true
        sendEvent(name: "battery", value: map.value as String, displayed: false)
		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() {
	log.debug "Refreshed ${device.name}"
	state.energyValue = -1		// force tile update
	state.powerValue = -1
	delayBetween([
		zwave.meterV2.meterGet(scale: 0).format(),
		zwave.meterV2.meterGet(scale: 2).format()
	])
}

def poll() {
	refresh()
}

// PING is used by Device-Watch in attempt to reach the Device
def ping() {
	refresh()
}

def resetkwh() {
	log.debug "${device.name} reset kWh/Cost values"
	def timeString = new Date().format("MM-dd-yy h:mm a", location.timeZone)
    def resetDisp = ""
    resetDisp = "kWh value at time of last reset was ${device.currentState('currentKWH')?.value}"
    sendEvent(name: "kWhLastReset", value: resetDisp, displayed: true)
    resetDisp = "Costs at time of last reset was ${device.currentState('kwhCosts')?.value}"
    sendEvent(name: "CostLastReset", value: resetDisp, displayed: true)
    def historyDisp = ""
	sendEvent(name: "resetMessage", value: "Energy Data (kWh/Cost) Reset On:\n"+timeString, unit: "", displayed: true)
	sendEvent(name: "currentKWH", value: "", unit: "", displayed: false)
	sendEvent(name: "kwhCosts", value: "", unit: "", displayed: false)
    historyDisp = "Minimum/Maximum Readings as of ${timeString}\n------------------------------------------------------\nPower Low : ${device.currentState('minWATTS')?.value}\nPower High : ${device.currentState('maxWATTS')?.value}\nMessages : ${device.currentState('resetMessage')?.value}"
    sendEvent(name: "history", value: historyDisp, displayed: false)
    state.energyValue = 0
	def cmd = delayBetween( [
		zwave.meterV2.meterReset().format(),
		zwave.meterV2.meterGet(scale: 0).format(),
		zwave.meterV2.meterGet(scale: 2).format()
	])
	cmd
}

def resetmin() {
	log.debug "${device.name} reset minimum watts value"
    def historyDisp = ""
	state.powerLow = 99999
	def timeString = new Date().format("MM-dd-yy h:mm a", location.timeZone)
	sendEvent(name: "resetMessage", value: "Watts Data Minimum Value Reset On:\n"+timeString, unit: "")
	sendEvent(name: "minWATTS", value: "", unit: "", displayed: false)
    historyDisp = "Minimum/Maximum Readings as of ${timeString}\n------------------------------------------------------\nPower Low : ${device.currentState('minWATTS')?.value}\nPower High : ${device.currentState('maxWATTS')?.value}\nMessages : ${device.currentState('resetMessage')?.value}"
    sendEvent(name: "history", value: historyDisp, displayed: false)
	def cmd = delayBetween( [
		zwave.meterV2.meterGet(scale: 0).format(),
		zwave.meterV2.meterGet(scale: 2).format()
	])
	cmd
}

def resetmax() {
	log.debug "${device.name} reset maximum watts value"
    def historyDisp = ""
	state.powerHigh = 0
	def timeString = new Date().format("MM-dd-yy h:mm a", location.timeZone)
	sendEvent(name: "resetMessage", value: "Watts Data Maximum Value Reset On:\n"+timeString, unit: "")
	sendEvent(name: "maxWATTS", value: "", unit: "", displayed: false)
    historyDisp = "Minimum/Maximum Readings as of ${timeString}\n------------------------------------------------------\nPower Low : ${device.currentState('minWATTS')?.value}\nPower High : ${device.currentState('maxWATTS')?.value}\nMessages : ${device.currentState('resetMessage')?.value}"
    sendEvent(name: "history", value: historyDisp, displayed: false)
	def cmd = delayBetween( [
		zwave.meterV2.meterGet(scale: 0).format(),
		zwave.meterV2.meterGet(scale: 2).format()
	])
	cmd
}

def resetMeter() {
	log.debug "Resetting all home energy meter values..."
    def resetDisp = ""
    resetDisp = "kWh value at time of last reset was ${device.currentState('currentKWH')?.value}"
    sendEvent(name: "kWhLastReset", value: resetDisp, displayed: true)
    resetDisp = "Costs at time of last reset was ${device.currentState('kwhCosts')?.value}"
    sendEvent(name: "CostLastReset", value: resetDisp, displayed: true)
    def historyDisp = ""
	state.powerHigh = 0
	state.powerLow = 99999
    state.energyValue = 0
	sendEvent(name: "minWATTS", value: "", unit: "", displayed: false)
	sendEvent(name: "maxWATTS", value: "", unit: "", displayed: false)
	sendEvent(name: "currentKWH", value: "", unit: "", displayed: false)
	sendEvent(name: "kwhCosts", value: "Cost\n--", unit: "", displayed: false)
	def timeString = new Date().format("MM-dd-yy h:mm a", location.timeZone)
	sendEvent(name: "resetMessage", value: "HEM was reset on "+timeString, unit: "", displayed: true)
    historyDisp = "Minimum/Maximum Readings as of ${timeString}\n------------------------------------------------------\nPower Low : ${device.currentState('minWATTS')?.value}\nPower High : ${device.currentState('maxWATTS')?.value}\nMessages : ${device.currentState('resetMessage')?.value}"
    sendEvent(name: "history", value: historyDisp, displayed: false)
	def cmd = delayBetween( [
		zwave.meterV2.meterReset().format(),
		zwave.meterV2.meterGet(scale: 0).format(),
		zwave.meterV2.meterGet(scale: 2).format()
	])
	cmd
}

def configure() {
	log.debug "${device.name} configuring..."

	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()
        // Accumulate kWh energy when Battery Powered. By default this is disabled to assist saving battery power. (0 == disable, 1 == enable)
        zwave.configurationV1.configurationSet(parameterNumber: 12, size: 1, scaledConfigurationValue: 1).format(),
        // Send data based on a time interval (0), or based on a change in wattage (1).	 0 is default and enables parameters 111, 112, and 113. 1 enables parameters 4 and 8.
        zwave.configurationV1.configurationSet(parameterNumber: 3, size: 1, scaledConfigurationValue: reportType).format(),
        // If parameter 3 is 1, don't send unless watts have changed by 50 <default> for the whole device.
        zwave.configurationV1.configurationSet(parameterNumber: 4, size: 2, scaledConfigurationValue: wattsChanged).format(),
        // If parameter 3 is 1, don't send unless watts have changed by 10% <default> for the whole device.
        zwave.configurationV1.configurationSet(parameterNumber: 8, size: 1, scaledConfigurationValue: wattsPercent).format(),
        // Defines the type of report sent for Reporting Group 1 for the whole device.	1->Battery Report, 4->Meter Report for Watt, 8->Meter Report for kWh
        zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, scaledConfigurationValue: 4).format(), //watts
        // If parameter 3 is 0, report every XX Seconds (for Watts) for Reporting Group 1 for the whole device.
        zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: secondsWatts).format(),
        // Defines the type of report sent for Reporting Group 2 for the whole device.	1->Battery Report, 4->Meter Report for Watt, 8->Meter Report for kWh
        zwave.configurationV1.configurationSet(parameterNumber: 102, size: 4, scaledConfigurationValue: 8).format(), //kWh
        // If parameter 3 is 0, report every XX seconds (for kWh) for Reporting Group 2 for the whole device.
        zwave.configurationV1.configurationSet(parameterNumber: 112, size: 4, scaledConfigurationValue: secondsKwh).format(),
        // Defines the type of report sent for Reporting Group 3 for the whole device.	1->Battery Report, 4->Meter Report for Watt, 8->Meter Report for kWh
        zwave.configurationV1.configurationSet(parameterNumber: 103, size: 4, scaledConfigurationValue: 1).format(), //battery
        // If parameter 3 is 0, report every XX seconds (for battery) for Reporting Group 2 for the whole device.
        zwave.configurationV1.configurationSet(parameterNumber: 113, size: 4, scaledConfigurationValue: secondsBattery).format()
	])

	cmd
}

Webcore Piston
**edited this part cause I found an error. here’s the new one so it doesn’t keep notifying

2 Likes

In case anyone wants it, i tooled with @bscuderi13’s mod and added plug control/status back in so you can see the status of the washer plug and have control for it and I changed the main tile color to green.

1 Like