Aeon Home Energy Meter v1 -- Read Clamps Separately

#2 is easy if they both drop to 0 at the end of the cycle. If not, see what the standby draw is. If less than 3w, again it’s easy. If not, I got nothing :slight_smile:

Both my washer and dryer power off at the end of the cycle (except if I have the keep wash fresh or wrinkle rid options on), so I can easily set the numbers based on minimum cycle wattage.

I did the same thing to setup notifications. I did, however, go the extra step of setting up Washer/Dryer On as a pushed event and Washer/Dryer Off as a held event, so I get notifications at the start and end of the cycle. This also allowed start/stop logging under Recent Activity.

Thanks!! Just loaded the DTH from your code and am getting the desired Button #1 and Button #2 options!

Thanks very much. I really wish I had time to sit down and learn how to code this myself…never wrote anything but DOS batch files myself, and I can copy/paste stuff when it’s pretty simple to add functions, but I want to do more.

Thanks!

1 Like

Thanks…unfortunately it’s not so simple as mine never get to zero…washer sits at 5 or 6 watts when idle, dryer at 3 or 4 watts. It’s hard to be sure, but it also looks in one place that it might have gone to 7 watts while idling. So I’m planning on using 9 and 6 for Washer and Dryer, respectively, for the “running watts.”

@MEarly, to do below did you change the code to get support for both push and hold options?

Add to On state:

//button event
if (!state.washerIsRunning)
  sendEvent(name: "button", value: "pushed", data: [buttonNumber: 1], descriptionText: "Washer has started.", isStateChange: true)

Modify Off state:

`//button event
 sendEvent(name: "button", value: "held", data: [buttonNumber: 1], descriptionText: "Washer has finished.", isStateChange: true)
1 Like

Thanks! Ended up with below, and it saved/published and my phone and hub haven’t exploded so presumably it works. :slight_smile:

if (state.washerIsRunning == true){ //button event sendEvent(name: "button", value: "pushed", data: [buttonNumber: 1], descriptionText: "Washer has started.", isStateChange: true) sendEvent(name: "button", value: "held", data: [buttonNumber: 1], descriptionText: "Washer has finished.", isStateChange: true) } sendEvent(name: "washerState", value: "off", displayed: true) state.washerIsRunning = false } } else { name = "dryerWatts" if (value >= settings.dryerRW.toInteger()){ //dryer is on sendEvent(name: "dryerState", value: "on", displayed: true) state.dryerIsRunning = true } else { //dryer is off if (state.dryerIsRunning == true){ //button event sendEvent(name: "button", value: "pushed", data: [buttonNumber: 1], descriptionText: "Dryer has started.", isStateChange: true) sendEvent(name: "button", value: "held", data: [buttonNumber: 2], descriptionText: "Dryer has finished.", isStateChange: true)

1 Like

Oh, and @ogiewon/Dan - the new icons are very cool!

2 Likes

So that code won’t work. It will send both push and hold back-to-back. Yours should look more like this:

if (scale == 2 ){ //watts
        	str = "watts"
            if (source == 1){
            	name = "washerWatts"
                if (value >= settings.washerRW.toInteger()){
                	//washer is on
                    sendEvent(name: "washerState", value: "on", displayed: false)
                    
                    //button event
                    if (!state.washerIsRunning)
                    	sendEvent(name: "button", value: "pushed", data: [buttonNumber: 1], descriptionText: "Washer has started.", isStateChange: true)
                        
                    state.washerIsRunning = true
                } else {
                	//washer is off
                    if (state.washerIsRunning == true){
                    	//button event
                        sendEvent(name: "button", value: "held", data: [buttonNumber: 1], descriptionText: "Washer has finished.", isStateChange: true)
                    }
                    sendEvent(name: "washerState", value: "off", displayed: false)
                    state.washerIsRunning = false
                }
            } else {
            	name = "dryerWatts"
                if (value >= settings.dryerRW.toInteger()){
                	//dryer is on
                    sendEvent(name: "dryerState", value: "on", displayed: false)
                    //button event
                    if (!state.dryerIsRunning)
                    	sendEvent(name: "button", value: "pushed", data: [buttonNumber: 2], descriptionText: "Dryer has started.", isStateChange: true)
                        
                    state.dryerIsRunning = true
                } else {
                	//dryer is off
                    if (state.dryerIsRunning == true){
                    	//button event
                        sendEvent(name: "button", value: "held", data: [buttonNumber: 2], descriptionText: "Dryer has finished.", isStateChange: true)
                    }
                    sendEvent(name: "dryerState", value: "off", displayed: false)
                    state.dryerIsRunning = false
                }
            }
2 Likes

Yeah, great icons! Added them to mine too.

2 Likes

Dammit, and I was so proud of myself!! :wink:

Thanks for the correction.

Glad hear you’ve got it working! This community, and its willingness to share, is the best part of ST.

2 Likes

OK!

Re-coded, re-factored, re-updated, re-borrowed (i.e., copied a bunch of stuff from you, @MEarly :slight_smile: ) and now have below, which even if it’s wrong (and I’m assuming it is) does seem to work somehow for my current purposes. :smiley: (Don’t confuse me with facts…)

I set up a CoRE piston to send me a text when my Dryer button changed to “Push” and sure enough, ran the dryer for a few minutes to get the reading up, opened the dryer door, and sure enough a “Dryer finished” text arrived. Tah-dah! It’s like I’m Thomas Edison and Albert Einstein, put together!

So my only remaining issue is how to manage when someone has to open the washer or dryer door for a moment during the cycle, to add an item or just to check how done things are in the dryer.

I haven’t figured out a good way to handle that yet…anyone else come up w/a clever way to avoid getting false positive “It’s done!” messages when someone interrupts the cycle before the wash/dry is finished? Since the reading when the washer or dryer is stopped in the middle of the cycle is the same as the reading when the are sitting there not doing anything, I can’t differentiate the “paused” versus “done” states via a watts value.

And here’s the updated section of the code…be gentlle.

[code] if (scale == 2 ){ //watts
str = "watts"
if (source == 1){
name = "washerWatts"
if (value >= settings.washerRW.toInteger()){
//washer is on
sendEvent(name: “washerState”, value: “on”, displayed: true)

                //button event
                if (!state.washerIsRunning)
                	sendEvent(name: "button", value: "pushed", data: [buttonNumber: 1], descriptionText: "Washer has started.", isStateChange: true)                        
                    
                    state.washerIsRunning = true
                } else {
                	//washer is off
                    if (state.washerIsRunning == true){
                    	//button event
                        sendEvent(name: "button", value: "held", data: [buttonNumber: 1], descriptionText: "Washer has started.", isStateChange: true)
                    }
                    sendEvent(name: "washerState", value: "off", displayed: false)
                    state.washerIsRunning = false
                }
            } else {
            	name = "dryerWatts"
                if (value >= settings.dryerRW.toInteger()){
                	//dryer is on
                    sendEvent(name: "dryerState", value: "on", displayed: false)
                    
                //button event
                if (!state.washerIsRunning)
                	sendEvent(name: "button", value: "pushed", data: [buttonNumber: 1], descriptionText: "Washer has started.", isStateChange: true)                        
                    
                    state.dryerIsRunning = true
                } else {
                	//dryer is off
                    if (state.dryerIsRunning == true){
                    	//button event
                        sendEvent(name: "button", value: "held", data: [buttonNumber: 1], descriptionText: "Dryer has started.", isStateChange: true)
                    }
                    sendEvent(name: "dryerState", value: "off", displayed: false)
                    state.dryerIsRunning = false
                }
            }
            if (state.washerIsRunning || state.dryerIsRunning){
            	sendEvent(name: "switch", value: "on", descriptionText: "Laundry has started...", displayed: true)
            } else {
            	sendEvent(name: "switch", value: "off", displayed: false)
            }
            //log.debug "mc3v- name: ${name}, value: ${value}, unit: ${str}"
        	return [name: name, value: value.toInteger(), unit: str, displayed: false]
        }
    }
}

}
[/code]

1 Like

So, I’ve given this a bit of thought as well. One particular solution was to assess the state over a period of time before issuing the “It’s done” alert. But this would not cover 100% of scenarios because I can empty a load and start a new one pretty quickly. So, it would be difficult to set a threshold.

My other solution is around $60 more expensive. It involves adding door sensors.

If isWasherRunning && isDoorOpened then wasCycleInterrupted = true.

1 Like

Sounds like we’ve both been thinking about similar possible approaches.

But…I hadn’t thought about door sensors! Really mostly need a way to avoid false positives for the dryer, which is typically the one that gets opened most often during a cycle. I have a spare door sensor sitting around, so I’m going to look into that approach! Luckily (for a change) I have an old-fashioned dryer w/the square metal door, so it’ll be really easy to add a door sensor to it.

The washer is really only ever opened during a cycle within the first couple of minutes of the start (and frankly I think I’m the only one in the family who knows how to do that). :slight_smile: I could put a state check in for the washer piston (i.e., if < 5 minutes since Push then ignore Hold. Frankly, the more I think about it, I really don’t need to worry too much about the washer and may just leave things w/out any checks for the washer and see it’s actually a problem.

Thanks for the idea! I owe you once again… :smiley:

1 Like

This worked great for me. Lost power today and wanted to monitor generator balance. Hooked one of the HEM to my generator feed and bam instant load balance monitoring. :slight_smile:

4 Likes

@MEarly; @ogiewon, @Omyn, @Jmtyra, and anyone else who is interested!

I’ve got my washer and dryer CoRE pistons set up and working and receive washer and dryer notifications, and they appear to work properly. I’ve edited the DTH to label all the settings that have been appearing in Preferences (some were blank, no labels) and fixed a few errors in my code (I think! :slight_smile: ) where I had not updated things properly.

I’d still like to do a couple more updates:

  1. Add reporting frequency (currently managed in the Configuration section of the code) to the Preferences - don’t know how (or if it’s possible) to do that.
  2. ID what kWhDelay and detailDelay settings do - I don’t understand what they affect.
  3. If kWhDelay and deatilDelay aren’t useful for users to edit, remove them from Preferences. (They showed up there unlabeled before I added them to the Preferences section of the code.)

If you (or anyone) sees any errors or problems w/the code, please fire away!! This is my first time sharing back modified code, kinda fun. :smiley:

/*
In-progress update of Mike Maxwell's HEM Laundry monitoring device for Aeon HEM V1. Includes customizations 
from Ogiewon and MEarly. 
SmartThings thread: https://community.smartthings.com/t/aeon-home-energy-meter-v1-read-clamps-separately/25480/100?u=danabw
Status: 
1. Done: Ogiewon - Fix reported number of buttons so both are announced/available in SmartApps  
2. Done: MEarly - Set Washer/Dryer On=pushed event; Washer/Dryer Off=held event. Allows notifications at start/end of cycle, & start/stop logging under Recent Activity.     
2. Done: Danabw - All Preferences entries labeled 
3. Need help: 1) Add reporting frequency setting to preferences (currently only managed in Configuration section, not available in preferences
4. Need help: 2) ID what KWhDelay and detailDelay settings control, and remove them from Preferences if user control not necessary  
*/

metadata {
	definition (name: "In-progress update of Maxwell's Aeon HEM V1 Laundry DTH", namespace:	"MikeMaxwell", author: "Mike Maxwell") 
	{
		capability "Configuration"
		capability "Switch"
        capability "Button"
        //capability "Energy Meter"
		capability "Actuator"
		capability "Holdable Button"
		capability "Sensor"

        attribute "washerWatts", "string"
        attribute "dryerWatts", "string"
        attribute "washerState", "string"
        attribute "dryerState", "string"
        
//        command "configure"
        
		fingerprint deviceId: "0x2101", inClusters: " 0x70,0x31,0x72,0x86,0x32,0x80,0x85,0x60"
	}

	preferences {
        input name: "c1Name", type: "text", title: "Clamp 1 device (e.g., Washer)", description: "", required: true
       	input name: "washerRW", type: "number", title: "Minimum watts device draws when running:", description: "", required: true
        input name: "c2Name", type: "text", title: "Clamp 2 device (e.g., Dryer)", description: "", required: true
        input name: "dryerRW", type: "number", title: "Minimum watts device draws when running:", description: "", required: true
        input name: "voltageValue", type: "number", title: "Line voltage: 120 or 240", description: "", required: true
        input name: "kWhCost", type: "number", title: "Cost per kWh", description: "", required: true 
//	Not sure what kWhDelay is or does. Not sure how to remove it from the Preferences screen - it displaye w/no label before I created this entry.  
		input name: "kWhDelay", type: "number", title: "kWh Delay", description: "", required: true  
//	Not sure what detailDelay is or does. Not sure how to remove it from the Preferences screen - it displaye w/no label before I created this entry. 
		input name: "detailDelay", type: "number", title: "Detail Delay", description: "", required: true  

//	Would like to add an entry in Preferences to set the HEM reporting frequency (it is included in the Configuration  
//	section at the end of the code, but I don't know how to do that. :)

    }
	
    simulator {

	}

	tiles(scale: 2) {
    	multiAttributeTile(name:"laundryState", type: "generic", width: 6, height: 4, canChangeIcon: false){
        	tileAttribute ("device.switch", key: "PRIMARY_CONTROL") {
//            	attributeState "on", label:'Laundry Running', icon:"st.Appliances.appliances1", backgroundColor:"#53a7c0"
//            	attributeState "off", label:'Laundry Done', icon:"st.Appliances.appliances1", backgroundColor:"#ffffff"
            	attributeState "on", label:'', icon:"st.samsung.da.dryer_ic_dryer", backgroundColor:"#79b821"
            	attributeState "off", label:'', icon:"st.samsung.da.dryer_ic_dryer", backgroundColor:"#ffffff"
        	}
                   
            tileAttribute("device.switch", key: "SECONDARY_CONTROL") {
             	attributeState "on", label:'Laundry Running'
            	attributeState "off", label:'Laundry Done'
    		}
        }   

/*        
        valueTile("washerState", "device.washerState", width: 3, height: 2, canChangeIcon: true) {
        	state "default", label:'Washer\n${currentValue}'        
        }
        valueTile("dryerState", "device.dryerState", width: 3, height: 2, canChangeIcon: true) {
        	state "default", label:'Dryer\n${currentValue}'        
        }
*/
        standardTile("washerState", "device.washerState", width: 3, height: 3, canChangeIcon: true) {
        	state "off", label:'${name}', icon: "st.samsung.da.washer_ic_washer", backgroundColor:"#ffffff"
            state "on", label:'${name}', icon: "st.samsung.da.washer_ic_washer", backgroundColor:"#79b821"
        }
        standardTile("dryerState", "device.dryerState", width: 3, height: 3, canChangeIcon: true) {
        	state "off", label:'${name}', icon: "st.samsung.da.dryer_ic_dryer", backgroundColor:"#ffffff"
            state "on", label:'${name}', icon: "st.samsung.da.dryer_ic_dryer", backgroundColor:"#79b821"
        }

		valueTile("washer", "device.washerWatts", width: 3, height: 2, decoration: "flat") {
            state("default", label:'Washer\n${currentValue} Watts', foregroundColor: "#000000")
        }

		valueTile("dryer", "device.dryerWatts", width: 3, height: 2, decoration: "flat") {
            state("default", label:'Dryer\n${currentValue} Watts', foregroundColor: "#000000")
        }
       
		standardTile("configure", "device.configure", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
			state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure"
		}

		main "laundryState"
		details(["laundryState","washerState","dryerState","washer","dryer","configure"])
	}
}

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(physicalgraph.zwave.commands.multichannelv3.MultiChannelCmdEncap cmd) {
	//log.info "mc3v cmd: ${cmd}"
	if (cmd.commandClass == 50) {  
    	def encapsulatedCommand = cmd.encapsulatedCommand([0x30: 1, 0x31: 1])
        if (encapsulatedCommand) {
        	def scale = encapsulatedCommand.scale
        	def value = encapsulatedCommand.scaledMeterValue
            def source = cmd.sourceEndPoint
            def str = ""
            def name = ""
        	if (scale == 2 ){ //watts
            	str = "watts"
                if (source == 1){
                	name = "washerWatts"
                    if (value >= settings.washerRW.toInteger()){
                    	//washer is on
                        sendEvent(name: "washerState", value: "on", displayed: true)
                        
                    //button event
                    if (!state.washerIsRunning)
                    	sendEvent(name: "button", value: "pushed", data: [buttonNumber: 1], descriptionText: "Washer has started.", isStateChange: true)                        
                        
                        state.washerIsRunning = true
                    } else {
                    	//washer is off
                        if (state.washerIsRunning == true){
                        	//button event
                            sendEvent(name: "button", value: "held", data: [buttonNumber: 1], descriptionText: "Washer has finished.", isStateChange: true)
                        }
                        sendEvent(name: "washerState", value: "off", displayed: false)
                        state.washerIsRunning = false
                    }
                } else {
                	name = "dryerWatts"
                    if (value >= settings.dryerRW.toInteger()){
                    	//dryer is on
                        sendEvent(name: "dryerState", value: "on", displayed: false)
                        
                    //button event
                    if (!state.dryerIsRunning)
                    	sendEvent(name: "button", value: "pushed", data: [buttonNumber: 2], descriptionText: "Dryer has started.", isStateChange: true)                        
                        
                        state.dryerIsRunning = true
                    } else {
                    	//dryer is off
                        if (state.dryerIsRunning == true){
                        	//button event
                            sendEvent(name: "button", value: "held", data: [buttonNumber: 2], descriptionText: "Dryer has finished.", isStateChange: true)
                        }
                        sendEvent(name: "dryerState", value: "off", displayed: false)
                        state.dryerIsRunning = false
                    }
                }
                if (state.washerIsRunning || state.dryerIsRunning){
                	sendEvent(name: "switch", value: "on", descriptionText: "Washer and/or Dryer running...", displayed: true)
                } else {
                	sendEvent(name: "switch", value: "off", displayed: false)
                }
                //log.debug "mc3v- name: ${name}, value: ${value}, unit: ${str}"
            	return [name: name, value: value.toInteger(), unit: str, displayed: false]
            }
        }
    }
}

def zwaveEvent(physicalgraph.zwave.Command cmd) {
	// Handles all Z-Wave commands we aren't interested in
    //log.debug "Unhandled event ${cmd}"
	[:]
}

def configure() {
	log.debug "configure()"
    initialize()
	def cmd = delayBetween([
    	//zwave.configurationV1.configurationSet(parameterNumber: 100, size: 4, scaledConfigurationValue:1).format(),	//reset if not 0
        //zwave.configurationV1.configurationSet(parameterNumber: 110, size: 4, scaledConfigurationValue: 1).format(),	//reset if not 0
        
    	zwave.configurationV1.configurationSet(parameterNumber: 1, size: 2, scaledConfigurationValue: 120).format(),		// assumed voltage
		zwave.configurationV1.configurationSet(parameterNumber: 3, size: 1, scaledConfigurationValue: 0).format(),			// Disable (=0) selective reporting
		zwave.configurationV1.configurationSet(parameterNumber: 9, size: 1, scaledConfigurationValue: 10).format(),			// Or by 10% (L1)
      	zwave.configurationV1.configurationSet(parameterNumber: 10, size: 1, scaledConfigurationValue: 10).format(),		// Or by 10% (L2)
		zwave.configurationV1.configurationSet(parameterNumber: 20, size: 1, scaledConfigurationValue: 1).format(),			//usb = 1
		zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, scaledConfigurationValue: 6912).format(),   	
		zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: 30).format() 		// Every 30 seconds
	], 2000)

	return cmd
}

def installed() {
	configure()
}

def updated() {
	configure()
}

def initialize() {
	sendEvent(name: "numberOfButtons", value: 2)
}
1 Like

Oh SO annoying…I’ve discovered an odd quirk in my washer…when it is sitting idle between loads it never gets over 8 watts.

However, at the end of a cycle, until you open the door, it sits there at 10 watts. It’s not doing anything - just sitting there w/damp clothes inside, showing 00 minutes left on the display. As soon as I open the door the watts drop to 8, 7, 6 range.

The problem is that it also goes down to 10 watts several times during a cycle, and in looking at the event list, even 9 watts. So 10 watts is both a “done” and a “running” value. So I’ve had to integrate a timer in the Washer piston, i.e., when the button is held (washer has fallen to 10 watts), wait 3 minutes, and if button is still held (still at 10 watts), then notify wash is done. So I should only get a notification on wash done when it holds at 10 watts for several minutes, which it doesn’t do during the cycle.

Is anyone running this device type on an iPhone with any success? If so please tell me how you got it to work and populate. Thanks

IS any one implement this with google sheets???
so each clamp report separately to google sheets??

Would someone please give me the Github settings for the IDE, I just want the one for reading separately, don’t need shut off etc… I think my problem is I have tried so many wrong codes it screwed things up.

1 Like