Espruino Weather Station

Espruino is a project that combines small, powerful, and efficient microcontrollers with a JavaScript runtime.

For this course, we will use an Espruino Wifi, a BME280 Environment Sensor (temperature, humidity, and atmospheric pressure), and a SSD1306 OLED display. We will combine all of these components to create a weather station running JavaScript!

weather station

The weather station records the temperature, humidity, and atmospheric pressure. The data can then be used to monitor and predict the weather.

The components are combined as illustrated below: board

CPINFO Espruino Circuit Diagram

1 Get Connected

  1. Connect your Espruino board to the USB port of the computer. Wait for Windows to indicate the drivers were correctly installed.
  2. Install the Espruino Web IDE and open it.
  3. Connect to your Espruino board by clicking on connect icon and choosing the Espruino connection: Web IDE Connect
  4. Click on the Run button to execute the code that is shown on the right half of the screen: Web IDE Run

    You can modify the code on the right half of the screen and then click the Run button again to see the changes live. You can also execute console.log("hello CPINFO") to log messages and data to the console of the left half of the screen.

2 OLED Display

The SSD1306 OLED is a 128x64 resolution monochrome OLED display. It communicates with the Espruino using a SPI protocol. Fortunately, this is already supported by Espruino.

  1. Setup the display by adding the following code to your project:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    
    let display;
    function setupDisplay() {
      I2C1.setup({scl: B8, sda: B9});
      B7.set();
      B6.reset();
      display = require('SSD1306').connect(I2C1, displayReady);
    }
    
    function displayReady() {
      display.drawString("Hello CPINFO");
      display.flip();
    }
    
    setupDisplay();
    

    The graphics library on Espruino allows changing the font, drawing lines, shapes, and much more.

  2. clear() and flip()

    The Espruino Graphics library lets us use “double buffering” to write to the display. First, we draw to a local variable (buffer) then we call the flip() function to write the buffer to the display. The function clear() clears the buffer.

    Double buffering techniques reduce flickering when drawing animations on a display.

  3. Refresh with setInterval()

    The function setInterval() allows executing a function at regular intervals. For example the following code will log a message every second (1000ms):

    1
    2
    3
    4
    5
    
    let count = 0;
    setInterval(() => {
      console.log('The count is:', count);
      count = count + 1;
    }, 1000);
    

    ☑️ Exercise 2.1 Use setInterval() to update the display with some changing text or shapes.

📖 Reference

3 BME280 Environment Sensor

  1. Setup the environment sensor by adding the following code to your project:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    
    let sensor;
    function setupSensor() {
      A4.reset();
      A5.set();
    
      console.log('Starting Temp');
      const i2c = new I2C();
      i2c.setup({scl: A1, sda: A0});
      sensor = require('BME280').connect(i2c);
    }
    
    setupSensor();
    
    const data = sensor.getData();
    console.log('Temp:', data.temp);
    console.log('Humidity:', data.humidity);
    console.log('Pressure:', data.pressure);
    

☑️ Exercise 3.1 Instead of displaying the data on the console, we should display it on the OLED dislplay! Use the drawString() functions to read the data from the sensor and display it on the OLED display.

☑️ Exercise 3.2: use setInterval to read the temperature and update the display

☑️ Bonus: Use the Graph library to draw cool graphs!!!

📖 Reference

4 Wifi

  1. The following code allows connecting to a wifi access point:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    
    const WIFI_NAME = "cpinfo";
    const WIFI_OPTIONS = { password : "javascript" };
    
    let wifi;
    function connectWifi() {
      wifi = require("Wifi");
      wifi.connect(WIFI_NAME, WIFI_OPTIONS, function(err) {
        if (err) {
          console.log("Connection error: "+err);
          return;
        }
    
        wifi.getIP((err, addr) => {
    
          if (err) {
            console.log("IP error: "+err);
            return;
          }
    
          console.log("Connected!", addr.ip);
        });
      });
    }
    
    connectWifi();
    

📖 Reference

5 Server

  1. Once we are connected to wifi, we can serve a page over http. Add the following line just after console.log("Connected!", addr.ip); from the previous section:

    1
    
    require("http").createServer(pageRequest).listen(80); // port 80
    
  2. Now add the request handler to return an html page:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    
    function pageRequest(req, res) {
      res.writeHead(200, {'Content-Type': 'text/html'});
      res.end(`
    <html>
      <body>
        <h1>Hello CPINFO</h1>
        The current time is ${new Date().toString()}
      </body>
    </html>`);
    }
    

    Notice that the inside the ` quotes, you can execute JavaScript to create dynamic strings. These are called template strings.

☑️ Exercise 5.1: Customize the page to return the current temperature, humidity, pressure.

☑️ Exercise 5.2: Imagine saving a history of the weather data… modify the program to record a log of data and return the data in the response. Consider adding a JavaScript graphing library such as chart.js into the HTML page.

📖 Reference

6 API

We can also serve multiple pages (routes) by parsing the URL sent to the Espruino.

  1. Inside the pageRequest() function add a route to get the live weather data:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    
    function pageRequest(request, res) {
      const a = url.parse(request.url, true);
    
      if (a.pathname === '/') {
        res.writeHead(200, {'Content-Type': 'text/html'});
        res.end(`
        <html>
         <!-- ... -->
        </html>`);
      } else if (a.pathname === '/data') {
        // ...
      }
    }
    

☑️ Exercise 6.1: Complete the /data route to return the live weather data from your Espruino weather station.

☑️ Bonus: Add another route /history to get the historic data.