Tag: Project

Fun with ESP, WS2812 and Homewizard

Fun with ESP, WS2812 and Homewizard

Well, I managed to get the ESP8266 working with the WS2812 in the Arduino IDE and it is time for some fun in combination with my Homewizard.

What I wanted to accomplish is this: I have solar panels at home and I have connected these to my Homewizard (a domotica appliance) along with the power meters which means my Homewizard knows about my power usage and my solar power production. What I wanted to do is have a small WS2812 ring show my usage and my production simultaneously. I defined usage as being the ‘red’ color and solar production as ‘yellow’. I want to show the production at the same time as the usage so I thought I would define each led to be the equivalent of 250 W power. I would ‘plot’ both the production and the usage on the circle starting at the same point. The overlap would be orange and excess solar power would be yellow and excess usage would be red, so if the circle showed 3 orange leds and 3 yellow, it meant I was producing 1500W (3+3 times 250W) while at the same time using 750W (3 times 250W). If the circle would show 3 orange and 3 red, it would mean 750W production and 1500W usage. After attempt 1 I found out that it was possible to use more than the LEDs would allow (ok, has not happened yet, but theoratically it is possible so I decided to add overflow. If production or usage would be over 3000W (12 times 250W), any excess would result in blue leds at the beginning, symbolizing double ‘value’ LEDs.

Still with me so far? After implementing, I found out that during Autumn, which is now when I created this project, production is not that high and my usage is usually also not that high, so often only 2 or 3 LEDs would light up. What I needed was increased resolution in such cases. I know, way too complex but he, it was meant to be a fun project. So I introduced green LEDs at the beginning. One green LED meant the resolution of the remaining 11 LEDs was 125W and two green LEDs mean the resolution of the remaining 10 LEDs was 50W.

The code will probably not be something you want to use without modifying but it might help you get some ideas on how to play with the WS2812. The code for getting the solar production and usage might be useful to others with a Homewizard.

github-mark-32px Available on GitHub with more comment in the code. Direct download.

Let’s look at the code:

#include <Adafruit_NeoPixel.h>
#include <ESP8266WiFi.h>
#include <PAM_WiFiConnect.h>
#include <PAM_WiFiClient.h>

#define CIRCLEPIN 2
#define PIXELCOUNT 12
#define POWERPERLED1 250
#define POWERPERLED2 125
#define POWERPERLED3 50

Adafruit_NeoPixel pixels = Adafruit_NeoPixel(PIXELCOUNT,CIRCLEPIN,
  NEO_GRB+NEO_KHZ800);

int solarPower = 0;
int powerConsumption = 0;
float solarPowerDay = 0;
float powerConsumptionDay = 0;

void setup() {
  Serial.begin(115200);
  wifiConnect("YourSSID","YourPassword");
  pixels.begin();
  for(byte i=0;i<PIXELCOUNT;i++){
    pixels.setPixelColor(i, pixels.Color(0,0,0));
  }
  pixels.show();
}

void readSolar () {
  String t = getURL("YourHomewizardUrl","/YourHWPassword/get-status",80);
  t = t.substring(t.indexOf("energylinks"));
  t = t.substring(t.indexOf("s1"));
  t = t.substring(t.indexOf("po")+4);
  int xsolarPower = t.substring(0,t.indexOf(",")).toInt();
  t = t.substring(t.indexOf("dayTotal")+10);
  int xsolarPowerDay = t.substring(0,t.indexOf(",")).toFloat()*1000;
  t = t.substring(t.indexOf("used"));
  t = t.substring(t.indexOf("po")+4);
  int xpowerConsumption = t.substring(0,t.indexOf(",")).toInt();
  t = t.substring(t.indexOf("dayTotal")+10);
  int xpowerConsumptionDay = t.substring(0,t.indexOf(",")).toFloat()*1000;
  t = t.substring(0,t.indexOf("heatlinks"));
  Serial.print("Solar       now :");
  Serial.println(solarPower);
  Serial.print("Consumption now :");
  Serial.println(powerConsumption);
  Serial.print("Solar       day :");
  Serial.println(solarPowerDay);
  Serial.print("Consumption day :");
  Serial.println(powerConsumptionDay);
  Serial.println();
  if (xsolarPower!=0 || xpowerConsumption!=0) {
    solarPower = xsolarPower;
    solarPowerDay = xsolarPowerDay;
    powerConsumption = xpowerConsumption;
    powerConsumptionDay = xpowerConsumptionDay;
  }
}

void loop() {
  readSolar();

  byte solarLed;
  byte powerLed;
  byte base;
  if (_max(solarPower,powerConsumption)<=POWERPERLED3*(PIXELCOUNT-2)) {
    solarLed = round((solarPower+POWERPERLED3/2)/POWERPERLED3)+4;
    powerLed = round((powerConsumption+POWERPERLED3/2)/POWERPERLED3)+4;
    base = 2;
    for (byte i=0;i<base;i++) {
      pixels.setPixelColor(i,pixels.Color(0,42,0));
    }
  } else if (_max(solarPower,powerConsumption)<=POWERPERLED2*(PIXELCOUNT-1)) {
    solarLed = round((solarPower+POWERPERLED2/2)/POWERPERLED2)+2;
    powerLed = round((powerConsumption+POWERPERLED2/2)/POWERPERLED2)+2;
    base = 1;
    pixels.setPixelColor(0,pixels.Color(0,42,0));
  } else {
    solarLed = round((solarPower+POWERPERLED1/2)/POWERPERLED1);
    powerLed = round((powerConsumption+POWERPERLED1/2)/POWERPERLED1);
    base = 0;
    if (solarLed>PIXELCOUNT || powerLed>PIXELCOUNT) {
      base = _max(solarLed,powerLed)-PIXELCOUNT;
      for (byte i=0;i<base;i++) {
        pixels.setPixelColor(i,pixels.Color(0,0,42));
      }
    }
  }
  for (byte i=base;i<_min(solarLed,powerLed)-base;i++) {
    pixels.setPixelColor(i,pixels.Color(110,27,0));
  }
  if (powerLed>solarLed) {
    for (byte i=_max(base,_min(solarLed,powerLed)-base);i<powerLed-base;i++) {
      pixels.setPixelColor(i,pixels.Color(55,0,0));
    }
    for (byte i=powerLed-base;i<PIXELCOUNT;i++) {
      pixels.setPixelColor(i,pixels.Color(0,0,0));
    }
  } else {
    for (byte i=_max(base,_min(solarLed,powerLed)-base);i<solarLed-base;i++) {
      pixels.setPixelColor(i,pixels.Color(55,42,0));
    }
    for (byte i=solarLed-base;i<PIXELCOUNT;i++) {
      pixels.setPixelColor(i,pixels.Color(0,0,0));
    }
  }
  pixels.show();
  delay(500);
}

Ok, maybe way to much code to just dump here but it’s not that difficult to read.

Let’s start with the includes; NeoPixel library from AdaFruit, the standard ESP8266WiFi library and my own two libraries, PAM_WiFiConnect and PAM_WiFiClient. Next we define our constants and initalize the NeoPixel library.

The setup function is straight forward, set up Serial, connect to wifi and set all pixels to black.

The readSolar function connects to the Homewizard and gets the status information. This json file is than parsed a couple of times to get the current solar power production in solarPower, the days solar power production solarPowerDay, the current power consumption, powerConsumption and finally the power consumption of the day, powerConsumptionDay. Both day values are not used in this sketch. I intend to make some kind of switches where you can choose to see the current production/consumption or the totals of the day.

The loop function is where the number of leds and color is determined. The first section, the extensive if statement, determines which value to assign to each led, 250W, 125W or 5oW. This is done by checking the maximum of the values of solarPower and powerConsumption. If the maximum is small enough to fit within the 50W scale that is used, if not it is checked whether it will fit in the 125W scale and else it will be put in the 250W scale. If it is 50W, the first 2 leds are made green (signifying a change from the default scale) and 125W shows 1 green led.

Next the color of the remaining leds is determined by checking the maximum (to see if blue leds are needed) and than counting how many should be red (power usage), yellow (power production) or orange (production and usage).

As mentioned before, you probably cannot use the supplied code straight ‘out of the box’ but you can use it for ideas.

The end result of my solar meter in a small plastic box:

ws2812funa

At the bottom left, a USB to serial adapter. In the bottom middle a ESP-12E on a small breakout board. At the middle left a reed contact which allows for an update to the code by holding a magnet near the back of the box and finally the 12 bit neopixel circle.

When the box is closed, there is a normal piece of paper at the top abive the lights so that they are not too bright and slightly diffused which gives this end result:

ws2812funb

Fun with HC-SR04 and WS2812

Fun with HC-SR04 and WS2812

After I managed to get the distance sensor HC-SR04 working and got the LED circle based on WS2812 working, I felt it was time to combine them in a fun project.

I connected two LED circles, 16 LEDs and 12 LEDs where the DO of the 16 went into the DI of the 12. What I wanted to do is in the outer circle have a red circle run in circles where the speed was dependant on the distance of an object in front of the sensor. The closer the object, the faster it moves. The inner circle shows the distance to the object. The farther the object, the more LEDs would light up.

github-mark-32px Available on GitHub with more comment in the code. Direct download.

The code for the Arduino IDE:

//
// The library from Adafruit which enables the use of the WS2812
// or NeoPixel
//
#include <Adafruit_NeoPixel.h>

//
// The pin the circle of WS2812 leds is connected to
//
#define CIRCLEPIN 6
//
// The number of leds in our two circles (12+16)
//
#define PIXELCOUNT 28

//
// Initialize the Adafruit library
//
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(PIXELCOUNT,CIRCLEPIN,
  NEO_GRB+NEO_KHZ800);

//
// The current position
//
int degree = 0;

//
// The trigger and echo pin for the HC-SR04
//
#define TRIGGERPIN 13
#define ECHOPIN 12

//
// How long we delay before the next read and update of the leds
//
int delayMove = 50;

void setup() {
  //
  // Start the led string and turn them all off
  //
  pixels.begin();
  for(int i=0;i<PIXELCOUNT;i++){
    pixels.setPixelColor(i, pixels.Color(0,0,0));
  }
  pixels.show();
  //
  // Prepare the HC-SR04 pins
  //
  pinMode(TRIGGERPIN, OUTPUT);
  pinMode(ECHOPIN, INPUT);
}

void loop() {
  //
  // Determine the distance between object and HC-SR04
  // Read about it in more detail on
  // https://piandmore.wordpress.com/2016/10/04/arduino-hc-sr04-ultrasonic-distance/
  //
  long duration, distanceCM;
  digitalWrite(TRIGGERPIN, LOW);
  delayMicroseconds(5);
  digitalWrite(TRIGGERPIN, HIGH);
  delayMicroseconds(10);
  digitalWrite(TRIGGERPIN, LOW);
  duration = pulseIn(ECHOPIN, HIGH);
  //
  // The distance in cms
  //
  distanceCM = (duration/2) / 29.1;
  //
  // Turn all pixels off
  //
  for(int i=0;i<PIXELCOUNT;i++){
    pixels.setPixelColor(i, pixels.Color(0,0,0));
  }
  //
  // Turn on the inner circle leds
  // 1 led for every 2 cm of distance
  //
  for (int i=16;i<16+distanceCM/2;i++) {
    pixels.setPixelColor(i, pixels.Color(0,50,0));
  }
  //
  // Determine the current position led of the outer circle
  // and turn on the required leds
  //
  int thisPixel = (degree*16)/360;
  pixels.setPixelColor((thisPixel+3)%16,pixels.Color(255,0,0));
  pixels.setPixelColor((thisPixel+2)%16,pixels.Color(100,0,0));
  pixels.setPixelColor((thisPixel+1)%16,pixels.Color(40,0,0));
  pixels.setPixelColor((thisPixel)%16,pixels.Color(15,0,0));
  pixels.show();
  //
  // Depending on the distance of an object, make the circle move
  // faster (if it is closer) or slower (if it is farther away)
  // and take the maximum time of it is very far away or
  // if there is no object
  //
  if (distanceCM>=200) {
    delayMove = 200;
  } else {
    delayMove = distanceCM;
  }
  delay(delayMove);
  degree += 10;
  if (degree>=360) {
    degree -= 360;
  }
}

The code looks a lot like the two earlier mentioned codes combined. What is added is the 12 LEDs which, as you can see, are addressed as being the next 12 on the same string as the 16.

Meet ESPöka

Meet ESPöka

This is Spöka, an IKEA led night light:
Spoka
and this is ESPöka:
Spoka
the ESP8266 enabled Spöka.

Why? Because it’s fun. ESPöka runs an improved version of my WebLights app on an ESP-12E.

So, let’s build this.

First, you take apart your Spöka. You start by removing the skin. This requires some force and you should be able to get it off without tearing the rubberlike skin. This leaves you with:
Spoka-1
Next, you remove the white bottom. I have taken apart two. One of the was slightly glued around the edges while the other was more or less clipped on. You should have something like this:
Spoka-3
Next you remove the board with the battery and the button:
Spoka-4
We will be using the button and you can still use the battery as well even though I have not tried the runtime with the ESP inside. In my case I wanted the ESPöka to be full RGB so I’ve removed all leds from the board as they will be replaced by RGB leds. I have also removed both ends of the button from the board.
Spoka-5

Now with the inside cleaned up, let’s get started on our remodelling.

What you will need (links to AliExpress):

First, you solder the ESP-12E to the board. I did this by first putting some solder on every connection point, then putting the ESP-12E on it, making sure it is aligned, hold it down and solder one side. Wait for it to cool a bit (so the ESP-12E does not move) and then turn around and do the other side. Use a meter to make sure that all connections are soldered probably. Next I soldered the pins to the board but next time I won’t do that so you might not want to do that now. You might also decide not to use the board at all either. (I will probably also use this 3.3v regulator for my next ESPöka because the pins get in the way a bit). You should now have this:
Spoka-6
Next we connect the wires. This is the layout of the ESP-12E chip:
ESP-12E Layout
We will need 3 ouput wires (I’ve used D2, D3 and D4) and one input (I’ve used D1).
Connect the 3.3v regulator input side to the points on the IKEA board to where the battery is connected. Please note that you have to do this from the top of the board because there is no room in the led light itself to run wires from the bottom to the top. The output side of the 3.3v regulator go to the VCC and GND pins. Also connect VCC to the EN pin. The button on top of the led light will be the acknowledge button. Connect one side to GND and the other to D1. In order to program the ESP-12E you will need to connect TXD and RXD. In this version I have an internal connector for TXD, RXD, GND and VCC. In the next version I plan to integrate a USB TTL adapter and replace the normal 5 volt plug with a mini USB connector so I can (re)program the ESPöka without opening it. Finally, connect D2, D3 and D4 to the RGB led pins (the long one is the common one) and connect to common anode to the resistor and the other end of the resistor to VCC (or if you have a common cathode, connect that to GND).

In the end it should look like this (without the RGB leds):
Spoka-7
and another angle, with the RGB leds:
Spoka-8

In a (very poorly drawn) schematic, your setup will look like this:
ESPoka layout

Now all that remains is programming the chip with my WebLights, which I will describe in my next post and than getting it back in the Spöka.

After installing the software, test it. Turn on the power and see if it connects. I initially tested with the TTL power, next without the TTL and with the original power adapter. Finally I tested when I put everything in the Spöka, right before I closed it.

Spoka-9
Spoka-13Spoka-11Spoka-12

 

What I did was put the ESP in first, to the back and than move the main board back (you have to wiggle a bit to get the power connector aligned again). The button and the Spöka board are up next. Then I put the 6 RGB leds in (I wanted these as close to the bottom as possible and finally squeeze in the resistor, regulator and TTL connector. Next close the Spöka making sure you again align the board and no wires get stuck between the many pins. Than put the white bottom on. Last step, put the skin back (again tricky because it’s quite tight and you need to align so the hole in the skin matches the power hole). That’s it, you’re done!

 

NodeMCU Web Lights

NodeMCU Web Lights

After experimenting a lot with the NodeMCU, I’ve soldered the first one to a board together with some leds, microswitches and a button. What this contribution does is what I call Web Lights. Basically it is a webserver which controls the set of 3 color leds. You can do an http call to set the lights to a color or give it a range of colors and it will loop through them.

The microswitches are connected to pins D1 and D2 which also have a pull up resistor (next to it in the picture). These are generally off and are only on, to prevent the main program to start or to start the config server (see my post on my init.lua). The button is connected to D6. The four 3 color leds are connected to pins D3, D4 and D5. The connector you see at the top is for easy connection of my USB to UART device.

Apart from the init.lua and accompanying files described in my earlier post on my init.lua and the one for managing the 3 color led this project requires 2 more files, one for the functions to allow for color switching and one for the http server.

The functions for color switching:

cl = {}
clpos = 0
clc = ""
clrpt = 0
cltmr = 0
mcltmr = 0

function setclrpos ()
  if clrpt>0 then
    cltmr = cltmr+1
    if cltmr>=mcltmr then
      cltmr = 0
      clpos = clpos+1
      if clpos>#clc then
        clrpt = clrpt-1
        if clrpt<=0 then
          resetcolor()
        else
          clpos = 1
        end
      end
      if clpos<=#clc then
        rgbcolor(cl[tonumber(clc:sub(clpos,clpos))])
      end
    end
  end
end

function multicol (xcllist,xclscheme,xclrpt,xcltmr)
  clrpt = 0
  cl = {}
  local k
  clc = ""
  if (xcllist~=nil) then
    for k in string.gmatch(xcllist,"(%w+),*") do
      cl[#cl+1] = k
      clc = clc..tostring(#cl)
    end
  end
  mcltmr = 2
  if xcltmr then
    mcltmr = tonumber(xcltmr)
    if cltmr<1 then
      mcltmr = 1
    elseif mcltmr>10 then
      mcltmr = 10
    end
  end
  if xclscheme then
    clc = xclscheme
  end
  cltmr = 0
  clpos = 0
  if xclrpt then
    clrpt = tonumber(xclrpt)
  else
    clrpt = 1
  end
end

function resetcolor (level)
  clrpt = 0
  rgbcolor("off")
end

tmr.alarm(2,250,1,setclrpos)

I know, quite a lot of code to dump on you but it’s not as bad as it looks. The mechanics behind this are as follows:

The function multicol accepts four parameters:

  • A list of comma seperated colors
  • A list of numbers in which order the colors provided in the first parameter should appear
  • A number value how many times the sequence should repeat
  • A timer value

Each of these, except the first one, has a default value but let’s first look at an example:

multicol("red,blue,green","1213",9999,200)

This call will give you the following colors (changed every 200 ms) red,blue,red,green and repeats until you set a different color scheme or call resetcolor (or if you wait 9999 cycles).

The function’s default values are such that if you just supply a range of colors, that range is cycled through once with a timer value of 500 milliseconds.

The function sets the global variables:

  • cl, a numbered array of colors, based on the first parameter
  • clc, the list of numbers referencing the color array cl to cycle through
  • clrpt, the number of times the cycle should repeat
  • clpos, the position of the character in clc where we are at

and uses one local variable:

  • cltmr, the timer value

After the variables are set, the timer is set with the function setclrpos.

The function setclrpos moves to the next character in the variable clc by increasing clpos. If clpos has moved beyond the end of the clc string, move it back to the start if you still need to do a cycle (checked by reducing clrpt). If there is no cycle repeat left, turn off the leds and stop the timer. The last set of lines in the function actually set the color.

The logistics behind this is a continuous timer, which triggers every 250 milliseconds, and runs setclrpos. If there is nothing to do, than the function will simple just stop.