Securifi Peanut Plug Power Meter

Just wondering if anyone ever managed to hack together a working driver to expose the power meter capability of these plugs.

The Generic Zigbee Outlet driver displays power. Mine shows power: 0 because I don’t have anything plugged in. It’s a repeater only for me .

EDIT: I went and plugged an iron into it which should be enough for it to detect power but it hasn’t so far, been about 12 minutes. Event logs show power equal to zero, implying the device sends that.

Edit2: After waiting til the iron self turned off, (25 min) there was no Power report from the Peanut Plug.

1 Like

The peanut plugs required a firmware update to report power, even on ST. And you can only update the firmware using an Almond router. Sorry.

3 Likes

Thanks for testing that and discovering what I was afraid of as well. I saw Ryan's comment as well. Maybe I'll pickup a used Almond router just for the heck of it sometime.
Thanks Guys!!

1 Like

Thanks for the info!!

1 Like

Don't bother picking up an almond. I have the latest firmware and it worked great with a custom DTH on ST with power and energy reporting. It doesn't really work with HE generic zigbee driver. The power reporting is all over the place.

1 Like

Yeahhh...I started messing with that driver in an attempt to port it to HE, but I don't think a few of the power reporting capabilities are in place yet in the com.hubitat.zigbee.DataType.
I was using this as the base:

Ha, I don't recall how I found it, nor does power reporting work(have latest firmware
Here's the driver from same guy, can't find the link for the life of me.
Hope it helps you

metadata {
definition (name: "Peanut Plug", namespace: "pakmanwg", author: "pakmanw@sbcglobal.net", ocfDeviceType: "oic.d.switch",
vid: "generic-switch-power-energy") {
capability "Energy Meter"
capability "Actuator"
capability "Switch"
capability "Power Meter"
capability "Polling"
capability "Refresh"
capability "Configuration"
capability "Sensor"
capability "Light"
capability "Health Check"
capability "Voltage Measurement"

	attribute "current","number"

	command "reset"
   
	fingerprint profileId: "0104", inClusters: "0000, 0003, 0004, 0005, 0006, 0B04, 0B05",
		outClusters: "0000, 0001, 0003, 0004, 0005, 0006, 0019, 0B04, 0B05"
}

// tile definitions
tiles {
	standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true) {
		state "on", label: '${name}', action: "switch.off", icon: "st.switches.switch.on", backgroundColor: "#00A0DC"
		state "off", label: '${name}', action: "switch.on", icon: "st.switches.switch.off", backgroundColor: "#ffffff"
	}
	valueTile("power", "device.power") {
		state "default", label:'${currentValue} W'
	}
	valueTile("energy", "device.energy") {
		state "default", label:'${currentValue} kWh'
	}
	valueTile("voltage", "device.voltage") {
		state "default", label:'${currentValue} V'
	}
	valueTile("current", "device.current") {
		state "default", label:'${currentValue} A'
	}
	standardTile("reset", "device.energy", inactiveLabel: false, decoration: "flat") {
		state "default", label:'reset kWh', action:"reset"
	}
	standardTile("refresh", "device.power", inactiveLabel: false, decoration: "flat") {
		state "default", label:'', action:"refresh.refresh", icon:"st.secondary.refresh"
	}

	main(["switch","power","energy","voltage","current"])
	details(["switch","power","energy","voltage","current","refresh","reset"])
}

}

def parse(String description) {

log.debug "description is $description"
def event = zigbee.getEvent(description)
if (event) {
	if (event.name == "power") {
		def powerValue
		powerValue = (event.value as Integer) * getPowerMultiplier()
		sendEvent(name: "power", value: powerValue)
		def time = (now() - state.time) / 3600000 / 1000
		state.time = now()
		log.debug "powerValues is $state.powerValue"
		state.energyValue = state.energyValue + (time * state.powerValue)
		state.powerValue = powerValue
		// log.debug "energyValue is $state.energyValue"
		sendEvent(name: "energy", value: state.energyValue)
	} else {
		sendEvent(event)
	}
} else if (description?.startsWith("read attr -")) {
	def descMap = zigbee.parseDescriptionAsMap(description)
    log.debug "Desc Map: $descMap"
    if (descMap.clusterInt == zigbee.ELECTRICAL_MEASUREMENT_CLUSTER) {
    	def intVal = Integer.parseInt(descMap.value,16)
    	if (descMap.attrInt == 0x0600) {
        	log.debug "ACVoltageMultiplier $intVal"
            state.voltageMultiplier = intVal
        } else if (descMap.attrInt == 0x0601) {
        	log.debug "ACVoltageDivisor $intVal"
            state.voltageDivisor = intVal
        } else if (descMap.attrInt == 0x0602) {
        	log.debug "ACCurrentMultiplier $intVal"
            state.currentMultiplier = intVal
        } else if (descMap.attrInt == 0x0603) {
        	log.debug "ACCurrentDivisor $intVal"
            state.currentDivisor = intVal
        } else if (descMap.attrInt == 0x0604) {
        	log.debug "ACPowerMultiplier $intVal"
            state.powerMultiplier = intVal
        } else if (descMap.attrInt == 0x0605) {
        	log.debug "ACPowerDivisor $intVal"
            state.powerDivisor = intVal
        } else if (descMap.attrInt == 0x0505) {
            def voltageValue = intVal * getVoltageMultiplier()
            log.debug "Voltage ${voltageValue}"
            state.voltage = $voltageValue
            sendEvent(name: "voltage", value: voltageValue)
        } else if (descMap.attrInt == 0x0508) {
            def currentValue = intVal * getCurrentMultiplier()
            log.debug "Current ${currentValue}"
            state.current = $currentValue
            sendEvent(name: "current", value: currentValue)
        }
    } else {
    	log.warn "Not an electrical measurement"
    }
} else {
	log.warn "DID NOT PARSE MESSAGE for description : $description"
	log.debug zigbee.parseDescriptionAsMap(description)
}

}

def installed() {
reset()
configure()
refresh()
}

def off() {
zigbee.off()
}

def on() {
zigbee.on()
}

def refresh() {
Integer reportIntervalMinutes = 5
zigbee.onOffRefresh() +
zigbee.simpleMeteringPowerRefresh() +
zigbee.electricMeasurementPowerRefresh() +
zigbee.onOffConfig(0, reportIntervalMinutes * 60) +
zigbee.simpleMeteringPowerConfig() +
zigbee.electricMeasurementPowerConfig() +
voltageMeasurementRefresh() +
voltageMeasurementConfig() +
currentMeasurementRefresh() +
currentMeasurementConfig() +
zigbee.readAttribute(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, 0x0600) +
zigbee.readAttribute(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, 0x0601) +
zigbee.readAttribute(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, 0x0602) +
zigbee.readAttribute(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, 0x0603) +
zigbee.readAttribute(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, 0x0604) +
zigbee.readAttribute(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, 0x0605)
}

def currentMeasurementConfig(minReportTime=1, maxReportTime=600, reportableChange=0x0030) {
zigbee.configureReporting(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, 0x0508, DataType.UINT16, minReportTime, maxReportTime, reportableChange)
}

def currentMeasurementRefresh() {
zigbee.readAttribute(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, 0x0508);
}

def voltageMeasurementConfig(minReportTime=1, maxReportTime=600, reportableChange=0x0018) {
zigbee.configureReporting(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, 0x0505, DataType.UINT16, minReportTime, maxReportTime, reportableChange)
}

def voltageMeasurementRefresh() {
zigbee.readAttribute(zigbee.ELECTRICAL_MEASUREMENT_CLUSTER, 0x0505);
}

def getCurrentMultiplier() {
if (state.currentMultiplier && state.currentDivisor) {
return (state.currentMultiplier / state.currentDivisor)
} else {
return 0.001831
}
}

def getVoltageMultiplier() {
if (state.voltageMultiplier && state.voltageDivisor) {
return (state.voltageMultiplier / state.voltageDivisor)
} else {
return 0.0045777
}
}

def getPowerMultiplier() {
if (state.powerMultiplier && state.powerDivisor) {
return (state.powerMultiplier / state.powerDivisor)
} else {
return 0.277
}
}

def configure() {
log.debug "in configure()"
return configureHealthCheck()
}

def configureHealthCheck() {
Integer hcIntervalMinutes = 12
sendEvent(name: "checkInterval", value: hcIntervalMinutes * 60, displayed: false, data: [protocol: "zigbee", hubHardwareId: device.hub.hardwareID])
return refresh()
}

def updated() {
log.debug "in updated()"
// updated() doesn't have it's return value processed as hub commands, so we have to send them explicitly
def cmds = configureHealthCheck()
cmds.each{ sendHubCommand(new hubitat.device.HubAction(it)) }
}

def ping() {
return zigbee.onOffRefresh()
}

def reset() {
state.energyValue = 0.0
state.powerValue = 0.0
state.voltage = 0.0
state.current = 0.0
state.time = now()
sendEvent(name: "energy", value: state.energyValue)
}

Did it work?

I don't have a Securifi Almond to update the Peanuts with so have paused my effort on this. If I ever come across a cheapo Almond I may try to make it work.

I have a couple of Peanut Plugs and installed this driver. It works for on/off, but never seems to get any values for any of the power settings. I had a driver installed in my ST days and it was always sketchy as well. I'll keep my eye out for anything I see.

My peanut plugs are up-to-date and with the above driver. It worked perfectly on ST but not on HE. I get this on HE in the log.

warnDID NOT PARSE MESSAGE for description : read attr - raw: 91AD010B040A0505215266, dni: 91AD, endpoint: 01, cluster: 0B04, size: 0A, attrId: 0505, encoding: 21, command: 0A, value: 5266

I updated the penaut plugs using almond router/hub
using generic zigbee outlet driver, it is working so far, but the values are sometimes wrong, like 2588 watts when it's usually around 250. not sure if someone has another code that I could try

did u sort out your peanut problems?

Sorry for the late response. Never got the power reading to work. I just use the plugs for ON/OFF and repeaters.

I have taken the original SmartThings driver written by pakmanwg and ported it to Hubitat.
I modified it to make the power/voltage/current work and allow the setting of reporting criteria.

The code is on GidHub at:

Peanut Plug Driver

It appears to be working on my Hubitat including reporting of power/voltage/current.
The installation instructions are in the readme.
If you have any problems with the driver, please let me know.
Hope folks find this useful.

5 Likes

@jim1 I am assuming that if the current and voltage read 0E-10 that it needs that upgrade you mentioned?

Oops. After posting I realized I'd gotten so busy getting the readme written and uploaded that I'd forgotten to upload the latest PeanutPlug.groovy.
It is now in GitHub. Try it again and see if it doesn't work ok.
Sorry, I didn't expect such quick response.

1 Like

@jim1 Loaded it in and here is a pic.

If you scroll down a bit to Preferences do you see 'Power Change Report Value, Power Reporting Interval, etc.?
If you do, then you have the correct version of the app.
It's curious that I have an entry for energy but you don't. You might try deleting the plug and re-paring it but I don't really expect that to help.
I've never tried using a Peanut Plug with the original firmware so I can't say for sure that this is what is happening but, the consensus from the postings I see is unanimous that old firmware WON'T report power. Even on SmartThings.
Any way you can update the firmware?

Edit:
I forgot to mention that after you update the app you need to click 'Save Preferences' and probably clicking 'Configure' and 'Refresh' wouldn't hurt either. Otherwise, it might not notice that the app has been changed.

1 Like