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 = "";    // Public Broker. Can use if you want
const char* mqtt_server = "";  // 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() {

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

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

  while (WiFi.status() != WL_CONNECTED) {


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

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("] ");
  for (int i = 0; i < length; i++) {

  // 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())) {
    } else {
      Serial.print("failed, rc=");
      Serial.println(" try again in 5 seconds");
      // Wait 5 seconds before retrying

void setup() {
  pinMode(swpin, INPUT);
  sw = digitalRead(swpin);
  lastsw = digitalRead(swpin);

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


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

  // Button

  sw = digitalRead(swpin);
  if (sw != lastsw) {
    if ((millis() - buttonTime) > 50)        // Number of mills for debounce counter
      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.

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.

Wednesday, 15 March 2017

Arduino Light Switch -- Making it WiFi (AKA Look maw, no PC)

This entry will detail my bridge step in making a WiFi to RF24 self contained bridge without a Pi or any other computer.  The final step will be to get rid of the RF24 and just have the WiFi module control the servo directly.

So my WiFi Shield (or in this case Shia1d) showed up today in the mail even though I wasn't expecting it for another month or so so I figured I would see what info I could find about it, and it didn't look good...

This $6 eBay special (ESP-12E ESP8266 UART WIFI Wireless Shield for Arduino UNO R3) had all sorts of tales of woe from lack of documentation to firmware issues to pins not connecting to the right place, but one site aggregated all the info and really helped me get this thing going.

These will be labeled as follows:
ESP8266 WiFi Sheild Version 1.0 by WangTongze
Designed in Beijjing P.R. China

First off, you need to know there are at least 4 different versions of the board and there are no promises which one you will get.

DIP 1 and 2 are _supposed_ to connect and disconnect the ESP from pins 0/1 (hardware serial) but they often DON'T DO ANYTHING...
DIP 2 and 3 are used to enable firmware flashing mode on the board on all revisions

The version I got is unstable running as a web server.  When placed in the right location I can get 0% packet loss (it is very picky about location) but I often don't get a page back. It does seem to always read my request and execute my code, so my lights always switch correctly but 40% of the time I don't get the web page back from it, which is no big deal for my current application but could be a deal breaker for someone trying to get status or other information from the device.
While I had the serial interface connected I would sometimes see TIMEOUT from the library talking to the ESP usually after a web request so this would probably explain it... You may be able to add some error checking in the sketch if it really bugs you, or just reload a few times and it will eventually work...

According to Claus, the new version (with the maintenance pins not populated, the word shield spelled correctly and a different shape on the antenna on the ESP module) provides a fast and stable web interface so try and get that version if you can.

To start you want to flash the latest firmware on the device, we will use the Uno as a TTL to serial converter. (You can use a TTL to serial cable if you want)

Put a jumper between RST (pin 3 on the power rail) and GND. This will keep the MCU out of the picture.

Connect your shield as follows (not plugged into the top of your Uno yet, but next to it).

Debug Port RX => Uno Pin 0 (Rx)
Debug Port TX => Uno Pin 1 (Tx)
Debug Port 5v => Uno 5v
Debug Port GND => Uno GND

The ESP is meant to use 3.3v logic but the Uno uses 5v.  You can use a level shifter if you want but I have yet to hear about anyone wrecking their device on 5v (me included on 2 different ones so far).  If you do happen to let the smoke though, don't blame me.

Open your serial monitor and set the baud to 115200... When you reset your ESP with the button it should show some garbage (the garbage is actually the boot loader at a different baud rate) and then say ready.

Set your terminal to CR & LF then send AT.  You should get an OK back from the ESP... If you don't make sure you didn't plug the ESP into the top of your Uno, and make sure you wires are secure...

Download this flasher utility from
And the Firmware from
You want the 1.1.1 Version as of this writing and the 115200 subset.  Make sure the file is about a meg (I got a bunk file somehow and it took me a while to figure out what was wrong)
1,044,480 ai-thinker-v1.1.1-115200.bin

Unplug your Uno and set dip switches 3 and 4 to ON on the shield, this will put your ESP into programming mode, then plug it back it... Make sure your serial monitor is closed.

Open the flash utility:
Click on Bin and locate the bin file you downloaded (don't bother with the included one in the zip)
Change the COM to the com port your Arduino is using (you can check this under Tools -> Port in the IDE)
You can leave the 0x0000000 defaults alone and hit Download...
It will say Erasing and then Writing, this process should take around a minute or so... When it gets to Leaving at the end it WILL return an error you can ignore this, it's normal.
Close the flasher, unplug your Arduino, turn switches 3 and 4 off and then plug er back in.

Open the serial monitor again and check your device boots still and that you can still get the OK.

If it doesn't give you the ready anymore, you can change the baud rate to 78 something and you can see the boot loader messages... Usually this means you flashed bad firmware... Check everything and then repeat the flashing steps, I don't think you can actually brick it... You can always flash the included firmware in the zip to see if you can flash working firmware on the device, but you need to update to the latest version still...

Finally since we have to use software serial we will need to slow the ESP down to 9600 BPS or we will  have communication issues.

In your terminal enter the following command: AT+UART_DEF=9600,8,1,0,0
This should return OK and will be stored in NVRam so you only need to do this once.  Reboot it and change your serial console to 9600 to make sure it took effect.

Phew that's finally over, now we can start the fun part!

Remove all the jumpers from the Uno side, and remove the wires from +5v and GND from the debug port.  We will need the RX and TX still though don't pull them off...

Now stick the shield onto your Uno.. The first pin on the power rail will hit the Reset pin on the Arduino, the first 2 aren't populated. The last pins should all line up properly.  Make sure you don't have any bent or missing pins..

Now plug the Debug RX into the pass through for pin 2 and the Debux TX into the pass through for pin 3.     Since we need the hardware serial for programming the Uno and Serial debug we will need to use software serial.

Note: If you have issues programming your Uno or using the serial console while the shield is plugged in make sure DIP 1 and 2 are off.. If it still won't work, try bending pins 0 and 1 so they don't plug into the Uno, this is a problem on some revisions.

Don't forget to switch your serial console back to 115200 at this point.

Grab the WiFiESP library from here and install the zip file (see my last post if you don't know how to download and install libraries)

Load the example code WiFiESP -> ScanNetworks
You will need to update the pin numbers with the following line: "SoftwareSerial Serial1(6,7)" to SoftwareSerial Serial1(3,2) -- The 3,2 being the only change!
Compile and run that and your ESP should come to life and show a list of networks in range and their power levels in the serial monitor.  If this doesn't work check your connections and make sure your PC is able to supply enough power (at least 350mA).

If all goes well, move on to the webserverled example... You need to put your SSID and password into the sketch before running it, then follow the instruction in the serial monitor to connect to your device with your web browser!

If all is well you should see the status and be given links to toggle LED 13 (you need to peek inside as this LED is covered by the shield).  Click the links and make sure the LED toggles and the status updates in your browser.  It may occasionally not load, just hit refresh... I think this just happens sometimes but it seems pretty rare if you have good power.

Great now for the "bridge" part of this project, we will connect the RF24 module like before and then run a modified version of the webserverled sketch to send out commands...

See my last post for detailed instructions on the RF24 but for quick reference:
Brown Wire -> GND
Red Wire -> 3.3v
Orange Wire -> Pin 7
Yellow Wire -> Pin 8
Blue Wire -> Pin 11
Purple Wire -> Pin 12
Green Wire -> Pin 13

Load up the following sketch substituting your SSID and password where requested...

Most of the code for the RF24 is copied from the previous sketch, see it if you want more comments..

----------------------Start Arduino Sketch----------------------------

 WiFiEsp example: WebServerLed
 A simple web server that lets you turn on and of an LED via a web page.
 This sketch will print the IP address of your ESP8266 module (once connected)
 to the Serial monitor. From there, you can open that address in a web browser
 to turn on and off the LED on pin 13.

 For more details see:

// RF24 to WiFi bridge

#include "WiFiEsp.h"

#include <SPI.h>
#include "RF24.h"

// Setup RF24
RF24 radio(7,8); // Stand Alone

bool radioNumber = 1; // Stand Alone
bool role = 1; // Stand alone
unsigned long cmd=255;                             // Do not send anything by default

byte addresses[][6] = {"1Node","2Node"};  // You can change the node names here if you'd like, I left them alone

// Emulate Serial1 on pins 3/2 if not present
#include "SoftwareSerial.h"
SoftwareSerial Serial1(3, 2); // RX, TX

char ssid[] = "YOURSSID";            // your network SSID (name)
char pass[] = "YOUR-WIFI-PASSWORD";        // your network password
int status = WL_IDLE_STATUS;

//int ledStatus = LOW;

WiFiEspServer server(80);

// use a ring buffer to increase speed and reduce memory allocation
RingBuffer buf(8);

void setup()
  // Setup RF24
  // It's now really close to my device and I want to conserve power. If you need more range change to MAX


  // WiFi Stuff
  //pinMode(LED_BUILTIN, OUTPUT); // initialize digital pin LED_BUILTIN as an output.
  Serial.begin(115200);   // initialize serial for debugging
  Serial1.begin(9600);    // initialize serial for ESP module
  WiFi.init(&Serial1);    // initialize ESP module

  // check for the presence of the shield
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    // don't continue
    while (true);

  // attempt to connect to WiFi network
  while (status != WL_CONNECTED) {
    Serial.print("Attempting to connect to WPA SSID: ");
    // Connect to WPA/WPA2 network
    status = WiFi.begin(ssid, pass);

  Serial.println("You're connected to the network");

  // start the web server on port 80

void loop()
  WiFiEspClient client = server.available();  // listen for incoming clients

  if (client) {                               // if you get a client,
    Serial.println("New client");             // print a message out the serial port
    buf.init();                               // initialize the circular buffer
    while (client.connected()) {              // loop while the client's connected
      if (client.available()) {               // if there's bytes to read from the client,
        char c =;               // read a byte, then
        buf.push(c);                          // push it to the ring buffer

        // printing the stream to the serial monitor will slow down
        // the receiving of data from the ESP filling the serial buffer
        // you got two newline characters in a row
        // that's the end of the HTTP request, so send a response
        if (buf.endsWith("\r\n\r\n")) {

        // Check to see if the client request was "GET /H" or "GET /L":
        if (buf.endsWith("GET /1")) {
          Serial.println("Turn light ON");
          //ledStatus = HIGH;
          // Send RF24 command
          radio.stopListening();                                    // First, stop listening so we can talk.
          cmd = 1;
          Serial.println("Trying to send to radio");
          if (!radio.write( &cmd, sizeof(unsigned long) )){
          if (!radio.write( &cmd, sizeof(unsigned long) )){

          if (!radio.write( &cmd, sizeof(unsigned long) )){

          if (!radio.write( &cmd, sizeof(unsigned long) )){

          if (!radio.write( &cmd, sizeof(unsigned long) )){
          Serial.println("Thats it...");
          radio.startListening();                                    // Listen again

          //digitalWrite(LED_BUILTIN, HIGH);   // turn the LED on (HIGH is the voltage level)
        else if (buf.endsWith("GET /0")) {
          Serial.println("Turn light OFF");
          // Send RF24 command
          radio.stopListening();                                    // First, stop listening so we can talk.
          cmd = 0;
          Serial.println("Trying to send to radio");
          if (!radio.write( &cmd, sizeof(unsigned long) )){
          if (!radio.write( &cmd, sizeof(unsigned long) )){

          if (!radio.write( &cmd, sizeof(unsigned long) )){

          if (!radio.write( &cmd, sizeof(unsigned long) )){

          if (!radio.write( &cmd, sizeof(unsigned long) )){
          Serial.println("Thats it...");
          radio.startListening();                                    // Listen again

          //ledStatus = LOW;
          //digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
        else if (buf.endsWith("GET /T")) {
          Serial.println("Toggle Light");
          // Send RF24 command
          radio.stopListening();                                    // First, stop listening so we can talk.
          cmd = 2;
          Serial.println("Trying to send to radio");
          if (!radio.write( &cmd, sizeof(unsigned long) )){
          if (!radio.write( &cmd, sizeof(unsigned long) )){

          if (!radio.write( &cmd, sizeof(unsigned long) )){

          if (!radio.write( &cmd, sizeof(unsigned long) )){

          if (!radio.write( &cmd, sizeof(unsigned long) )){
          Serial.println("Thats it...");
          radio.startListening();                                    // Listen again

          //ledStatus = LOW;
          //digitalWrite(LED_BUILTIN, LOW);    // turn the LED off by making the voltage LOW
    // close the connection
    Serial.println("Client disconnected");

void sendHttpResponse(WiFiEspClient client)
  // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK)
  // and a content-type so the client knows what's coming, then a blank line:
  client.println("HTTP/1.1 200 OK");

  // the content of the HTTP response follows the header:
  client.print("<b>Office Lights Control</b>");
  //client.print("The LED is ");

  client.println("Click <a href=\"/1\">here</a> turn the lights on<br>");
  client.println("Click <a href=\"/0\">here</a> turn the lights off<br>");
  client.println("Click <a href=\"/T\">here</a> toggle the lights<br>");

  // The HTTP response ends with another blank line:

void printWifiStatus()
  // print the SSID of the network you're attached to
  Serial.print("SSID: ");

  // print your WiFi shield's IP address
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");

  // print where to go in the browser
  Serial.print("To see this page in action, open a browser to http://");
------------------------------ END SKETCH --------------------------------

Upload the sketch and open the serial monitor... If your Uno starts disconnecting from USB you aren't providing enough power to keep it running.. You can probaly move it to a plug or USB charger now though assuming it's working and you have written down it's IP.

You can now send commands by browsing to your devices IP and clicking the links or accessing /1 /2 or /T URLs.   This should in turn control your servo half of the project without any changes.

You should get the following page in your browser:

The strings are obvious in the sketch, feel free to make them your own!!

Though the browser works fine, it will make spurious requests (like favicon) and send a ton of extra data which can slow down and overwhelm your little ESP so it's not ideal to access it this way all the time.. For best results use the script below...

Now all that's left is a super simple Python script to control the lights from any machine on your network for easy integration into your automation system.  

---------------------Start ----------------------------------
import urllib2, sys

ip = ""     # This is the IP of your ESP

cmd = sys.argv[1]

out = ""
if cmd == "1": out = "1"
if cmd == "0": out = "0"
if cmd.lower() == "t": out = "T"

x = urllib2.urlopen('http://%s/%s' % (ip,out), timeout=1).read()
print x
print "Retrying..."
x = urllib2.urlopen('http://%s/%s' % (ip,out), timeout=1).read()
print x


Then just run python 0 for off, python 1 for on and python t for toggle.

Let me know if you have any questions or found this information helpful in the comments.

Thursday, 9 March 2017

$16 Wireless Lightswitch Mark II

                                        BEFORE                                                    AFTER 

Update 2: I made a WiFi to RF24 bridge and can now directly access this without it being plugged into a Pi.  This new article is in addition to this one and explains how to modify this build to run on WiFi directly instead of serial.

Update: Due to all the complaining about the sheer ugliness of this build, I cleaned up the extra tape and glue, removed the black tape from the wall, replaced the servo screw with a properly sized one and made a little paper box that matches the wall plate (if I had some white paint I'd paint it white but I don't so I won't) I hope your happy :P  I realize it's still not pretty but it's much nicer looking than it was.

I have a first world problem.... My light switch is too far away from my desk and sometimes I want the lights off to watch a movie but then I need them on again to work on a project or even to make it through the mindfield of bits and bobs on my floor to the way to the light switch...  Sure I could stop being lazy, or heaven forbid clean up the crap on the floor but that isn't the hacker way!

First I though I'll just get a Fing-longer (TM) but Amazon doesn't ship them to Canada, those bastards!

Image result for fing longer

So I ordered a couple Arduino's to play with and a servo and built my first serial controlled light switch, but that required a laptop (or a trip-wire across my already cluttered floor to my PC) and that was super overkill to run a light switch, so I searched for the right solution..

I tried an ESP8266 but alas I didn't have the right power source or much else beyond a pack a resistors (I am just starting out hardware hacking, I don't have a ton of parts yet) and though this worked it would only get on the network about 20% of the time, this was much worse than the laptop, alas...

I didn't have enough time/interest at this point to do anymore with this and just left it running on the laptop....

Then I read about someone using the NRF24 chips on Hack A Day in a project and figured I would give them a shot as it seemed much simpler and lower power than a ESP, and this seemed to do the trick! (Though I do intend for the final thing to be on WiFi and connect to my existing MQTT network.. I have parts coming)

The idea is to very simply be able to send a single character from an automation system to either turn my lights on, off or toggle them and possibly have a switch close to my desk, a-la 3-way switch but without ripping up walls, dealing with high voltages or running wires across my office.

Today I will describe how you can make a remotely controlled (via RF) light switch (that can be controlled via anything that can talk serial) using 2x Arduino Uno clones, 2x NRF24L01+ modules, 1x Servo motor and an optional switch (which requires a resistor as well).

Build of Materials:
2 x Arduino Uno clones $7.10
2 x nRF24L01+ modules $1.66
1 x 9G SG90 Servo $1.88
1 x 100k Ohm Resistor (brown-black-yellow-gold) $0.01
1 x Decora light switch $3.95
2 x USB A to B cables $1.48 (Included with the above Arudino's)
Total Cost: $16.08 though this actually cost me much less since I had a lot of the parts lying around from other projects and you probably do too!

You will also need some Dupont hookup wire or some regular wire and a soldering iron, and a hot glue gun. You'll also need a PC to program it with and if you want a Raspberry Pi to control it, or you can even use your PC if you prefer. The point is you don't need anything fancy or expensive to do this project.

This build isn't super pretty or anything but it can be mounted on any Decora style switch, and it mounts to the plate so you can even do this if you don't own the property.  You can get a switch plate for 50 cents at Home Depot.  It does not require modifying any mains wiring, it's non permanent and doesn't interfere with regular operation of the switch!

Note: If you have an old style toggle switch you can very easily change it out for a Decora style switch, make sure to turn off the breaker if you decide to do this, this is not part of my project!

 There are also other projects that adapt the servo to a toggle style switch, here is one on Hack A Day but you need to 3D print a special wall plate and arm for it... You can still follow my instructions to get the wireless and local switch part through while using his servo mount.

So I've got some parts, made a revision to my switch...
I got 10 x NRF24L01+ 2.4 GHz transceivers on eBay for about 6 bucks...
These are basically over the air serial devices, they run in 3.3v and are 5v logic tolerant and use MUCH less current than an ESP WiFi board... (15 mA I believe).  The majority of stability issues are resolved by putting a cap between VCC and GND if you have any.

These can take up to a few months to get to you from China so make sure you order them well in advance of your project... Fortunately you get a lot of them in a package..

So I have 2 knockoff Arduino Uno clones and my sketches are based on the simplest example code with the RF24 module...

I spent about a day trying to get the Raspberry Pi to talk with the NRF module directly with SPI but I was having major software issues and decided just to plug a spare $4 Arduino into the Pi instead...

Wiring the devices is super simple...
Image result for nrf24l01+ pinoutNRF: (GND has a square around it)

[GND] [CE]    [SCK]    [MISO]

VCC -> 3.3v  Arduino (Red wire)
GND -> GND Arduino (Brown or Black wire)
CE -> Pin 7 Arduino (Orange wire) [Chip Enable]
CSN -> Pin 8 Arduino (Yellow wire)  [Slave Select]
MOSI -> Pin 11 Arduino (Blue wire) [Master Output, Slave Input]
MISO -> Pin 12 Arduino (Purple wire) [Master Input, Slave Output]
SCK -> Pin 13 Arduino (Green wire) [Serial Clock]

The nRF24 talks SPI serial.

Here is a picture I found on Google (slightly modified) for those who like a visual aide:

I also have a switch which allows me to control the light locally, this is using a pull-down resistor and a regular light switch....(This allows me to control the light switch by the door from my chair without interacting with a computer, I've also got a hacked Dash button that will do the same)

You can choose in the code if you want it to toggle every time you flip it, or have one position be on and one position be off, or if you are using a momentary button you can set it up for that so it won't switch twice or you can take the switch out completely if you don't need it.
There are comments on the lines you need to change for this purpose.

The resistor is connected between GND and pin 6, and the switch is connected to 5v on the Arduino and the leg of the resistor that is connected to pin 6 (not the GND side).

Finally your light switch 'Duino has a servo connected to 5v and GND on the power wires and signal conneced to pin 9.  The servo is then hot glued to the switch plate with the horn perpendicular to the light switch at idle. (with the shaft of the servo lined up about with the center of the switch).

The following sketch which isn't perfect (I've got some kind of issue with my character buffers and I commented out the response for now) but for the simple task of sending on, off and toggle it works fine...

The sketch works for both the server and the client device, you just need to change 2 lines near the top to tell it which side it is.

The side that connects to the Pi only needs the 7 wires connected to the NRF module and a USB cable.

I will probably try and clean this up another time, but for anyone interested here's the work in progress:

It would stop responding to the wireless after a few messages and I don't know why yet, it always worked after a reset so I added code to reset the program in software and to keep the state in an uninitialized area of ram so it would survive a reboot (but not a power loss).  This has been working perfectly for 2 days now.

For those of you new to Arduino like I was still am, I'll save you the trouble of Googling how to install the RF24 library you will need to install for this sketch...

First download the zip from here: (You click the green Clone or Download and choose download as Zip)

Then in Arduino click on Sketch -> Include Library -> Add Zip Library then locate the Zip file from above... That's it, it's that simple!


* Getting Started example sketch for nRF24L01+ radios
* This is a very basic example of how to send data from one node to another
* Updated: Dec 2014 by TMRh20


#include <SPI.h>
#include "RF24.h"
#include <Servo.h>

void(* resetFunc2) (void) = 0;//declare reset function at address 0  // Calling this will reset the Arduino without needing any wires

void resetFunc() {
  // This will make us wait a second before restarting so that only 1 command is processed even though it's sent a few times
  //Serial.println("Restart Requested...");
  delay(1000);  // Wait 1 second

Servo myservo;  // create servo object to control a servo
int sw = 6;  // Switch pin number
int servopin == 9; // Servo control pin
int pos = 0;    // variable to store the switch position
int val; // value to store current switch state in
int lastval = 0; // Last value from switch
int scmd; // Special command -- Used to tell the program the switch was flipped
unsigned long buttonTime = 0; // Used for debouncing

//non-initialized value
// This structure will never be initialized by the compiler so even when the device is reset this value will remain
// On first power up there will be random garbage in here and that is deal with in setup.
union configUnion{
  uint8_t    byte[1]; // match the below struct...
  struct {
    uint16_t value1;
  } val ;
} config  __attribute__ ((section (".noinit")));

/****************** User Config ***************************/
/***      Set this radio as radio number 0 or 1         ***/


bool radioNumber = 0; // Servo Board
//bool radioNumber = 1; // Stand Alone / Raspi

/* Hardware configuration: Set up nRF24L01 radio on SPI bus plus pins 7 & 8 */
RF24 radio(7,8); // Stand Alone

byte addresses[][6] = {"1Node","2Node"};  // You can change the node names here if you'd like, I left them alone

// Used to control whether this node is sending or receiving
bool role = 0; // Servo board
//bool role = 1; // Stand alone

unsigned long cmd=255;                             // Do not send anything by default

void setup() {
  pinMode(sw, INPUT);    // declare switch as input
  // Initialize the switch in it's current position, we don't want to toggle it on bootup!!
  val = digitalRead(sw);
  lastval = val;

  // See if our presistant var has been initialized already
  int un = 1;   // Assume it's not...

  // If it has a valid value in it, assume it is (It's highly unlikely it will ever boot with just a 0 or 1 in that location)
  if (config.val.value1 == 0) { un = 0; }
  if (config.val.value1 == 1) { un = 0; }

  if (un == 1) { config.val.value1 = 0; } // Initialize the presistant state (this is probably first boot)
  if (un == 0) { pos = config.val.value1; } // It's already good, update position to match the stored value

  myservo.attach(servopin);  // attaches the servo on pin 9 to the servo object

  Serial.begin(115200);   // Speed for serial communications
  Serial.println("RF24-Point-to-Point Light Switch....");   // Startup/welcome message
  //Serial.println(config.val.value1);  // Some debugging stuff
  //Serial.println(lastval); // Some debugging stuff

  // Set the PA Level low to prevent power supply related issues since this is a
 // getting_started sketch, and the likelihood of close proximity of the devices. RF24_PA_MAX is default.
 // Living dangerously! Power to the MAX!

  // Open a writing and reading pipe on each radio, with opposite addresses

  // Start the radio listening for data

void loop() {
    val = digitalRead(sw); // Check that state of the switch  
    if (val != lastval) // Only run this code if the state of the switch changed
      if ((millis() - buttonTime) > 50)        // Number of mills for debounce counter

          // scmd: 1 - Toggle, 2 - Off, 3 - On
          // For a Forced on/off light switch Pressed scmd = 3, Released scmd = 2
          // For a Toggle light switch Pressed scmd = 1, Released scmd = 1
          // For a momentary pushbutton Pressed scmd = 1, remove scmd from Released

          // Setup for a standard light switch to toggle.
          if (val == 1) { Serial.println("Switch Pressed!");  scmd = 1; }
          if (val == 0) { Serial.println("Switch Relased!");  scmd = 1;} // Don't put scmd here for a momentary switch
          lastval = val;  // Store the last changed value
          buttonTime = millis();    // Store the last time the button was pressed so we can debounce it

/****************** Ping Out Role ***************************/
// Transmitter Part....
if (role == 1)  {
    if (cmd != 255) // We only want to sent if it's not 255...
    radio.stopListening();                                    // First, stop listening so we can talk.
    Serial.println(F("Now sending..."));

    unsigned long start_time = micros();                             // Take the time, and send it.  This will block until complete
    //unsigned long cmd = 7;                             // Command to send
     //if (!radio.write( &start_time, sizeof(unsigned long) )){

     if (!radio.write( &cmd, sizeof(unsigned long) )){
    radio.startListening();                                    // Now, continue listening
    unsigned long started_waiting_at = micros();               // Set up a timeout period, get the current microseconds
    boolean timeout = false;                                   // Set up a variable to indicate if a response was received or not
    while ( ! radio.available() ){                             // While nothing is received
      if (micros() - started_waiting_at > 200000 ){            // If waited longer than 200ms, indicate timeout and exit while loop
          timeout = true;
    if ( timeout ){                                             // Describe the results
        Serial.println(F("Failed, response timed out."));
        unsigned long got_time;                                 // Grab the response, compare, and send to debugging spew
        char resp[10];
        // &got_time, sizeof(unsigned long) ); &resp, 10 );
        unsigned long end_time = micros();
        // Spew it
        //Serial.print(F("Sent "));
        Serial.print(F("Response: "));
        //Serial.print(F(", Round-trip delay "));
        //Serial.println(F(" microseconds"));

    // Try again 1s later  
   //This code sends the message over and over again until reset, turns out this is good for packet loss
  //(the resending for a bit) but I think adding a cmd=255 here would stop it from doing so... I'm not
//concerned enough at the moment to grab the unit from the basement and test though!

/****************** Pong Back Role ***************************/
// Receiver part -- Servo module
// NOTE: When I had some loose or broken wires on my nRF24 I was getting random 0's out of it
// If it starts turning your lights off randomly, check your wiring
// It also may be advisable to replace the 0 radio command with something else
// My transmitter is already installed and I don't care to get it to modify the code
// 2 days so far and I haven't had a problem since replacing and re-soldering the wires

  if ( role == 0 )

    if (scmd == 3) // Local switch ON
      scmd = 0;
      Serial.println("SWITCH ON");
      myservo.write(140);    // ON    
      Serial.println("Lights On!");
      pos = 1;
      config.val.value1 = 1; // Set the persistant value
      myservo.write(90);    // Neutral    
      resetFunc2(); // Reset the thing instantly

      if (scmd == 2) // Local switch OFF
      scmd = 0;
      Serial.println("SWITCH OFF");
      myservo.write(50);    // ON    
      Serial.println("Lights Off!");
      pos = 0;
      config.val.value1 = 0; // Set the persistant value
      myservo.write(90);    // Neutral    
      resetFunc2(); // Reset the thing instantly

    if (scmd == 1 ) // For local commands from switch - Will toggle.
      scmd = 0;
      Serial.println("Toggling Lights");
      if (pos == 0) {                
            myservo.write(140);    // ON    
            Serial.println("Lights On!");
            pos = 1;
            config.val.value1 = 1; // Set the persistant value
     } else {
          myservo.write(50);    // OFF    
            Serial.println("Lights Off!");
            pos = 0;
            config.val.value1 = 0; // Set the persistant value

          myservo.write(90);    // Neutral    
          resetFunc2(); // Reset the thing instantly

    unsigned long got_time;
     unsigned long rec;
    if( radio.available()){  
    // Trouble happens down here...
    // Let's try not responding at all - This didn't fix anything but this isn't too imporant so it's still commented out...
      while (radio.available()) {                                   // While there is data ready
        // &got_time, sizeof(unsigned long) );             // Get the payload &rec, sizeof(unsigned long) );             // Get the payload

        if (rec == 1) {
          pos = 1;
          config.val.value1 = 1; // Set the persistant value
          myservo.write(140);    // ON    
          myservo.write(90);    // Neutral    
          resetFunc(); // Reset the thing
          //radio.stopListening();                                        // First, stop listening so we can talk
          //char resp[] = "Lights On";
          //radio.write( &resp, 9 );              // Send the final one back.            
          //radio.startListening();                                       // Now, resume listening so we catch the next packets.  

        if (rec == 0) {
          pos = 0;
          config.val.value1 = 0; // Set the persistant value
          myservo.write(50);    // OFF    
          myservo.write(90);    // Neutral    
          resetFunc(); // Reset the thing
          //radio.stopListening();                                        // First, stop listening so we can talk
          //char resp[] = "Lights Off";
          //radio.write( &resp, 10 );              // Send the final one back.            
          //radio.startListening();                                       // Now, resume listening so we catch the next packets.  


    if (rec == 2) // Radio toggle
      Serial.println("Toggling Lights");
      if (pos == 0) {                
            myservo.write(140);    // ON    
            Serial.println("Lights On!");
            pos = 1;
            config.val.value1 = 1; // Set the persistant value
     } else {
          myservo.write(50);    // OFF    
            Serial.println("Lights Off!");
            pos = 0;
            config.val.value1 = 0; // Set the persistant value

          myservo.write(90);    // Neutral    
          resetFunc(); // Reset the thing



      //radio.stopListening();                                        // First, stop listening so we can talk
      //radio.write( &got_time, sizeof(unsigned long) );              // Send the final one back.    
      //radio.startListening();                                       // Now, resume listening so we catch the next packets.  
      //Serial.print(F("Sent response "));

/****************** Change Roles via Serial Commands ***************************/

  if ( Serial.available() )
    //char c = toupper(;
    // Read data from the serial (for the client / Raspi side)
    // To talk to this just open the serial port, send 0 for off, 1 for on or t for toggle then close the port
    unsigned long c  = toupper(;

    int match  = 0;
    if (c == 48) { cmd = 0; match = 1; Serial.println("Lights Off Request..."); }
    if (c == 49) { cmd = 1; match = 1;  Serial.println("Lights On Request..."); }
    if (c == 84) { cmd = 2; match = 1;  Serial.println("Lights Toggle Request..."); }

    if (match == 0) { cmd = 255; } // Switc the command back to -don't send anything mode-
//    if ( c == 'T' && role == 0 ){    
  //    Serial.println(F("*** CHANGING TO TRANSMIT ROLE -- PRESS 'R' TO SWITCH BACK"));
    //  role = 1;                  // Become the primary transmitter (ping out)
    //if ( c == 'R' && role == 1 ){
      //Serial.println(F("*** CHANGING TO RECEIVE ROLE -- PRESS 'T' TO SWITCH BACK"));    
       //role = 0;                // Become the primary receiver (pong back)
//    }

} // Loop

----END SKETCH------

Finally this simple python script to control the whole thing:

Requires the pyserial library be installed to work.

----PYTHON CODE------
import serial, time, sys
ser = serial.Serial('/dev/ttyUSB0', 115200)  # op

#print ser
time.sleep(1) # wait for duino to wake up
x = # Read the header
        cmd = sys.argv[1]
        print "Remote Controlled Lightswitch"
        print "Command Line Arguments:"
        print "0\tOff"
        print "1\tOn"
        print "t\tToggle"

cmd = cmd.lower()
if cmd == "0": print "Turning Lights Off"
if cmd == "1": print "Turning Lights On"
if cmd == "t": print "Toggling Lights"

# It seems to keep sending until reset, so reset it...
# Send the command a few times, the Servo will sleep for a second after the first command so it will only take this once but if there's any packet loss OTA one of the re-sends will hit...

ser = serial.Serial('/dev/ttyUSB0', 115200)  # op

----END CODE------

This is all very rough, it was built in a few hours with example code...  This is probably a temporary setup since I will be getting some ESP based WiFi boards in the next month or so and that's where this project will probably end up (and I will do another write up on setting that up then)

I would like to work more with these NRF modules to make a low power stick up toggle switch that will cost under $15 and run on batteries for a long time.

Add on wireless switches that could through a gateway talk to an MQTT server are a pretty big need when retrofitting a home with automation gear when you can't run wires... I have yet to find a really good solution that's easy to use (doesn't have like 6-10 buttons on a panel), works reliably and quickly, doesn't eat battieres and doesn't cost $30+ per switch...

If you know of a product like this on the market already do please let me know.

If you decide to try this yourself please post a comment or let me know how it works and if you have any questions just ask!

Video of it in action:

Thursday, 23 February 2017

Arduino Uno Light switch

Update: I have since built the $16 nRF24 wireless serial controlled light switch and the ESP8266 based WiFi to nRF24 bridge.  Please see the above links for project write-up.

I made a serially controlled light switch by combining a $3 servo, a $4 Arduino Uno and an old laptop...
I used some mounting tape and hot glue to keep the servo on the switch plate, and the servo stays in neutral position when not activated so the light switch (decora style) can be operated by hand for ease of use.

I've got a Wi-Fi shield on the way and I plan on getting rid of the laptop and will probably re-write the sketch at that point... Stay Tuned for more details and pictures!!

Raspberry Pi Water Sensor

Since I'm already using my Raspberry Pi as a radius and Amazon button server I figured I may as well start learning some hardware hacking and I've had water in the basement before so I want to know about it before it happens again...

I already had a 4 conductor wire running from my automation area to my utility room for a previously failed washing machine detector project (replaced with a Wemo Insight now fully functional)

I made 3 detection areas, 1 for fun and 2 practical...

One right under the hot water tank, one on the floor and right behind the washing machine and one inside the drain of the washing machine.

For the hot water tank I took 2 pieces of wire and stripped them bare and ran them along the under side of the tank spaced fairly close together but not touching... On either end I put in a few conductive wood screws and wrapped the wire around the threads.

I did the same thing near the floor and behind the washing machine, I had multiple wire/contacts on a single sensor so if either one gets wet it will trip the system.

The final one is a pair of bare wires going down the drain, this can tell me when the washing machine is draining in it's cycle and confirm the whole thing is still working.

On the Pi, I connected GPIO 23, 24 and 25 and a common ground which one of each of the wire pairs was connected to and tied together with a wire nut.

I then wrote a little python script that would periodically poll those GPIOs and send me an alert if one went low (was using internal pull up) or switched states for more than 10 seconds (this would stop it from toggling back and forth as it dried out, and stop nuisance alerts)

This was a super easy project and a great start to working directly with hardware...

RDING Temper in Python on Windows

I got this device for a few bucks on eBay:

And it seems to work decently... It came with really awful windows software and the only real way to get data from it (short of using the HID keyboard typing excel) was to get their pretty awful software to write out a CSV every second and then compile and delete the data files it made... The software would also do weird things, crash, and leave weird dialogs on the screen...  I built a program to deal with most of these issues until I had a chance to get the data from USB properly.

I found info on using pywinusb.hid to grab info from HID devices and I also found this module which did not seem to work... I think it's meant for Linux, I did not troubleshoot it very much..

As I was playing with the pywinusb raw example I found out that it was able to get temperature readings while the temper application was running, so I decided to see if I could make this work, and I did...

Here is the code if anyone wants to read the temperature from your module.

This is my first time doing any direct USB stuff so it may not be perfect, but it seems to work... If you have any suggestions leave them in the comments.

======================= ===========================
#!/usr/bin/env python
# -*- coding: utf-8 -*-

Handling raw data inputs example
from time import sleep
from msvcrt import kbhit

import pywinusb.hid as hid

def sample_handler(data):
    # For debugging purposes or getting data from other sensors
    #print("Raw data: {0}".format(data))
    temp = str(data).split(',')
    temp = int(temp[3]) + int(temp[4])/256.0
    temperature = round(temp,2)
    print temperature
    # You can put your own code here to do whatever you want with the temp readings!

def raw_test():
    # locate the proper device based on it's Vendor and Product ID
    temper = hid.HidDeviceFilter(vendor_id = 0x0c45, product_id = 0x7401).get_devices()
    # Only continue if the device is found, otherwise return an error below
    if temper:
        while True:
        device = temper[0]
            #Setup the callback for when data comes in from the device
            # Keep going at this main loop until the device is unplugged
            while device.is_plugged():
                # Keep device open and rx new events...
                # We have to make a request for the temperature from the device
                report = device.find_output_reports()[ 0 ]
                # This is the command to request temperature
                report[ 0xff000001 ].value = 0x01,0x80,0x33,0x01,0x00,0x00,0x00,0x00
                # Send the command

                # Wait this long between requests... You can make this shorter or longer based on your needs
            # close the device if it's been removed
        # The device wasn't found, return an error and exit
        print("Can't find a Temper device")
if __name__ == '__main__':
    # first be kind with local encodings
    import sys
    if sys.version_info >= (3,):
        # as is, don't handle unicodes
        unicode = str
        raw_input = input
        # allow to show encoded strings
        import codecs
        sys.stdout = codecs.getwriter('mbcs')(sys.stdout)
# Start the main loop/listener
=================================== SNIP ==================

Dash Button Update (How to change the battery)

Well it finally happened! After only about a month my Dash battery died!  I got the red light of death!!

Since I can't get these easily or cheaply since I don't live in a dash "friendly" area I decided to see if I can put new batteries in...

I took my utility knife in it's shortest blade form as to not touch the board inside and cut and pushed along the seam, after a little cutting it was clear it had broken free enough to put my blade under it and wedge it up.  The bottom popped off cleanly! Yay!

The second one did not come apart as nicely, but it eventually yielded and I was able to get at the battery without damaging the unit.

I removed an replaced the AAA battery and now I'm getting a red error light like it's not registered....
I ran the Amazon app and got it to go through registration (even with my prime subscription over) it still worked just fine, except it would fail at registering.. Then I remembered I had it blocked from the internet, so I removed that temporarily so it could talk to Amazon's server and, bam It's back to normal again!!  I can even almost get the case to "snap" shut, though it will never be perfect again..

UPDATE: I had to change the batteries again and go through setup again... I was trying ot figure out how to do this without having to re-configure the WiFi settings and it turns out you can pull and replace the battery without it loosing anything.  The problem seems to arise when the device boots in a low battery condition and you get the "red light of death" instead of the happy white light.  I started logging clicks so I can tell approximately how many I get from a battery and I will add a low battery message to tell me to check the battery before it goes dead.

Things to note:
- WiFi settings seem to be on battery backed ram, not fash.. If you want to keep your WiFi settings keep the juice flowing while you change the battery, otherwise prepare to go through setup again
- Make sure you change the batteries before you get the read light of death or your settings will be erased
- Opening the case is less difficult that I thought it would be, just be careful as there are bits and bobs around the edges, don't go too deep
- The top half with the button is mounted to the PCB with screws I believe, the bottom is just a big empty shell and they will separate as the score line (where the clip attaches)
- The clip will probably never work again after you open it and you will need to tape it back together, it doesn't snap back together in any meaningful way.