Month: November 2016

Update for library PAM_WiFiServer

Update for library PAM_WiFiServer

An update to the PAM_WiFiServer library which will generate a settings.htm page based on the variables created with the PAM_Tools library. This way if you log variables using the PAM_Tools library, you can also easily maintain them with this function. Think for example of an API key or timeout parameters.

Example 2 is an elaborate example of how to use this function.

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

Update for library PAM_Tools

Update for library PAM_Tools

While creating projects with my libraries, I found that most of them required some additions which I have created and will document here.

I have expanded the PAM_Tools library to allow it to handle float and bool as well. To this I have created the following functions:

float getFloatKey (String, String);
bool getBoolKey (String, String);
void putFloatKey (String, String, float);
void putBoolKey (String, String, bool);
float getPutFloatKey (String, String, float);
bool getPutBoolKey (String, String, bool);

They work the same as the versions for String and int except that since there are only two values possible for bool there is no way to detect if there is no value present so it will return false if there is no way. If you want to have a default value, you can use getPutBoolKey.

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

Update for library PAM_WiFiConnect

Update for library PAM_WiFiConnect

I recently had a short power outage. Nothing major but a feature request for the connect library did come out of that. When the power came back on, my ESP with my temperature logger was back on faster than my wifi which meant that after the wifiConnect nothing else happened. Ok, I could have coded that in the program but than I realized that if you have some sort of IoT device, it does not make sense to return to the setup function from the wifiConnect if you have no wifi. A need was born.

The result? A function called waitWiFiConnect which does what it’s name implies; it waits for a wifi connection. It does this by turning on the internal led, GPIO2, try to connect via wifiConnect. When it returns from that function it checks whether there is a connection. If there is a connection the led is turned off and the function ends. If not, the led blinks shortly after which we wait for 1 minute before trying again. It will only return to the caller after it has a wifi connection.

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

Arduino IDE libraries

Arduino IDE libraries

After creating my initial library, I saw it grow rapidly with more generic functions I wanted so instead of staying with one library which could grow out of proportion (from a code size perspective), I decided to create a library for each of my needs (which of course makes sense from a lot of angles). So far this I have created the following libraries (so far mostly aimed at the ESP8266):

  • PAM_Tools
    This library contains functions to access the file system to store and retrieve information;
  • PAM_WiFiConnect
    This library contains functions to easily connect to the wifi, including selecting one of multiple access points;
  • PAM_WiFiClient
    This library contains functions to easily retrieve a webpage;
  • PAM_WebAPI
    This library contains functions to use web based APIs such as IFTTT and ThingSpeak.
  • PAM_WiFiServer
    This library contains functions for creating a webserver.

 

Library PAM_WiFiServer

Library PAM_WiFiServer

After working with the Arduino IDE for some time, I decided it is time to write some convenient libraries that will help me quickly do some of the tasks that occur often and could do with a convenient wrapper.

This library is there to easily create a webserver.

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

Let’s look at the functions:

void wifiServerStart()

This function needs to be called once before you use any of the other functions.

bool serverRequestReceived()

This function you should call frequently in your loop function. If true, you should create a webpage to be send back using the other functions.

String pageRequested ()

You can call this function if a serverRequestReceived returned true and it will return the name of the page that is requested.

String giveURLParam (String search)

If a serverRequestReceived than you can check with this function whether a specific parameter has been send. It will return the value of that parameter or PARAMNOTFOUND if the parameter is not in the list. This function is used to get the values submitted for example throught a form.

void serverSendPage (String paramName[], String paramValue[], int paramCount, String pageName)

This is the function that sends back a page. The way it works is that a pageName is retrieved from the filesystem /page/<pageName> and line by line each parameter given in paramName is replaced by the corresponding paramValue. So for every line retrieved, the function loops through all paramNames and replaces each instance of %paramName% with the corresponding value. The value paramCount should contain the number of elements in both paramName and paramValue. The pageName variable should contain the page that needs to be parsed and send back to the client.

There are multiple instances of this function defined. If no pageName is given, it is assumed to be index.htm. If no parameters are given, no parameter replacement will be done. If neither parameters nor a pageName is given, the file index.htm will be send without parsing.

If the requested pageName is not found, the headers will be send put the page will be blank.

 

Library PAM_WebAPI

Library PAM_WebAPI

After working with the Arduino IDE for some time, I decided it is time to write some convenient libraries that will help me quickly do some of the tasks that occur often and could do with a convenient wrapper.

This library is there to use different web based APIs such as that of IFTTT and ThingSpeak.

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

Let’s look at the functions:

String ifttt (String event, String value1, String value2, String value3)

If This Than That, IFTTT, is a very extensive online tool that allows you to act on an event. The concept is based on channels that can send and receive data. A specific combination of channels and actions is called an applet.

There is also a channel called Maker which you can use for your own IoT devices. This is what this library is for. You get your own Maker key which you should put in the library PAM_Defines.h which is nothing more than a way for you to select which APIs are compiled in. If you don’t use IFTTT for example, you should also not have to overhead when compiling so if you do not define a key, the functions will be excluded from the library which should save memroy. I will not go into detail on IFTTT usage just now. Suffice it to say you need a key which you define in PAM_Defines.h:

#ifndef PAM_Defines_H
#define PAM_Defines_H

//
// This is where you define your own IFTTT.com key
//
#define IFTTTKEY "YOUR-KEY-HERE"

#endif

and you need an event type which defines what kind of trigger you want to send. I have also defined these in my PAM_Defines.h:

#define IFTTT_BOOT "PAM_BOOT"
#define IFTTT_HTTP "PAM_HTTP"
#define IFTTT_MSG "PAM_MSG"

There are multiple instances of the same function created in the library so you can call it with no values, one, two or all three.

As an example, I use the event IFTTT_BOOT to send me a message if an IoT device boots where I send it’s IP as value 1. If it also contains a webserver I use the event IFTTT_HTTP along with it’s IP as value 1 so the message can actually contain a link to the IP.

I use IFTTT_MSG to send a message, for example if my plant needs watering.

void thingspeak (String api, String field1, String field2, String field3, String field4)

void thingspeak (String api, float field1, float field2, float field3, float field4)

The next API included is that for ThingSpeak. ThingSpeak call themselves an open data platform for the Internet of Things. In order to work with ThingSpeak, you need to set up an account and than set up a channel. Unlike IFTTT, you need a different API key per channel so in the library I choose to have one define to say you want to use the library. I use seperate defines for each of my channels:

#define THINGSPEAK
#define TS_TEST "MY-API-KEY"

The #define THINGSPEAK is needed to compile this part of the library. Like IFTTT there are multiple instances of the library. You can call the function with just one parameter or up to four parameters (ThingSpeak actually allows eight but I have not set up for that yet. If it is needed, let me know). The API key is mandator as well as the first field. The API of ThingSpeak allows you to set a date time for the event and if you don’t current date time is used. Since I wanted to keep the library small, I did not implement the seperate date time parameter.

You can use String for the values or int/float.

Library PAM_WiFiClient

Library PAM_WiFiClient

After working with the Arduino IDE for some time, I decided it is time to write some convenient libraries that will help me quickly do some of the tasks that occur often and could do with a convenient wrapper.

This library can be used for easy webpage retrieval. You can do a fire and forget or parse through every line, with or without the header.

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

Let’s look at the functions:

String getURLParse (String host, String url, bool fullContent, void (*g)(String l), int port)

This is the main function to retrieve a webpage. All other page retrieval functions call this function. You pass a host and a url, starting with a /, tell it whether to send just the body (false) or include the header (true) followed by a function which receives one String at a time which will be the retrieved String and finally a port. The port can be omitted in which case it defaults to port 80.

This function will send a request to the host asking for the specificed url. It will than retrieve every line of the page, it will determine where the header stops and the page begins and send it to the function g (only the body if that was requested in the boolean fullContent).

The last line received will be returned in the String.

String getURLFullParse (String host, String url, void (*g)(String l), int port)

This function will call the main function requesting to send all lines, including the header to the function g. The port is optional. If omitted it will default to port 80.

String getURLBodyParse (String host, String url, void (*g)(String l), int port)

The function will call the main function requesting to send all lines of the body of the page to the fuction g. The port is optional. If omitted it will default to port 80.

String getURL (String host, String url, int port)

The fire and forget version, get the url but do not use the resulting webpage. Again, the port is optional and will default to port 80.

void doSerial (String webLine)

If you are debugging it could be convenient to see what the host is sending back. If you use the function doSerial as the function to process your lines, you will see the page received on your serial monitor.

 

Library PAM_Tools

Library PAM_Tools

After working with the Arduino IDE for some time, I decided it is time to write some convenient libraries that will help me quickly do some of the tasks that occur often and could do with a convenient wrapper.

This library is aimed at using the file system to store keys.

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

Let’s look at the functions:

The following four functions are used to store and retrieve String and int values persistently (meaning between reboots).

String getStringKey (String location, String key)

This function will retrieve the content of a file in a string where the filename is /<location>/<key>.txt The .txt extension is used so on Windows you can create
the needed files in a data directory which you can than upload using the ESP8266 Sketch Data Upload. If the key is not found a NOSTRINGKEYFOUND will be returned.

int getIntKey (String location, String key)

This function will retrieve the content of a file and put it in an int where the filename is /<location>/<key>.txt The .txt extension is used so on Windows you can create
the needed files in a data directory which you can than upload using the ESP8266 Sketch Data Upload. If the key is not found a NOINTKEYFOUND will be returned.

void putStringKey (String location, String key, String value)

This function will put a String value into the file with filename
/<location>/<key>.txt If the file exists it will be overwritten.

void putIntKey (String location, String key, int value)

This function will put an int value into the file with filename
/<location>/<key>.txt If the file exists it will be overwritten.

 

Library PAM_WiFiConnect

Library PAM_WiFiConnect

After working with the Arduino IDE for some time, I decided it is time to write some convenient libraries that will help me quickly do some of the tasks that occur often and could do with a convenient wrapper.

This library is aimed at easily connecting to wifi. I know that there are other libraries that support this but mine supports me better and might support you better too.

The library needs one other library, PAM_Tools.

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

Let’s look at the functions:

void wifiConnect (String ssid, String password)

This function will connect you to the specified SSID using the specified  password. It is different from the standard connect to wifi and just waiting on a connected in two ways:

  • It will break trying to connect after 5 runs of 10 seconds waiting on a connection
  • It will disconnect from wifi and try again in every run.

In my experience some of the connections might not work in the first try (especially hotspots on a mobile phone) and by stopping the connection and starting again I noticed that most connections will succeed within 15 seconds.

I also wanted the wifi connection not to run forever but break off at some point so you could do some error handling.

void wifiConnect (String ssid)

This instance of the function will get the password for the specified SSID from the file system, through one of the functions in PAM_Tools, and than uses wifiConnect to connect to it.

Passwords are stored in a file on the file system in the directory wifi where the full name of the file will be /wifi/ssid.txt and this file will contain one line and that is the password for that ssid. There are two advantages to do this:

  • If you share your code and you forget to change your ssid to Your-SSID at least you will not have given away your password
  • If you have multiple ssid’s that you can connect to, which is what wifiConnect does if you do not supply any SSID, you do not have to have all SSIDs and passwords in your file.

void wifiConnect (bool debug)

This instance of the function in the library is probably the most powerful/convenient. What it does is scan the available networks and check for each one found whether there is a associated password stored in the file system. If so, it will try to connect.

You can list preferred networks by storing SSIDs in a numbered file in the same directory. So if there is a file called 1.txt in the wifi directory, it will open that file and check whether that SSID is available. If not it will try 2.txt etc. If none of them are available or there is no 1.txt then it will try to use any of it’s other credentials. If there is still no connection, it will try the SSID in 0.txt which could be a hidden SSID. I found this function works great if you have a mobile IoT device. Even with fixed devices I now use it and put my mobile hotspot as the first to check (1.txt). It usually isn’t on, but if I want to isolate the IoT, for example for testing, I can turn on my hotspot, reset it and it will connect to my hotspot.

If you want to see which networks are found and how it decides to connect to it, you can call it with a parameter true after which it prints out what it does on Serial.

void wifiConnect ()

This instance of the function in the library will call wifiConnect(false) and as a result try to automatically connect to a wifi network as described above.

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