Skip to content

Instantly share code, notes, and snippets.

@Jotschi
Created October 16, 2021 15:07
Show Gist options
  • Save Jotschi/63152f665cefe56a71b0d3f2d15bd797 to your computer and use it in GitHub Desktop.
Save Jotschi/63152f665cefe56a71b0d3f2d15bd797 to your computer and use it in GitHub Desktop.
Sonoff TH10 + AM2301 Sensor OTA Sketch
#include <DHT.h>
#include <DHT_U.h>
#include <ArduinoOTA.h>
#include <ESP8266WiFi.h>
#include <ESP8266WebServer.h>
#include <HampelFilter.h>
const char *ssid = "*********";
const char *password = "********";
const int BUTTON_PIN = 0;
const int RELAY_PIN = 12;
const int BLUE_LED_PIN = 13;
#define DHTPIN 14
#define DHTTYPE DHT21
#define INTERVAL_AUTOCHECK 20
unsigned long tick = 0;
unsigned long marker = 0;
unsigned long marker2 = 0;
byte mac[6];
ESP8266WebServer server(80);
#define HUM_CAL 11
boolean relayMode = false;
DHT_Unified dht(DHTPIN, DHTTYPE);
boolean autoMode = true;
double humidityMax = 60.0;
double hys = 10;
sensors_event_t temp;
sensors_event_t humidity;
float medianHumidity;
float medianTemp;
int nMEASUREMENTS = 20; // 20 measurements over 1s each = 20s
HampelFilter humidityBuffer = HampelFilter(20, nMEASUREMENTS, 1.50);
HampelFilter tempBuffer = HampelFilter(20, nMEASUREMENTS, 1.50);
ICACHE_RAM_ATTR void buttonPress() {
toggle();
}
void toggle() {
relayMode = !relayMode;
digitalWrite(RELAY_PIN, relayMode);
}
void on() {
relayMode = true;
digitalWrite(RELAY_PIN, relayMode);
}
void off() {
relayMode = false;
digitalWrite(RELAY_PIN, relayMode);
}
void setupPins() {
pinMode(RELAY_PIN, OUTPUT);
pinMode(BLUE_LED_PIN, OUTPUT);
pinMode(BUTTON_PIN, INPUT_PULLUP);
attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), buttonPress, RISING);
}
/**
* Initialize the wifi and over the air update mechanism
*/
void initWLAN() {
Serial.println();
Serial.print("Connecting to ");
Serial.println(ssid);
// Change MAC
byte *mac = (byte *)malloc(6);
WiFi.macAddress(mac);
mac[0] = 0x20;
mac[1] = 0x11;
mac[2] = 0xCA;
mac[3] = 0x8A;
mac[4] = 0x11;
mac[5] = 0x21;
wifi_set_macaddr(STATION_IF, mac);
free(mac);
WiFi.mode(WIFI_STA);
WiFi.hostname("sonoff-big");
WiFi.begin(ssid, password);
while (WiFi.waitForConnectResult() != WL_CONNECTED) {
Serial.println("Connection Failed! Rebooting...");
delay(5000);
ESP.restart();
}
ArduinoOTA.setHostname("sonoff-big");
ArduinoOTA.onStart([]() {
String type;
if (ArduinoOTA.getCommand() == U_FLASH) {
type = "sketch";
} else {
// U_SPIFFS
type = "filesystem";
}
// NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
Serial.println("Start updating " + type);
});
ArduinoOTA.onEnd([]() {
Serial.println("\nEnd");
});
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) {
float val = (progress / (total / 100));
Serial.printf("Progress: %u%%\r", val);
});
ArduinoOTA.onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) {
Serial.println("Auth Failed");
} else if (error == OTA_BEGIN_ERROR) {
Serial.println("Begin Failed");
} else if (error == OTA_CONNECT_ERROR) {
Serial.println("Connect Failed");
} else if (error == OTA_RECEIVE_ERROR) {
Serial.println("Receive Failed");
} else if (error == OTA_END_ERROR) {
Serial.println("End Failed");
}
});
ArduinoOTA.begin();
}
void handleNotFound() {
server.send(404, "text/plain", "Not found");
}
float readCalHum() {
float hum = humidity.relative_humidity - HUM_CAL;
if (hum < 0) {
return 0;
} else {
return hum;
}
}
/**
* Add basic routes for the HTTP server
*/
void setupServer() {
/**
* Turn the power relay on
*/
server.on("/on", []() {
on();
server.send(200, "text/plain", "ON");
});
/**
* Turn the power relay off
*/
server.on("/off", []() {
off();
server.send(200, "text/plain", "OFF");
});
/**
* Return measured temperature
*/
server.on("/temp", []() {
server.send(200, "text/plain", String(temp.temperature));
});
/**
* Metrics endpoint which can be scraped by prometheus
*/
server.on("/metrics", []() {
String output = "";
output += "# TYPE humidity gauge\n";
output += "# HELP humidity Humidity value of the sensor\n";
output += "humidity " + String(readCalHum()) + "\n";
output += "# TYPE humidity_med gauge\n";
output += "# HELP humidity_med Median humidity value of the sensor\n";
output += "humidity_med " + String(medianHumidity) + "\n";
output += "# TYPE temp gauge\n";
output += "# HELP temp Humidity value of the sensor\n";
output += "temp " + String(temp.temperature) + "\n";
output += "# TYPE temp_med gauge\n";
output += "# HELP temp_med Median temperatur value of the sensor\n";
output += "temp_med " + String(medianTemp) + "\n";
output += "# TYPE humidity_max gauge\n";
output += "# HELP humidity_max Configured humidity trigger value\n";
output += "humidity_max " + String(humidityMax) + "\n";
String toggleStr = relayMode ? "1" : "0";
output += "# TYPE toggle gauge\n";
output += "# HELP toggle Current state of the relay\n";
output += "toggle " + toggleStr + "\n";
output += "# TYPE mode gauge\n";
output += "# HELP mode Mode of the ESP\n";
String modeStr = autoMode ? "1" : "0";
output += "mode " + modeStr + "\n";
server.send(200, "text/plain; version=0.0.4;charset=UTF-8", output);
});
/**
* Return the calibrated humidity value
*/
server.on("/humidity", []() {
server.send(200, "text/plain", String(readCalHum()));
});
/**
* Return the median temperature
*/
server.on("/med_temp", []() {
server.send(200, "text/plain", String(medianTemp));
});
/**
* Return the median humidity
*/
server.on("/med_humidity", []() {
server.send(200, "text/plain", String(medianHumidity));
});
/**
* Set the maximum humidity for the auto mode which turns on/off the power relay.
*/
server.on("/max_humidity", []() {
String value = server.arg("val");
if (value == "") {
server.send(200, "text/plain", "Parameter val not found");
} else {
float max = value.toFloat();
humidityMax = max;
server.send(200, "text/plain", "New maximum value set: " + String(max));
}
});
/**
* Enable the auto mode. Power relay will be enabled automatically.
*/
server.on("/auto_on", []() {
autoMode = true;
server.send(200, "text/plain", "Auto Mode enabled");
});
/**
* Disable the auto mode. Power relay will not be enabled automatically.
*/
server.on("/auto_off", []() {
autoMode = false;
server.send(200, "text/plain", "Auto Mode disabled");
});
/**
* Return the power relay state and current tick value
*/
server.on("/status", []() {
String mode = relayMode ? "ON" : "OFF";
server.send(200, "text/plain", mode + " " + String(tick));
});
server.on("/toggle", []() {
toggle();
server.send(200, "text/plain", "TOGGLE");
});
server.onNotFound(handleNotFound);
server.begin();
Serial.println("HTTP server started");
}
/**
* Setup the sensors/wifi/buttons
*/
void setup() {
Serial.begin(115200);
initWLAN();
setupPins();
setupServer();
dht.begin();
off();
}
/**
* Read the sensor values and process them.
*/
void measureValues() {
dht.humidity().getEvent(&humidity);
// Add the humidity value to the hampelfilter buffer to allow filtering
humidityBuffer.write(readCalHum());
// Update the current median value via the filter
medianHumidity = humidityBuffer.readMedian();
Serial.println("Current Humidity: " + String(humidity.relative_humidity));
Serial.println("Med Humidity: " + String(medianHumidity));
dht.temperature().getEvent(&temp);
if (!isnan(temp.temperature)) {
tempBuffer.write(temp.temperature);
}
medianTemp = tempBuffer.readMedian();
Serial.println("Current Temp: " + String(temp.temperature));
Serial.println("Med Temp: " + String(medianTemp));
Serial.println();
}
void loop() {
// Act upon OTA requests
ArduinoOTA.handle();
// Act upon HTTP client request
server.handleClient();
// Collect sensor data every 1s
if ((millis() - marker) > 1000) {
marker = millis();
measureValues();
tick++;
}
// Handle the auto mode when enabled and only every 20s
if (autoMode == true) {
if (tick >= marker2 + INTERVAL_AUTOCHECK) {
marker2 = tick + INTERVAL_AUTOCHECK;
// Enable power relay when median humidity exceeds max value + hysteresis value.
// The hysteresis value and interval check helps to avoid bogus power relay state changes
if (medianHumidity >= humidityMax + hys) {
on();
} else if (medianHumidity < humidityMax - hys) {
off();
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment