NvrjMh

WiFi smart power strip retrofit based on ESP8266 and Buffalo Cloud

 
Overview
This project involves
modifying a purchased standard power strip to allow individual control of each socket via Buffalo Cloud.
0805 surface-mount capacitors and 1206 surface-mount resistors are used for easy soldering.
This power strip uses 220V AC power. DIY projects and actual use may involve risks of electric shock, burns, and other potential injuries, disabilities, or death. Please strictly follow safety regulations and take adequate precautions. Minors should operate under the supervision of a guardian. By using this solution, you acknowledge the safety risks; please ensure you have sufficient knowledge before proceeding. You are solely responsible for any losses or consequences incurred, and I assume no legal liability.
I am not a professional in electronics hardware or software; I am merely an amateur enthusiast. Therefore, I may lack basic hardware and software knowledge. Any errors in the circuit diagrams or code are sincerely appreciated and I would be grateful for any corrections.
Materials required
(BOM is automatically generated, please refer to this list for details)
: Power strip: Round power strip, Quantity 1;
WiFi module: ESP8266 (this project uses E103-W01 module, compatible with ESP12F, etc.), Quantity 1;
Magnetic latching relay: Hongfa magnetic latching relay HF3F-L-05-1HL1T, Quantity 3;
Relay control chip: TC118S, Quantity 3;
ACDC power module: Hailingke HLK-5M05, Quantity 1;
Inductor: Common mode inductor UU9.8 20MH, Quantity 1;
Capacitor: Safety capacitor X2 275V 0.1uF lead spacing 10mm, Quantity 1;
Aluminum electrolytic capacitor 10V 220uf 5x11, Quantity 1;
0805 SMD capacitor 22uF, Quantity 2;
0805 SMD capacitor 100nF, Quantity 7;
Fuse: 5x20 fuse tube 250V 1A, Quantity 1;
5x20 fuse holder, quantity 1;
1206 resettable fuse 6V 1.1A, quantity 1;
Resistor: 10D561K varistor 560V, quantity 1;
1206 SMD resistor 1kΩ, quantity 3;
1206 SMD resistor 10kΩ, quantity 5;
Linear regulator: AMS1117-3.3 SOT-89, quantity 1;
Diode: Schottky diode SS14, quantity 1;
0805 LED, quantity 3;
**The power strip uses Y-type screws, a Y-type screwdriver is required!**
The software code
is for reference only.
/*
* Bafa Technology
* Supports network configuration via Bafa app and mini-program. Long press the button to reconfigure the network.
*/
#include
#include
#include
#include
#include
#include
WiFiClient client_bemfa_WiFiClient;
HTTPClient http_bemfa_HTTPClient;
// Bafa cloud server address (default is fine)
#define TCP_SERVER_ADDR "bemfa.com"
// Server port, TCP Maker Cloud port 8344
#define TCP_SERVER_PORT "8344"



//*****Places that can be modified******//
String aptype = "001"; // 001 socket type, 002 light type, 003 fan type, 004 sensor, 005 air conditioner, 006 switch, 009 curtain
String Name = "table lamp"; // Device nickname, can be modified at will
String verSion = "3.1"; // 3.1 is TCP protocol, 1.1 is MQTT protocol,
String room = ""; // Room. For example, living room, bedroom, etc., are empty by default.
int adminID = 0; //It is fine to leave it empty by default. Enterprise ID, recommended for enterprise users. The device will be automatically bound to the enterprise. See section 5.17 of the access documentation for how to obtain the ID.
`int protoType = 3; // 3 is the TCP device port 8344, 1 is the MQTT device`

`const int Pin1 = 13;
const int Pin1_2 = 12; const
int Pin2 = 16
; const int Pin2_2 = 14;
const int Pin3 = 5;
const int Pin3_2 = 4; // Microcontroller LED pin value, GPIO0 pin. For other development boards, modify to your own pin, for example, modify to D4 on the NodeMCU development board`
`int failCount = 0; // Define the number of failed connections`
`String upUrl = "http://bin.bemfa.com/b/3BcZGJhMGI4ZjJlNThhNDA4MmIwZDI3YTA3YWQ1NWNjOWY=158145183001.bin";` //OTA firmware link, please replace with your own firmware link. If you receive msg=update, start the firmware upgrade.//**********************//
//


Check if this is the first time connecting to WIFI
bool firstWIfiConfig = false;
String topic = "";

//Maximum number of bytes
#define MAX_PACKETSIZE 512
//Set heartbeat value to 30s
#define KEEPALIVEATIME 60 * 1000



//TCP client related initialization, default settings are fine
WiFiClient TCPclient;
String TcpClient_Buff = "";
unsigned int TcpClient_BuffIndex = 0;
unsigned long TcpClient_preTick = 0;
unsigned long preHeartTick = 0; //Heartbeat
unsigned long preTCPStartTick = 0; //Connection
bool preTCPConnected = false;


//Related function initialization
//Connect to WIFI
void doWiFiTick();
void startSTA();

//TCP initialization connection
void doTCPClientTick();
void startTCPClient();
void sendtoTCPServer(String p);

//led control functions
void turnOnLed1();
void turnOffLed1();
void turnOnLed2();
void turnOffLed2(); void turnOnLed3();
void
turnOffLed3();






int httpCode = 0;
String UID = "";
String TOPIC1 = "";
String TOPIC2 = "";
String TOPIC3 = "";
#define HOST_NAME "bemfa"
char config_flag = 0;
#define MAGIC_NUMBER 0xAA

/**
* Structure used to store network configuration information
*/
struct config_type {
char stassid[32];
char stapsw[64];
char cuid[40];
char ctopic[32];
uint8_t reboot;
uint8_t magic;
};
config_type config;



char packetBuffer[255]; // Send data packets
WiFiUDP Udp;


void saveConfig();
void initWiFi();
void loadConfig();
void restoreFactory();
void waitKey();
void checkFirstConfig();
void apConfig();

// Print logs when the upgrade starts
void update_started() {
Serial.println("CALLBACK: HTTP update process started");
}

// Print logs when the upgrade ends
void update_finished() {
Serial.println("CALLBACK: HTTP update process finished");
}

// During the upgrade, print logs
void update_progress(int cur, int total) {
Serial.printf("CALLBACK: HTTP update process at %d of %d bytes...
", cur, total);
}

// When the upgrade fails, print logs
void update_error(int err) {
Serial.printf("CALLBACK: HTTP update fatal error code %d
", err);
}



/**
* Firmware upgrade function
* Add this function where an upgrade is needed, for example, add updateBin() in setup;
* Principle: Obtain remote firmware through an HTTP request to achieve the upgrade
*/
void updateBin() {
Serial.println("start update");
WiFiClient UpdateClient;

ESPhttpUpdate.onStart(update_started); // When the upgrade starts,
ESPhttpUpdate.onEnd(update_finished); // When the upgrade ends ,
ESPhttpUpdate.onProgress(update_progress); // When the upgrade is in progress,
ESPhttpUpdate.onError(update_error); // When the upgrade fails,

t_httpUpdate_return ret = ESPhttpUpdate.update(UpdateClient, upUrl);
switch (ret) {
case HTTP_UPDATE_FAILED: // When the upgrade fails
Serial.println("[update] Update failed.");
break;
case HTTP_UPDATE_NO_UPDATES: //When there is no update
Serial.println("[update] Update no Update.");
break;
case HTTP_UPDATE_OK: //When the update is successful
Serial.println("[update] Update ok.");
break;
}
}





/**
* Store network configuration information
*/
void saveConfig() {
int rand_key;
uint8_t mac[6];
WiFi.macAddress(mac);
config.reboot = 0;
EEPROM.begin(256);
uint8_t* p = (uint8_t*)(&config);
for (int i = 0; i < sizeof(config); i++) {
EEPROM.write(i, *(p + i));
}
EEPROM.commit();
}
Ticker delayTimer;
void delayRestart(float t) {
delayTimer.attach(t, []() {
ESP.restart();
});
}

/**
* Initialize WiFi information and connect to the router network
*/
void initWiFi() {

if (WiFi.status() != WL_CONNECTED) {
WiFi.disconnect(); // Disconnect
WiFi.mode(WIFI_STA); // STA mode
WiFi.begin(config.stassid, config.stapsw); // Connect to the router
}
int num = 0;
while (WiFi.status() != WL_CONNECTED && num < 120) { // Check if the connection is successful
delay(500);
num = num + 1;
Serial.print(".");
}
Serial.println("wifi config ok");
}

/**
* Load the stored information and check if the factory reset has been performed after 5 restarts
*/
uint8_t* p = (uint8_t*)(&config);
void loadConfig() {
uint8_t mac[6];
WiFi.macAddress(mac);
EEPROM.begin(256);
for (int i = 0; i < sizeof(config); i++) {
*(p + i) = EEPROM.read(i);
}
config.reboot = config.reboot + 1;
if (config.reboot >= 4) {
restoreFactory();
}
if (config.magic != 0xAA) {
config_flag = 1;
} for (int i = 0; i < sizeof(config); i++) { EEPROM.write(i, *(p + i)); } EEPROM.commit(); delay(2000); EEPROM.begin(256);
config.reboot = 0; for (int i = 0; i < sizeof(config); i++) { EEPROM.write(i, *(p + i)); } EEPROM.commit(); delay(2000); } /** * /* Restore factory settings and clear stored Wi-Fi information */ void restoreFactory() { Serial.println("Restore Factory....... "); config.magic = 0x00; strcpy(config.stassid, ""); strcpy(config.stapsw,"");





















strcpy(config.cuid, "");
strcpy(config.ctopic, "");
saveConfig();
delayRestart(1);
while (1) {
delay(100);
}
}


/*
First network configuration check for WIFI, save WIFI configuration information, and create a topic
*/
void checkFirstConfig()
{
if(firstWIfiConfig){
// Set target URL
http_bemfa_HTTPClient.begin(client_bemfa_WiFiClient,"http://pro.bemfa.com/vs/web/v1/deviceAddTopic");
// Create JSON object
StaticJsonDocument<200> jsonDoc;
jsonDoc["uid"] = config.cuid;
jsonDoc["name"] = Name;
jsonDoc["topic"] = topic;
jsonDoc["type"] = protoType;
jsonDoc["room"] = room;
jsonDoc["adminID"] = adminID;
jsonDoc["wifiConfig"] = 1; //Required field

// Converts the JSON object to a string
String jsonString;
serializeJson(jsonDoc, jsonString);
http_bemfa_HTTPClient.addHeader("Content-Type", "application/json; charset=UTF-8");
// Send the request
int httpCode = http_bemfa_HTTPClient.POST(jsonString);
if (httpCode == 200) {
Serial.println("POST succeeded with code:");
Serial.println(httpCode);
String payload = http_bemfa_HTTPClient.getString();
Serial.println(payload);

// Parse the JSON data
StaticJsonDocument<200> doc;
DeserializationError error = deserializeJson(doc, payload);
if (error) {
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.c_str());
}

int code = doc["code"];
if (code == 0) {
int resCode = doc["data"]["code"];
if(resCode == 40006 || resCode ==0 ){
String docUID = doc["uid"];
Serial.print("create topic ok:");
Serial.println(topic);
if(firstWIfiConfig){
config.reboot = 0;
config.magic = 0xAA;
saveConfig();
}

}else{
Serial.println(" config ERROR....");
}
} else {
Serial.println(" config ERROR....");
}
} else if (httpCode != 200) {
Serial.println("POST failed with code:");
Serial.println(httpCode);
} else {
Serial.println("Unknown error");
}
http_bemfa_HTTPClient.end();
}
}


void apConfig(String mac){
if(config_flag == 1){
WiFi.softAP("bemfa_"+mac);
Udp.begin(8266);
Serial.println("Started Ap Config...");
}
topic = mac;
while(config_flag){//如果未配网,开启AP配网,并接收配网信息
int packetSize = Udp.parsePacket();
if (packetSize) {
Serial.print("Received packet of size ");
Serial.println(packetSize);
Serial.print("From ");
IPAddress remoteIp = Udp.remoteIP();
Serial.print(remoteIp);
Serial.print(", port ");
Serial.println(Udp.remotePort());


int len = Udp.read(packetBuffer, 255);
if (len > 0) {
packetBuffer[len] = 0;
}
Serial.println("Contents:");
Serial.println(packetBuffer);
StaticJsonDocument<200> doc;

DeserializationError error = deserializeJson(doc, packetBuffer);
if (error) {
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
return;
}
int cmdType = doc["cmdType"].as();;

if (cmdType == 1) {
const char* ssid = doc["ssid"];
const char* password = doc["password"];
const char* token = doc["token"];
strcpy(config.stassid, ssid);
strcpy(config.stapsw, password);
strcpy(config.cuid, token);
//收到信息,并回复
String ReplyBuffer = "{"cmdType":2,"productId":""+topic+"","deviceName":""+Name+"","protoVersion":""+verSion+""}";
Udp.beginPacket(Udp.remoteIP(), Udp.remotePort());
Udp.write(ReplyBuffer.c_str());
Udp.endPacket();

}else if(cmdType == 3){
config_flag = 0;
firstWIfiConfig = true;
WiFi.softAPdisconnect(true);
}
}
}
}


/**
* 检查是否需要airkiss配网
*/
void waitKey() {
if (config_flag == 1) {
apConfig(TOPIC1);//加载ap
}
}

/*
*发送数据到TCP服务器
*/
void sendtoTCPServer(String p) {

if (!TCPclient.connected()) {
Serial.println("Client is not readly");
return;
}
TCPclient.print(p);
Serial.println("[Send to TCPServer]:String");
Serial.println(p);
preHeartTick = millis(); //Heartbeat timer starts, data needs to be sent every 60 seconds
}



/*
*Initialize and establish connection with the server
*/
void startTCPClient() {
if (TCPclient.connect(TCP_SERVER_ADDR, atoi(TCP_SERVER_PORT))) {
Serial.print("
Connected to server:");
Serial.printf("%s:%d
", TCP_SERVER_ADDR, atoi(TCP_SERVER_PORT));

String tcpTemp = ""; //Initialize string
tcpTemp = "cmd=1&uid=" + UID + "&topic=" + TOPIC3+","+ TOPIC2 +","+ TOPIC1 + "
"; //Construct subscription command
Serial.println(tcpTemp);
sendtoTCPServer(tcpTemp); //Send subscription command
tcpTemp = ""; //Clear

preTCPConnected = true;
TCPclient.setNoDelay(true);
failCount = 0;
} else {
failCount = failCount+1;
if(failCount>2){ //If the connection fails 3 times, restart the system
delayRestart(0);
}
Serial.print("Failed connected to server:");
Serial.println(TCP_SERVER_ADDR);
TCPclient.stopAll();
preTCPConnected = false;
}
preTCPStartTick = millis();
}


/*
*Check data, send heartbeat
*/
void doTCPClientTick() {
//Check if disconnected, reconnect
if (WiFi.status() != WL_CONNECTED) return;

if (!TCPclient.connected()) { //Reconnect if disconnected

if (preTCPConnected == true) {

preTCPConnected = false;
preTCPStartTick = millis();
Serial.println();
Serial.println("TCP Client disconnected.");
TCPclient.stopAll();
} else if (millis() - preTCPStartTick > 1 * 1000) //Reconnect
TCPclient.stopAll();
startTCPClient();
} else {
if (TCPclient.available()) { //Receive data
char c = TCPclient.read();
TcpClient_Buff += c;
TcpClient_BuffIndex++;
TcpClient_preTick = millis();

if (TcpClient_BuffIndex >= MAX_PACKETSIZE - 1) {
TcpClient_BuffIndex = MAX_PACKETSIZE - 2;
TcpClient_preTick = TcpClient_preTick - 200;
}
}
if (millis() - preHeartTick >= KEEPALIVEATIME) { //Keep heartbeat
Serial.println("--Keep alive:");
sendtoTCPServer("cmd=0&msg=keep
");
}
}
if ((TcpClient_Buff.length() >= 1) && (millis() - TcpClient_preTick >= 200)) { //data ready
TCPclient.flush();
Serial.print("Rev string:
TcpClient_Buff.trim(); // Remove leading and trailing spaces
Serial.println(TcpClient_Buff); // Print the received message
String getTopic = "";
String getMsg = "";
if (TcpClient_Buff.length() > 15) { // Note that TcpClient_Buff is just a string, initialized at the beginning above String TcpClient_Buff = "";
// At this point, the push command will be received, the command is roughly cmd=2&uid=xxx&topic=light002&msg=off
int topicIndex = TcpClient_Buff.indexOf("&topic=") + 7; // C language string search, find the position of &topic= and move 7 positions. If you don't understand, you can search for C language string search on Baidu
int msgIndex = TcpClient_Buff.indexOf("&msg="); // C language string search, find the position of &msg=
getTopic = TcpClient_Buff.substring(topicIndex, msgIndex); // C language string truncation, truncates to topic. (For those unfamiliar, search "C language string truncation" on Baidu)
getMsg = TcpClient_Buff.substring(msgIndex + 5); // C language string truncation, truncates to message
Serial.print("topic:------");
Serial.println(getTopic); // Prints the truncate topic value
Serial.print("msg:--------");
Serial.println(getMsg); // Prints the truncate message value
}
if(getTopic == TOPIC1){ // If it's a message sent to topic1
if(getMsg == "on"){ // If it's a message ==
turnOnLed1();//topic1 on
}else if(getMsg == "off"){ // If it's a message ==
turnOffLed1();//topic1 off
}
}else if(getTopic == TOPIC2){ // If it's a message sent to topic1
if(getMsg == "on"){ // If it's a message ==
turnOnLed2(); // topic2 on
} else if(getMsg == "off"){ // If it's a message ==
turnOffLed2(); // topic2 off
}

} else if(getTopic == TOPIC3){ // If it's a message sent to topic1
if(getMsg == "on"){ // If it's a message ==
turnOnLed3(); // topic3 ​​on
} else if(getMsg == "off"){ // If it's a message ==
turnOffLed3(); // topic3 ​​off
}

} else if (getMsg == "update") {
Serial.println("[update] Update Start......");
updateBin();
}

TcpClient_Buff = "";
TcpClient_BuffIndex = 0;
}
}

void startSTA() {
WiFi.disconnect(); // Disconnect
WiFi.mode(WIFI_STA); // STA mode
WiFi.begin(config.stassid, config.stapsw); // Connect to router
}



/***************************************************************************
WIFI
******************************************************************************/
/*
WiFiTick
checks if WiFi needs initialization.
Checks if WiFi is connected. If the connection is successful, starts the TCP Client
to control the indicator light.
*/
void doWiFiTick() {
static bool startSTAFlag = false;
static bool taskStarted = false;
static uint32_t lastWiFiCheckTick = 0;

if (!startSTAFlag) {
startSTAFlag = true;
startSTA();
Serial.printf("Heap size:%d
", ESP.getFreeHeap());
}

//未连接1s重连
if (WiFi.status() != WL_CONNECTED) {
if (millis() - lastWiFiCheckTick > 1000) {
lastWiFiCheckTick = millis();
}
taskStarted = false;
}
//连接成功建立
else {
if (taskStarted == false) {
taskStarted = true;
Serial.print("
Get IP Address: ");
Serial.println(WiFi.localIP());
startTCPClient();
}
}
}
//打开继电器
void turnOnLed1() {
Serial.println("Turn ON1");
digitalWrite(Pin1, HIGH);
digitalWrite(Pin1_2, LOW);
delay(500);
digitalWrite(Pin1, HIGH);
digitalWrite(Pin1_2, HIGH);
delay(500);
}
//关闭继电器
void turnOffLed1() {
Serial.println("Turn OFF1");
digitalWrite(Pin1, LOW);
digitalWrite(Pin1_2, HIGH);
delay(500);
digitalWrite(Pin1, LOW);
digitalWrite(Pin1_2, LOW);
delay(500);
}


void turnOnLed2() {
Serial.println("Turn ON2");
digitalWrite(Pin2, HIGH);
digitalWrite(Pin2_2, LOW);
delay(500);
digitalWrite(Pin2, HIGH);
digitalWrite(Pin2_2, HIGH);
delay(500);
}

void turnOffLed2() {
Serial.println("Turn OFF2");
digitalWrite(Pin2, LOW);
digitalWrite(Pin2_2, HIGH);
delay(500);
digitalWrite(Pin2, LOW);
digitalWrite(Pin2_2, LOW);
delay(500);
}


void turnOnLed3() {
Serial.println("Turn ON3");
digitalWrite(Pin3, HIGH);
digitalWrite(Pin3_2, LOW);
delay(500);
digitalWrite(Pin3, HIGH);
digitalWrite(Pin3_2, HIGH);
delay(500);
}

void turnOffLed3() {
Serial.println("Turn OFF3");
digitalWrite(Pin3, LOW);
digitalWrite(Pin3_2, HIGH);
delay(500);
digitalWrite(Pin3, LOW);
digitalWrite(Pin3_2, LOW);
delay(500);
}


// 初始化,相当于main 函数
void setup() {
Serial.begin(115200);
pinMode(Pin1, OUTPUT);
digitalWrite(Pin1, LOW); //写入默认状态
pinMode(Pin1_2, OUTPUT);
digitalWrite(Pin1_2, LOW); //写入默认状态
pinMode(Pin2, OUTPUT);
digitalWrite(Pin2, LOW); //写入默认状态
pinMode(Pin2_2, OUTPUT);
digitalWrite(Pin2_2, LOW); // Write the default state
pinMode(Pin3, OUTPUT);
digitalWrite(Pin3, LOW); // Write the default state
pinMode(Pin3_2, OUTPUT);
digitalWrite(Pin3_2, LOW); // Write the default state


Serial.println("Beginning...");

TOPIC1 = WiFi.macAddress().substring(8); // Get the MAC address for the theme
TOPIC1.replace(":", "1"); // Remove the colon
TOPIC1 = TOPIC1 + aptype;
TOPIC2 = WiFi.macAddress().substring(8); // Get the MAC address for the theme
TOPIC2.replace(":", "2"); // Remove the colon
TOPIC2 = TOPIC2 + aptype;
TOPIC3 = WiFi.macAddress().substring(8); // Get the MAC address for the theme
TOPIC3.replace(":", "3"); // Remove the colon
TOPIC3 = TOPIC3 + aptype;
loadConfig();
waitKey();

initWiFi();
// getUid(topicMac, false);
checkFirstConfig();
UID = config.cuid; // Assign UID
}

// Loop
void loop() {
doWiFiTick(); // Check WiFi
doTCPClientTick(); // TCP message reception
}

Note:
Due to the large current, exposed copper areas of the PCB can be soldered as appropriate
. This project uses 220V AC mains power, please operate with caution!
Actual
PCB:
Soldering front:
Soldering back:
Complete assembly:
Lighting up:
References
This project references the following projects or web pages, and we are very grateful.
Project:
New National Standard Five-Hole Metering Socket 10A
Smart Power Strip
Data:
AP Distribution Network 2.0, Automatic Distribution Network Transmission Key
Bafa Cloud Access Document
HF3F-L-05-1HL1T Datasheet
TC118S Datasheet
HLK-5M05 Datasheet
参考设计图片
×
 
 
Search Datasheet?

Supported by EEWorld Datasheet

Forum More
Update:2026-03-28 21:22:28

EEWorld
subscription
account

EEWorld
service
account

Automotive
development
community

Robot
development
community

About Us Customer Service Contact Information Datasheet Sitemap LatestNews


Room 1530, 15th Floor, Building B, No.18 Zhongguancun Street, Haidian District, Beijing, Postal Code: 100190 China Telephone: 008610 8235 0740

Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号