Aeon Home Energy Meter v1 -- Read Clamps Separately

Yes I remember that. I have been involved in the computer industry since 1964. During that period until a few years ago I worked for a company that produced computer shows, and I managed them. So you can imagine all the equipment I had. I have built at least 500 PC’s for people and companies. I loved the PC until I got my first Mac. I now have 4 Macs, two iPads and two iPhones.

1 Like

Great question. I’m not really using it for anything right now other than checking my phone while I’m out of the house to ensure nothing is major is running. At this point, I just wanted a proof of concept that I could capture them as different data points and my next steps will be putting the the data points to use.

My intentions are things like:

  • High load appliance logging (gives me insight into cost of appliance as opposed to whole house energy costs)
  • Alerts based on the transition of load to non-load to monitor when appliances like dryer/washer/dishwasher complete their cycles
  • I would also like some type of energy usage dashboard that will give me more level of granularity than just whole house usage.

Run a VM with Android on it… There are plenty of free applications that let you run a VM of android on desktop. Not sure what’s available for Mac but there has to be something available.

Any idea why mine will not populate?

Perfect timing, @Omyn.

I just picked up a second short extension cord today and hooked up the washer w/it and put the second clamp on it so I’m officially monitoring both washer and dryer w/my first HEM.

I was coming back here to see if it’s going to be possible to create a CoRE piston based on individual clamp readings?

I.e., create two CoRE pistons, one watching clamp 1 (washer) and the other watching clamp 2 (dryer). E.g., monitor Clamp 1 on washer - when goes from >30 to <15 (washer resting draw when on is about 11) means that washer just finished up and send a push message/text to let us know the washer just finished. Similar for the dryer.

Will we be able to do that?

Here is how I used an Aeon HEM v1 to monitor and provide alerts for both my washer and dryer.

2 Likes

Looked at that, but:

  1. When I go to set up a piston on CoRE, and select the HEM as the button device, it only represents one button. I don’t get an option to choose Button 1 or Button 2 for the “If” statement - only

  2. The dryer is easy to set up (or will be, once I work out issue #1 above) as it runs close to 500 watts the entire time. The washer, however, ranges from 3 watts to 300 watts during the wash cycle (3 watts during short rest periods). So it’s not clear to me how to set up a rule for that.

Any help on 1 and 2 above?

Dana,

Oh yea, I remember that issue now… Here is a copy of my tweaked version of @Mike_Maxwell’s DTH for the Washer/Dryer Aeon HEM v1 device. This will properly “announce” the correct number of “buttons” for this device as 2, thereby allowing Core to receive each of the button events so you can send out push/text messages. This has been 100% reliable for me. Hope this helps!

Not sure about your second issue. Does it ever drop below 3W?

/*
Custom Laundry monitor device for Aeon HEM V1 

*/

metadata {
	definition (name: "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: "washerRW", type: "number", title: "Washer running watts:", description: "", required: true
        input name: "dryerRW", type: "number", title: "Dryer running watts:", description: "", required: true
    }
	
    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)
                        state.washerIsRunning = true
                    } else {
                    	//washer is off
                        if (state.washerIsRunning == true){
                        	//button event
                            sendEvent(name: "button", value: "pushed", 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: 2], descriptionText: "Dryer has finished.", isStateChange: true)
                        }
                        sendEvent(name: "dryerState", value: "off", displayed: true)
                        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]
            }
        }
    }
}

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)
}
6 Likes

#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