Saturday, 18 March 2017

Wemos ESP8266 based (WiFi) Stick-A-Switch Arduino Compatible




I got this guy off eBay for $4, I'm pretty sure it's a Chinese clone of the actual thing and it _might_ be an older revision but it seems to work...

The board is a Wemos D1, I believe in this boards case you are programming the ESP chip itself and it does not have the usual Atmega processor.  It works with the Arduino IDE however and programs in the same way so  there is no learning curve.

You will need to load the ESP boards into your Arduino IDE, so follow these instructions to do that.

This unit seems to take longer to actually upload sketches to, but it seems to be much more reliable as far as staying on and responding on the WiFi and being less location sensitive than the WiFi Shield I used in my last project.

I believe it has less inputs (for sure on the analog side it only has 1). It should have 11 input pins but apparently they don't match the standard pin numbering. They are also labeled with specific purposes (SPI it looks like) so I'm not sure if you are required to use them for that or not, I put this one into a project so I can't test it, I have another on the way and I'll add some more details in the future.

According to the datasheet:
11 digital input/output pins, all pins have interrupt/pwm/I2C/one-wire supported(except for D0)
1 analog input(3.2V max input)
Power jack, 9-24V power input.

You can find more information on it here:

It seems to have internal pullup/pulldown on some pins, again according to the datasheet.

Anyway enough jibber-jabbering... Let's do something fun with it!

I decided to try and make a switch that could send messages to control something with this...
I decided I wanted to get MQTT working so this will tell you how to make this.

I also today learned about this library called WiFiManager which mimics the usual behavior of IoT devices providing an AP to configure it's WiFi parameters so I have added this to the project as well.

It is possible to add additional settings such as MQTT server to WiFi manager so you can set everything up on the fly via your smartphone, but I haven't done that yet, I have just put the servers IP into the code.

So I took a box (which happened to be from a WiFi Controller for some connected bulbs) that was the perfect size for the switch and somewhat rigid.  I cut a hole in it so the back of the standard light switch would slip in there and bolted it to the box.

I put a resistor into GND and pin D2 on the Wemos board, and the plugged the switch into 5v and the D2 side of the resistor and wrapped it all in electical tape to keep it from shorting out.  I then put some tape on the bottom of the board to make sure it wouldn't short out against the switch and jammed it into the box.   A cover plate for the switch completed the build.

I then loaded the following sketch onto the board, and added a new topic to my X10 controller's MQTT receiver (that currently controls the lights in the bathroom)..

You will need to load the PubsubClient (MQTT Client)
You will also need  WiFi Manager if you plan on using it as I did in this sketch
The rest should already be installed with the board.

============Start Sketch ==============

/*
 *  MQTT Light switch by Guyfromhe
 */

#include <ESP8266WiFi.h>
#include <PubSubClient.h>
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#include <WiFiManager.h>

const char* ssid = ".....";   // Not used if using WiFiManager
const char* password = "......"; // Not used if using WiFiManager





const int swpin = 16;  // This is pin D2 on the board... Don't ask me :P
int sw = 0;
int lastsw = 0;
int buttonTime = 0;

//const char* mqtt_server = "broker.mqtt-dashboard.com";    // Public Broker. Can use if you want
const char* mqtt_server = "192.168.0.xxx";  // Mosquito on my Raspberry Pi (apt-get install mosquitto)
WiFiClient espClient;   // Init WiFi
PubSubClient client(espClient);  //Init MQTT client
long lastMsg = 0;
char msg[50];
int value = 0;

void setup_wifi() {

  delay(10);
  // We start by connecting to a WiFi network
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  //WiFi.begin(ssid, password);  // Uncomment this if you want to use the credentials at the top
   WiFiManager wifiManager;   // or use WiFi manager for credentials
   wifiManager.autoConnect("AutoConnectAP");

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  randomSeed(micros());

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void callback(char* topic, byte* payload, unsigned int length) {
// This will print out messages from topics we are subbed to
// This is the default code from the PubSub Example, it will control the LED
  Serial.print("Message arrived [");
  Serial.print(topic);
  Serial.print("] ");
  for (int i = 0; i < length; i++) {
    Serial.print((char)payload[i]);
  }
  Serial.println();

  // Switch on the LED if an 1 was received as first character
  if ((char)payload[0] == '1') {
    digitalWrite(BUILTIN_LED, LOW);   // Turn the LED on (Note that LOW is the voltage level
    // but actually the LED is on; this is because
    // it is acive low on the ESP-01)
  } else {
    digitalWrite(BUILTIN_LED, HIGH);  // Turn the LED off by making the voltage HIGH
  }

}

void reconnect() {
  // Loop until we're reconnected
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    // Create a random client ID
    String clientId = "ESP8266Client-";
    clientId += String(random(0xffff), HEX);
    // Attempt to connect
    if (client.connect(clientId.c_str())) {
      Serial.println("connected");
      client.subscribe("inTopic");
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying
      delay(5000);
    }
  }
}

void setup() {
  pinMode(swpin, INPUT);
  sw = digitalRead(swpin);
  lastsw = digitalRead(swpin);
  Serial.begin(115200);

  // Bring up MQTT
  pinMode(BUILTIN_LED, OUTPUT);     // Initialize the BUILTIN_LED pin as an output
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(callback);




}

void loop() {
  // MQTT
 if (!client.connected()) {
    reconnect();
  }
  client.loop();



  // Button



  sw = digitalRead(swpin);
  if (sw != lastsw) {
    if ((millis() - buttonTime) > 50)        // Number of mills for debounce counter
      Serial.println(sw);
      lastsw = sw;
      buttonTime = millis();
      if (sw == 0) { client.publish("MySwitchTopic", "Switch Off!"); }
      if (sw == 1) { client.publish("MySwitchTopic", "Switch On!"); }
   
  }

}

============ End Sketch ==============

After running a short USB cable to it (since it needs constant power) I stuck it to the wall with some mounting tape.  Works great and is simple to use.

EDIT: Recently upgraded from X10 to Lutron for control of the actual fixture and now the delay between flipping the switch and the light changing states is gone.  See my post on Lutron for details.

In the future I would like to make it much thinner by modifying the switch and run it on batteries by building an Arduino from scratch and using ultra low power sleep mode along with an nRF24 in sleep mode.

Total cost $4.



Stay tuned for more projects, and cheap hacks.

2 comments: