it was fun
This commit is contained in:
@@ -0,0 +1,212 @@
|
||||
#include <ESP8266WiFi.h>
|
||||
#include <ESP8266HTTPClient.h>
|
||||
#include <ArduinoJson.h>
|
||||
#include <U8g2lib.h>
|
||||
|
||||
#ifdef U8X8_HAVE_HW_SPI
|
||||
#include <SPI.h>
|
||||
#endif
|
||||
#ifdef U8X8_HAVE_HW_I2C
|
||||
#include <Wire.h>
|
||||
#endif
|
||||
|
||||
#define OLED_SCL 14
|
||||
#define OLED_SDA 12
|
||||
|
||||
#define UPDATE_INTERVAL_MS 1000
|
||||
|
||||
#define SERVER_URL "http://awair-server/air-data/latest"
|
||||
|
||||
#define SSID "-"
|
||||
#define PASSWD "-"
|
||||
|
||||
WiFiClient client;
|
||||
HTTPClient http;
|
||||
|
||||
struct AwairData{
|
||||
private:
|
||||
int score = 0;
|
||||
float temp = .0f;
|
||||
float humid = .0f;
|
||||
int co2 = 0;
|
||||
int voc = 0;
|
||||
int pm25 = 0;
|
||||
|
||||
bool updated = false;
|
||||
|
||||
template <typename T>
|
||||
void update_var(T* var, T value){
|
||||
if(*var == value) return;
|
||||
*var = value;
|
||||
updated = true;
|
||||
}
|
||||
|
||||
public:
|
||||
void set_score(int value){ update_var<int>(&score, value); }
|
||||
void set_temp(float value){ update_var<float>(&temp, value); }
|
||||
void set_humid(float value){ update_var<float>(&humid, value); }
|
||||
void set_co2(int value){ update_var<int>(&co2, value); }
|
||||
void set_voc(int value){ update_var<int>(&voc, value); }
|
||||
void set_pm25(int value){ update_var<int>(&pm25, value); }
|
||||
|
||||
int get_score(void) const { return score; }
|
||||
float get_temp(void) const { return temp; }
|
||||
float get_humid(void) const { return humid; }
|
||||
int get_co2(void) const { return co2; }
|
||||
int get_voc(void) const { return voc; }
|
||||
int get_pm25(void) const { return pm25; }
|
||||
|
||||
void update(int score, float temp, float humid, int co2, int voc, int pm25){
|
||||
set_score(score);
|
||||
set_temp(temp);
|
||||
set_humid(humid);
|
||||
set_co2(co2);
|
||||
set_voc(voc);
|
||||
set_pm25(pm25);
|
||||
}
|
||||
|
||||
bool has_updated(void) const { return updated; }
|
||||
void reset_updated(void){ updated = false; }
|
||||
};
|
||||
|
||||
class Panel{
|
||||
private:
|
||||
U8G2_SSD1306_128X64_NONAME_F_SW_I2C panel;
|
||||
|
||||
public:
|
||||
Panel() : panel(U8G2_R0, OLED_SCL, OLED_SDA, U8X8_PIN_NONE){}
|
||||
|
||||
void begin(void){
|
||||
panel.begin();
|
||||
}
|
||||
|
||||
void show_failed(void){
|
||||
panel.clearBuffer();
|
||||
panel.setFont(u8g2_font_ncenB08_tr);
|
||||
panel.drawStr(0, 10, "Something failed");
|
||||
panel.sendBuffer();
|
||||
}
|
||||
|
||||
void update(const AwairData& data){
|
||||
char buffer[16];
|
||||
|
||||
panel.clearBuffer();
|
||||
|
||||
panel.setFont(u8g2_font_ncenB08_tr);
|
||||
panel.drawStr(0, 9, "Score:");
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "%d", data.get_score());
|
||||
panel.drawStr(42, 9, buffer);
|
||||
|
||||
panel.drawHLine(0, 12, 128);
|
||||
|
||||
panel.setFont(u8g2_font_6x10_tr);
|
||||
|
||||
panel.drawStr(0, 24, "Temp");
|
||||
snprintf(buffer, sizeof(buffer), "%.1f C", data.get_temp());
|
||||
panel.drawStr(0, 35, buffer);
|
||||
|
||||
panel.drawStr(68, 24, "Humid");
|
||||
snprintf(buffer, sizeof(buffer), "%.1f %%", data.get_humid());
|
||||
panel.drawStr(68, 35, buffer);
|
||||
|
||||
panel.drawStr(0, 47, "CO2");
|
||||
panel.drawStr(47, 47, "VOC");
|
||||
panel.drawStr(87, 47, "PM2.5");
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "%d", data.get_co2());
|
||||
panel.drawStr(0, 59, buffer);
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "%d", data.get_voc());
|
||||
panel.drawStr(47, 59, buffer);
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "%d", data.get_pm25());
|
||||
panel.drawStr(87, 59, buffer);
|
||||
|
||||
panel.sendBuffer();
|
||||
}
|
||||
};
|
||||
|
||||
bool parseAwairJson(const String& payload, AwairData& data) {
|
||||
JsonDocument doc;
|
||||
|
||||
auto error = deserializeJson(doc, payload);
|
||||
if(error){
|
||||
Serial.print("JSON error: ");
|
||||
Serial.println(error.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
int score = doc["score"] | 0;
|
||||
float temp = doc["temp"] | .0f;
|
||||
float humid = doc["humid"] | .0f;
|
||||
int co2 = doc["co2"] | 0;
|
||||
int voc = doc["voc"] | 0;
|
||||
int pm25 = doc["pm25"] | 0;
|
||||
|
||||
data.update(score, temp, humid, co2, voc, pm25);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int request_data(AwairData* data){
|
||||
if(!http.begin(client, SERVER_URL)){
|
||||
Serial.println("Failed to request URL!");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int http_code = http.GET();
|
||||
int result = 1;
|
||||
if(http_code == HTTP_CODE_OK){
|
||||
if(parseAwairJson(http.getString(), *data)) result = 0;
|
||||
}
|
||||
else{
|
||||
Serial.print("Failed GET request: ");
|
||||
Serial.println(http_code, 10);
|
||||
}
|
||||
|
||||
http.end();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Panel panel;
|
||||
AwairData data;
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
panel.begin();
|
||||
|
||||
http.setTimeout(3000);
|
||||
|
||||
WiFi.begin(SSID, PASSWD);
|
||||
while(WiFi.status() != WL_CONNECTED) delay(100);
|
||||
|
||||
Serial.println("Connected!");
|
||||
}
|
||||
|
||||
void loop() {
|
||||
/*
|
||||
static auto start = millis() - UPDATE_INTERVAL_MS;
|
||||
auto current = millis();
|
||||
|
||||
if(current - start < UPDATE_INTERVAL_MS) return;
|
||||
start = current;
|
||||
*/
|
||||
|
||||
if(WiFi.status() != WL_CONNECTED){ delay(100); return; }
|
||||
|
||||
Serial.println("Requesting data...");
|
||||
if(request_data(&data) != 0){ panel.show_failed(); }
|
||||
|
||||
if(data.has_updated()){
|
||||
Serial.println("Got new data -> Updating...");
|
||||
panel.update(data);
|
||||
data.reset_updated();
|
||||
}
|
||||
else Serial.println("Got data but nothing new!");
|
||||
|
||||
Serial.println("---------- ---------- ----------\n");
|
||||
delay(UPDATE_INTERVAL_MS); // simple delay is enough <- no state machine
|
||||
}
|
||||
Reference in New Issue
Block a user