|
|
@ -32,6 +32,8 @@ |
|
|
|
#include "network/XD0OTA.h" |
|
|
|
#include "network/XD0MQTT.h" |
|
|
|
|
|
|
|
#include <ArduinoJson.h> |
|
|
|
|
|
|
|
#include "SensorHistory.h" |
|
|
|
|
|
|
|
#include "icons.h" |
|
|
@ -57,8 +59,10 @@ SdsDustSensor sds(Serial2); |
|
|
|
Adafruit_VEML6075 uv = Adafruit_VEML6075(); |
|
|
|
BH1750 lightMeter; |
|
|
|
|
|
|
|
XD0OTA ota("esp32-weatherstation"); |
|
|
|
constexpr unsigned int JSON_BUF_LEN = 512; |
|
|
|
constexpr unsigned int JSON_CAPACITY = JSON_OBJECT_SIZE(16) + 0*JSON_ARRAY_SIZE(2) + 120; |
|
|
|
XD0MQTT mqtt; |
|
|
|
XD0OTA ota("esp32-weatherstation"); |
|
|
|
|
|
|
|
struct __attribute__((packed)) network_t { |
|
|
|
uint32_t ip; |
|
|
@ -374,9 +378,11 @@ void getSensorMeasurements() { |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
void receiveMqtt(const char* topic, const char* data) { |
|
|
|
void receiveMqtt(const char* topic, const char* data, int data_len) { |
|
|
|
sensor_readings_t* sensor = NULL; |
|
|
|
|
|
|
|
ESP_LOGI(TAG, "received MQTT message on subscribed topic %s", topic); |
|
|
|
|
|
|
|
if (strstr(topic, "thomas/sensor/a4cf1211c3e4") == topic) { |
|
|
|
sensor = &sensors_a4cf1211c3e4; |
|
|
|
} else if (strstr(topic, "thomas/sensor/246f28d1fa5c") == topic) { |
|
|
@ -390,8 +396,32 @@ void receiveMqtt(const char* topic, const char* data) { |
|
|
|
char* topic_last = strrchr(topic, '/'); |
|
|
|
|
|
|
|
if (topic_last && sensor) { |
|
|
|
if (strcmp("/temperature", topic_last) == 0) { |
|
|
|
if (strcmp("/json", topic_last) == 0) { |
|
|
|
StaticJsonDocument<JSON_CAPACITY+120> jsonDoc; |
|
|
|
DeserializationError err = deserializeJson(jsonDoc, data, data_len); |
|
|
|
if (err) { |
|
|
|
ESP_LOGW(TAG, "Error parsing JSON, code: %s", err.c_str()); |
|
|
|
} else { |
|
|
|
// got json
|
|
|
|
sensor->temperature = jsonDoc["temperature"].as<float>(); |
|
|
|
sensor->humidity = jsonDoc["humidity"].as<float>(); |
|
|
|
sensor->pressure = jsonDoc["pressure"].as<float>(); |
|
|
|
sensor->voc = jsonDoc["voc"].as<uint32_t>(); |
|
|
|
sensor->lux = jsonDoc["lux"].as<float>(); |
|
|
|
sensor->uvi = jsonDoc["uvi"].as<float>(); |
|
|
|
sensor->uva = jsonDoc["uva"].as<float>(); |
|
|
|
sensor->uvb = jsonDoc["uvb"].as<float>(); |
|
|
|
sensor->pm10 = jsonDoc["pm10"].as<float>(); |
|
|
|
sensor->pm25 = jsonDoc["pm2.5"].as<float>(); |
|
|
|
sensor->battery = jsonDoc["voltage"].as<int>(); |
|
|
|
sensor->rssi = jsonDoc["rssi"].as<int8_t>(); |
|
|
|
sensor->lastUpdate = jsonDoc["timestamp"].as<time_t>(); |
|
|
|
ESP_LOGI(TAG, "got new values from %s, timestamp: %lu", topic, sensor->lastUpdate); |
|
|
|
ESP_LOGI(TAG, "%lu seconds ago", topic, getTimestamp() - sensor->lastUpdate); |
|
|
|
} |
|
|
|
} else if (strcmp("/temperature", topic_last) == 0) { |
|
|
|
sensor->temperature = atof(data); |
|
|
|
sensor->lastUpdate = getTimestamp(); |
|
|
|
} else if (strcmp("/humidity", topic_last) == 0) { |
|
|
|
sensor->humidity = atof(data); |
|
|
|
} else if (strcmp("/pressure", topic_last) == 0) { |
|
|
@ -411,7 +441,6 @@ void receiveMqtt(const char* topic, const char* data) { |
|
|
|
} else if (strcmp("/voc", topic_last) == 0) { |
|
|
|
sensor->voc = atof(data); |
|
|
|
} |
|
|
|
sensor->lastUpdate = getTimestamp(); // ToDo
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
@ -426,6 +455,7 @@ void displayValues() { |
|
|
|
char timeStr[40]; |
|
|
|
getTime(timeStr, sizeof(timeStr), "%d. %b %Y %H:%M:%S"); |
|
|
|
|
|
|
|
ESP_LOGD(TAG, "displayValues()"); |
|
|
|
|
|
|
|
if (display.epd2.hasFastPartialUpdate) { |
|
|
|
display.setPartialWindow(0, 0, display.width(), display.height()); |
|
|
@ -608,21 +638,57 @@ void displayValues() { |
|
|
|
|
|
|
|
|
|
|
|
void sendValues() { |
|
|
|
for (int tries=0; mqtt.isConnected() == false && tries < 10; tries++) { |
|
|
|
ESP_LOGD(TAG, "waiting for mqtt connection"); |
|
|
|
delay(300); |
|
|
|
} |
|
|
|
|
|
|
|
/* send values MQTT JSON */ |
|
|
|
char buf[JSON_BUF_LEN]; |
|
|
|
StaticJsonDocument<JSON_CAPACITY> jsonDoc; |
|
|
|
if (sensors_active.bme280 || sensors_active.bme680) { |
|
|
|
jsonDoc["temperature"] = sensor_readings.temperature; |
|
|
|
jsonDoc["humidity"] = sensor_readings.humidity; |
|
|
|
jsonDoc["pressure"] = sensor_readings.pressure; |
|
|
|
} |
|
|
|
if (sensors_active.bme680) { |
|
|
|
jsonDoc["voc"] = sensor_readings.voc; |
|
|
|
} |
|
|
|
if (sensors_active.light) { |
|
|
|
jsonDoc["lux"] = sensor_readings.lux; |
|
|
|
} |
|
|
|
if (sensors_active.uv) { |
|
|
|
jsonDoc["uvi"] = sensor_readings.uvi; |
|
|
|
jsonDoc["uva"] = sensor_readings.uva; |
|
|
|
jsonDoc["uvb"] = sensor_readings.uvb; |
|
|
|
} |
|
|
|
if (sensors_active.sds) { |
|
|
|
jsonDoc["pm10"] = sensor_readings.pm10; |
|
|
|
jsonDoc["pm2.5"] = sensor_readings.pm25; |
|
|
|
} |
|
|
|
jsonDoc["voltage"] = sensor_readings.battery; |
|
|
|
jsonDoc["rssi"] = sensor_readings.rssi; |
|
|
|
jsonDoc["timestamp"] = sensor_readings.lastUpdate; |
|
|
|
serializeJson(jsonDoc, buf, JSON_BUF_LEN); |
|
|
|
String topic_json = String("thomas/sensor/") + ota.getMAC() + String("/json"); |
|
|
|
mqtt.publish(topic_json.c_str(), buf, strlen(buf), 1, 1); |
|
|
|
delay(10); |
|
|
|
|
|
|
|
/* send values MQTT */ |
|
|
|
if (sensors_active.bme280 || sensors_active.bme680) { |
|
|
|
String topic_temperature = String("thomas/sensor/") + ota.getMAC() + String("/temperature"); |
|
|
|
String topic_humidity = String("thomas/sensor/") + ota.getMAC() + String("/humidity"); |
|
|
|
String topic_pressure = String("thomas/sensor/") + ota.getMAC() + String("/pressure"); |
|
|
|
mqtt.publishf2(topic_temperature.c_str(), 1, 1, "%.2f", sensor_readings.temperature); |
|
|
|
mqtt.publishf(topic_temperature.c_str(), "%.2f", sensor_readings.temperature); |
|
|
|
delay(10); |
|
|
|
mqtt.publishf2(topic_humidity.c_str(), 1, 1, "%.2f", sensor_readings.humidity); |
|
|
|
mqtt.publishf(topic_humidity.c_str(), "%.2f", sensor_readings.humidity); |
|
|
|
delay(10); |
|
|
|
mqtt.publishf2(topic_pressure.c_str(), 1, 1, "%.2f", sensor_readings.pressure); |
|
|
|
mqtt.publishf(topic_pressure.c_str(), "%.2f", sensor_readings.pressure); |
|
|
|
delay(10); |
|
|
|
} |
|
|
|
if (sensors_active.bme680) { |
|
|
|
String topic_voc = String("thomas/sensor/") + ota.getMAC() + String("/voc"); |
|
|
|
mqtt.publishf2(topic_voc.c_str(), 1, 1, "%.2f", sensor_readings.voc / 1000.0F); |
|
|
|
mqtt.publishf(topic_voc.c_str(), "%.2f", sensor_readings.voc / 1000.0F); |
|
|
|
delay(10); |
|
|
|
} |
|
|
|
|
|
|
@ -630,35 +696,35 @@ void sendValues() { |
|
|
|
String topic_uvi = String("thomas/sensor/") + ota.getMAC() + String("/uvi"); |
|
|
|
String topic_uva = String("thomas/sensor/") + ota.getMAC() + String("/uva"); |
|
|
|
String topic_uvb = String("thomas/sensor/") + ota.getMAC() + String("/uvb"); |
|
|
|
mqtt.publishf2(topic_uvi.c_str(), 1, 1, "%.2f", sensor_readings.uvi); |
|
|
|
mqtt.publishf2(topic_uva.c_str(), 1, 1, "%.2f", sensor_readings.uva); |
|
|
|
mqtt.publishf2(topic_uvb.c_str(), 1, 1, "%.2f", sensor_readings.uvb); |
|
|
|
mqtt.publishf(topic_uvi.c_str(), "%.2f", sensor_readings.uvi); |
|
|
|
mqtt.publishf(topic_uva.c_str(), "%.2f", sensor_readings.uva); |
|
|
|
mqtt.publishf(topic_uvb.c_str(), "%.2f", sensor_readings.uvb); |
|
|
|
delay(10); |
|
|
|
} |
|
|
|
|
|
|
|
if (sensors_active.light) { |
|
|
|
String topic_lux = String("thomas/sensor/") + ota.getMAC() + String("/lux"); |
|
|
|
mqtt.publishf2(topic_lux.c_str(), 1, 1, "%.2f", sensor_readings.lux); |
|
|
|
mqtt.publishf(topic_lux.c_str(), "%.2f", sensor_readings.lux); |
|
|
|
delay(10); |
|
|
|
} |
|
|
|
|
|
|
|
if (sensors_active.sds) { |
|
|
|
String topic_pm10 = String("thomas/sensor/") + ota.getMAC() + String("/pm10"); |
|
|
|
String topic_pm25 = String("thomas/sensor/") + ota.getMAC() + String("/pm25"); |
|
|
|
mqtt.publishf2(topic_pm10.c_str(), 1, 1, "%.2f", sensor_readings.pm10); |
|
|
|
mqtt.publishf2(topic_pm25.c_str(), 1, 1, "%.2f", sensor_readings.pm25); |
|
|
|
mqtt.publishf(topic_pm10.c_str(), "%.2f", sensor_readings.pm10); |
|
|
|
mqtt.publishf(topic_pm25.c_str(), "%.2f", sensor_readings.pm25); |
|
|
|
delay(10); |
|
|
|
} |
|
|
|
|
|
|
|
{ |
|
|
|
String topic_battery = String("thomas/sensor/") + ota.getMAC() + String("/battery"); |
|
|
|
mqtt.publishf2(topic_battery.c_str(), 1, 1, "%.2f", (sensor_readings.battery/4096.0)*2*3.42); |
|
|
|
mqtt.publishf(topic_battery.c_str(), "%.2f", (sensor_readings.battery/4096.0)*2*3.42); |
|
|
|
delay(10); |
|
|
|
} |
|
|
|
|
|
|
|
{ |
|
|
|
String topic_rssi = String("thomas/sensor/") + ota.getMAC() + String("/rssi"); |
|
|
|
mqtt.publishf2(topic_rssi.c_str(), 1, 1, "%d", sensor_readings.rssi); |
|
|
|
mqtt.publishf(topic_rssi.c_str(), "%d", sensor_readings.rssi); |
|
|
|
delay(10); |
|
|
|
} |
|
|
|
|
|
|
@ -803,10 +869,10 @@ void setup() |
|
|
|
ESP_LOGD(TAG, "connecting to MQTT"); |
|
|
|
mqtt.begin(); |
|
|
|
|
|
|
|
if (!ota.getMAC().equals("a4cf1211c3e4")) mqtt.subscribe("thomas/sensor/a4cf1211c3e4/#", receiveMqtt); |
|
|
|
if (!ota.getMAC().equals("246f28d1fa5c")) mqtt.subscribe("thomas/sensor/246f28d1fa5c/#", receiveMqtt); |
|
|
|
if (!ota.getMAC().equals("246f28d1a080")) mqtt.subscribe("thomas/sensor/246f28d1a080/#", receiveMqtt); |
|
|
|
if (!ota.getMAC().equals("246f28d1eff4")) mqtt.subscribe("thomas/sensor/246f28d1eff4/#", receiveMqtt); |
|
|
|
if (!ota.getMAC().equals("a4cf1211c3e4")) mqtt.subscribe("thomas/sensor/a4cf1211c3e4/json", receiveMqtt); |
|
|
|
if (!ota.getMAC().equals("246f28d1fa5c")) mqtt.subscribe("thomas/sensor/246f28d1fa5c/json", receiveMqtt); |
|
|
|
if (!ota.getMAC().equals("246f28d1a080")) mqtt.subscribe("thomas/sensor/246f28d1a080/json", receiveMqtt); |
|
|
|
if (!ota.getMAC().equals("246f28d1eff4")) mqtt.subscribe("thomas/sensor/246f28d1eff4/json", receiveMqtt); |
|
|
|
|
|
|
|
/* temp: publish version */ |
|
|
|
String topic_version = String("thomas/sensor/") + ota.getMAC() + String("/version"); |
|
|
@ -842,8 +908,9 @@ void loop() |
|
|
|
} |
|
|
|
|
|
|
|
getSensorMeasurements(); |
|
|
|
displayValues(); |
|
|
|
sendValues(); |
|
|
|
delay(1); |
|
|
|
displayValues(); |
|
|
|
|
|
|
|
int runtime = millis()/1000; |
|
|
|
if (runtime < 0 || runtime >= TIME_TO_SLEEP) runtime = 0; |
|
|
|