Introduction

It is difficult to count the times I wished I had remote access (via Internet) to my PC while being away from it and I am sure every power user has been in this position.

In the usual case where the PC is powered off, there are two distinct problems for achieving this:

  1. Powering on the PC
  2. Establishing a remote connection to it from an accessible nearby device

Starting from the second one, today, luckily, it has pretty much been solved. Reliable services offer full remote PC access from another PC or a smartphone. All somebody has to do is install an application like teamviewer, set a strong password and adjust it to start with windows. At this point he can be confident that if the PC is powered on, he can access it. This takes us to the first problem: remotely powering the PC on.

Wake on Lan (WoL) is a technology that allows a computer to be turned on or woken up when it receives a special network message(called magic packet). If the magic packet could somehow make it from a remote node to the target PC via Internet, it seems to be exactly what we are looking for. Unfortunately there are some serious drawbacks:

  • It requires a motherboard that supports WoL.
  • WoL is not supported from all S states. Practically that means it will only work from sleep or hibernate state and not from shut down state.
  • If behind router, it requires proper setting of port forwarding rules, for the magic packet to reach its final destination and, even then, is not guaranteed to work with any router.
  • There are very few, if any, wireless NICs with WoL support.
  • It requires the user to know the internet side (external) IP of the target node. This makes it highly unreliable as most users opt for dynamic IP which may change anytime by the ISP. There are some workarounds like DDNS services but this adds up to more hassle.
  • WoL protocol by itself provides no feedback hence there is no easy way to tell if the target node was actually turned on or not.

Overall, WoL over Internet is considered unreliable and is a cause of a lot of frustration. This is why I came up with a much more reliable way of remotely powering on a PC, which also does away with all of the aforementioned problems and provides soft realtime feedback. The name of this concept is WoL++.

WoL++ Overview

The system consists of:

  1. an ESP8266 SoC, electrically connected to both power and reset switch pins on the motherboard of the target PC as well as to the 12V power supply of a molex connector coming from target PC’s power supply.
  2. the client application: used by the remote user to trigger some action remotely on the PC. It was developed as an android application

The key detail of the system is that its constituent parts do not communicate directly with each other but only via an IoT service, namely Thingspeak. In its basic form, thingspeak service provides user with cloud-stored variables which can be CRUD-ed in a RESTful way with simple HTTP requests from anyone who has an appropriate API access key. Two of these variables (called “fields” in thingspeak’s terms) were utilized. One, namely the “command” field, for the client to send action requests to target PC and one more (the “power” field) for the target PC to expose its current power state as a feedback for the client.

The command field can have any of these values:

Value Meaning
0 Idle
1 power button short press pending
2 power button long press pending
3 reset button short press pending

and the power field can be either 0 (power off) or 1 (power on).

Unlike traditional WoL, there is no need for special motherboard, NIC or router nor any static IP or DDNS service. The system also works fine with a wifi-connected (or even an offline) PC which can be powered on from any S state. Only things required are physical access to motherboard, wifi internet access and a USB power supply for the NodeMCU module, although, in most cases there is no need for a dedicated power supply, as the module can be powered directly from an Always On/Powered USB port of the PC, if available.

The sequence diagram below depicts a typical interaction scenario assuming both used fields are initially set to 0.

Sequence Diagram of a typical scenario

Electronic circuit

The electronic circuit built to interconnect an esp8266-based module with the actual PC on the “target PC” side is shown in the schematic below. The circuit was designed to be electrically isolated from the PC. The power sense is being done via an opto-isolator. For interfacing with the power and reset buttons, two small ssr’s were connected to the motherboard, in parallel with the power and reset hard buttons. In this way, they not only provide the required electrical isolation but also eliminate the need for specific polarity connection with the motherboard.

After initial testing, a small PCB was designed to directly interface with an esp8266-based module (wemos D1 mini) resulting on a very small device which can also be fit inside the PC case.

WOLpp schematic diagram

pin header connector used for interfacing with the motherboard

Molex connector for power sense, WOL++ circuit prototype, finished PCB

Client Application

An android app was developed for debugging and demonstration purposes of the system. However, the app provides all the client’s side functionality and can also be considered for ordinary use of the system.

WOLpp client main screen

Its main screen is comprised of:

  1. an indication of the values of the thingspeak fields used
  2. a text field for user feedback on the state of the app
  3. a set of buttons triggering the available tasks. There is also a clear button which writes the value ‘0’ on the command field. Normally this is not used but it was implemented for debugging purposes.
  4. An update button which updates the aforementioned thingspeak fields’ indications and an exit button for easy exiting the app.

There is also a settings menu for the user to declare his personal thingspeak channel (thingspeak fields are organized in entities called channels) to be used along with the necessary thingspeak API keys for accessing it.

Here is a demonstration of the remote power on procedure and the feedback provided to the user:

schematic as eagle sch file

arduino source code

WOLpp android client:

While I was serving as a lab assistant in advanced programming techniques course’s lab, the professor wanted to introduce an exercise where each student would get a Raspberry Pi (RPi) device in which he would develop a program and execute it.

But a non-trivial problem emerged while figuring out the exercise’s details. The lab is equipped with VGA monitors and PS/2 keyboards and mouses, hence connection of the essential peripherals to the RPi boards, in order to interact with them, was not straightforward (RPi’s only support HDMI and USB).

One possible solution to the problem was to operate the RPis headless (without dedicated monitor and input devices) but connected to university’s LAN and control them via RDP, VNC or even an SSH connection from a nearby PC. But in order to do that, each student must somehow acquire the IP address of his own RPi so he can connect to it. The university network’s administrator didn’t allow giving static IPs to our devices so I had to come up with an alternative solution:

RPi Identification System

The idea I came up with is this: each RPi, after booting and connecting to the local network (via Ethernet) would report its IP along with a unique ID to a dedicated server. The server would serve a web page in which every reported ID - IP pair would be listed. Each student, after connecting his RPi to Ethernet port and power, would wait a little and load this web page on a web browser to get the IP of his RPi. Problem solved!

Implementation

IP Reporter

Starting with the client part, which will run on every RPi, it was developed as a Java application. As each RPi has a unique id, the application makes use of a properties file for increased flexibility and easier deployment. During development of the application, it was noticed that usually, a host has lots of network interfaces and each interface may be bound to more than one IP address. As all the university’s network IPs are taken from the 150.140.xxx.xxx address pool, a workaround was to accept only the reported IP that starts with the 150.140. octets. This ip-starts-with string was implemented as another entry in the properties file so that the program can be used in other networks. Let’s have a look at the main method of the application:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
public static void main(String[] args) {

	//get parameters from properties file
	PropertiesHandler propertiesHandler = new PropertiesHandler();
	System.out.println("id=" + propertiesHandler.getID());

	try {
		//get the correct own IP
		InetAddress trueIP = IPManager.getTrueIP(propertiesHandler.getIpPrefix());
		
		if (trueIP == null)throw new NullPointerException();
		System.out.println("trueIP=" + trueIP.getHostAddress());

		//send the request to server
		HttpRequester.sendRequest(propertiesHandler.getServerUrl(),
				propertiesHandler.getID(), trueIP.getHostAddress());

	} catch (NullPointerException e) {
		System.err.println("no matching IP found");
	} catch (IOException e) {
		System.err.println("connection error");
		e.printStackTrace();
	} catch (Exception e) {
		e.printStackTrace();
	}
}

What is going on here is rather simple.

Server side

The server side was implemented as a java servlet. It keeps internally a list of all the devices that have reported their ID-IP pair. An entry is added in the list (or updated) every time a compatible PUT request is received:

1
2
3
4
5
6
7
8
9
10
11
12
protected void doPut(HttpServletRequest request,
		HttpServletResponse response) throws ServletException, IOException {

	// PRINT CLIENT IP
	String addr = request.getRemoteAddr();
	System.out.println("got PUT request from " + addr);
	// ---
	DeviceEntry deviceEntry = new DeviceEntry(request.getParameter("id"),
			request.getParameter("ip"));
	devicesList.addOrUpdate(deviceEntry);

}

Whenever a GET request is received, it responds with an an HTML page containing a table with all the current entries:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
protected void doGet(HttpServletRequest request,
		HttpServletResponse response) throws ServletException, IOException {

	// PRINT CLIENT IP
	String addr = request.getRemoteAddr();
	System.out.println("got GET request from " + addr);
	PrintWriter out = response.getWriter();

	out.print("<html><body>");

	devicesList.printAsHtmlTable(out);

	out.print("</body></html>");

}
Sample HTML page returned by the server on GET request

Το complete the system, a unique ID should be given to each RPi and the IPReporter.properties file on each RPi must be modified accordingly. Finally, a “cron job” can be used to execute IPReporter.jar every time the RPi is booted. This can be done by executing crontab -e to edit crontab and adding one or more suitable lines, e.g.:

    @reboot sudo java -jar IPReporter.jar
    * * * * * sudo java -jar IPReporter.jar

source code