#include <Adafruit_HTU21DF.h>
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
#include <Wire.h>
#include "NTPClient.h"
#include "data/root.html.h"
const char* ssid = "...";
const char* password = "...";
const char* alternative_ssid = "...";
const char* alternative_password = "...";
float averageTemperature;
float averageHumidity;
ESP8266WebServer server(80);
Adafruit_HTU21DF htu = Adafruit_HTU21DF();
NTPClient ntpclient("pool.ntp.org", 1);
unsigned long unixTime;
unsigned long previousMillisSensor = 0;
unsigned long previousMillisHistoryShort = 0;
unsigned long previousMillisHistoryLong = 0;
const long intervalSensor = 200;
const long intervalHistoryShort = 1000 * 5;
const long intervalHistoryLong = 1000 * 60 * 1;
typedef struct {
float temperature;
float humidity;
uint32_t timestamp;
} SHT21_DataPoint;
#define HISTORY_SHORT_SIZE (5 * 60 * 1000) / intervalHistoryShort // 5 minutes * (1 sample / 5 second)
#define HISTORY_LONG_SIZE (1 * 24 * 60 * 60 * 1000) / intervalHistoryLong // 1 days * (1 sample / 1 minutes)
typedef struct {
SHT21_DataPoint *values;
size_t current;
size_t count;
size_t capacity;
} history_t;
SHT21_DataPoint bufferShort[HISTORY_SHORT_SIZE];
SHT21_DataPoint bufferLong[HISTORY_LONG_SIZE];
history_t historyShort = {.values = bufferShort, .current = 0, .count = 0, .capacity = HISTORY_SHORT_SIZE};
history_t historyLong = {.values = bufferLong, .current = 0, .count = 0, .capacity = HISTORY_LONG_SIZE};
inline int min(int a, int b) { return ((a)<(b) ? (a) : (b)); }
void historyInit(history_t *history) {
memset(history->values, 0, history->capacity * sizeof(SHT21_DataPoint));
}
SHT21_DataPoint* historyShift(history_t *history) {
SHT21_DataPoint *next = &history->values[history->current];
if(history->count < history->capacity) {
history->count++;
}
history->current = (history->current + 1) % history->capacity;
return next;
}
SHT21_DataPoint* historyPrev(history_t *history, size_t num) {
size_t index = (history->current - 1 - num + history->capacity) % history->capacity;
return &history->values[index];
}
void readSensor();
void sendHistoryShort() {
String message = "var timeSeries = [";
for(size_t i = 0; i < min(historyShort.count, 36); i++) {
SHT21_DataPoint *cur = historyPrev(&historyShort, i);
message += (i != 0)?",{temperature:":"{temperature:";
message += cur->temperature;
message += ",humidity:";
message += cur->humidity;
message += ",timestamp:";
message += cur->timestamp;
message += "}";
}
message += "];";
server.send(200, "text/javascript", message);
}
void sendHistoryLong() {
String message = "var timeSeries = [";
for(size_t i = 0; i < min(historyLong.count, 30); i++) {
SHT21_DataPoint *cur = historyPrev(&historyLong, i);
message += (i != 0)?",{temperature:":"{temperature:";
message += cur->temperature;
message += ",humidity:";
message += cur->humidity;
message += ",timestamp:";
message += cur->timestamp;
message += "}";
}
message += "];";
server.send(200, "text/javascript", message);
}
void handleRoot() {
server.send(200, "text/html", index_html);
}
void setup(void) {
Serial.begin(115200);
Wire.pins(0, 2); //on ESP-01.
WiFi.begin(ssid, password);
// Wait for connection
Serial.print("Starting WIFI module");
unsigned short numTries = 20;
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
if(numTries-- <= 0) {
const char* tmp_ssid = ssid;
const char* tmp_password = password;
ssid = alternative_ssid;
password = alternative_password;
alternative_ssid = tmp_ssid;
alternative_password = tmp_password;
numTries = 20;
WiFi.begin(ssid, password);
}
}
Serial.println("");
Serial.print("Connected to ");
Serial.println(ssid);
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
if (MDNS.begin("esp8266")) {
Serial.println("MDNS responder started");
}
if (htu.begin()) {
Serial.println("Sensor ready");
averageTemperature = htu.readTemperature();
averageHumidity = htu.readHumidity();
historyInit(&historyShort);
historyInit(&historyLong);
}
Serial.print("Request NTP time: ");
ntpclient.begin();
unixTime = ntpclient.getRawTime();
Serial.println(unixTime);
server.on("/", handleRoot);
server.on("/history/short.js", sendHistoryShort);
server.on("/history/long.js", sendHistoryLong);
server.begin();
Serial.println("HTTP server started");
}
void loop(void) {
unsigned long currentMillis = millis();
// periodic sensor read
if (currentMillis - previousMillisSensor >= intervalSensor) {
previousMillisSensor = currentMillis;
readSensor();
}
// short term history
currentMillis = millis();
if (currentMillis - previousMillisHistoryShort >= intervalHistoryShort) {
previousMillisHistoryShort = currentMillis;
SHT21_DataPoint *sample = historyShift(&historyShort);
sample->temperature = averageTemperature;
sample->humidity = averageHumidity;
// TODO: sample timestamp as unixtime
sample->timestamp = unixTime + currentMillis / 1000;
}
// long term history
currentMillis = millis();
if (currentMillis - previousMillisHistoryLong >= intervalHistoryLong) {
previousMillisHistoryLong = currentMillis;
SHT21_DataPoint *sample = historyShift(&historyLong);
const size_t num_samples = min((intervalHistoryLong / intervalHistoryShort), historyShort.count);
for(int i = 0; i < num_samples; i++) {
SHT21_DataPoint *cur = historyPrev(&historyShort, i);
sample->temperature += cur->temperature;
sample->humidity += cur->humidity;
}
sample->temperature /= num_samples;
sample->humidity /= num_samples;
// TODO: sample timestamp as unixtime
sample->timestamp = unixTime + currentMillis / 1000;
}
// client requests
server.handleClient();
}
void readSensor(void) {
const float alpha = 0.3;
averageTemperature = alpha * htu.readTemperature() + (1 - alpha) * averageTemperature;
averageHumidity = alpha * htu.readHumidity() + (1 - alpha) * averageHumidity;
}