Best laundry alerts for stackable units?

I’ve tried to read through existing posts and I’m pretty confused about my current options for laundry monitoring and alerts. I have stackable units and want independent information, so motion based alone probably isn’t for me… I’m going to assume I need power monitoring on each device so I can sense when things are really done (which is fine).

Does good monitoring exist that I can install now from OEM or via GitHub?

Thanks!

Brand and model of the laundry units? There are a number of available monitoring devices, but compatibility does depend in part on The specific units being monitored. :sunglasses:

If your Dryer is gas and the washer and dryer has separate 120v cords then a couple of Iris Smart Plugs worked perfect for me.

I have a CoRE Piston that notifies me when the Washer or Dryer Starts/Stops, how many Loads have been completed per day/week and if the clothes are in the washer too long after the dryer has stop to nag the family. It also notifies me when the dryer is overloaded by knowing if it has been running too long.

Works perfect!

1 Like

My direct answer is:

  • Washing Machine: LG WM2455HW
    • 120VAC electric, of course, this is on the ground
  • Dryer: Maytag Neptune MDG4000BWW
    • gas, although not officially stackable I have it on top of the washer (secured), thus pure motion sensing of the dryer isn’t going to work well (there will likely be a ton of false-positive readings from the washer underneath that shakes it)

More generally, my answer is that I’m looking for a solution that is abstracted away from make/model, mostly because I know my specific versions are far too old to have any meaningful intelligence in them. With that said, I could be wrong so I’m happy to hear about any neat integrations I can do! I’m comfortable opening these up and attaching to the control circuitry if there were a reason to do that, however, I’m guessing that’s probably not going to be too helpful.

Thanks!

They are separate, yes! I assume I’ll need at least to Smart Plugs and, possibly, some multipurpose sensors. Honestly I am hoping there’s a clean out-of-the-box SmartApp that can elegantly monitor things instead of my creating my own CoRE logic from scratch (which is my default plan, but I posted here juuuuust in case there really are prefab apps that will, almost certainly, do a better job than my clunky DIY logic!).

Thanks!

It can’t be completely abstracted away from the make/model, although I wasn’t thinking of anything that would void the warranty on the unit to require the units themselves to be smart.

Some of it is just as simple as is it a gas or electric dryer and in particular does it plug into normal 120 V outlets or does it need a 240 or a 20 Amp outlet. You need something to read the electricity that’s being used, and the easiest choice is a plug-in pocket socket, but that isn’t going to work with all machines. :sunglasses:

Right right! That’s why I answered the part about make/model to make sure it is clear that both are 120VAC appliances that can be monitored via a socket, for sure! Thanks again

1 Like

There use to be an App in Market Place called Laundry Monitor…Not sure if it is still there or not…

However, the webCoRE Laundry Monitor Piston is available for import on the webCoRE thread.

I use Mike’s dth that another member of community modified two include two buttons (#1one button is the dryer,#2 button is ‘washer’ or however you adapt the energy clamps) combined with webcore, it’s working solid.

Hardware You need: DSB09104 find it in link here:

/*
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 "Power Meter"
        capability "Actuator"
		capability "Holdable Button"
		capability "Sensor"
         capability "Refresh"
        capability "Polling"
        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 {
//nothing currently in In-Progress
//}

	// simulator metadata
	simulator {
		for (int i = 0; i <= 10000; i += 1000) {
			status "power  ${i} W-ZZ": 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-ZZ": 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
	}



}// end of metadata
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.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 = "2Ulices Total\n${formattedValue}\nkWh"		// total kWh label
                sendEvent(name: "energyDisp", value: dispValue as String, unit: "", descriptionText: "Display Energy: ${newValue} kWh", displayed: true)
                state.energyValue = newValue
                [name: "energy", value: newValue, unit: "kWh", descriptionText: "Ulices1 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 = "Power \n"+newValue+"\nWatts"	// Total watts label
                sendEvent(name: "powerDisp", value: dispValue as String, unit: "", descriptionText: "Display Power: ${newValue} Watts", displayed: true)
                state.powerValue = newValue
                [name: "power", value: newValue, unit: "W", descriptionText: "TPower: ${formattedValue}W"]
           }
		}
 	}     
}


tiles(scale: 1) {
	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")
    }

   
   	valueTile("power", "device.dryerWatts") {
			state (	"default", label:'${currentValue}W', foregroundColor: "#000000", backgroundColor:"#79b821" )
		}
   
   
	standardTile("configure", "device.configure", width: 2, height: 2, inactiveLabel: false, decoration: "flat") {
		state "configure", label:'', action:"configuration.configure", icon:"st.secondary.configure"
	}

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





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

Rad! I have a bunch of those just sitting around! I’ll try this out tonight.

So I got the HEMv1 installed and reporting data. I see a lot of threads about checking the firmware version and I think people care because you can control the reporting frequency (or just “make the cadence more regular”). Regardless, I’m having a really hard time finding official information about my device on the Aeon page https://aeotec.freshdesk.com/support/home

Specifically, I know from a purchase perspective that there are V1 and V2 devices, possibly more. When I go to Aeon they only refer to G2 and Gen5 (they don’t even use the same nomenclature, WTF?!?!). I have no idea how to identify which helpdocs relate to me because nothing seems to refer to V1 (or even V2, so I can’t deduce the right one). I want to be ultra careful because flashing wrong firmware, just in general, tends to brick devices.

Can anyone help me figure out which firmware to flash? Where do I get the binary? I can’t even find that on Aeon support site.

From the debug string I believe my monitor is on firmware 3.60 right now.

I can’t help on the firmware, but as far as the terminology, “Gen 5” refers to the Z wave chip inside the device. “GEN five” “fifth generation” “Z wave plus” “500 series chip” are all the same thing.

G2 refers to the model of this particular device. This was originally called the “second edition” of the home energy monitoring module. Then they started calling it the second generation.

And then they released a zwave plus version which they call GEN5 but that was referring to the protocol, not the specific model.

OK here are three different devices. Going by model numbers.

DSB09

Home Energy Meter

DSB28
Home Energy Meter G2

ZW095

Home Energy Meter GEN5

1 Like

Looks like I’ve got the DSB28 aka Home Energy Meter G2. Thanks

1 Like

Two questions (I’m kinda stuck on both):

  1. Is there a repo I can subscribe to instead of a static cut-and-paste for this DTH? I’ve got it manually installed for now.
  2. I can launch the app and it says “laundry running” but I’m not quite sure how to configure it… the Configure button doesn’t automatically work . Any chance you can point me at the original threads and/or some installation and usage information?

Here’s the original post.

Aeon Labs Energy Meter clamps .

The way i configured mine was by first monitoring the minimum watts each appliance needs to be considered ‘on’.

Here are the values for mine for example:

Once you do that you use core or webcore to do your monitoring.

Cool, that got me half way there. I was confused because the “Configure” button literally doesn’t work, however, clicking the “gear” in the upper right got me to the self-explanatory menu you’ve screenshotted. Step complete!

Ummm… I’m still missing something fundamental - what do I need to monitor with CoRE (<- I haven’t switched over to webcore)? Do I need to setup a piston to refresh or something?

1 Like

Here’s my washer Core piston.

IMG_1943

Pics out of sequence but hope you get the idea. you also ceeate another one for your dryer but with button#2.

I have a smart outlet on my washer to turn off so thats extra (last action). i couldn’t do that for my dryer since it uses 240v.

1 Like

Ah, I see. You’re using CoRE to monitor state and push alerts.

Did your phone really use up 53% in 13 minutes (from 77% -> 24% battery)…?! I hope those are old screenshots. Ha!

Lol yes the config are old ones .

1 Like