WiFi Switch for home appliances with ESP8266

Learn how the build your own WiFi switch with the ESP module and how to control any appliance of your favorite place.

What are WiFi Switches?

Nowadays we are living in an Internet of Things age and WiFi Switches are basically the foundation of it. They are devices that can turn on, off or dim home appliances like lights, fans, etc remotely or autonomously, controlled by our cellphones, our voice, the room temperature or even weather reports.

How do they work?

They are based on wireless communication (commonly known as WiFi) that let them connect to the internet and process data, so they can take action due to certain conditions established by the user.

Application requirements:

  • ESP8266 Module (ESP-01)
  • PCB board
  • Breadboard
  • Wiring cables
  • Ubidots account
  • Arduino nano

1. Schematic:

Materials:

3x 1k ohm resistors 1/4w

2x 470 ohm resistors 1/2w

1x dual in line female connector (U3)

1x MOC3010 (Opto-triac)

1x Triac BTA24

1x 100nf 400v Capacitor

1x Hi-Link 3.3v Power Supply

1x Terminal Block 2p

1x Terminal Block 3p

PCB: Link to download Gerber file!

PCB made with PCBGOGO (PCB manufacture Industry)

2. Ubidots Device and variable creation.

Go to the Device section of your Ubidots account and create a new device called "wifiswitch".

Inside your "wifiswitch" device, create a variable called "light".

3. Ubidots Dashboard and Widget creation.

Once our device and variable are created, we can create a dashboard and widget to control the light from a web or mobile dashboard. To create a new dashboard, press the "Data > Dashboard". Then press the plus icon and complete the dashboard configuration as is desired.

Now, create a control widget to set the status of the light bulb associated with the variable "light". To create the control widget, select the plus icon located at the right upper side of the page. Then press "Switch" as widget type, select the variable desired to be controlled and complete the widget configuration as is desired.

Then you are ready to program and test your project.

4. Programing with the Arduino IDE.

1. If not done yet, download the Arduino IDE.

1a. Open the Arduino IDE and select Files -> Preferences

1b. Add the url below into the Additional Board Manager URLs field. You can add multiple URLs by separating them with commas.

http://arduino.esp8266.com/stable/package_esp8266com_index.json

2. Open and Install the ESP8266 board in the Boards Manager: Tools -> Board -> Boards Manager

2a. You can easily find the board by typing “ESP8266” in the search bar.

3. Now, select the Generic ESP8266 board from Tools -> Board menu

4. Define or double check the Port of your PC which the device is communicating with. Go to Tools -> Port: -> Select the port

4b. Ensure your IDE Upload Speed is 115200 by going to Tools -> Upload Speed -> 115200

5. Download the UbidotsESPMQTT library if you haven’t already. Now, click on Sketch –> Include Library –> Add .ZIP Library and choose the Ubidots ESP8266 MQTT library

If properly uploaded, you get the response: "Library added to you libraries."

8. Close and open again the Arduino IDE.

Programming the ESP8266:

Once your ESP8266 is set up, we can start publishing and subscribing data from/to Ubidots in order to control the Wifi Switch.
1. Copy and paste the following code in the Arduino IDE. Don’t forget to customize the Wi-Fi SSID and password and your Ubidots Token.



/****************************************

 * Libraries

 ****************************************/

#include "UbidotsESPMQTT.h"


/****************************************

 * Define constants
 
 ****************************************/

#define TOKEN "............................." // Your Ubidots TOKEN

#define WIFINAME "........." //Your SSID

#define WIFIPASS "........." // Your Wifi Pass

#define DEVICE_LABEL "wifiswitch"   // Name of the device

#define VARIABLE_LABEL1  "light"  // Name of the Ubidots variable

const int ERROR_VALUE = 65535;  // Error value 

const uint8_t NUMBER_OF_VARIABLES = 2; // Cantidad de variables a las que el programa se va a suscribir
char * variable_labels[NUMBER_OF_VARIABLES] = {"light"}; // Variables names


#define luz  0
#define boton  2

int seguro=0;

int ledState = LOW;         // the current state of the output pin
int buttonState;             // the current reading from the input pin
int lastButtonState = HIGH;   // the previous reading from the input pin
int reading;
unsigned long lastDebounceTime = 0;  // the last time the output pin was toggled
unsigned long debounceDelay = 50; 

float estadoluz; // Variable to be used in the code

float value; // Variable to store input data
uint8_t variable; // To use with the switch case

Ubidots ubiClient(TOKEN);

WiFiClient client;

/****************************************

 * Auxiliar functions

 ****************************************/

void callback(char* topic, byte* payload, unsigned int length) {
  char* variable_label = (char *) malloc(sizeof(char) * 30);
  get_variable_label_topic(topic, variable_label);
  value = btof(payload, length);
  set_state(variable_label);
  execute_cases();
  free(variable_label);
  /////////////////Light////////////////////

  digitalWrite(luz, estadoluz);
 
  /////////////////Light////////////////////
  
}

// Parse topic to extract the variable label which changed value
void get_variable_label_topic(char * topic, char * variable_label) {
  Serial.print("topic:");
  Serial.println(topic);
  sprintf(variable_label, "");
  for (int i = 0; i < NUMBER_OF_VARIABLES; i++) {
    char * result_lv = strstr(topic, variable_labels[i]);
    if (result_lv != NULL) {
      uint8_t len = strlen(result_lv);      
      char result[100];
      uint8_t i = 0;
      for (i = 0; i < len - 3; i++) { 
        result[i] = result_lv[i];
      }
      result[i] = '\0';
      Serial.print("Label is: ");
      Serial.println(result);
      sprintf(variable_label, "%s", result);
      break;
    }
  }
}

// cast from an array of chars to float value.
float btof(byte * payload, unsigned int length) {
  char * demo = (char *) malloc(sizeof(char) * 10);
  for (int i = 0; i < length; i++) {
    demo[i] = payload[i];
  }
  float value = atof(demo);
  free(demo);
  return value;
}

// State machine to use switch case
void set_state(char* variable_label) {
  variable = 0;
  for (uint8_t i = 0; i < NUMBER_OF_VARIABLES; i++) {
    if (strcmp(variable_label, variable_labels[i]) == 0) {
      break;
    }
    variable++;
  }
  if (variable >= NUMBER_OF_VARIABLES) variable = ERROR_VALUE; // Not valid
  
}

// Function with switch case to determine which variable changed and assigned the value accordingly to the code variable
void execute_cases() {  
  switch (variable) {
    case 0:
      estadoluz = value;
      Serial.print("Luz: ");
      Serial.println(estadoluz);
      Serial.println();
      break;
    case ERROR_VALUE:
      Serial.println("error");
      Serial.println();
      break;
    default:
      Serial.println("default");
      Serial.println();
  }

}
/****************************************

 * Funcion principal

 ****************************************/

void setup() {

  // put your setup code here, to run once:
  pinMode(luz, OUTPUT);  
  pinMode(boton, INPUT); 
  ubiClient.ubidotsSetBroker("industrial.api.ubidots.com"); // Sets the broker properly for the business account
  ubiClient.setDebug(true); // Pass a true or false bool value to activate debug messages
  Serial.begin(115200);
  ubiClient.wifiConnection(WIFINAME, WIFIPASS);
  ubiClient.begin(callback);
  if(!ubiClient.connected()){
    ubiClient.reconnect();
  }

  char* deviceStatus = getUbidotsDevice(DEVICE_LABEL);

  if (strcmp(deviceStatus, "404") == 0) {
    ubiClient.add("light", 0); //Insert your variable Labels and the value to be sent
    ubiClient.ubidotsPublish(DEVICE_LABEL);
    ubiClient.loop();
  }

  ubiClient.ubidotsSubscribe(DEVICE_LABEL,VARIABLE_LABEL1); //Insert the Device and Variable's Labels
  Serial.println(variable_labels[1]);

}

void loop() {
  // put your main code here, to run repeatedly:
  if(!ubiClient.connected()){
    ubiClient.reconnect();
    ubiClient.ubidotsSubscribe(DEVICE_LABEL,VARIABLE_LABEL1); //Insert the Device and Variable's Labels
  }
  ubiClient.loop();    
  
  readit();

  debounce();

  // save the reading. Next time through the loop, it'll be the lastButtonState:
  lastButtonState = reading;
          
}

void readit(){
  // read the state of the switch into a local variable:
  reading = digitalRead(boton);
  if (reading != lastButtonState) {
    // reset the debouncing timer
    lastDebounceTime = millis();
  }
}

void debounce(){
  if ((millis() - lastDebounceTime) > debounceDelay) {
    // whatever the reading is at, it's been there for longer than the debounce
    // delay, so take it as the actual current state:
    readit2();  
  }
}

void readit2(){
    // if the button state has changed:
    if (reading != buttonState) {
      buttonState = reading;
      toggle();      
    }
}

void toggle(){
  // only toggle the LED if the new button state is LOW
  if (buttonState == LOW) {
    ledState = !ledState;
    // set the LED:
    digitalWrite(luz, ledState);
    ubiClient.add("light", ledState); //Insert your variable Labels and the value to be sent
    ubiClient.ubidotsPublish(DEVICE_LABEL);
  }  
}

char* getUbidotsDevice(char* deviceLabel) {
  char* data = (char *) malloc(sizeof(char) * 700);
  char* response = (char *) malloc(sizeof(char) * 400);
  sprintf(data, "GET /api/v1.6/devices/%s/", deviceLabel);
  sprintf(data, "%s HTTP/1.1\r\n", data);
  sprintf(data, "%sHost: industrial.api.ubidots.com\r\nUser-Agent:wifiswitch/1.0\r\n", data);
  sprintf(data, "%sX-Auth-Token: %s\r\nConnection: close\r\n\r\n", data, TOKEN);
  free(data);
 
  if (client.connect("industrial.api.ubidots.com", 80)) {
    client.println(data);
  } 
  else {
    free(data);
    free(response);
    return "e";
  }
  int timeout = 0;
  while(!client.available() && timeout < 5000) {
    timeout++;
    if (timeout >= 4999){
      free(data);
      free(response);
      return "e";
    }
    delay(1);
    }

  int i = 0;
  while (client.available()) {
    response[i++] = (char)client.read();
    if (i >= 399){
      break;
    }
  }
  char * pch;
  char * statusCode;
  int j = 0;
  pch = strtok (response, " ");
  while (pch != NULL) {
    if (j == 1 ) {
      statusCode = pch;
    }

    pch = strtok (NULL, " ");
    j++;
  }
  free(response);
  return statusCode;

}

2. Uploading the code to the ESP8266:

To upload the code to the ESP8266 we need a serial interface to communicate (Programmer) the module with the PC, we can use USB to TTL converters, but in this case, we are going to use the serial of the Arduino that do a very good job.

To upload the code into the ESP8266 you have to follow the connections below.

Arduino Nano ESP8266
TXD TXD
RXD RXD
3.3V VCC
GND GND
3.3V CH_PD
GND GPIO0

NOTE: Please be careful with the VCC of the ESP8266, it works only with a 3.3V supply.

Now, verify your code is correct by clicking the check button in the Arduino IDE above the editor.

Once the code is verified, you will receive a response similar to the one below, indicating that it is properly set up.

Next, your have to upload the code into your NodeMCU. To do this, choose the right-arrow icon besides the check icon.

Once the code is uploaded, you will receive the message below in the Arduino IDE:

5. Configure voice commands using Google Assistant:

To control your “WiFi Switch” with Google Home, first we need to configure an intermediary platform called IFTTT, this will let us to pair our Switch with the Google Assistant. To configure correctly, follow the steps shown below.

If you don't have an account, Sign up.

Click on “My Applets”.

Then, click on “New Applet”.

Click on “+ this” to configure the trigger of your condition.


Search for “Google assistant” service and click on it.

Click on “Say a simple phrase”.

Complete the trigger fields with the phrases you want to use to control the light, the response  and the language, then click “Create trigger”.

Then, click on “+that” to configure the action.

Search for the “Webhooks” action service.

Click on “Make a web request”.

Complete action fields:

Field Argument
URL http://things.ubidots.com/api/v1.6/devices/wifiswitch?token=(Here goes your Ubidots Token)
Method POST
Content Type application/json
Body To turn on {“light”:1}, to turn off {“light”:0}

Finally, click on Finish.

NOTE: Repeat everything to set the “Turn off the light” applet, with the correct Body statement.

6. Testing Session:

Due to the diagram shown in the picture, connect correctly the module to your AC appliance.

Home Module
Line L
Neutral N
Light Line' B

Add a momentary button of your preference in the terminal block called SW.

Identify the Line, Neutral and Light cables:

Make the connections and place the button, tight the screws and test.

In case you're a visual learner check out the following video tutorial. You can find all the steps I made to build this project carefully explained:

Summary:

In this guide, we just learned how to build a WiFi switch that can be controlled over the internet by your voice, cellphone app, or your PC, that let you control a light bulb of a bedroom or any other place. This device works based on the ESP8266 WiFi module, that is a tiny module that let the project get online easily. And this device can be applied in the control of many different devices like fans, motors, curtains, lights, led strips, and much more.

Start developing your IoT solutions with Ubidots, today.