Month: September 2016

Flash ESP8266 with AT binary

Flash ESP8266 with AT binary

Sometimes you want your ESP8266 back in it’s original firmware, namely the firmware the supports the AT commands. For example if you want to use it as a wifi module for your Arduino.

I’m assuming you have read my article on flashing the NodeMCU which also works on other ESP’s. If not, do so now.

Basically what we want to do is get the original firmware and flash that on the ESP. Well it turns out it is not as simple as you migth think.

First, let’s download the most recent AT firmware, which you can do here. You will get to a page which has multiple latests releases (at least at the time of writing). Select the one called Non-OS SDK with a version number and click on Click to Download which takes you to the next page. This page will have a lot of text about what was updated in English and Chinese. Near the end of the page, you will find ATTACHMENTS which has a link to the ZIP file you want. Download the file and unzip it to a temporary folder. There are a lot of folders inside. You will need to go the one that does not have a reference to MAC in there, and select the bin directory. There will be several files there and some directories.

Start up the ESP Flasher tool (which I described here). Go to the config page. You need to list 4 files and 4 addresses. Below a screenshot of the config page:

flashat

Ignore the red background. It is because I removed part of the path to get it readable in the screen. Please make sure you select the addresses correctly and make sure you mark them to be uploaded (the x at the complete left).

Next go back to the operation page, make sure your ESP can be flashed (the Wemos will do this automatically as some others might, but for example the NodeMCU will require you to tie GPIO0/D3 to GND and press reset afterwards). Press Flash and wait for it to be done. You should get a green check mark. If not, try again and if that fails, make sure you are on the correct COM port and that your ESP is indeed ready to be flashed.

When it’s done, remove, if needed, the connection to flash the ESP and reset it. It should now be serving AT firmware. You can test this by make a serial connection on the COM port at baud 115200. If you are connected and you press reset you should receive a ready. If you send the command AT to it, you should receive an OK.

If for some reason you need a slightly older version, you can that here. The upload process is the same.

Now your ESP is ready to receive AT commands (a list of the commands can be found here) and you can tie it for example to an Arduino.

Arduino, OLED LCD & 4 sensors

Arduino, OLED LCD & 4 sensors

After describing four sensors, the SI7021, TLS2561, BH1750 and the BMP180, I wanted to see if I could combine all of these on one bus and display information on an OLED screen, also I2C.

In short, it is very possible and it is combining the different code to read the sensors and than creating some lines to display on the OLED screen.

combiningi2c-1

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

Since the code is not that difficult, I will share it here and in a later stage, describe it in more detail:

//
// LCD
//
#include "U8glib.h"

U8GLIB_SSD1306_128X64 u8g(U8G_I2C_OPT_NONE);

//
// SI7021
//
#include <Wire.h>
#include <SI7021.h>

#if defined(ESP8266)
//
// For the ESP8266 we need these to be defined for I2C
//
#define SDA 4
#define SCL 5
#endif

SI7021 sensor;

float temperature;
int humidity;

//
// TSL2561
//
#include "TSL2561.h"

TSL2561 tsl(TSL2561_ADDR_FLOAT); 

boolean hasTSL = false;
uint16_t lux1;

//
// BH1750
//
#include <BH1750.h>

BH1750 lightMeter;

uint16_t lux2;

//
// BMP180
//
#include <SFE_BMP180.h>
#define ALTITUDE 0

SFE_BMP180 pressure;

boolean hasBMP = false;
double temperature2,pressure2,altitude2;

//
// LCD, the function that is called to draw to the OLED
//
void draw() {
  //
  // Set the correct values for drawing with the u8g library
  //
  u8g.setFont(u8g_font_6x10);
  u8g.setFontRefHeightExtendedText();
  u8g.setDefaultForegroundColor();
  u8g.setFontPosTop();
  char printThis[14];
  String t;
  //
  // Temperature from SI7021 and if we have it
  // the BMP180 (which is than averaged)
  //
  float tmp2 = temperature;
  if (hasBMP) {
    tmp2 = (tmp2+temperature2)/2;
  }
  t = "Temp:";
  t.toCharArray(printThis,13);
  u8g.drawStr(0,0,printThis);
  //
  // The temperature with degrees and C added
  //
  t = String(tmp2,1)+" "+(char)176+"C";
  t.toCharArray(printThis,13);
  u8g.drawStr(50,0,printThis);
  //
  // Humidity from the SI7021
  //
  t = "Humi:";
  t.toCharArray(printThis,14);
  u8g.drawStr(0,11,printThis);
  //
  // The humidity and % added
  //
  t = String(humidity)+" %";
  t.toCharArray(printThis,14);
  u8g.drawStr(50,11,printThis);
  //
  // The lux from the BH1750 and from the
  // TSL2561 if we have it (it is averaged if we have it)
  //
  t = "Lux:";
  t.toCharArray(printThis,14);
  u8g.drawStr(0,22,printThis);
  uint16_t tmp = lux2;
  if (hasTSL) {
    tmp = (tmp+lux1)/2;
  }
  //
  // The lux with lx added
  //
  t = String(tmp)+" lx";
  t.toCharArray(printThis,8);
  u8g.drawStr(50,22,printThis);
  //
  // The pressure from the BMP180
  //
  t = "Press:";
  t.toCharArray(printThis,14);
  u8g.drawStr(0,33,printThis);
  //
  // The pressure with mb added
  //
  t = String(pressure2,0)+" mb";
  t.toCharArray(printThis,14);
  u8g.drawStr(50,33,printThis);
  //
  // The altitude from BMP180
  //
  t = "Alti:";
  t.toCharArray(printThis,14);
  u8g.drawStr(0,44,printThis);
  //
  // The altitude with m added
  //
  t = String(altitude2,0)+" m";
  t.toCharArray(printThis,14);
  u8g.drawStr(50,44,printThis);
}

void setup() {
  //
  // I2C startup
  //
#if defined(ESP8266)
  //
  // For the ESP8266 we need to start the sensor with SDA and SCL pin numbers
  //
  sensor.begin(SDA,SCL);
#else
  //
  // For Arduino we can just call begin.
  //
  sensor.begin();
#endif
  //
  // SI7021
  //
  temperature = 0;
  humidity = 0;
  
  //
  // TSL2561
  //
  if (tsl.begin()) {
    hasTSL = true;
    tsl.setGain(TSL2561_GAIN_16X);
    tsl.setTiming(TSL2561_INTEGRATIONTIME_13MS);
  }

  //
  // BH1750
  //
  lightMeter.begin();
  //
  // BMP180
  //
  if (pressure.begin()) {
    hasBMP = true;
  }
}

void loop() {
  //
  // LCD, the draw routine is handled by the u8g library
  //
  u8g.firstPage();  
  do {
     draw();
  } while(u8g.nextPage());

  //
  // SI7021
  //
  temperature = sensor.getCelsiusHundredths();
  temperature = temperature / 100;
  humidity = sensor.getHumidityPercent();

  //
  // TSL2561
  //
  if (hasTSL) {
    uint32_t lum = tsl.getFullLuminosity();
    uint16_t ir, full;
    ir = lum >> 16;
    full = lum & 0xFFFF;
    lux1 = tsl.calculateLux(full, ir);
  }

  //
  // BH1750
  //
  lux2 = lightMeter.readLightLevel();

  //
  // BMP180
  //
  if (hasBMP) {
    char status;
    status = pressure.startTemperature();
    if (status != 0) {
      delay(status);
      status = pressure.getTemperature(temperature2);
      if (status != 0) {
        status = pressure.startPressure(3);
        if (status != 0) {
          delay(status);
          status = pressure.getPressure(pressure2,temperature2);
          if (status != 0) {
            double p0 = pressure.sealevel(pressure2,ALTITUDE);
            altitude2 = pressure.altitude(pressure2,p0);
          }
        }
      }
    }
  }
  
  delay(50);
}

If you have any questions/remarks, feel free to post them below.

Arduino or ESP & BH1750 light sensor

Arduino or ESP & BH1750 light sensor

One of the sensors I bought is a BH1750 (on the print it looks like BHI750, but it’s not an I but a 1) light sensor which measures the available light and has an I2C interface.

Again, getting this to work is not that hard. First you need to download the BHI1750 Library

which you add to Arduino IDE with Sketch, Include Library, Add .ZIP Library and select your file. The library comes with an example. In my case the file was called BH1750Test.pde. My computer did not have an association set up for .pde but if you change it to .ino it will work.

I have tested this code with an Arduino Nano and an ESP8266 and both worked. If you want to connect it to another Arduino or are going to use a seperate power source, please make sure you do not supply it with more than 4.5 volts as that is it’s maximum input power.

A copy of the example code:

/*

Example of BH1750 library usage.

This example initalises the BH1750 object using the default
high resolution mode and then makes a light level reading every second.

Connection:
 VCC-5v
 GND-GND
 SCL-SCL(analog pin 5)
 SDA-SDA(analog pin 4)
 ADD-NC or GND

*/

#include 
#include 


BH1750 lightMeter;


void setup(){
  Serial.begin(9600);
  lightMeter.begin();
  Serial.println("Running...");
}


void loop() {
  uint16_t lux = lightMeter.readLightLevel();
  Serial.print("Light: ");
  Serial.print(lux);
  Serial.println(" lx");
  delay(1000);
}

It’s amazingly short.

As you will have seen, the sensor has five pins while we need four for I2C. The fifth pin is called addr:

bh1750back

and this can be used to set the I2C address of the sensor. Floating or connected to GND, the I2C address will be 0x23 which is also the default in the library. If you connect it to VCC the address will be 0x5C and you will have to modify the library (unfortunately). I am working on suggesting an update to this library.

Arduino & TSL2561

Arduino & TSL2561

There is a nice sensor called the TSL2561 which gives an indication of the brightness in both the visible and the infrared spectrum. It works on an I2C bus and has a library for the Arduino.

tsl2561back

You can download the library here and you install it like you would any other ZIP library; Sketch, Include Library, Add .ZIP Library. Don’t forget to restart your IDE.

The ZIP files comes with a directory called .github which you should remove (otherwise the IDE won’t stop talking about it). Also in the examples directory, the example ends with a .pde extension. On my computer .pde was not associated with the Arduino IDE so I renamed it to .ino.

There is an example in the library folder on how to use the libary:

#include <Wire.h>
#include "TSL2561.h"

// Example for demonstrating the TSL2561 library - public domain!

// connect SCL to analog 5
// connect SDA to analog 4
// connect VDD to 3.3V DC
// connect GROUND to common ground
// ADDR can be connected to ground, or vdd or left floating to change the i2c address

// The address will be different depending on whether you let
// the ADDR pin float (addr 0x39), or tie it to ground or vcc. In those cases
// use TSL2561_ADDR_LOW (0x29) or TSL2561_ADDR_HIGH (0x49) respectively
TSL2561 tsl(TSL2561_ADDR_FLOAT); 

void setup(void) {
  Serial.begin(9600);
  
  if (tsl.begin()) {
    Serial.println("Found sensor");
  } else {
    Serial.println("No sensor?");
    while (1);
  }
    
  // You can change the gain on the fly, to adapt to brighter/dimmer light situations
  //tsl.setGain(TSL2561_GAIN_0X);         // set no gain (for bright situtations)
  tsl.setGain(TSL2561_GAIN_16X);      // set 16x gain (for dim situations)
  
  // Changing the integration time gives you a longer time over which to sense light
  // longer timelines are slower, but are good in very low light situtations!
  tsl.setTiming(TSL2561_INTEGRATIONTIME_13MS);  // shortest integration time (bright light)
  //tsl.setTiming(TSL2561_INTEGRATIONTIME_101MS);  // medium integration time (medium light)
  //tsl.setTiming(TSL2561_INTEGRATIONTIME_402MS);  // longest integration time (dim light)
  
  // Now we're ready to get readings!
}

void loop(void) {
  // Simple data read example. Just read the infrared, fullspecrtrum diode 
  // or 'visible' (difference between the two) channels.
  // This can take 13-402 milliseconds! Uncomment whichever of the following you want to read
  uint16_t x = tsl.getLuminosity(TSL2561_VISIBLE);     
  //uint16_t x = tsl.getLuminosity(TSL2561_FULLSPECTRUM);
  //uint16_t x = tsl.getLuminosity(TSL2561_INFRARED);
  
  Serial.println(x, DEC);

  // More advanced data read example. Read 32 bits with top 16 bits IR, bottom 16 bits full spectrum
  // That way you can do whatever math and comparisons you want!
  uint32_t lum = tsl.getFullLuminosity();
  uint16_t ir, full;
  ir = lum >> 16;
  full = lum & 0xFFFF;
  Serial.print("IR: "); Serial.print(ir);   Serial.print("\t\t");
  Serial.print("Full: "); Serial.print(full);   Serial.print("\t");
  Serial.print("Visible: "); Serial.print(full - ir);   Serial.print("\t");
  
  Serial.print("Lux: "); Serial.println(tsl.calculateLux(full, ir));
  
  delay(100); 
}

It is quite an extensive example and that is because the sensor has quite some features which the example shows nicely.

This library unfortunately does not work on the ESP, but I did find another library which should work on both which I will discuss later.

Arduino or ESP & SI7021

Arduino or ESP & SI7021

The SI7021 is a high quality sensor for humidity and temperature. Of course there is a library for it for the Arduino IDE. As you can see in the picture, it has an I2C interface. The back side of the sensor:

si7021back

The connection is the same as with other I2C devices, use A4 SDA and A5 SCL or on the ESP D2 for SDA and D1 for SCL.

Below a slightly updated version of the example which comes with the library to have it compile correctly on the ESP8266.

#include 
#include 

#if defined(ESP8266)
// For the ESP8266 we need these to be defined
#define SDA 4
#define SCL 5
#endif

SI7021 sensor;

void setup() {
  Serial.begin(9600);
  Serial.println("Ready!");
#if defined(ESP8266)
// For the ESP8266 we need to start the sensor with SDA and SCL pin numbers
  sensor.begin(SDA,SCL);
#else
// For Arduino we can just call begin.
  sensor.begin();
#endif
}


void loop() {
  // temperature is an integer in hundredths
  float temperature = sensor.getCelsiusHundredths();
  temperature = temperature / 100;
  Serial.println("------------");
  Serial.print("Temperature in Celsius: ");
  Serial.println(temperature);

  // humidity is an integer representing percent
  int humidity = sensor.getHumidityPercent();
  Serial.print("Humidity: ");
  Serial.print(humidity);
  Serial.println("%");

  // this driver should work for SI7020 and SI7021, this returns 20 or 21
  int deviceid = sensor.getDeviceId();
  Serial.print("This is a SI70");
  Serial.println(deviceid);

  Serial.println();
  Serial.println("Heating");
  // enable internal heater for testing
  sensor.setHeater(true);
  delay(20000);
  sensor.setHeater(false);
  Serial.println("Done heating");
  
  // see if heater changed temperature
  temperature = sensor.getCelsiusHundredths();
  temperature = temperature / 100;
  Serial.print("Temperature in Celsius: ");
  Serial.println(temperature);

  Serial.println();
  Serial.println("Cooling");
  //cool down
  delay(20000);

  // get humidity and temperature at same time (also saves power)
  si7021_env data = sensor.getHumidityAndTemperature();
  Serial.println();
  Serial.print("Temperature in Celsius: ");
  Serial.println(data.celsiusHundredths/100);
  Serial.print("Humidity: ");
  Serial.print(data.humidityBasisPoints/100);
  Serial.println("%");
  
  Serial.println();
  Serial.println("Pausing");
  delay(5000);
}
Arduino and LM75A

Arduino and LM75A

The LM75A is a temperature sensor on an I2C bus. It has a very large range (-55°C to 125°C) with a moderate accuracy. In the range of -25°C to 100°C (the range you will probably be in), the accuracy is ±2°C.

In my experience the accuracy tends to be stable so what you could do is calibrate it against a sensor with higher accuracy and then take the deviation and subtract (or add) it to your measured temperature.

There already is a library for the sensor which you can download the library here. You have to install this library through Sketch, Include Library, Add .ZIP Library.

I have compiled the example that is included with the library against both the Arduino Nano and the ESP8266 and the same code worked for both. Remember to use the standard ports for I2C with the ESP8266 (D2, GPIO4 for SDA and D1, GPIO5 for SCL).

/*
 * \brief Show temperature in degrees and fahrenheit every second
 *
 * \author Quentin Comte-Gaz <quentin@comte-gaz.com>
 * \date 8 July 2016
 * \license MIT License (contact me if too restrictive)
 * \copyright Copyright (c) 2016 Quentin Comte-Gaz
 * \version 1.0
 */

#include <LM75A.h>

LM75A lm75a_sensor/*(false, //A0 LM75A pin state
                   false, //A1 LM75A pin state
                   false, //A2 LM75A pin state)*/; // Create I2C LM75A instance

void setup(void)
{
  Serial.begin(9600);
  Serial.println("Temperatures will be displayed every second:");
}

void loop()
{
  float temperature_in_degrees = lm75a_sensor.getTemperatureInDegrees();

  if (temperature_in_degrees == INVALID_LM75A_TEMPERATURE) {
    Serial.println("Error while getting temperature");
  } else {
    Serial.print("Temperature: ");
    Serial.print(temperature_in_degrees);
    Serial.print(" degrees (");
    Serial.print(LM75A::degreesToFahrenheit(temperature_in_degrees));
    Serial.println(" fahrenheit)");
  }

  delay(1000);
}

As you can see, the code is relatively straight forward, initial the library and read from the sensor.

ESP8266 & Real Time Clock

ESP8266 & Real Time Clock

I bought a DS3231 which is a real time clock (RTC) with a cell battery on it. It works through the I2C interface so it should not be too difficult to set up.

It turns out there already is a library for it for Arduino and that same library works on the ESP. Even the code is the same.

To hook up the D3231 RTC you need four wires, 3.3V, GND, SDA and SCL. 3.3V (marked as VCC on the board) and GND are easy. Standard I2C ports are 4 for SDA and 5 for SCL. On the ESP this will be D2 for SDA and D1 for SCL.

Setting up the library is straight forward. Download it here and extract it to your Arduino library directory …\Arduino\libraries or something alone those lines. You have to rename the directory called RTCLib-Master to RTCLib and restart Arduino IDE (make sure to close all instances).

Next load the ds3231 example that you can find in …\Arduino\libraries\RTCLib\examples\ds3231. Upload it to your ESP and watch the serial monitor. You will see something like:

2016/9/21 (Wednesday) 17:26:31
 since midnight 1/1/1970 = 1474478791s = 17065d
 now + 7d + 30s: 2016/9/29 5:56:37

If you look at the code you can see it’s rather straight forward. You include Wire.h, the I2C library and RTCLib.h for the RTC library. Initiate the instance RTC_DS3231 rtc and you are set. There is some code in the setup to give the RTC time to boot up. The most important call is rtc.now() which returns the current date time in a DateTime type variable. Also note that the function TimeSpan takes four arguments, days, hours, minutes and seconds. The comment in the code suggests that TimeSpan(7,12,30,6) calculates the time ahead of 7 days and 30 seconds. This should be 7 days, 12 hours, 30 minutes and 6 seconds.

// Date and time functions using a DS3231 RTC connected via I2C and Wire lib
#include 
#include "RTClib.h"

RTC_DS3231 rtc;

char daysOfTheWeek[7][12] = {"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"};

void setup () {

#ifndef ESP8266
  while (!Serial); // for Leonardo/Micro/Zero
#endif

  Serial.begin(9600);

  delay(3000); // wait for console opening

  if (! rtc.begin()) {
    Serial.println("Couldn't find RTC");
    while (1);
  }

  if (rtc.lostPower()) {
    Serial.println("RTC lost power, lets set the time!");
    // following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(F(__DATE__), F(__TIME__)));
    // This line sets the RTC with an explicit date & time, for example to set
    // January 21, 2014 at 3am you would call:
    // rtc.adjust(DateTime(2014, 1, 21, 3, 0, 0));
  }
}

void loop () {
    DateTime now = rtc.now();
    
    Serial.print(now.year(), DEC);
    Serial.print('/');
    Serial.print(now.month(), DEC);
    Serial.print('/');
    Serial.print(now.day(), DEC);
    Serial.print(" (");
    Serial.print(daysOfTheWeek[now.dayOfTheWeek()]);
    Serial.print(") ");
    Serial.print(now.hour(), DEC);
    Serial.print(':');
    Serial.print(now.minute(), DEC);
    Serial.print(':');
    Serial.print(now.second(), DEC);
    Serial.println();
    
    Serial.print(" since midnight 1/1/1970 = ");
    Serial.print(now.unixtime());
    Serial.print("s = ");
    Serial.print(now.unixtime() / 86400L);
    Serial.println("d");
    
    // calculate a date which is 7 days and 30 seconds into the future
    DateTime future (now + TimeSpan(7,12,30,6));
    
    Serial.print(" now + 7d + 30s: ");
    Serial.print(future.year(), DEC);
    Serial.print('/');
    Serial.print(future.month(), DEC);
    Serial.print('/');
    Serial.print(future.day(), DEC);
    Serial.print(' ');
    Serial.print(future.hour(), DEC);
    Serial.print(':');
    Serial.print(future.minute(), DEC);
    Serial.print(':');
    Serial.print(future.second(), DEC);
    Serial.println();
    
    Serial.println();
    delay(3000);
}
Arduino & RFID

Arduino & RFID

I bought a RFID module some time ago, the RC522, to connect to an ESP8266. I never got that working but since I have stepped into Arduino, I wanted to give it another try. Turns out, it is very simple. Of course what helps is that there is a very good library for RFID which you can find here on github (it also has installation instructions you should follow). The MFRC522 or RC522 I bought through AliExpress as I do with a lot of my electronics.

Once you have the library installed, you need to connect the RFID reader to your Arduino. The interface is an SPI interface which means you need 4 connections to the board for the message bus, 2 for power and the RC522 requires a reset wire as well. I found this article useful to get my setup working.

I have used the following connections to get the RC522 connected to my Arduino Nano:

Description RC522 (left to right) Nano
SDA 1 10
SCK 2 13
MOSI 3 11
MISO 4 12
IRQ 5 nc
GND 6 GND
RST 7 9
3.3V 8 3.3V

And some pictures. I have given every wire a different color. Note the pin between green and black is not connected.rfid-1

And the Arduino Nano side:

rfid-2

rfid-3

It is a bit hard to see because of the angle of the picture, the black wire is connected to GND which is the second pin from the left at the top of the Arduino (if it is oriented the same way as in the picture). The others you can see more easily. The first row on my breadboard is not used, so blue is connected to the right most pin of the Nano.

Now we are all set for our first program. If you download the DumpInfo example from the RFID library examples, you should be able to run that without changing it because we are using the same pin layout as the example.

For my first program using RFID, I wanted to have the UID in a variable and not read the RFID in the loop function but rather in a seperate function.

The code:

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

#define RST_PIN         9
#define SS_PIN          10
MFRC522 mfrc522(SS_PIN, RST_PIN);
#define LED_PIN     3

String lastUID, currentUID;

void setup() {
  Serial.begin(9600); 
  Serial.println("Ready to read RFID cards!");
  Serial.println("");
  pinMode(LED_PIN, OUTPUT);
  digitalWrite(LED_PIN, LOW);
  lastUID = "";
  currentUID = "";
  SPI.begin();
  mfrc522.PCD_Init();
}

void loop() {
  rfidScan();
  if (currentUID!=lastUID) {
    if (currentUID!="") {
      Serial.print("New card: ");
      Serial.println(currentUID);
      digitalWrite(LED_PIN, HIGH);
    } else {
      Serial.println("Card "+lastUID+" is gone.");
      digitalWrite(LED_PIN, LOW);
    }
    lastUID = currentUID;
  }
}

String getCurrentUID (byte *buffer, byte bufferSize) {
  String s;
  s = "";
  for (byte i=0; i<bufferSize; i++) {
    s = s+(buffer[i] < 0x10 ? "0" : "");
    s = s+String(buffer[i],HEX);
  }
  s.toUpperCase();
  return s;
}

void rfidScan() {
  if ( ! mfrc522.PICC_IsNewCardPresent()) {
    if ( ! mfrc522.PICC_IsNewCardPresent()) {
      currentUID = "";
      return;
    }
  }

  if ( ! mfrc522.PICC_ReadCardSerial()) {
    return;
  }
  currentUID = getCurrentUID(mfrc522.uid.uidByte, mfrc522.uid.size);
}

So what I want is a variable with the current UID (currentUID) and I want to know if it has changed so I can do some action. In this example I just print to the serial monitor that a card shows up or is removed. I also turn on the internal led if there is a card present and off it is removed.

In setup we set up SPI for the RC522 and initialize serial and the variables (where lastUID is the lastUID we have seen).

In the loop function we scan the RFID reader with rfidScan and whether there is a change we do something with the led and send info to serial.

The getCurrentUID is slightly different from the some of the examples as I have removed the spaces. I want the UID to be a whole block without spaces.

Finally the function rfidScan does the actual scanning, check whether there is a card present, read it’s info and if all goes well, get the UID.

In the original code, the function mfrc522.PICC_IsNewCardPresent is called and if nothing is returned it sends a return which means the function loop starts over again. For some reason, I don’t know why, I kept on getting an empty currentUID if I only called the function once every other time, even if the card was still there. That is the reason why there is a double call to the mfrc522.PICC_IsNewCardPresent function. Very dirty but it works. If someone knows how to fix this cleaner, I would sure be happy to know.

With this program, if you put a card on the reader, you can see it and if it is removed you can also see it. It is a good start for triggering something based on an RFID card.

Creating an Arduino library

Creating an Arduino library

UPDATE: Even though the description of how to create a library is still correct, I have renamed the library and created some more. Click here to see the list of articles

After creating a first step in some convenient WiFi functions, I wanted some way to have these available without continously copying the actual text. The answer is of course in a library. So I read up on how to create a library for Arduino. There is a lot to read but I wanted something simple at first. After reading and getting it working I decided to share the short version of how to create a library if you, just like me, want to combine some functions.

You will need to create four files and one directory:

  • yourChosenName.h
  • yourChosenName.cpp
  • keywords.txt
  • library.properties
  • examples/

The last three are optional. The keywords.txt and library.properties are not that hard. If you are planning to share your work than I suggest creating a directory with examples as well.

The .h file is the header file and the .cpp file is your code file. Let’s start with those. I will use the functions I created for WiFi as an example to create this library. The .cpp file will be the same as the full example except for the functions printToSerial, setup and loop. You will also need to include your own .h file. Below the result of removing the three functions and adding #include at the top (I decided to call the library PAM_WiFi):

#include 
#include 

String WiFiConnect (char* ssid, char* password) {
  WiFi.begin(ssid,password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }
  return WiFi.localIP().toString();
}

void doNothing (String webLine) {
}

String getURLParse (char* host, char* url, bool fullContent, void (*g)(String l)) {
  String lastline;
  boolean inPage;
  inPage = false;
  WiFiClient client;
  if (!client.connect(host,80)) {
    return "ERR:noconnect";
  }
  client.print(String("GET ") + url + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" + 
               "Connection: close\r\n\r\n");
  unsigned long timeout = millis();
  while (client.available() == 0) {
    if (millis() - timeout > 5000) {
      client.stop();
      return "ERR:timeout";
    }
  }
  lastline = "";
  while(client.available()){
    String line = client.readStringUntil('\r');
    line.replace("\n","");
    if (line.length()>0) {
      lastline = line;
    }
    if (fullContent || inPage) {
      g(line);
    }
    if (line.length()==0) {
      inPage = true;
    }
  }
  return lastline;
}

String getURLFullParse (char* host, char* url, void (*g)(String l)) {
  return getURLParse(host,url,true,g);
}

String getURLBodyParse (char* host, char* url, void (*g)(String l)) {
  return getURLParse(host,url,false,g);
}

String getURL (char* host, char* url) {
  return getURLParse(host,url,false,doNothing);
}

In other trials of creating a library I have found that libraries tend to be a little more strict in order of functions than main programs seem to be. Just make sure that any function you use is already defined before you use it. For example in my case, getURLParse is defined before it is called in getURLFullParse. If for some reason you need circular reference (I’m sure you will be careful of the infinite loop), you will need to do a forward declaration.

I will get to the reason why at the end, but make sure you create a directory with the name of your library and keep all the files in this directory (and only these files). In my case I have a directory which is called PAM_WiFi and I have just put PAM_WiFi.cpp in there. Next up, PAM_WiFi.h (or yourChoseName.h).

The header file which is what the .h is, contains the declarations of all variables and functions listed. The difference is that the .h file does not contain the variable names that are passed as arguments, just the types. You will also need to include a way to make sure the functions are only included once which you can do as follows:

#ifndef yourChosenName_H
#define yourChosenName_H

...

#endif

The text … will only be included if yourChosenName_H is not defined (#ifndef). If it isn’t than it is defined and the … is included. If it is already defined than anything until the #endif will be ignored.

In my case the PAM_WiFi.h file will be:

#ifndef PAM_WiFi_H
#define PAM_WiFi_H

#include 

String WiFiConnect (char*, char*);
String getURL (char*, char*);
String getURLFullParse (char*, char*, void (*)(String));
String getURLBodyParse (char*, char*, void (*)(String));
String getURLParse (char*, char*, bool, void (*)(String));
void doNothing (String);

#endif

As you can see, it is basically a listing of all my functions but with the name of the variables, so String WiFiConnect (char* ssid, char* password) becomes WiFiConnect(char*, char*).

I have included Arduino.h which I read is needed because I use the String type.

I have now saved this in the PAM_WiFi directory as PAM_WiFi.h and the directory now contains two files.

The next file is simple and it is keywords.txt. This file will contain all function names as keywords. The format is function name followed by a tab and followed KEYWORD1 or KEYWORD2 (please note it has to be a tab and not spaces). KEYWORD1 is used for classes and KEYWORD2 for functions so in my example the file keywords.txt will be:

WiFiConnect    KEYWORD2
getURL    KEYWORD2
getURLFullParse    KEYWORD2
getURLBodyParse    KEYWORD2
getURLParse    KEYWORD2
doNothing    KEYWORD2

Save the file in the directory.

The final file is library.properties. This is a text file which describes your library. What can be in there is described on the Arduino site. The tags I use are rather self explanatory. One of the places it is used is in the library manager. My file will be:

name=PAM_WiFi, wrapper for ESP8266Wifi.h
version=0.2
author=PiAndMore
maintainer=PiAndMore <myemail@mydomain.com>
sentence=PAMWifi, a wrapper for commonly used ESP8266WiFi functions
paragraph=Functions to access the ESP8266Wifi more easily, like WiFiConnect, getURL, getURLBodyParse, getURLFullParse
category=Communication
url=https://github.com/somePlaceIfYouWant
architectures=esp8266

The sentence is the short description you see in the library manager and the paragraph is what you see below that. I had to look up what needed to be in the place of architectures. You can put a * which means it applies to all. In my case, since I use the ESP8266Wifi library, I added that the only architecture it applies to is esp8266.

That concludes the fourth file. The next step is to create a zip file with those four files in there (make sure you include the directory). In my case I right clicked on the PAM_WiFi folder and selected send to followed by compressed (zipped) folder. Once you have the zip file you can install your library.

In the Arduino IDE, select Sketch, Include Library, Add .ZIP Library and find your zip file. Select it and click open. Now your library is installed.

Final part is using the library. We use the same functions that we removed earlier but than in a new sketch.

#include 

void printToSerial (String webLine) {
  Serial.println("@:"+webLine);
}

void setup() {
  Serial.begin(9600);
  Serial.println("Getting last line from webpage.");
  WiFiConnect("YourSSID","YourPassword");
  Serial.print("Last line is:");
  Serial.println(getURL("10.123.12.18","/webs/test.php"));
  Serial.println();
  Serial.println("Getting only body lines from webpage.");
  getURLBodyParse("10.123.12.18","/webs/test.php",printToSerial);
  Serial.println();
  Serial.println("Getting all lines from webpage.");
  getURLFullParse("10.123.12.18","/webs/test.php",printToSerial);
}

void loop() {
}

As you can see the setup function is the same as well as the printToSerial and loop functions. The only difference is at the top where we do not include ESP8266Wifi.h but rather PAM_WiFi.h which is the name of the library. As long as you do not need functions specifically defined in ESP8266Wifi.h you do not need to include it.

A small word of warning; it is of course tempting to put all functions you need in one library, just one include and you’re done. Remember however that usually on Arduino and the ESP, memory is scarce and if you include all of your functions in one library, all code will be included with one include.

HTTP GET using Arduino IDE

HTTP GET using Arduino IDE

As I am now using more and more the Arduino IDE to program the ESP8266, I need to create some basic functions that I had with my LUA implementation.

One of the main functions of the ESP compared to the Arduino is of course the built in WiFi. When you have installed the ESP libraries for the Arduino IDE, you will also have a library called ESP8266WiFi, which is the library to use to address the wifi module. There are some nice examples that come with the library and some of them I have used to get a better understanding. What I wanted to share here is the functions I have created to do a connect to wifi and to get a URL.

Let’s start with the code first:

#include 

void printToSerial (String webLine) {
  Serial.println("@:"+webLine);
}

void setup() {
  Serial.begin(9600);
  Serial.println("Getting last line from webpage.");
  WiFiConnect("MySSID","MyPasswd");
  Serial.print("Last line is:");
  Serial.println(getURL("MyTestHost","/test.php"));
  Serial.println();
  Serial.println("Getting only body lines from webpage.");
  getURLBodyParse("MyTestHost","/test.php",printToSerial);
  Serial.println();
  Serial.println("Getting all lines from webpage.");
  getURLFullParse("MyTestHost","/test.php",printToSerial);
}

void loop() {
}

String WiFiConnect (char* ssid, char* password) {
  WiFi.begin(ssid,password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
  }
  return WiFi.localIP().toString();
}

void doNothing (String webLine) {
}

String getURLParse (char* host, char* url, bool fullContent, void (*g)(String l)) {
  String lastline;
  boolean inPage;
  inPage = false;
  WiFiClient client;
  if (!client.connect(host,80)) {
    return "ERR:noconnect";
  }
  client.print(String("GET ") + url + " HTTP/1.1\r\n" +
               "Host: " + host + "\r\n" + 
               "Connection: close\r\n\r\n");
  unsigned long timeout = millis();
  while (client.available() == 0) {
    if (millis() - timeout > 5000) {
      client.stop();
      return "ERR:timeout";
    }
  }
  lastline = "";
  while(client.available()){
    String line = client.readStringUntil('\r');
    line.replace("\n","");
    if (line.length()>0) {
      lastline = line;
    }
    if (fullContent || inPage) {
      g(line);
    }
    if (line.length()==0) {
      inPage = true;
    }
  }
  return lastline;
}

String getURLFullParse (char* host, char* url, void (*g)(String l)) {
  return getURLParse(host,url,true,g);
}

String getURLBodyParse (char* host, char* url, void (*g)(String l)) {
  return getURLParse(host,url,false,g);
}

String getURL (char* host, char* url) {
  return getURLParse(host,url,false,doNothing);
}

Let me start of by saying there is no error checking done. If it fails, it fails.

The code consists of two main functions: WiFiConnect and getURLParse.

The WiFiConnect is, as the name implies, the function you call to connect to WiFi. It is almost copied straight from the example, just a one call function to get connected to WiFi and return after it is done.

The function getURLParse is the main function for three other functions:

  • getURL: you call it with a hostname and a url and you get as a return value the last non empty line. Usefull if you want to call an API and either don’t care about the result or are just looking for the “OK” reply.
  • getURLBodyParse: this is the little more complex function which you call with a hostname, a url and a function which is called for every line received. In the example above the function printToSerial is called which just prints whatever it receives to serial. This function will only give you the lines of the body.
  • getURLFullParse: this function is similar to getURLBodyParse except it does not only pass every line of the body it gets to the supplied function, but all lines.

If you look at the serial output of the example above where I used my test server you will get this:

Getting last line from webpage.
Last line is:OK

Getting only body lines from webpage.
@:OK

Getting all lines from webpage.
@:HTTP/1.1 200 OK
@:Date: Mon, 19 Sep 2016 17:04:02 GMT
@:Server: MYSRV
@:X-Powered-By: PHP/5.2.10
@:Content-type: text/html
@:
@:OK

I hope this is useful. Next step, put it all in a library that I can use without copying the text every time.