mirror of
https://github.com/revspace/operame
synced 2024-12-04 21:57:30 +00:00
Code cleanup
- Removed unused #define and 'using namespace' - Moved magic literals to global const - Reordered functions - Changed timers in main loop to simple macro instead of Timer class - Changed several identifiers - Reformatted global variable assignments
This commit is contained in:
parent
a9242b549b
commit
f4fe6e3a1e
398
operame.ino
398
operame.ino
@ -1,4 +1,3 @@
|
||||
#define Sprintf(f, ...) ({ char* s; asprintf(&s, f, __VA_ARGS__); String r = s; free(s); r; })
|
||||
#include <WiFi.h>
|
||||
#include <MQTT.h>
|
||||
#include <SPIFFS.h>
|
||||
@ -10,48 +9,36 @@
|
||||
#include <logo.h>
|
||||
#include <list>
|
||||
|
||||
using namespace std;
|
||||
|
||||
unsigned long mqtt_interval;
|
||||
const int portalbutton = 35;
|
||||
const int demobutton = 0;
|
||||
bool ota_enabled;
|
||||
int co2_warning;
|
||||
int co2_critical;
|
||||
int co2_blink;
|
||||
|
||||
enum Driver { AQC, MHZ };
|
||||
Driver driver;
|
||||
Driver driver;
|
||||
MQTTClient mqtt;
|
||||
HardwareSerial hwserial1(1);
|
||||
TFT_eSPI display;
|
||||
TFT_eSprite sprite(&display);
|
||||
MHZ19 mhz;
|
||||
|
||||
int mhz_co2_init = 410; // magic value reported while initializing
|
||||
const int pin_portalbutton = 35;
|
||||
const int pin_demobutton = 0;
|
||||
const int pin_backlight = 4;
|
||||
const int pin_sensor_rx = 27;
|
||||
const int pin_sensor_tx = 26;
|
||||
const int pin_pcb_ok = 12; // pulled to GND by PCB trace
|
||||
int mhz_co2_init = 410; // magic value reported during init
|
||||
|
||||
MQTTClient mqtt;
|
||||
HardwareSerial hwserial1(1);
|
||||
TFT_eSPI display;
|
||||
TFT_eSprite sprite(&display);
|
||||
MHZ19 mhz;
|
||||
String mqtt_topic;
|
||||
String mqtt_template;
|
||||
bool add_units;
|
||||
bool wifi_enabled;
|
||||
bool mqtt_enabled;
|
||||
int max_failures;
|
||||
// Configuration via WiFiSettings
|
||||
unsigned long mqtt_interval;
|
||||
bool ota_enabled;
|
||||
int co2_warning;
|
||||
int co2_critical;
|
||||
int co2_blink;
|
||||
String mqtt_topic;
|
||||
String mqtt_template;
|
||||
bool add_units;
|
||||
bool wifi_enabled;
|
||||
bool mqtt_enabled;
|
||||
int max_failures;
|
||||
|
||||
struct Timer {
|
||||
unsigned long previous;
|
||||
unsigned long interval;
|
||||
std::function<void()> function;
|
||||
void operator()() {
|
||||
if (millis() - previous >= interval) {
|
||||
function();
|
||||
previous = millis();
|
||||
}
|
||||
}
|
||||
Timer(unsigned long ms, std::function<void()> f)
|
||||
: interval(ms), function(f) {}
|
||||
};
|
||||
|
||||
void retain(String topic, String message) {
|
||||
void retain(const String& topic, const String& message) {
|
||||
Serial.printf("%s %s\n", topic.c_str(), message.c_str());
|
||||
mqtt.publish(topic, message, true, 0);
|
||||
}
|
||||
@ -103,47 +90,6 @@ void display_logo() {
|
||||
sprite.pushSprite(0, 0);
|
||||
}
|
||||
|
||||
void panic(const String& message) {
|
||||
display_big(message, TFT_RED);
|
||||
delay(5000);
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
void setup_ota() {
|
||||
ArduinoOTA.setHostname(WiFiSettings.hostname.c_str());
|
||||
ArduinoOTA.setPassword(WiFiSettings.password.c_str());
|
||||
ArduinoOTA.onStart( []() { display_big("OTA", TFT_BLUE); });
|
||||
ArduinoOTA.onEnd( []() { display_big("OTA done", TFT_GREEN); });
|
||||
ArduinoOTA.onError( [](ota_error_t e) { display_big("OTA failed", TFT_RED); });
|
||||
ArduinoOTA.onProgress([](unsigned int p, unsigned int t) {
|
||||
String pct { (int) ((float) p / t * 100) };
|
||||
display_big(pct + "%");
|
||||
});
|
||||
ArduinoOTA.begin();
|
||||
}
|
||||
|
||||
bool button(int pin) {
|
||||
if (digitalRead(pin)) return false;
|
||||
unsigned long start = millis();
|
||||
while (!digitalRead(pin)) {
|
||||
if (millis() - start >= 50) display_big("");
|
||||
}
|
||||
return millis() - start >= 50;
|
||||
}
|
||||
|
||||
void check_portalbutton() {
|
||||
if (button(portalbutton)) WiFiSettings.portal();
|
||||
}
|
||||
|
||||
void check_demobutton() {
|
||||
if (button(demobutton)) ppm_demo();
|
||||
}
|
||||
|
||||
void check_buttons() {
|
||||
check_portalbutton();
|
||||
check_demobutton();
|
||||
}
|
||||
|
||||
void display_ppm(int ppm) {
|
||||
int fg, bg;
|
||||
if (ppm >= co2_critical) {
|
||||
@ -170,7 +116,7 @@ void ppm_demo() {
|
||||
delay(1000);
|
||||
for (int p = 400; p < 1200; p++) {
|
||||
display_ppm(p);
|
||||
if (button(demobutton)) {
|
||||
if (button(pin_demobutton)) {
|
||||
display_logo();
|
||||
delay(500);
|
||||
return;
|
||||
@ -181,27 +127,162 @@ void ppm_demo() {
|
||||
delay(5000);
|
||||
}
|
||||
|
||||
void panic(const String& message) {
|
||||
display_big(message, TFT_RED);
|
||||
delay(5000);
|
||||
ESP.restart();
|
||||
}
|
||||
|
||||
bool button(int pin) {
|
||||
if (digitalRead(pin)) return false;
|
||||
unsigned long start = millis();
|
||||
while (!digitalRead(pin)) {
|
||||
if (millis() - start >= 50) display_big("");
|
||||
}
|
||||
return millis() - start >= 50;
|
||||
}
|
||||
|
||||
void check_portalbutton() {
|
||||
if (button(pin_portalbutton)) WiFiSettings.portal();
|
||||
}
|
||||
|
||||
void check_demobutton() {
|
||||
if (button(pin_demobutton)) ppm_demo();
|
||||
}
|
||||
|
||||
void check_buttons() {
|
||||
check_portalbutton();
|
||||
check_demobutton();
|
||||
}
|
||||
|
||||
void setup_ota() {
|
||||
ArduinoOTA.setHostname(WiFiSettings.hostname.c_str());
|
||||
ArduinoOTA.setPassword(WiFiSettings.password.c_str());
|
||||
ArduinoOTA.onStart( []() { display_big("OTA", TFT_BLUE); });
|
||||
ArduinoOTA.onEnd( []() { display_big("OTA done", TFT_GREEN); });
|
||||
ArduinoOTA.onError( [](ota_error_t e) { display_big("OTA failed", TFT_RED); });
|
||||
ArduinoOTA.onProgress([](unsigned int p, unsigned int t) {
|
||||
String pct { (int) ((float) p / t * 100) };
|
||||
display_big(pct + "%");
|
||||
});
|
||||
ArduinoOTA.begin();
|
||||
}
|
||||
|
||||
void connect_mqtt() {
|
||||
if (mqtt.connected()) return; // already/still connected
|
||||
|
||||
static int failures = 0;
|
||||
if (mqtt.connect(WiFiSettings.hostname.c_str())) {
|
||||
failures = 0;
|
||||
} else {
|
||||
failures++;
|
||||
if (failures >= max_failures) panic("MQTT onbereikbaar");
|
||||
}
|
||||
}
|
||||
|
||||
int aqc_get_co2() {
|
||||
static bool initialized = false;
|
||||
|
||||
const uint8_t command[9] = { 0xff, 0x01, 0xc5, 0, 0, 0, 0, 0, 0x3a };
|
||||
uint8_t response[9];
|
||||
int co2 = -1;
|
||||
|
||||
for (int attempt = 0; attempt < 3; attempt++) {
|
||||
hwserial1.flush();
|
||||
int limit = 20; // .available() sometimes stays true
|
||||
while(hwserial1.available() && --limit) hwserial1.read();
|
||||
|
||||
hwserial1.write(command, sizeof(command));
|
||||
delay(50);
|
||||
size_t c = hwserial1.readBytes(response, sizeof(response));
|
||||
if (c != sizeof(response) || response[0] != 0xff || response[1] != 0x86) {
|
||||
continue;
|
||||
}
|
||||
uint8_t checksum = 255;
|
||||
for (int i = 0; i < sizeof(response) - 1; i++) {
|
||||
checksum -= response[i];
|
||||
}
|
||||
if (response[8] == checksum) {
|
||||
co2 = response[2] * 256 + response[3];
|
||||
break;
|
||||
}
|
||||
delay(50);
|
||||
}
|
||||
|
||||
if (co2 < 0) {
|
||||
initialized = false;
|
||||
return co2;
|
||||
}
|
||||
|
||||
if (!initialized && (co2 == 9999 || co2 == 400)) return 0;
|
||||
initialized = true;
|
||||
return co2;
|
||||
}
|
||||
|
||||
void mhz_setup() {
|
||||
mhz.begin(hwserial1);
|
||||
// mhz.setFilter(true, true); Library filter doesn't handle 0436
|
||||
mhz.autoCalibration(true);
|
||||
char v[5] = {};
|
||||
mhz.getVersion(v);
|
||||
v[4] = '\0';
|
||||
if (strcmp("0436", v) == 0) mhz_co2_init = 436;
|
||||
}
|
||||
|
||||
int mhz_get_co2() {
|
||||
int co2 = mhz.getCO2();
|
||||
int unclamped = mhz.getCO2(false);
|
||||
|
||||
if (mhz.errorCode != RESULT_OK) {
|
||||
delay(500);
|
||||
mhz_setup();
|
||||
return -1;
|
||||
}
|
||||
|
||||
// reimplement filter from library, but also checking for 436 because our
|
||||
// sensors (firmware 0436, coincidence?) return that instead of 410...
|
||||
if (unclamped == mhz_co2_init && co2 - unclamped >= 10) return 0;
|
||||
|
||||
// No known sensors support >10k PPM (library filter tests for >32767)
|
||||
if (co2 > 10000 || unclamped > 10000) return 0;
|
||||
|
||||
return co2;
|
||||
}
|
||||
|
||||
int get_co2() {
|
||||
// <0 means read error, 0 means still initializing, >0 is PPM value
|
||||
|
||||
if (driver == AQC) return aqc_get_co2();
|
||||
if (driver == MHZ) return mhz_get_co2();
|
||||
|
||||
// Should be unreachable
|
||||
panic("driverfout");
|
||||
return -1; // suppress warning
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
Serial.println("Operame start");
|
||||
SPIFFS.begin(true);
|
||||
pinMode(portalbutton, INPUT_PULLUP);
|
||||
pinMode(demobutton, INPUT_PULLUP);
|
||||
pinMode(4, OUTPUT);
|
||||
digitalWrite(4, HIGH);
|
||||
|
||||
pinMode(pin_portalbutton, INPUT_PULLUP);
|
||||
pinMode(pin_demobutton, INPUT_PULLUP);
|
||||
pinMode(pin_pcb_ok, INPUT_PULLUP);
|
||||
pinMode(pin_backlight, OUTPUT);
|
||||
|
||||
digitalWrite(pin_backlight, HIGH);
|
||||
|
||||
display.init();
|
||||
display.fillScreen(TFT_BLACK);
|
||||
display.setRotation(1);
|
||||
sprite.createSprite(display.width(), display.height());
|
||||
|
||||
pinMode(12, INPUT_PULLUP);
|
||||
while (digitalRead(12)) {
|
||||
while (digitalRead(pin_pcb_ok)) {
|
||||
display_big("module verkeerd om!", TFT_RED);
|
||||
delay(1000);
|
||||
}
|
||||
|
||||
hwserial1.begin(9600, SERIAL_8N1, 27, 26);
|
||||
hwserial1.begin(9600, SERIAL_8N1, pin_sensor_rx, pin_sensor_tx);
|
||||
|
||||
if (aqc_get_co2() >= 0) {
|
||||
driver = AQC;
|
||||
@ -298,7 +379,7 @@ void setup() {
|
||||
}
|
||||
|
||||
if (ota_enabled) ArduinoOTA.handle();
|
||||
if (button(portalbutton)) ESP.restart();
|
||||
if (button(pin_portalbutton)) ESP.restart();
|
||||
};
|
||||
|
||||
if (wifi_enabled) WiFiSettings.connect(false, 15);
|
||||
@ -309,139 +390,36 @@ void setup() {
|
||||
if (ota_enabled) setup_ota();
|
||||
}
|
||||
|
||||
void connect_mqtt() {
|
||||
if (mqtt.connected()) return; // already/still connected
|
||||
|
||||
static int failures = 0;
|
||||
if (mqtt.connect(WiFiSettings.hostname.c_str())) {
|
||||
failures = 0;
|
||||
} else {
|
||||
failures++;
|
||||
if (failures >= max_failures) panic("MQTT onbereikbaar");
|
||||
}
|
||||
}
|
||||
|
||||
int aqc_get_co2() {
|
||||
static bool initialized = false;
|
||||
|
||||
const uint8_t command[9] = { 0xff, 0x01, 0xc5, 0, 0, 0, 0, 0, 0x3a };
|
||||
uint8_t response[9];
|
||||
int co2 = -1;
|
||||
|
||||
for (int attempt = 0; attempt < 3; attempt++) {
|
||||
hwserial1.flush();
|
||||
int limit = 20; // .available() sometimes stays true
|
||||
while(hwserial1.available() && --limit) hwserial1.read();
|
||||
|
||||
hwserial1.write(command, sizeof(command));
|
||||
delay(50);
|
||||
size_t c = hwserial1.readBytes(response, sizeof(response));
|
||||
if (c != sizeof(response) || response[0] != 0xff || response[1] != 0x86) {
|
||||
continue;
|
||||
}
|
||||
uint8_t checksum = 255;
|
||||
for (int i = 0; i < sizeof(response) - 1; i++) {
|
||||
checksum -= response[i];
|
||||
}
|
||||
if (response[8] == checksum) {
|
||||
co2 = response[2] * 256 + response[3];
|
||||
break;
|
||||
}
|
||||
delay(50);
|
||||
}
|
||||
|
||||
if (co2 < 0) {
|
||||
initialized = false;
|
||||
return co2;
|
||||
}
|
||||
|
||||
if (!initialized && (co2 == 9999 || co2 == 400)) return 0;
|
||||
initialized = true;
|
||||
return co2;
|
||||
}
|
||||
|
||||
void mhz_setup() {
|
||||
mhz.begin(hwserial1);
|
||||
// mhz.setFilter(true, true); Library filter doesn't handle 0436
|
||||
mhz.autoCalibration(true);
|
||||
char v[5] = {};
|
||||
mhz.getVersion(v);
|
||||
v[4] = '\0';
|
||||
if (strcmp("0436", v) == 0) mhz_co2_init = 436;
|
||||
}
|
||||
|
||||
int mhz_get_co2() {
|
||||
int co2 = mhz.getCO2();
|
||||
int unclamped = mhz.getCO2(false);
|
||||
|
||||
if (mhz.errorCode != RESULT_OK) {
|
||||
delay(500);
|
||||
mhz_setup();
|
||||
return -1;
|
||||
}
|
||||
|
||||
// reimplement filter from library, but also checking for 436 because our
|
||||
// sensors (firmware 0436, coincidence?) return that instead of 410...
|
||||
if (unclamped == mhz_co2_init && co2 - unclamped >= 10) return 0;
|
||||
|
||||
// No known sensors support >10k PPM (library filter tests for >32767)
|
||||
if (co2 > 10000 || unclamped > 10000) return 0;
|
||||
|
||||
return co2;
|
||||
}
|
||||
|
||||
int get_co2() {
|
||||
// <0 means read error, 0 means still initializing, >0 is PPM value
|
||||
|
||||
if (driver == AQC) return aqc_get_co2();
|
||||
if (driver == MHZ) return mhz_get_co2();
|
||||
|
||||
// Should be unreachable
|
||||
panic("driverfout");
|
||||
return -1; // suppress warning
|
||||
}
|
||||
|
||||
#define every(t) for (static uint16_t _lasttime; (uint16_t)((uint16_t)millis() - _lasttime) >= (t); _lasttime += (t))
|
||||
|
||||
void loop() {
|
||||
static int co2;
|
||||
|
||||
static Timer read_sensor {
|
||||
5000,
|
||||
[] {
|
||||
co2 = get_co2();
|
||||
Serial.println(co2);
|
||||
}
|
||||
};
|
||||
read_sensor();
|
||||
every(5000) {
|
||||
co2 = get_co2();
|
||||
Serial.println(co2);
|
||||
}
|
||||
|
||||
static Timer display {
|
||||
50,
|
||||
[] {
|
||||
if (co2 < 0) {
|
||||
display_big("sensorfout", TFT_RED);
|
||||
} else if (co2 == 0) {
|
||||
display_big("wacht...");
|
||||
} else {
|
||||
// some MH-Z19's go to 10000 but the display has space for 4 digits
|
||||
display_ppm(co2 > 9999 ? 9999 : co2);
|
||||
}
|
||||
every(50) {
|
||||
if (co2 < 0) {
|
||||
display_big("sensorfout", TFT_RED);
|
||||
} else if (co2 == 0) {
|
||||
display_big("wacht...");
|
||||
} else {
|
||||
// some MH-Z19's go to 10000 but the display has space for 4 digits
|
||||
display_ppm(co2 > 9999 ? 9999 : co2);
|
||||
}
|
||||
};
|
||||
display();
|
||||
}
|
||||
|
||||
static Timer publish {
|
||||
mqtt_interval,
|
||||
[] {
|
||||
if (co2 <= 0) return;
|
||||
if (mqtt_enabled) {
|
||||
mqtt.loop();
|
||||
every(mqtt_interval) {
|
||||
if (co2 <= 0) break;
|
||||
connect_mqtt();
|
||||
String message = mqtt_template;
|
||||
message.replace("{}", String(co2));
|
||||
retain(mqtt_topic, message);
|
||||
}
|
||||
};
|
||||
if (mqtt_enabled) {
|
||||
mqtt.loop();
|
||||
publish();
|
||||
}
|
||||
|
||||
if (ota_enabled) ArduinoOTA.handle();
|
||||
|
Loading…
Reference in New Issue
Block a user