One of my big Todo List projects is temperature monitoring for the house. Being a big fan of wired approaches, many available solutions don’t match my requirements or are far to expensive. Luckily Olimex published the perfect plattform a while back. I finally managed to get one. Here are some insights.

The best fit for requirements I’ve found so far is the Gude 7213. It has one internal temperature and humidity sensor and ports for two more (i.e. One mid rack, one on the floor, one close to the top). It’s connected via Ethernet and offers REST API, Web and MQTT access, power is provided by PoE. While having installed them at work and being happy with them, the close to 300€ make them by far too expensive for me.

Tinkering

As everybody who has played with microcontrollers and Ethernet probably knows, it’s not a lot of fun and usually either expensive or instable…

Solution

The solution, at least for, is the ESP-POE-EA-IND from Olixmex, which at just under 30€ does the job perfectly. It’s based on a ESP32 module and comes with seriously functioning example code. Sadly “only” as Arduino/C and not micro-/circuitPython, but hey.
What made write this post right now, is the fact that I got it running in under 30 minutes and am pretty happy right now.

ESP-POE-EA-IND

Sensor

While ordering the ESP-POE-EA-IND I saw that it had a UEXT connector, which is Olimex’s interface for various sensor expansions etc. (I2C…). To make life easy I decided to order a MOD-BME280, which features a Bosch BME280 for humidity, temperature and pressure measurements.

MOD-BME280 top MOD-BME280

API

Future

Should I find the time, which I guess I won’t, I’d love to redesign the ESP-POE-EA-IND to a round shape, to fit wall boxes (Hohlwanddosen) or square, to fit the typical small junction boxes for electrics (Abzweigdose), simply to be able to properly install them. Maybe also add LSA headers for connecting the ethernet cable, instead of the RJ45 jack. Let’s see. :)

The Code

/*
 * Based on
 * https://github.com/OLIMEX/ESP32-POE/blob/master/SOFTWARE/ARDUINO/ESP32_PoE_WebServer_Demo/ESP32_PoE_WebServer_Demo.ino
 * https://github.com/OLIMEX/ESP32-POE/blob/master/SOFTWARE/ARDUINO/ESP32_PoE_MOD_BME280/ESP32_PoE_MOD_BME280.ino
*/

#include <ETH.h>
#include <WebServer.h>
#include <ESPmDNS.h>
#include <Wire.h>
#include "Adafruit_BME280.h"

#define SEALEVELPRESSURE_HPA (1013.25)  // required for MOD-BME280

Adafruit_BME280 bme; // I2C

static bool eth_connected = false;
char Buff[100];
float Temperature, Pressure, Altitude, Humidity;
WebServer server(80);

// Web Server: handle a request to / (root of the server)
void handleRoot() {
  String response = "PoE Sensor Board\n";
  response += "Available URLs\n/temperature\n/humidity\n/pressure\n/altitude\n/api";
  server.send(200, "text/plain", response);
}

// Web Server: handle a request to an unknown URI (unknown "File")
void handleNotFound() {
  String message = "File Not Found\n\n";
  message += "URI: ";
  message += server.uri();
  message += "\nMethod: ";
  message += (server.method() == HTTP_GET) ? "GET" : "POST";
  message += "\nArguments: ";
  message += server.args();
  message += "\n";
  for (uint8_t i = 0; i < server.args(); i++) {
    message += " " + server.argName(i) + ": " + server.arg(i) + "\n";
  }
  server.send(404, "text/plain", message);
}



// Initializing everything at start up / after reset:
void setup()
{
  // Wait for the hardware to initialize:
  delay(500);

  // This sketch will log some information to the serial console:


  Serial.begin(115200); // Assuming computer will be connected to serial port at 115200 bauds
  Serial.print("Setup...");
  
  // Add a handler for network events. This is misnamed "WiFi" because the ESP32 is historically WiFi only,
  // but in our case, this will react to Ethernet events.
  Serial.print("Registering event handler for ETH events...");

  
  // Starth Ethernet (this does NOT start WiFi at the same time)
  Serial.print("Starting ETH interface...");
  ETH.begin();


  // Web Server handlers: 
  // Handle a request to / (root of the server)
  server.on("/", handleRoot);
  // Minimalistic handling of another URI:
    server.on("/temperature", []() {
    get_temperature();
    server.send(200, "text/plain", String(Temperature));
  });
  server.on("/pressure", []() {
    get_pressure();
    server.send(200, "text/plain", String(Pressure));
  });
  server.on("/humidity", []() {
    get_humidity();
    server.send(200, "text/plain", String(Humidity));
  });
  server.on("/altitude", []() {
    get_altitude();
    server.send(200, "text/plain", String(Altitude));
  });
  server.on("/api", []() {
    get_temperature();
    get_humidity();
    get_pressure();
    get_altitude();
    String response ="{\n";
    response += "\"temperature\":" + String(Temperature) + ",\n";
    response += "\"humidity\":" + String(Humidity) + ",\n";
    response += "\"pressure\":" + String(Pressure) + ",\n";
    response += "\"altitude\":" + String(Altitude) + ",\n";
    response += "}";
    server.send(200, "text/json", response);
  });
  // Handle all other URIs:
  server.onNotFound(handleNotFound);

  server.begin();
  Serial.println("HTTP server started");
  
  Wire.begin (13, 16);  // init I2C on the respective pins
  bme.begin(0x77);
  get_sensors();
}

void get_temperature ()
{
  Temperature = bme.readTemperature();
}

void get_pressure ()
{
  Pressure = bme.readPressure() / 100.0F;
}

void get_altitude ()
{
  Altitude = bme.readAltitude(SEALEVELPRESSURE_HPA);
}

void get_humidity ()
{
  Humidity = bme.readHumidity();
}

void get_sensors ()
{
  get_temperature();
  get_pressure();
  get_altitude();
  get_humidity();
  sprintf (Buff, "Temperature = %.2f C\nPressure = %.2f hPa\nAltitude = %.2f m\nHumidity = %.2f %%\n\n\n", Temperature, Pressure, Altitude, Humidity);
  Serial.print (Buff);
}

void loop ()
{
  server.handleClient();
  delay(2);//allow the cpu to switch to other tasks
}