Category Archives: EPS32

Matters relating to the EPS32 hardware chip and boards derived from it.

Building the hardware for a room sensor

The final sensor housing design

Here at Cranfield University we are putting in place plans related to the new ‘Living Laboratory’ project, part of our ‘Urban Observatory’. This project sits within the wider UKCRIC initiative, across a number of universities. Of the many experiments in development, we are gathering environmental data from IoT devices and building data dashboards to show the data and related analyses. One of our projects will be to investigate air quality on the campus, in our lecture rooms and public spaces. Cranfield is a unique University in the UK for having its own airfield as part of the campus – we want to monitor any particular impacts that can arise from this. In this blog we discuss building the hardware for a room sensor to detect levels for temperature, humidity, barometric pressure and VOC (volatile organic compounds).

In previous blogs, we have explored the use of the fantastic Bosch BME680 sensor from PiMoroni with the equally fantastic Particle Photon board to detect environmental characteristics. This blog post is more about building the hardware for the sensor, describing a prototype design.

An initial issue is how to site the sensor in a room. We were considering at first fixing sensors to walls, and running power to the case with trunking going up the wall from power sockets. This is all pretty unsightly and obtrusive. However, an idea then emerged that offers a perfect solution. Each room has a WiFi router positioned centrally on the ceiling, and each router has a spare USB socket. The design goal was therefore to design a plug-in unit that can be positioned in this USB socket. There certainly shouldn’t be an issue with WiFi connectivity!

WiFi ceiling mounted routers
Routers have a spare USB socket

We therefore looked to find a suitable case to fit a Particle photon, and the sensor, with the ability to plug into the USB socket. We found the perfect case from Farnell, the Hammond 1551USB3TSK USB Plastic Enclosure. We also bought a right angled USB PCB plug. Together with the Photon and BME680, all the parts looked like this.

Components being assembled for build

The next stage involved soldering the PCB USB connector onto a piece of veroboard and cutting it to fit with the trusty Dremmel saw, drill and deburring tool.

After much fiddling with the components, the piece was starting to take shape. The first task was to fit the USB connector. We cut out a piece of veroboard and then cut it to fit. As can be seen this was a pretty fiddly task. The USB plug needed fixing in place so the case could plugged in and removed without the USB plugboard moving. Next time we realised we should use the case pillars better and cut a slot out to fit around them!

Finally, after the USB board was fitted, the rest of the components could be fitted and wired up. The other end of the case then had a small slot routed in to allow the sensor to be stuck through to poke outside. We found that in use the Photon can heat up, so we wanted the temperature sensor located as far away as possible from it and to have the sensor exposed to the air. We then needed to wire the components up permanently which meant soldering wires in rather than using the header pillars that our earlier prototype had used. We had our wiring diagram to work to from our prototype.

We realised there was not enough space in the case for adding header blocks on the Photon or the sensor, so soldering directly to their PCBs was the only way to proceed. Soldering makes a permanent join, but the electronics of both the photon and BME680 sensor are very delicate, so we were careful to use the absolute minimum heating time from the soldering iron to make the joins, and use a solder with plenty of flux. This resulted in satisfactory joins. Also, we needed to get the 5v power to the Photon from the USB plug unit. To to this we took the power lines off and soldered directly to the VIn and Gnd pins on the photon (bypassing the micro USB socket).

The final wiring in place, the unit is ready for assembly

Once the wiring was all in place and all the solder joints checked carefully under a powerful magnifying lens (to check there were no ‘dry’ joints), the components could be packed out with sticky pads to ensure there was no rattling around. Finally we could fit the lid on the case and screw it all into place.

The final assembly was very satisfactory. We could turn it on to test it by plugging it into a USB charger battery. The photon was brand new and so commenced the setup routine with the flashing blue light. We were able to then connect to it with our mobile, claim and name the deice, and then upload the source code previously written. able to save off a JSON structure with all the data included to the Particle cloud on a regular basis. The Photon’s excellent design means that even once one or more units are deployed, their code can be flashed remotely to update their functionality. Multiple devices can be grouped into ‘products’ to allow concurrent code maintenance. We realise we will have to work out how to have photons automatically identify themselves individually when multiple data sources are collated to one database – something to think about next!

The new sensor in use and generating data

A test of the electrical current for the completed unit shows a draw of about 530mAh, which is pretty small for such a sensor and acceptable in that it isn’t drawing off too much current.

Epilogue

The exercise here is more one of hardware than of software – all the code and software methodologies were sorted as described with the earlier prototype. Here we have a physical design which will do what we want, plugging unobtrusively into a spare USB socket located on a WiFi router on the ceiling. The device will be now fixed into place in a lecture room and tested. To extend the project to a campus-wide solution, ideally a custom PCB would be created, designed to fit the case perfectly (or a dedicated case could be designed and 3D printed). Also, to gather the data together, potentially from multiple sources we will need a ‘dashboard’ and a linked database in a system able to receive the data streams. This solution would be bigger than the ThingSpeak tooling we have used for recent prototypes. We have been experimenting with ThingsBoard for this system scale solution, with a provisional version already running on a test Raspberry Pi – perhaps this will become the subject for a future blog.

BME680 and the Particle Photon

Introduction

Here at Cranfield University we are putting in place plans related to the new ‘Living Laboratory’ project, part of our ‘Urban Observatory’. This project sits within the wider UKCRIC initiative, across a number of universities. Of the many experiments in development, we are gathering environmental data from IoT devices and building data dashboards to show the data and related analyses. One of our projects will be to place environmental sensors in our lecture rooms and public spaces to allow our facilities team to monitor conditions across the campus. In this blog, we show how this project is starting to take shape, and in so doing explain how we are connecting the Particle Photon device up with Bosch’s amazing multifunction BME680 sensor.

The controller we use is the Particle Photon, described in an earlier post. We started with a device without header poles, and then soldered in the ones we will use [D0, D1, +ve, Gnd]. The Photon was then connected to the WiFi network, following the instructions on the particle website Quick Start Guide.

Hardware

Particle Photon

Next we used a Bosch BME680 sensor. This is able to measure temperature, pressure, humidity, and indoor air quality (IAQ) – the device currently returns gas resistivity in KOhms, rather than IAQ. It is also able to use the i2C interface, which only needs two connections, plus power (4 cables). Here the connection sockets are shown having been soldered in.

Bosch BME680 multi-function sensor



We then prepared four appropriate cables.

Cables

and then wired the devices up. The wiring connections used were:

PhotonBME680
D0SDA
D1SCL
3.3V2-6V
GNDGND













Code

Next, we opened the Particle Photon oneline cloud Web IDE. We created a new app, and located the Adafruit BME680 library and sample code.

The full code is presented below.

/***************************************************************************
  This is a library for the BME680 gas, humidity, temperature & pressure sensor
  Designed specifically to work with the Adafruit BME680 Breakout
  ----> http://www.adafruit.com/products/3660
  These sensors use I2C or SPI to communicate, 2 or 4 pins are required
  to interface.
  Adafruit invests time and resources providing this open source code,
  please support Adafruit and open-source hardware by purchasing products
  from Adafruit!
  Written by Limor Fried & Kevin Townsend for Adafruit Industries.
  BSD license, all text above must be included in any redistribution
 ***************************************************************************/

#include "Adafruit_BME680.h"

#define BME_SCK 13
#define BME_MISO 12
#define BME_MOSI 11
#define BME_CS 10

#define SEALEVELPRESSURE_HPA (1013.25)

Adafruit_BME680 bme; // I2C
//Adafruit_BME680 bme(BME_CS); // hardware SPI
//Adafruit_BME680 bme(BME_CS, BME_MOSI, BME_MISO,  BME_SCK);

double temperatureInC = 0;
double relativeHumidity = 0;
double pressureHpa = 0;
double gasResistanceKOhms = 0;
double approxAltitudeInM = 0;

void setup() {
   
  if (!bme.begin(0x76)) {
    Particle.publish("Log", "Could not find a valid BME680 sensor, check wiring!");
  } else {
    Particle.publish("Log", "bme.begin() success =)");
    // Set up oversampling and filter initialization
    bme.setTemperatureOversampling(BME680_OS_8X);
    bme.setHumidityOversampling(BME680_OS_2X);
    bme.setPressureOversampling(BME680_OS_4X);
    bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
    bme.setGasHeater(320, 150); // 320*C for 150 ms

    Particle.variable("temperature", &temperatureInC, DOUBLE);
    Particle.variable("humidity", &relativeHumidity, DOUBLE);
    Particle.variable("pressure", &pressureHpa, DOUBLE);
    Particle.variable("gas", &gasResistanceKOhms, DOUBLE);
    Particle.variable("altitude", &approxAltitudeInM, DOUBLE);
  }
}

void loop() {
  if (! bme.performReading()) {
    Particle.publish("Log", "Failed to perform reading :(");
  } else {
    temperatureInC = bme.temperature;
    relativeHumidity = bme.humidity;
    pressureHpa = bme.pressure / 100.0;
    gasResistanceKOhms = bme.gas_resistance / 1000.0;
    approxAltitudeInM = bme.readAltitude(SEALEVELPRESSURE_HPA);

    // ThingSpeak Channel Info                        
    unsigned long myChannelNumber =999999;      //  From your ThingSpeak Account Info
    const char * myWriteAPIKey = "YOURAPIKEY";  //  From your ThingSpeak Account Info (API KEYS tab)

    String data = String::format(
      "{"
        "\"temperatureInC\":%.2f,"
        "\"humidityPercentage\":%.2f,"
        "\"pressureHpa\":%.2f,"
        "\"gasResistanceKOhms\":%.2f,"
        "\"approxAltitudeInM\":%.2f,"
        "\"key\":\"%s\""
      "}",
      temperatureInC,
      relativeHumidity,
      pressureHpa,
      gasResistanceKOhms,
      approxAltitudeInM,
      myWriteAPIKey);

    Particle.publish("Sensor", data, 60, PRIVATE, NO_ACK);
  
  }
  delay(10 * 1000);
}

Receiving data

Note the inclusion of the ThingsBoard API key ‘myWriteAPIKey’ into the JSON structure. ThingsBoard is used below.

Once we verified and flashed this code to the new Photon, it was able to start generating data. It took about 20 minutes to stabilise readings. Data was then picked up from the Particle.publish command in the source code on the Particle Console view. The data JSON structure is shown being generated (key not shown).

Particle Console

ThingSpeak Dashboard

Finally, following the approach outlined in this earlier blog, we built a ‘Webhook’ integration from the Particle web Console to ThingSpeak, and added a new Channel to receive the data to create a dashboard.

ThingsSpeak Dashboard – data shown with spline and averaged over 10 minutes

and as before the range of visualisations can be customised, and indeed the power of Matlab analytics can be blended in also.

Alternate dashboard with gauges

Epilogue

This blog has shown how easy it is to get a Particle Photon working with a Bosch BME680 multifunction sensor. As can be seen, the sensor outputs a range of data streams, barometric pressure, humidity, temperature and gas, and of these it is the gas resistance level, from which an Indoor Air Quality (IAQ) can be calculated, that is of particular interest. To quote Bosch, ‘The gas sensor within the BME680 can detect a broad range of gases to measure indoor air quality for personal well being. Gases that can be detected by the BME680 include: Volatile Organic Compounds (VOC) from paints (such as formaldehyde), lacquers, paint strippers, cleaning supplies, furnishings, office equipment, glues, adhesives and alcohol.’ This opens up a range of applications for this sensor which, combined with our project to monitor continuously public areas around the campus, a lot of options. As the Bosch technical sheet notes, IAQ provides a value from 0-500, with the following classification:

IAQ IndexAir Quality
0 – 50good
51 – 100average
101 – 150little bad
151 – 200bad
201 – 300worse
301 – 500very bad

The current device and software library only returns gas resistance, but a future project can be to link this to the Bosch libraries that calculate IAQ. There is also an interesting thread on the Pi Moroni blog for achieving this oneself, and more information here also.

Voice Activated Wio Node temperature sensor

Here at Cranfield University we are interested in the ‘Internet of Things’ for environmental sensing. In this blog, we use one off SeedStudio’s Wio Node devices, with a home-made connection to a one wire temperature sensor, and finally an IOS shortcut on an iPhone to read and speak the value using Siri. In part, this blog follows this project.

Hardware

The WioNode from SeeedStudio

Microprocessor: We’ve had a few projects reported here with Arduino’s, Photons and Raspberry Pis, so it was interesting to get hold of a Wio Node device from Seeed Studio. This is an inexpensive ESP8266 based open-source Wi-Fi development board that supports Seeed’s Plug-n-Play Grove standard. There are two Grove sockets on the Node device. The node is marketed as permitting one to create a working IoT application in 5 minutes. Key to this is the Plug-n-Play physical sensor design, and the modular software tools in the app.

Sensor: To measure temperature, we used a DS18B20 Waterproof Temperature Sensor, available cheaply from a range of sources, such as here. The three wires are Red(VCC), Yellow (DATA), Black(GND).

Construction

The Grove standard is a modular, standardized connector prototyping system, permitting Plug-n-Play connectivity with scores of sensor devices for measuring a wide range of phenomena. The advantage of Seeed Studio’s Wio range is that these simply plug into the sockets on the board. However, if one has a sensor without a Grove plug, there is a Protoshield prototyping board available. This can be used to wire up a sensor such as the DS18B20 to allow it to be connected.

Unfortunately we didn’t have a Protoshield, however, we did have a pre-wired grove compatible plug that fitted the socket on the Wio Node – so a visit to the trusty soldering iron and heat-shrink cable was required. To make the DS18B20 work, a 4.7k pull-up resistor is required between the VCC and signal lines. The wiring diagram is as follows:

Wio Node wiring diagram

After wiring up the temperature sensor as shown, and plugging it in, we could turn to the software to control it.

Software controller

Wio Link Configuration

There is a Wio Link App available for smartphones, such as the Apple phone, that hugely simplifies the process of plugging in and operating sensors. We installed the app, and followed the simple instructions to add a new Wio Node device, and to enable Wi-Fi on it. Once this was working, we configured the Node to add our new sensor to the ‘S0’ port (there are two ports – S0 and S1).

REST endpoints for new sensor

The option used was ‘One Wire Temperature Sensor’ on the GPIO toolbar. Once this was working, we ‘flashed’ the new settings onto the Node via the ‘Update Firmware’ option. Next, we could view the API settings for the new configuration.

The URL REST endpoints are shown and can be used to access the temperature value from the sensor. A test option within the app allows one to access the reading directly.

The REST URL takes the form, thus:

https://us.wio.seeed.io/v1/node/GroveTemp1WireD1/temp?access_token=TOKEN_GOES_HERE

The temperature values are returned as a JSON string, appearing thus:

{"temperature":19.1800000000001}

To access the actual value from the JSON, we will need to extract the number from the data pair (see step 3 below). Once we were happy the approach was all working, we copied the URL off for use in the next stage of the project.

Voice control

The project at this point is all working well – the temperature sensor reports to the Wio Node, and an API REST URL can be used to access the value. However, we can go further. We next used an Apple iPhone X, and its newly introduced ‘Shortcuts’ capability. This involves firstly installing the Shortcuts app from the iTunes App Store.

Shortcuts allow one to build a relatively sophisticated programme very simply. We therefore set out to develop a ‘Shortcut’ that accessed the new sensor – for this we needed the URL (REST endpoint) from before. The shortcut settings are shown below, namely: (1) URL – enter in the URL from above; (2) Get Contents of URL [use Advanced options – method: GET, Header: temperature; (3) Get Dictionary Value [Key – temperature]; (4) Set Variable [Temperature] (saves value off to a new variable called Temperature); (5) Text [degrees Celsius] (creates a block of text to append); (6) Add to Variable [Temperature] (appends text to variable); (7) Combine Text [Separator – New Lines]; (8) Speak Text [Wait Until Finished]. A further elaboration is to use the ‘If‘ statement to check there was a valid reading (e.g. temperature > -20) ‘Else‘ advise of a problem.

We then added a custom icon ‘glyph’ (thermometer!) and colouring for the shortcut, and added this to the home screen of the phone. This allows the shortcut to be run easily.

As a final finishing touch, we then also added a Siri shortcut with a simple voice command ‘temperature’ – this allows one to call ‘Hey Siri’ and give the command. The device sensor temperature reading is then spoken back. Pretty amazing! See the video below for an example.

Epilogue

This approach worked well, and could be developed to work with any of the other Grove sensors plugged into the Wio Node. For more complex projects, the Wio Node, with its two connectors could be limiting. Fortunately there are a whole range of extended micro controllers, such as the Wio Link, with 6 Grove connectors – as well as lots of great projects to try.

IOT Project – Using an ESP8266 with IOS Push Notifications

Following on from a recent post http://www.geothread.net/iot-project-using-an-esp32-device-to-check-a-web-service/, here at Cranfield University, we wanted to explore the use of ‘Push Notifications‘ to a mobile phone or tablet from an event triggered on a ESP8266 Internet of Things device. This could be useful for a range of applications – for example following a trigger from a sensor to indicate that some threshold has been exceeded (e.g. a set temperature or humidity), or from the utility previously described, testing periodically to see if a web service is running or not.

Contents:
Parts required
Push notification configuration and Prowl
Hardware
Configuring Arduino
Test Sketch
Results
Next Steps
Buttons Sketch
Web Service monitoring with push notifications

To get this all working we need a simple test rig, described here, to bring together all the parts.

Parts required:

top
IOS device – Apple iPhone (Android is OK too – comments below)
– installed with ‘Prowl’ app
ESP8266 device – We used a ‘TOOGOO ESP8266’
Arduino IDE correctly configured
– installed with ESP8266WiFi and EspProwl libraries
– suitable serial driver

Push notification configuration and Prowl:

top
If we want to be informed of Internet events, we can make devices trigger communications in. number of ways – examples being emails, tweets, and push notifications. Of these, ‘Push Notifications’ are the most immediate. They can put a note up on the home screen of a mobile device (phone or tablet) to draw immediate attention. We used a mobile phone for this test, an Apple iPhone running IOS.

The leading IOS push notifier is Prowl – https://www.prowlapp.com. The web service is free to use, so we registered a login account with Prowl. The next step is to generate a unique API keycode in Prowl. In doing this, a short description can be added to remind what it relates to, e.g. ‘IoT notifications’. One can have multiple API key codes for different applications/projects.

Once that is done, the next step is to install the Prowl app on the iPhone. The app is available on the iTunes App Store.

Note that the app is not free, but it is priced modestly, and is fair given the great service Prowl provides. Once the app is installed, the account details set above on the website can be entered.

We are now ready to receive push notifications.

Android

The Prowl app is designed for IOS devices. Android has its own equivalent utilities such as PushBullet, described in a similar tutorial blog online here.

Hardware:

top
The last post used an ESP32 device. These chips are newer than the ESP8266 devices, being slightly more expensive, and with BlueTooth as an additional feature alongside WiFi. To keep costs down, we used the TOOGOO ESP8266 device, available from a range of providers, eg. Amazon. The ESP8266 is described well in this blog article.

Configuring Arduino:

top
The ESP8266 device is designed to operate with the Arduino IDE development environment. As described fully in the earlier post, using a MacBook, one needs to install a serial driver to communicate with the hardware, and the appropriate cables. Next, as the device is an ESP8266, we need to install the appropriate device libraries.

In the Arduino ‘Preferences’ dialog, one can add references to external libraries through adding a line to the source. We added the ESP8266 source thus:

http://arduino.esp8266.com/stable/package_esp8266com_index.json

Now in the Arduino, under ‘Sketch’ -> ‘Include Library’, we can see ‘ESP8266WiFi’, which can be added to our test sketch.

For the particular TOOGOO ESP8266 device, we used the Arduino board definition ‘NodeMCU 1.0 (ESP-12e Module)’.

EPS8266 notifications

We now need a means in the Arduino code sketch to configure and initiate push notifications. Fortunately we can use the excellent EspProwl library described online at https://github.com/marcos69/EspProwl. The code here can be downloaded to the library folder of the Arduino installation folder. Now the library can be added to the Sketch code (e.g. #include <EspProwl.h>), and then used in the code.

Once this is all in place, we can develop a minimal test sketch to open a WiFi connection and initiate a push notification.

Test Sketch code:

top

#include &lt;ESP8266WiFi.h&gt;
#include &lt;EspProwl.h&gt;

// WiFi parameters
char* ssid = "MYSSID";
char* password = "MYWIFIKEY";

void setup() {
       // Start Serial
       Serial.begin(115200);
       WiFi.begin(ssid, password);
       while (WiFi.status() != WL_CONNECTED) {
          delay(500);
          Serial.print(".");
       }
       Serial.println("");
       Serial.println("WiFi now connected at address");
       // Print the IP address
       Serial.println(WiFi.localIP());
       EspProwl.begin();
       EspProwl.setApiKey("MY_PROWL_API_CODE");
       EspProwl.setApplicationName("ESP6266 Prowl test");
       int returnCode = EspProwl.push("Hello World event", "Initial notification", 0);
}

void loop() {
  // not used in this test
}

Results:

top

The result of the test sketch is that once it runs, a WiFi connection is made, and then a push notification initiated. Note that the push here is placed in the ‘Setup’ block – so it only runs once (fine for testing). Note also that one can firstly set an Application Name, and secondly, a Push Title and Message. This permits a lot of flexibility in the messaging options open. Hopefully when run the results will appear on the mobile device as shown.

The Prowl app does permit some filtering and the ability to (temporarily) filter messages and have quiet times etc. which could be useful if there are a lot of messages appearing.

Next Steps:

top
This project has shown how to create push notifications, triggered by the ESP8266 device. Note, we used the Setup block in the code example above – in reality one would use the ‘Loop’ block for event monitoring and message triggering. However, more programmatic control is needed for this to be used in a real project. For example, if one is say monitoring temperature every few minutes, the operator may not wish to receive a push notification at the same frequency, or once messaged, another trigger notification may not be wanted until the threshold is crossed once more. In either case, a secondary ‘loop’ or register could be configured in the code sketch, within the continuously running 5 minute loop, so as to restrict messaging to say an hourly basis or just when significant changes occur – this might prove especially relevant if some other action is being undertaken at the finer timestep – such as database logging of data. It depends on the application – but overall push notifications offer a very useful tool for building up control and monitoring systems.

Buttons Sketch:

top
The hardware device also has a few in-built buttons. So we created a simple sketch that triggers push notifications when they are pressed and released:

#include &lt;avdweb_Switch.h&gt;
// See https://github.com/avandalen/avdweb_Switch
#include &lt;ESP8266WiFi.h&gt;
#include &lt;EspProwl.h&gt;
// Drawing on code at https://github.com/marcos69/EspProwl

// Buttons - FLATH, RSET, D5, D6, D7
const byte buttonUp_Pin = D6;
Switch buttonUp = Switch(buttonUp_Pin);
const byte buttonDown_Pin = D7;
Switch buttonDown = Switch(buttonDown_Pin);
const byte buttonPress_Pin = D5;
Switch buttonPress = Switch(buttonPress_Pin);
int i;

// WiFi parameters
char* ssid = "MYSSID";
char* password = "MYWIFIKEY";

void setup() {
       Serial.begin(115200);
       Serial.println("Starting:");
       WiFi.begin(ssid, password);
       while (WiFi.status() != WL_CONNECTED) {
          delay(500);
          Serial.print(".");
       }
       Serial.println("");
       Serial.println("WiFi now connected at address");
       // Print the IP address
       Serial.println(WiFi.localIP());
       EspProwl.begin();
       EspProwl.setApiKey("MY_PROWL_API_CODE");
       EspProwl.setApplicationName("ESP6266 Prowl test");
       int returnCode = EspProwl.push("Button press test", "Ready", 0);
}

void loop() {
       buttonUp.poll();
       if(buttonUp.pushed()) {
           Serial.print(++i); Serial.print(" "); Serial.print("Up pushed, ");
           int returnCode = EspProwl.push("Up", "Pushed", 0);
       }
       if(buttonUp.released()) {
           Serial.println("Up released");
           int returnCode = EspProwl.push("Up", "Release", 0);
       }
       buttonDown.poll();
       if(buttonDown.pushed()) {
           Serial.print(++i); Serial.print(" "); Serial.print("Down pushed, ");
           int returnCode = EspProwl.push("Down", "Pushed", 0);
       }
       if(buttonDown.released()) {
            Serial.println("Down released");
            int returnCode = EspProwl.push("Down", "Release", 0);
       }
       buttonPress.poll();
       if(buttonPress.pushed()) {
            Serial.print(++i); Serial.print(" "); Serial.print("Press pushed, ");
            int returnCode = EspProwl.push("Press", "Pushed", 0);
       }
       if(buttonPress.released()) {
            Serial.println("Press released");
            int returnCode = EspProwl.push("Press", "Release", 0);
       }
}


Web Service monitoring with push notifications:

top
An earlier blog showed how to use an EPS device to monitor a web service, http://www.geothread.net/iot-project-using-an-esp32-device-to-check-a-web-service/. We can revisit that code now, and add in Prowl push alert code. We can also make the code a little more sophisticated too to avoid false positives. As before you will need to add in the SSID and WiFi passcode, and the website address and REST endpoint, as well as the Prowl API code. Here is the source code, edited to work on an EPS8266 device, rather than EPS32 device (its the slightly cheaper older chip).

// TTGO EPS8266_WebServiceCheck : WiFi & Bluetooth Battery ESP32 Module - webservices checker

// Import required libraries
#include <Wire.h>
#include <OLEDDisplayFonts.h>
#include <OLEDDisplay.h>
#include <OLEDDisplayUi.h>
#include <SSD1306Wire.h>
#include <SSD1306.h>
#include "images.h"
#include "fonts.h"
#include <ESP8266WiFi.h>
#include <EspProwl.h>

// The built-in OLED is a 128*64 mono pixel display
// i2c address = 0x3c
// SDA = 5
// SCL = 4
SSD1306 display(0x3c, 5, 4);

// Web service to check
const int httpPort = 80;
const char* host = "MYWEBSERVICE_HOSTNAME";

// WiFi parameters
const char* ssid = "MYSSID";
const char* password = "MYWIFIKEY";

void setup() {
       // Initialize the display
       display.init();
       //display.flipScreenVertically();
       display.setFont(Roboto_Medium_14);

       // Start Serial
       Serial.begin(115200);
       // Connect to WiFi
       display.drawString(0, 0, "Going online");
       display.drawXbm(34, 14, WiFi_Logo_width, WiFi_Logo_height, WiFi_Logo_bits);
       display.display();
       WiFi.begin(ssid, password);
       while (WiFi.status() != WL_CONNECTED) {
          delay(500);
          Serial.print(".");
       }
       Serial.println("");
       Serial.println("WiFi now connected at address");
       // Print the IP address
       Serial.println(WiFi.localIP());
       display.clear();
       EspProwl.begin();
       EspProwl.setApiKey("MY_PROWL_API_CODE");
       EspProwl.setApplicationName("Web Service Checker");
       int returnCode = EspProwl.push("Checker", "System up", 0);
}

void loop() {
       Serial.print("\r\nConnecting to ");
       Serial.println(host);
       display.clear();
       display.setTextAlignment(TEXT_ALIGN_LEFT);
       display.drawString(0, 0, "Check web service");
       display.display();
       Serial.println("Check web service");
       
       // Setup URI for GET request
       String url = "/PATH/TO/REST/ENDPOINT/";
       // if service is up ok, return will contain: 'Service running'

       WiFiClient client;
       if (!client.connect(host, httpPort)) {
         Serial.println("Connection failed");
         display.clear();
         display.drawString(0, 0, "Connection failed");
         display.display();
         return;
       }

       client.print("GET " + url + " HTTP/1.1\r\n");
       client.print("Host: " + (String)host + "\r\n");
       client.print("Authorization: Basic YWRtaW46NSs2KndralhLcVApOVd2JWokQ2o=\r\n");
       client.print("User-Agent: Arduino/1.0\r\n");
       client.print("Cache-Control: no-cache\r\n\r\n");

       // Read all the lines of the reply from server
       delay(800);
       bool running = false;
       while (client.available()) {
         String line = client.readStringUntil('\r\n');
         Serial.println(line);
         if (line == "Service running") {
           running = true;
         }
       }
       if (running == true) {
           display.drawString(0, 25, "Service up OK");
           display.display();
           delay(3000);
           ProwlAlert(running);       
       } else {
           display.drawString(0, 25, "Service DOWN");
           display.display();
           delay(3000);
           ProwlAlert(running);       
       }

       Serial.println();
       Serial.println("Closing connection");
       Serial.println("=================================================");
       Serial.println("Sleeping");
       display.clear();
       display.drawString(0, 0, "Closing connection");
       display.display();
       delay(1000);
       display.clear();
       client.stop();
       // progress bar
       for (int i=1; i<=28; i++) {
         float progress = (float) i / 28 * 100;
         delay(500); // = all adds up to delay 14000 (14 sec)
         // draw percentage as String
         display.drawProgressBar(0, 32, 120, 10, (uint8_t) progress);
         display.display();
         display.setTextAlignment(TEXT_ALIGN_CENTER);
         display.drawString(64, 15, "Sleeping " + String((int) progress) + "%");
         display.display();
         display.clear();
         Serial.print((int) progress);Serial.print(",");
       }
       delay (1000);
}

int ProwlAlert(bool running) {
        // prevent too many false positives
        static int counter = 0;
        static bool resumed = true;
        int returnCode = -999;
        Serial.print("Status: ");
        Serial.print(running);
        Serial.print(" | Run count: ");
        Serial.println(counter);
        if (running == true) {
           counter = 0;
           if (resumed == false) {
              returnCode = EspProwl.push("Checker", "Service resumed as normal", 0);
              resumed = true;
           }
        } else {
           counter = counter + 1;
           resumed = false;       
        }
        if (counter == 5) {
           returnCode = EspProwl.push("Checker", "Service detected as being down - attention required", 0);
           counter = 0;
        }
        return returnCode;
}

IOT Project – Using an ESP32 device to monitor a web service

There is a lot of interest in the Internet of Things here at Cranfield University. Especially now there is a new generation of super-cheap ESP8266 and ESP32 devices which can be deployed as IoT controllers. Many of these devices are now also available with in-built OLED screens – very helpful for showing messages and diagnostics.

We will use one of these devices to develop our project.

Contents
The project
The device
Coding the EPS32
Configuring the development environment
Connecting to the device
USB drivers
OLED Screen drivers
Configuring the Arduino IDE
Uploading the Source Code
The Source Code
– – Authorisation
In operation
Next steps

The project

top
Nowadays, web services are used for all sorts of applications – for providing access to data and functionality online. A useful application then for the EPS32 is for it to act as a monitor for a web service, repeatedly polling the service to see if it is operating correctly. If the web service goes down, we need to know – the EPS32 can keep an eye on the service and report any problems.

This project describes how an EPS32 device can be configured and programmed to monitor a web service. The web service we will monitor is developed (in node.js) with an API that includes a ‘current status’ call – if all is well calling this returns a success message which we can capture.

The device

top
For this project, we are using the TTGO-WiFi-Bluetooth-Battery-ESP32-Module-ESP32-0-96-inch-OLED-development-tool from Aliexpress, although these devices are widely available from many retailers. This particular model also has a battery holder for a long-use LIPO battery on the rear of the board.

Coding the EPS32

top
There are a few options for coding the ESP devices. Most easily, it is possible to use the Arduino development environment (with a few tweaks). Another possibility is using the Atom implementation at platformio: https://platformio.org/platformio-ide. We used the Arduino tool.

Configuring the development environment

top
The Arduino development environment by default does not have the libraries and configurations to allow it to programme the EPS32. There are a few steps needed to enable this.

Connecting to the device

top
The EPS32 board has a micro-USB port, permitting connection to the programming computer. We used an Apple Mac laptop for programming – so a micro-USB to USB-C cable/convertor was required.

USB drivers

top
The EPS32 device needs a software driver installed on the programming computer. We used the Silicon Labs drivers available online here. There are other alternatives (some commercial) for drivers – notably the Mac-usb-serial drivers online.

OLED Screen drivers

top
The EPS32 device also has an in-built OLED screen. Although very small, at 128*64 pixels, this mono display is quite large enough to show text messages with different fonts, simple bitmap graphics, progress bars and drawing elements (lines, rectangles etc.) – amazing! However, a library is needed to allow access to this device. We used the ThingPulse OLED library.

The library can be downloaded as a zip file from GitHub to the library folder in the Arduino installation folder. On the Mac for example this is:

/Users/USER/Documents/Arduino/libraries/esp8266-oled-ssd1306-master


This library comes with lots of example programmes showing how to programme the screen, how to encode bitmaps, add progress bars, create fonts etc. From the code below, it can be seen that the Sketch ‘SSD1306SimpleDemo.ino‘ offers a great starting point for learning, referencing for example the ways described at Squix for encoding images and fonts. I selected the Roboto Medium font and encoded the WiFi graphic (using this online tool).
When completed, the two header files for fonts and images respectively were:
fonts header file – fonts.h
images header file – images.h

Configuring the Arduino IDE

top
Configuring the Arduino IDEHaving installed these drivers and libraries, the Arduino IDE then needs to be configured.

To do this, the board was set as a device of type ‘ESP32 Arduino’ -> ‘ESP32 Dev Module’, the baud rate set to 115200. Having installed the USB driver above, the port could be set to ‘/dev/cu.SLAB_USBtoUART’.

Uploading the Source Code

top
The Arduino IDE allows one to compile and upload code to the device. Critically, one has to hold down the ‘Boot’ button on the device as the programme is uploaded (for a few seconds) to allow the device code to be uploaded. If the boot button is NOT held down, there will be errors reported and the code will not be uploaded! (this took ages to work out!!)

The Source Code

top
In coding the device in the Arduino development environment, one can refer usefully to the Arduino code reference. The final working code is shown below. Note the calls to the Serial monitor to allow debugging information to be shown while the device is connected to the computer.

// TTGO WiFi &amp; Bluetooth Battery ESP32 Module - webservices checker
// Import required libraries
#include "Wire.h"
#include "OLEDDisplayFonts.h"
#include "OLEDDisplay.h"
#include "OLEDDisplayUi.h"
#include "SSD1306Wire.h"
#include "SSD1306.h"
#include "images.h"
#include "fonts.h"
#include "WiFi.h"
#include "WiFiUdp.h"
#include "WiFiClient.h"
// The built-in OLED is a 128*64 mono pixel display
// i2c address = 0x3c
// SDA = 5
// SCL = 4
SSD1306 display(0x3c, 5, 4);

// WiFi parameters
const char* ssid = "MYSSID";
const char* password = "MYWIFIKEY";

// Web service to check
const int httpPort = 80;
const char* host = "MYWEBSERVICE_HOSTNAME";

void setup() {
	// Initialize the display
	display.init();
	//display.flipScreenVertically();
	display.setFont(Roboto_Medium_14);

	// Start Serial
	Serial.begin(115200);
	// Connect to WiFi
	display.drawString(0, 0, "Going online");
	display.drawXbm(34, 14, WiFi_Logo_width, WiFi_Logo_height, 			 WiFi_Logo_bits);
	display.display();
	WiFi.begin(ssid, password);
	while (WiFi.status() != WL_CONNECTED) {
	 	 delay(500);
	 	 Serial.print(".");
	}
	Serial.println("");
	Serial.println("WiFi now connected at address");
	// Print the IP address
	Serial.println(WiFi.localIP());
	display.clear();
}

void loop() {
	Serial.print("\r\nConnecting to ");
	Serial.println(host);
	display.clear();
	display.setTextAlignment(TEXT_ALIGN_LEFT);
	display.drawString(0, 0, "Check web service");
	display.display();
	Serial.println("Check web service");

	// Setup URI for GET request
	String url = "SPECIFIC_WEBSERVICE_URL";
	// if service is up ok, return string will contain: 'Service running'

	WiFiClient client;
	if (!client.connect(host, httpPort)) {
		Serial.println("Connection failed");
		display.clear();
		display.drawString(0, 0, "Connection failed");
		display.display();
		return;
	}

	client.print("GET " + url + " HTTP/1.1\r\n");
	client.print("Host: " + (String)host + "\r\n");
	// If authorisation is needed it can go here
	//client.print("Authorization: Basic AUTHORISATION_HASH_CODE\r\n");
	client.print("User-Agent: Arduino/1.0\r\n");
	client.print("Cache-Control: no-cache\r\n\r\n");

	Serial.print("GET " + url + " HTTP/1.1\r\n");
	Serial.print("Host: " + (String)host + "\r\n");
	// If authorisation is needed it can go here
	//Serial.print("Authorization: Basic AUTHORISATION_HASH_CODE\r\n");
	Serial.print("User-Agent: Arduino/1.0\r\n");
	Serial.print("Cache-Control: no-cache\r\n\r\n");

// Here's an alternative form if the service API uses HTTP POST
/*
client.print("POST " + url + " HTTP/1.1\r\n");
client.print("Host: " + (String)host + "\r\n");
// If authorisation is needed it can go here
//client.print("Authorization: Basic AUTHORISATION_HASH_CODE\r\n");
client.print("User-Agent: Arduino/1.0\r\n");
client.print("Cache-Control: no-cache\r\n\r\n");
*/

	// Read all the lines of the reply from server
	delay(500);
	bool running = false;
	while (client.available()) {
		String line = client.readStringUntil('\r\n');
	 	Serial.println(line);
	 	if (line == "Service running") {
	 		running = true;
		}
	}
	if (running == true) {
		display.drawString(0, 25, "Service up OK");
	 	display.display();
		delay(3000);
	} else {
	 	display.drawString(0, 25, "Service DOWN");
	 	display.display();
	 	delay(3000);
		// Text/email administrator
	}

// Here's some alternative methods to read web output
/*
while (client.available()) {
	 Serial.print("&gt;");
	 char c = client.read();
	 Serial.print(c);
	 Serial.print("&lt;");
}
*/
/*
int c = '\0';
unsigned long startTime = millis();
unsigned long httpResponseTimeOut = 10000; // 10 sec
while (client.connected() &amp;&amp; ((millis() - startTime) &lt; 	 	 	 httpResponseTimeOut)) {
	 if (client.available()) {
	 	 c = client.read();
	 	 Serial.print((char)c);
	} else {
	 	 Serial.print(".");
	 	 delay(100);
	}
}
*/

	Serial.println();
	Serial.println("Closing connection");
	Serial.println("=================================================");
	Serial.println("Sleeping");
	display.clear();
	display.drawString(0, 0, "Closing connection");
	display.display();
	delay(1000);
	display.clear();
	client.stop();
	// progress bar
	for (int i=1; i<=28; i++) {
	 	float progress = (float) i / 28 * 100;
	 	delay(500); // = all adds up to delay 14000 (14 sec)
		// draw percentage as String
	 	display.drawProgressBar(0, 32, 120, 10, (uint8_t) progress);
	 	display.display();
	 	display.setTextAlignment(TEXT_ALIGN_CENTER);
	 	display.drawString(64, 15, "Sleeping " + String((int) progress) + "%");
	 	display.display();
	 	display.clear();
	 	Serial.print((int) progress);Serial.print(",");
	}
	delay (1000);
}

Authorisation

top
Note that the connection to the service can use either HTTP GET or POST according to need (POST is considered a better approach). A further embellishment for security is if the web service uses authorisation (username and password to connect). If it does, then a hash of the combination of username and password can be passed in the header as shown in the code. To do this we use the excellent Postman tool. Postman allows one to manually create a connection conversation with an API server, including say a basic authorisation, and then view the full code of this – which can be copied into the Arduino code as shown above.

Note that it is critical to have a second carriage return at the end of the HTTP conversation (shown as ‘\r\n‘ in the code – so the last item has ‘\r\n\r\n’ for the blank line). Without this blank line it will not work!

In operation

top
Here is a short video of the device in operation. Excuse the use of image stabilisation – original video was filmed handheld.

The code is designed to open a connection, check on the status of the web service, then sleep for a period before repeating in an endless loop.

Next steps

top
This code currently only flashes up on the tiny screen when the service is found to be up or down. To be really useful, the tool should be able to alert one or more administrators – perhaps by push messaging to their mobile phones, or email.

The next stage can add this capability using approaches using Prowl, and Avviso. Perhaps the subject of a future blog posting.