Need help writing a WOL integration that gets triggered as a switch

I noticed that a WOL command can be sent via ST hub as mentioned here: Newly documented Wake on Lan (WOL) functionality (2016)

However, I am very new to ST and would appreciate if someone can point me in the right direction on how to create this WOL action as a virtual switch that I can call from Alexa or trigger when a Harmony activity fires. My use case is to wake up my media server on-demand from sleep.

TIA!

1 Like

Ok, so I read several articles on how to get started and was able to create a device handler and a device using that device handler. However, it does not wake my desktop when I click refresh for this virtual device in the app. Anyone can quickly validate what am I missing?

Here is the device handler code based on refresh capability. Once this works, I will change it to switch and add ping, etc.:

metadata {
	definition (name: "wol-refresh", namespace: "mynamespace", author: "my name") {
		capability "Refresh"
	}


	simulator {
		// TODO: define status and reply messages here
	}

	tiles {
		// TODO: define your main and details tiles here
                standardTile("refresh", "command.refresh", inactiveLabel: false, decoration: "flat") {
			state "default", action:"refresh.refresh", icon:"st.secondary.refresh" // CUSTOMIZATION
		}
	}
}

// parse events into attributes
def parse(String description) {
	log.debug "Parsing '${description}'"
}

def myWOLCommand() {
    def result = new physicalgraph.device.HubAction (
        "wake on lan myrealmacid",
        physicalgraph.device.Protocol.LAN,
        null,
        [:]
    )
    return result
}

// handle commands
def refresh() {
    log.debug "Executing 'refresh'"
    def result = myWOLCommand()
    log.debug "result ${result}" // this prints result myrealmacid
}

Anyone who can help and point me in the right direction?

In case anyone else is interested…

Figured out the issue. I had to use “sendHubCommand” like this to get it to work.

sendHubCommand(new physicalgraph.device.HubAction (
        "wake on lan myrealmacid",
        physicalgraph.device.Protocol.LAN,
        null,
        [:]
    ))

Hey, are you able to upload your full Device Handler completed?

/**

  • WOL Switch
  • Copyright 2016 Sumit Garg
  • Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except
  • in compliance with the License. You may obtain a copy of the License at:
  •  http://www.apache.org/licenses/LICENSE-2.0
    
  • Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
  • on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
  • for the specific language governing permissions and limitations under the License.

*/
metadata {
definition (name: “WOL Switch”, namespace: “sumitkgarg”, author: “Sumit Garg”) {
// capability “Actuator”
// capability "Sensor"
capability "Switch"
capability “Refresh”
}

preferences {
    input "macAddress", "string", title: "MAC Address", description: "Enter the MAC address of the computer", required: true, displayDuringSetup: true
    input "ipAddress", "string", title: "IP Address", description: "Enter the IP address of the computer", required: true, displayDuringSetup: true
}

simulator {
}

tiles(scale: 2) {
    standardTile("switch", "device.switch", decoration: "flat", width: 6, height: 4, canChangeIcon: true) {
		state "on", label:'${currentValue}', icon:"st.switches.switch.on", backgroundColor:"#79b821"
        state "off", label:'${currentValue}', icon:"st.switches.switch.off", backgroundColor:"#ffffff"
        state "scanning", label:'SCANNING', icon:"st.switches.switch.off", backgroundColor:"#ffa81e"
	}
    
    standardTile("turnon", "device.switch", decoration: "flat", width: 2, height: 2) {
		state "on", label:'On', action:"switch.on", icon:"st.switches.switch.on", backgroundColor: "#aaefad" //"#79b821" //"#dff0d8"
        state "off", label:'On', action:"switch.on", icon:"st.switches.switch.on", backgroundColor:"#aaefad"
	}
    
    standardTile("turnoff", "device.switch", decoration: "flat", width: 2, height: 2) {
		state "on", label:'Off', action:"switch.off", icon: "st.switches.switch.off", backgroundColor: "#efaaaa" //"#f2dede"
        state "off", label:'Off', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#efaaaa"
	}

    standardTile("refresh", "device.switch", decoration: "flat", width: 2, height: 2) {
		state "default", action:"refresh.refresh", icon:"st.secondary.refresh" //, backgroundColor: "#efd2aa"
	}
    
    main "switch"
    details (["switch", "turnon", "turnoff", "refresh"])
}

}

def parse(description) {
def msg = parseLanMessage(description)
def ok = msg.status == 200
def switchResponse = msg.port == “0050”

// log.debug "${description}"

if (switchResponse) {
	setSwitchValue(ok ? "on" : "off")
}

}

// Get the state of the machine
def machineGET() {
sendHubCommand(new physicalgraph.device.HubAction([
method: “GET”,
path: “/”,
headers: [
HOST: “${ipAddress}:80”,
]]))

log.debug "Sent HTTP request to PC - ${ipAddress}:80"

}

// Using a third party app on the windows server
// to make the computer go to sleep by making a GET request
def machineSleepGET() {
sendHubCommand(new physicalgraph.device.HubAction([
method: “GET”,
path: “/?action=System.Sleep”,
headers: [
HOST: “${ipAddress}:8000”,
]]))

log.debug "Sent HTTP SLEEP request to PC - ${ipAddress}:8000"

}

def sendWOL() {
sendHubCommand(new physicalgraph.device.HubAction(
“wake on lan ${macAddress.replaceAll(’:’,’’).replaceAll(’ ‘,’’).toLowerCase()}”,
physicalgraph.device.Protocol.LAN,
null,
[:]
))

log.debug "Sent WOL request to PC - ${ipAddress}"

}

def on() {
initializeCron()
log.debug “Executing ‘on’”

setScanningMode()
sendWOL()
machineGET() // in case it is already on - for more immediate feedback
runIn(7, machineGET) // in case it is still waking up
runIn(12, timeout)

}

def off() {
initializeCron()
log.debug “Executing ‘off’”

// setScanningMode()
machineSleepGET()
setSwitchValue("off")

}

def refresh() {
initializeCron()
if (getSwitchValue() != “scanning”) {
log.debug “Executing ‘refresh’”

    setScanningMode()    
    machineGET()

    runIn(5, timeout)
}

}

def initializeCron() {
if (state.initialized != “true”) {
state.initialized = “true”
// refresh every 10 minutes.
def cronExpression = "0 0/10 * 1/1 * ? *"
log.debug "Initializing refresh schedule based on cron expression - ‘${cronExpression}’"
schedule(cronExpression, refresh)
}
}

def timeout() {
if (getSwitchValue() == “scanning”) {
log.debug "Executing ‘timeout’ for switch"
setSwitchValue(“off”)
}
}

def getSwitchValue() {
return state.switch
}

def setScanningMode(){
setSwitchValue(“scanning”)
}

def setSwitchValue(val) {
if (state.switch != val) {
state.switch = val
sendEvent(name: “switch”, value: val)
log.debug “Set Switch value to ${val}”
}
}

def setDeviceNetworkId(dni) {
log.debug "Changing DNI to ${dni}"
device.setDeviceNetworkId(dni)
}

def getDeviceNetworkId(port) {
return “${convertIPtoHex(ipAddress)}:${convertPortToHex(port)}”
}

private String convertIPtoHex(ipAddress) {
return ipAddress.tokenize(’.’).collect{String.format(’%02x’, it.toInteger())}.join()
}

private String convertPortToHex(port) {
return port.toString().format(’%04x’, port.toInteger())
}

// c0a80010:0050 - 192.168.0.16:80
// c0a80010:7e90 - 192.168.0.16:32400
// c0a80010:1f40 - 192.168.0.16:8000
// C0A85634:0050 - 192.168.86.52:80
// change the dni in My Devices for this device if IP address changs

2 Likes

my device settings. make sure that your Device Network Id is set correctly to ip:port in hex form.

1 Like

Hi, Im new on this. Can you explain how to get everything set to make this work. Like tutorial and if needed another app to meke this funtional… Thanks!

Is this a two-way communication switch? If so, I would like to incorporate this into my PC control tutorial.

I’ve written a tutorial that not only keeps the PC switch in sync, but you can also use the switch to “Turn Off” the PC or put it in hibernation. Super Cool! You can also send ST information like if your computer is active or inactive basically using the PC as a presence sensor. Basically, you can use ST to tell your computer to do anything and you can use your computer to tell ST to do anything. Total two-way communication!

This integration uses an always on PC to ping the various IP devices connected to the network. Can also run on a $40 Pi.

Here’s a tutorial.

Hi, I try the tutorial but I dont undertand it :frowning: Sorry but thanks for you
time :slight_smile:

I know this over a year old and wasn’t really a release of sorts but, I thought I would chime in and say I was able to successfully use the code posted above by @sumitkgarg with EventGhost to turn my computer on and off. It even works with google assistant/home with no extra config. It will use WOL to turn it on without using EventGhost but if you want it to indicate whether the computer is on or be able to turn it off you need to install EventGhost on the PC intended to be controlled and configure a few things.

Yeah it works well.
However I just want basic WOL, don’t need to know if it’s on/off or tied to EventGhost. Not sure how to cut out the right code, not an expert at this.
Is there a way to cut this down and turn it into just a basic WOL switch without having to scan and populate unnecessary activity

So, I see the device handler sends an HTTP request to port 80 to determine if the PC is already turned on.
I take it the PC’s firewall will need to have port 80 open to allow that? Doesn’t something need to be listening on port 80?

I currently get:
20:11:44: debug Set Switch value to off
20:11:44: debug Executing ‘timeout’ for switch
20:11:39: debug Sent HTTP request to PC - 192.168.1.100:80
20:11:39: debug Set Switch value to scanning
20:11:39: debug Executing ‘refresh’

I just revisted the Device Handler after I had to reset my ST. I added the port to be added as hex in the options. Hope it helps someone. I use webshutdown by Renato Silvan my PCs. No Pistons or anything else required.

Copy and paste the below into a Device handler.

/**

WOL Switch
Copyright 2016 Sumit Garg
Licensed under the Apache License, Version 2.0 (the “License”); you may not use this file except
in compliance with the License. You may obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed
on an “AS IS” BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License
for the specific language governing permissions and limitations under the License.

*/
metadata {
definition (name: “WOL Switch”, namespace: “sumitkgarg”, author: “Sumit Garg”) {
// capability “Actuator”
// capability “Sensor”
capability “Switch”
capability “Refresh”
}

preferences {
input “macAddress”, “string”, title: “MAC Address”, description: “Enter the MAC address of the computer”, required: true, displayDuringSetup: true
input “ipAddress”, “string”, title: “IP Address”, description: “Enter the IP address of the computer”, required: true, displayDuringSetup: true
input “HEXPort”, “string”, title: “HEXPort”, description: “Enter the Port for status in HEX”, required: true, displayDuringSetup: true
input “Port”, “string”, title: “Port”, description: “Enter the Port for status”, required: true, displayDuringSetup: true
}

simulator {
}

tiles(scale: 2) {
standardTile(“switch”, “device.switch”, decoration: “flat”, width: 6, height: 4, canChangeIcon: true) {
state “on”, label:’${currentValue}’, icon:“st.switches.switch.on”, backgroundColor:"#79b821"
state “off”, label:’${currentValue}’, icon:“st.switches.switch.off”, backgroundColor:"#ffffff"
state “scanning”, label:‘SCANNING’, icon:“st.switches.switch.off”, backgroundColor:"#ffa81e"
}

standardTile("turnon", "device.switch", decoration: "flat", width: 2, height: 2) {
	state "on", label:'On', action:"switch.on", icon:"st.switches.switch.on", backgroundColor: "#aaefad" //"#79b821" //"#dff0d8"
    state "off", label:'On', action:"switch.on", icon:"st.switches.switch.on", backgroundColor:"#aaefad"
}

standardTile("turnoff", "device.switch", decoration: "flat", width: 2, height: 2) {
	state "on", label:'Off', action:"switch.off", icon: "st.switches.switch.off", backgroundColor: "#efaaaa" //"#f2dede"
    state "off", label:'Off', action:"switch.off", icon:"st.switches.switch.off", backgroundColor:"#efaaaa"
}

standardTile("refresh", "device.switch", decoration: "flat", width: 2, height: 2) {
	state "default", action:"refresh.refresh", icon:"st.secondary.refresh" //, backgroundColor: "#efd2aa"
}

main "switch"
details (["switch", "turnon", "turnoff", "refresh"])

}
}

def parse(description) {
def msg = parseLanMessage(description)
def ok = msg.status == 200
def switchResponse = msg.port == “${HEXPort}”

// log.debug “${description}”

if (switchResponse) {
setSwitchValue(ok ? “on” : “off”)
}
}

// Get the state of the machine
def machineGET() {
sendHubCommand(new physicalgraph.device.HubAction([
method: “GET”,
path: “/”,
headers: [
HOST: “${ipAddress}:${Port}”,
]]))

log.debug “Sent HTTP request to PC - ${ipAddress}:${Port}”
}

// Using a third party app on the windows server
// to make the computer go to sleep by making a GET request
def machineSleepGET() {
sendHubCommand(new physicalgraph.device.HubAction([
method: “GET”,
path: “/shutdown?auth=Shutd0wN”,
headers: [
HOST: “${ipAddress}:${Port}”,
]]))

log.debug “Sent HTTP SLEEP request to PC - http://${ipAddress}:${Port}/shutdown?auth=Shutd0wN”
}

def sendWOL() {
sendHubCommand(new physicalgraph.device.HubAction(
“wake on lan ${macAddress.replaceAll(’:’,’’).replaceAll(’ ‘,’’).toLowerCase()}”,
physicalgraph.device.Protocol.LAN,
null,
[:]
))

log.debug “Sent WOL request to PC - ${ipAddress}”
}

def on() {
initializeCron()
log.debug “Executing ‘on’”

setScanningMode()
sendWOL()
machineGET() // in case it is already on - for more immediate feedback
runIn(7, machineGET) // in case it is still waking up
runIn(12, timeout)
}

def off() {
initializeCron()
log.debug “Executing ‘off’”

// setScanningMode()
machineSleepGET()
setSwitchValue(“off”)
}

def refresh() {
initializeCron()
if (getSwitchValue() != “scanning”) {
log.debug “Executing ‘refresh’”

setScanningMode()    
machineGET()

runIn(5, timeout)

}
}

def initializeCron() {
if (state.initialized != “true”) {
state.initialized = “true”
// refresh every 10 minutes.
def cronExpression = “0 0/10 * 1/1 * ? *”
log.debug “Initializing refresh schedule based on cron expression - ‘${cronExpression}’”
schedule(cronExpression, refresh)
}
}

def timeout() {
if (getSwitchValue() == “scanning”) {
log.debug “Executing ‘timeout’ for switch”
setSwitchValue(“off”)
}
}

def getSwitchValue() {
return state.switch
}

def setScanningMode(){
setSwitchValue(“scanning”)
}

def setSwitchValue(val) {
if (state.switch != val) {
state.switch = val
sendEvent(name: “switch”, value: val)
log.debug “Set Switch value to ${val}”
}
}

def setDeviceNetworkId(dni) {
log.debug “Changing DNI to ${dni}”
device.setDeviceNetworkId(dni)
}

def getDeviceNetworkId(port) {
return “${convertIPtoHex(ipAddress)}:${convertPortToHex(port)}”
}

private String convertIPtoHex(ipAddress) {
return ipAddress.tokenize(’.’).collect{String.format(’%02x’, it.toInteger())}.join()
}

private String convertPortToHex(port) {
return port.toString().format(’%04x’, port.toInteger())
}

// c0a80010:0050 - 192.168.0.16:80
// c0a80010:7e90 - 192.168.0.16:32400
// c0a80010:1f40 - 192.168.0.16:8000
// C0A85634:0050 - 192.168.86.52:80
// change the dni in My Devices for this device if IP address changs

1 Like