A couple of years ago I built a pretty basic smart home application allowing me to control my remote controlled sockets via an Android app or a Web Extension. It’s based on the rcswitch library run on an Apache. The 433 MHz signals are sent by a FS1000A transmitter hooked up via GPIO to a Raspberry Pi. The whole setup lied on the ground in a corner of my apartment behind a curtain next to my network wall jack. Now where we have just moved to a nice new and twice as big home, I needed a solution which could be placed in the middle of all rooms to allow the rather weak 433 MHz signals to reach every receiver. Additionally, I wanted to get rid of having to maintain a full Ubuntu server, which only serves as a light switch for the most part.

Around that time, I stumbled upon the ESP8266: a low-cost WiFi microchip with full TCP/IP stack and microcontroller capability – ideally soldered on a NodeMCU or Wemos D1 for the maximum level of convenience. Arduino and Wifi: a whole new world of IoT-possibilities. Once you’ve added the board manager to your Arduino IDE, you can use those tiny boards just like an ordinary Arduino. As the Arduino WebServer library can turn a NodeMCU development board into a light-weight HTTP server and the rcswitch library is also available on Arduino, I decided to put both – NodeMCU and FS1000A – into a junction box to create a DIY 433 MHz RF WiFi bridge.
To reach the bridge you should either assign a static IP or use mDNS. Keep in mind that mDNS is not supported by all operating systems out of the box. If in doubt, use a static IP. To make the bridge accessible from outside your home network, you need to open and forward a port on your router (port 80 by default and can be changed in line 10). It’s recommend to secure any connection made through the public internet. By the time I was writing the script, there hasn’t been a HTTPS server implementation around. However, I found HelloServerBearSSL while writing this article. It looks very promising and is definitely worth a try.

This project works with simple DIP-switch remote outlets only. It became quite hard to get the “old” DIP outlets as most producers switched to the “new” outlets, which use a button on the receivers to “learn” a signal. There is a NewRemoteSwitch library to deal with them. But as I just recently found one last triple pack in a dollar store, I am stocked until I will eventually move to Wifi controlled outlets.
Enough talk. A typical request contains the five digit system code, five digit unit code and a binary power code separated by comma. You can also concatenate multiple commands using semicolon. A sample request to switch on outlet A and switch off outlet B would look like this:
x.x.x.x/switch?command=10010,00001,1;10010,0010,0
Here is the code. Further down is a download link.
#include <ESP8266mDNS.h>
#include <ESP8266WebServer.h>
#include <ESP8266WiFi.h>
#include <RCSwitch.h>
#include <WiFiClient.h>
const char* ssid = "SSID";
const char* password = "PASSWORD";
ESP8266WebServer server(80);
RCSwitch rcswitch = RCSwitch();
void setup(void) {
Serial.begin(115200);
digitalWrite(2, HIGH); // Turn onboard led off
rcswitch.enableTransmit(15);
WiFi.mode(WIFI_STA); // (WIFI_AP) will spawn an access point. useful when no router is present.
WiFi.begin(ssid, password);
Serial.println("");
if (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("Wifi connect failed! Rebooting...");
delay(5000);
ESP.restart();
}
MDNS.begin("bridge"); // will make the bridge available under bridge.local
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
server.on("/switch", handleSwitchRequest); //Associate the handler function to the path
server.begin();
Serial.println("HTTP server started");
}
int countCharacterOccurrence(char *haystack, char needle) {
int count = 0;
for (int i = 0; i < strlen(haystack); i++)
if (haystack[i] == needle) {
count++;
}
return count;
}
void handleSwitchRequest() {
bool isBadRequest = false;
String response = "";
if (server.arg("command") != "") {
char commands[1024]; // make some room to get the string server args
server.arg("command").toCharArray(commands, sizeof(commands)); // convert string to char array
char *pointerCommands = commands; // create a pointer and store commands at its memory's address
char *commandToken;
char *subCommandToken;
while ((commandToken = strsep(&pointerCommands, ";")) != NULL) { // delimiter is the semicolon. we are using the address of the pointer to the input string. strsep expects the address (pointer) of a pointer to the string that should be separated. if found, pointerCommands is updated to point past the delimiter. returns a pointer to the result token.
int counter = 0;
char* commandArray[3];
if (countCharacterOccurrence(commandToken, ',') != 2) {
isBadRequest = true;
response += "ERROR:\t" + String(commandToken) + " - Bad format. Expected: ?command=10000,10000,1;\n";
continue;
}
while ((subCommandToken = strsep(&commandToken, ",")) != NULL) { // delimiter is the comma
commandArray[counter++] = subCommandToken;
}
if (strcmp(commandArray[2], "1") == 0) {
rcswitch.switchOn(commandArray[0], commandArray[1]);
response += "ON:\t" + String(commandArray[0]) + "," + String(commandArray[1]) + "," + String(commandArray[2]) + "\n";
} else if (strcmp(commandArray[2], "0") == 0) {
rcswitch.switchOff(commandArray[0], commandArray[1]);
response += "OFF:\t" + String(commandArray[0]) + "," + String(commandArray[1]) + "," + String(commandArray[2]) + "\n";
} else {
isBadRequest = true;
response += "ERROR:\t" + String(commandArray[0]) + "," + String(commandArray[1]) + "," + String(commandArray[2]) + " - Power must be either 1 or 0.\n";
}
delay(50); // will otherwise hick up and fatal
}
}
server.send(isBadRequest ? 400 : 200, "text / plain", response);
}
void loop(void) {
server.handleClient();
}
DOWNLOAD: 433MHzWifiBridge Project


