Many companies discover their best products unintentionally. WhatsApp began as a simple status-update app, and only after a large portion of users started using status messages to communicate did the team realize messaging was the real value. Slack started as a multiplayer game called Glitch, but the founders soon noticed that the internal chat tool they had built for the team was far more useful than the game itself. Post-it Notes originated from a failed attempt to create a strong adhesive, which unexpectedly became a wildly successful product. You get the idea.
The TP-Link HS1xx line only rose to fame among home-lab enthusiasts and hackers after George Georgovassilis inspected its network traffic with Wireshark. Hidden in plain sight was exactly what people had been wishing for: a simple, easy-to-use API. That discovery transformed the device from an ordinary smart plug into a cult favorite.
Here's a tiny Java implementation you might find useful. If you decide to try it, let us know in the comments what you’re controlling. At wasteofserver, we use it to manage several electric heaters. A bunch of ESP32 continuously monitors room temperature through thermal sensors, based on that data we control HS100 plugs to switch the heaters on or off as needed. This gives us far more consistent temperature control than the heaters' built-in thermostats can provide.
We'll share that code eventually, but for now, go grab a few HS110 plugs, recently rebranded Kasa Smart Plug, and start automating your home! 😉

package org.frankie.util;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.Socket;
import java.util.Base64;
public class TpLinkClient {
private static final String PAYLOAD_ON = "AAAAKtDygfiL/5r31e+UtsWg1Iv5nPCR6LfEsNGlwOLYo4HyhueT9tTu36Lfog==";
private static final String PAYLOAD_OFF = "AAAAKtDygfiL/5r31e+UtsWg1Iv5nPCR6LfEsNGlwOLYo4HyhueT9tTu3qPeow==";
private static final String PAYLOAD_SYSINFO = "AAAAI9Dw0qHYq9+61/XPtJS20bTAn+yV5o/hh+jK8J7rh+vLtpbr";
private static final String PAYLOAD_EMETER = "AAAAJNDw0rfav8uu3P7Ev5+92r/LlOaD4o76k/6buYPtmPSYuMXlmA==";
private static final int DEFAULT_HS100_PORT = 9999;
public static String on(String ip) throws IOException {
return sendToPlug(ip, DEFAULT_HS100_PORT, PAYLOAD_ON);
}
public static String off(String ip) throws IOException {
return sendToPlug(ip, DEFAULT_HS100_PORT, PAYLOAD_OFF);
}
public static String sys_info(String ip) throws IOException {
return sendToPlug(ip, DEFAULT_HS100_PORT, PAYLOAD_SYSINFO);
}
public static String emeter(String ip) throws IOException {
return sendToPlug(ip, DEFAULT_HS100_PORT, PAYLOAD_EMETER);
}
/**
* Sends a Base64 encoded command to the plug and returns the raw response bytes.
* <p>
* Method is synchronized as IoT hardware is generally low-spec, and there's really not
* a valid case for concurrent access
*
* @param ip The IP address of the plug
* @param port The port (usually 9999)
* @param base64Payload The Base64 encoded command string
* @return The response from the plug
*/
public static synchronized String sendToPlug(String ip, int port, String base64Payload) throws IOException {
byte[] commandBytes = Base64.getDecoder().decode(base64Payload);
try (Socket socket = new Socket(ip, port)) {
socket.setSoTimeout(5000); // Timeout to avoid hanging forever
try (OutputStream out = socket.getOutputStream();
DataInputStream in = new DataInputStream(socket.getInputStream())) {
out.write(commandBytes);
out.flush();
// The TP-Link protocol response starts with a 4-byte big-endian length header.
// Reading this allows us to know exactly how much data to expect.
int length = in.readInt();
byte[] response = new byte[length];
in.readFully(response);
return decodeResponse(response);
}
}
}
private static String decodeResponse(byte[] data) {
int key = 171;
StringBuilder sb = new StringBuilder();
for (byte b : data) {
// MASKING WITH 0xFF IS CRITICAL, treats the byte as unsigned (0 to 255) preventing negative numbers
int nextKey = b & 0xFF;
int decrypted = key ^ nextKey;
key = nextKey;
sb.append((char) decrypted);
}
return sb.toString();
}
}
As an Amazon Associate I may earn from qualifying purchases on some links.
If you found this page helpful, please share.