[DEPRECATED THREAD: visit community.webcore.co for assistance] WebCoRE - Example Pistons

No luck here either when I tried before… I got some wierd combos :smiley:

I don’t even know where to begin. I want to make a piston that turns a couple lights on each night and then off but vary the time by a few minutes. Basically vacation lighting. The on and off at a set time is easy, but the varying the time stumps me.

Here is one that I use.
There are some virtual switchs that I use for testing and other things that can be left out.
You can leave the set piston state out as well.

I know what you’re saying.
This simulates my wife going to the en suite 50 times a night. :wink:
This one doesn’t.

2 Likes

This is an autolock for any of my three zwave locks. This changes the TCP to cancel on piston only. This seems to work for the scenario where one lock unlocks, another lock unlocks, the original lock locks and then unlocks again, all within the lock timer (three minutes in my example). I noticed my piston was getting cancelled if multiple locks opened, and I assumed there could be a situation where if you locked the lock and unlocked it again the original 3 minute timer would lock it early. The async if/while and cancel on piston only seem to account for this.

This piston was created with the help of @bangali who set up the Piston State messages and provides an example of a complex piston state setup. The concept of the piston is to turn devices (in my case, a wall heater and a water heater) on a specified time before the time for which your Wake-Up alarm is set. If the device is not turned on by the piston, the reason why the device was not turned on (i.e. the condition which had not been met), is displayed in the webCore Dashboard. A few examples of the piston state in the Dashboard:

The piston (Important: For the piston state to be set correctly, Condition traversal optimization has to be turned off. (In Edit mode, click on Settings > Gear Icon > Look for CTO and turn it off):

The Alarm (Piston) is Turned On or Off and the Wake-up time of the piston is set with this device handler, which is an adaptation of a DTH was originally created by @Arnqvist:

/**
 * This is copied directly from the Z-wave switch with power metering from SmartThings, i added a Image Capture
 * capability just to be able to send a string to webcore, the string is the departure time which represent
 * when you are leaving your home so the switch turns on a couple of hours before if you have plugged in
 * your engine heater cable. All rules are set in webcore though. This just provides an easy way of setting
 * a departure time.
 */
metadata {
	definition (name: "Z-Wave Metering Switch With Timer", namespace: "arnqvist", author: "Petter Arnqvist Eriksson", ocfDeviceType: "oic.d.switch") {
		capability "Energy Meter"
		capability "Actuator"
		capability "Switch"
		capability "Power Meter"
		capability "Polling"
		capability "Refresh"
		capability "Configuration"
		capability "Sensor"
		capability "Light"
		capability "Health Check"
        capability "Image Capture"
       
        attribute "departure", "string"

		command "reset"

		fingerprint inClusters: "0x25,0x32"
		fingerprint mfr:"0086", prod:"0003", model:"0012", deviceJoinName: "Aeon Labs Micro Smart Switch"
	}
    
    preferences {
    input name: "timer", type: "time", title: "Tid för avresa:", description: "Ange tid", required: false
	}

	// simulator metadata
	simulator {
		status "on":  "command: 2003, payload: FF"
		status "off": "command: 2003, payload: 00"

		for (int i = 0; i <= 10000; i += 1000) {
			status "power  ${i} W": new physicalgraph.zwave.Zwave().meterV1.meterReport(
				scaledMeterValue: i, precision: 3, meterType: 4, scale: 2, size: 4).incomingMessage()
		}
		for (int i = 0; i <= 100; i += 10) {
			status "energy  ${i} kWh": new physicalgraph.zwave.Zwave().meterV1.meterReport(
				scaledMeterValue: i, precision: 3, meterType: 0, scale: 0, size: 4).incomingMessage()
		}

		// reply messages
		reply "2001FF,delay 100,2502": "command: 2503, payload: FF"
		reply "200100,delay 100,2502": "command: 2503, payload: 00"

	}

	// tile definitions
	tiles {
		standardTile("switch", "device.switch", width: 2, height: 2, canChangeIcon: true, decoration: "flat") {
			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("departure", "device.departure") {
			state "default", label:'Avresa: ${currentValue}'
		}
		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","departure"])
		details(["switch","power","energy","departure","refresh","reset"])
	}
}

def installed() {
	// 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])
}

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])
	try {
		if (!state.MSR) {
			response(zwave.manufacturerSpecificV2.manufacturerSpecificGet().format())
		}
	} catch (e) { log.debug e }
    
       def time = timer.substring(11,16)
        def tz = location.timeZone
		def schedTime = timeToday(timer, tz)
		//*def time = schedTime.format("H",tz)
		//def min = schedTime.format("m",tz
       // def time = schedTime.format('yyyy-MM-dd HH:mm:ss', tz).toString()

    if(timer) {
    		log.debug "Departure time set to: $timer"
    		sendEvent("name":"image", "value":timer)
            sendEvent("name":"departure", "value":time)
    } else {
    		log.debug "No departure time is set"
    		}
}

def getCommandClassVersions() {
	[
		0x20: 1,  // Basic
		0x32: 1,  // SwitchMultilevel
		0x56: 1,  // Crc16Encap
		0x72: 2,  // ManufacturerSpecific
	]
}

def parse(String description) {
	def result = null
	if(description == "updated") return
	def cmd = zwave.parse(description, commandClassVersions)
	if (cmd) {
		result = zwaveEvent(cmd)
	}
	return result
}

def zwaveEvent(physicalgraph.zwave.commands.meterv1.MeterReport cmd) {
	if (cmd.scale == 0) {
		createEvent(name: "energy", value: cmd.scaledMeterValue, unit: "kWh")
	} else if (cmd.scale == 1) {
		createEvent(name: "energy", value: cmd.scaledMeterValue, unit: "kVAh")
	} else if (cmd.scale == 2) {
		createEvent(name: "power", value: Math.round(cmd.scaledMeterValue), unit: "W")
	}
}

def zwaveEvent(physicalgraph.zwave.commands.basicv1.BasicReport cmd)
{
	def evt = createEvent(name: "switch", value: cmd.value ? "on" : "off", type: "physical")
	if (evt.isStateChange) {
		[evt, response(["delay 3000", zwave.meterV2.meterGet(scale: 2).format()])]
	} else {
		evt
	}
}

def zwaveEvent(physicalgraph.zwave.commands.switchbinaryv1.SwitchBinaryReport cmd)
{
	createEvent(name: "switch", value: cmd.value ? "on" : "off", type: "digital")
}

def zwaveEvent(physicalgraph.zwave.commands.manufacturerspecificv2.ManufacturerSpecificReport cmd) {
	def result = []

	def msr = String.format("%04X-%04X-%04X", cmd.manufacturerId, cmd.productTypeId, cmd.productId)
	log.debug "msr: $msr"
	updateDataValue("MSR", msr)

	// retypeBasedOnMSR()

	result << createEvent(descriptionText: "$device.displayName MSR: $msr", isStateChange: false)

	if (msr.startsWith("0086") && !state.aeonconfig) {  // Aeon Labs meter
		state.aeonconfig = 1
		result << response(delayBetween([
			zwave.configurationV1.configurationSet(parameterNumber: 101, size: 4, scaledConfigurationValue: 4).format(),   // report power in watts
			zwave.configurationV1.configurationSet(parameterNumber: 111, size: 4, scaledConfigurationValue: 300).format(), // every 5 min
			zwave.configurationV1.configurationSet(parameterNumber: 102, size: 4, scaledConfigurationValue: 8).format(),   // report energy in kWh
			zwave.configurationV1.configurationSet(parameterNumber: 112, size: 4, scaledConfigurationValue: 300).format(), // every 5 min
			zwave.configurationV1.configurationSet(parameterNumber: 103, size: 4, scaledConfigurationValue: 0).format(),    // no third report
			//zwave.configurationV1.configurationSet(parameterNumber: 113, size: 4, scaledConfigurationValue: 300).format(), // every 5 min
			zwave.meterV2.meterGet(scale: 0).format(),
			zwave.meterV2.meterGet(scale: 2).format(),
		]))
	} else {
		result << response(delayBetween([
			zwave.meterV2.meterGet(scale: 0).format(),
			zwave.meterV2.meterGet(scale: 2).format(),
		]))
	}

	result
}

def zwaveEvent(physicalgraph.zwave.commands.crc16encapv1.Crc16Encap cmd) {
	def versions = commandClassVersions
	def version = versions[cmd.commandClass as Integer]
	def ccObj = version ? zwave.commandClass(cmd.commandClass, version) : zwave.commandClass(cmd.commandClass)
	def encapsulatedCommand = ccObj?.command(cmd.command)?.parse(cmd.data)
	if (encapsulatedCommand) {
		zwaveEvent(encapsulatedCommand)
	}
}

def zwaveEvent(physicalgraph.zwave.Command cmd) {
	log.debug "$device.displayName: Unhandled: $cmd"
	[:]
}

def on() {
	[
		zwave.basicV1.basicSet(value: 0xFF).format(),
		zwave.switchBinaryV1.switchBinaryGet().format(),
		"delay 3000",
		zwave.meterV2.meterGet(scale: 2).format()
	]
}

def off() {
	[
		zwave.basicV1.basicSet(value: 0x00).format(),
		zwave.switchBinaryV1.switchBinaryGet().format(),
		"delay 3000",
		zwave.meterV2.meterGet(scale: 2).format()
	]
}

def poll() {
	delayBetween([
		zwave.switchBinaryV1.switchBinaryGet().format(),
		zwave.meterV2.meterGet(scale: 0).format(),
		zwave.meterV2.meterGet(scale: 2).format()
	])
}

/**
 * PING is used by Device-Watch in attempt to reach the Device
 * */
def ping() {
	log.debug "ping() called"
	refresh()
}

def refresh() {
	delayBetween([
		zwave.switchBinaryV1.switchBinaryGet().format(),
		zwave.meterV2.meterGet(scale: 0).format(),
		zwave.meterV2.meterGet(scale: 2).format()
	])
    
}

def configure() {
	zwave.manufacturerSpecificV2.manufacturerSpecificGet().format()
}

def reset() {
	return [
		zwave.meterV2.meterReset().format(),
		zwave.meterV2.meterGet(scale: 0).format()
	]
} 

I use the above piston in conjunction with this one. This one handles stuff like turning the bedroom lights and TV on in the morning. It also warns you if the Wake-Up alarm is turned off.

Both pistons are controlled by the same DTH provided above:

2 Likes

My first contribution to this thread.

Here’s a piston that will display tiles for two Nest thermostats as well as a piston state.

The tiles will show blue when cooling, orange when heating (hopefully, I am NOT testing that in this heat right now, LOL) and black when idle. The main temp value on the tile is the setpoint. The temp in the footer is the actual temp.

Temps in the piston state will show different colours based on the temps but you may not see much change as it’s likely your temps will remain in a tight zone.

I am pretty sure this can be accomplished in a much cleaner fashion by using variables because as it stands there are lot of edits a user needs to do to make it theirs. I will have a go at that next. For now this was just a learning experience for me to get all the conditions in the expressions working.

EDIT: Hold up folks. I just noticed some errors in the logs even though things are working generally okay. I need to figure out what the issue is.

SECOND EDIT: Errors fixed.

4 Likes

This sends a notification if any exterior doors are open while away or asleep.

(modified the battery notification example piston)

Hey quick question for you, how did you go about hunting down all your sonos information?

Good old fashion trial and error

I’ve tweaked things a little further.

  • Added support for fan only operating state (covers Airwave too I believe)
  • Changed the tile colors to match Nest’s actual coloring (I’ll update heat/orange once I can test heat)
  • Tiles now update on change of operating state, actual temp or setpoint

Again, I need to change this to work with variables as this is an edit fest for anyone wanting to change it to their devices.

(The garbage on line 29 has been reported to Ady. It’s just in the snapshot).

I reworked your piston to use any number of Thermostats - just add as many as you want to the initial thermostatList variable. I will create a tile for each thermostat and doesn’t require any editing of the piston (note that I only tried with a single thermostat but it should work with any number…).

Note: when using “Auto” rather than “Heat” or “Cool”, the thermostatSetpoint is 0 - I assume the coolingSetpoint and heatingSetpoint should be used instead.

2 Likes

Appreciate that, thanks!

Ah, thanks. I wondered when those other attributes were relevant.

Any examples on using a light switch to temporarily override motion-activated lights?

Anybody have a good dog door piston? Turns light on when door opens, then turns it off on the second close. Maybe with some work arounds for when the light is manually turned on, etc.

hmmm, was hoping to turn on on open, off on close. thanks though!

Just need to get @bamarayne to create his from http://thingsthataresmart.wiki/index.php?title=CoREsamples in webCoRE… :nudge: :nudge: :wink: :wink:

@Automated_House try this:

2 Likes

This looks really elaborate and nice can you break this down for me to understand the purpose of why it is written the way it is and how does the variable play a role

@Ronald_Balu so the variable is just a check to show when someone is in the bathroom - the same thing you turn in a public toilet to show the stall is engaged. This variable is set as a global variable so I can control it from other sources e.g. When leaving home I can flip to default state if it didn’t go back to false correctly as part of the piston. It is defined as a Boolean variable (true/false).

The bottom IF section is designed to speak the text out of my Sonos speaker when the kids leave the bathroom door open and walk off.

The rest of the piston Ian pretty simple to follow:
if the bathroom door opens and the light is off inside the room, switch it on and set the variable to true (occupied).
When the door opens again, the person is leaving the room, so switch off the light and set the variable back to not occupied.
The last ELSE section from line 38 covers the door being opened and staying open for 10 seconds or more but not closing ( i.e. Kids go in to wash hands etc but don’t close the door behind them). Without this section the light would stay on when hand washing is finished and door finally closes