diff --git a/src/main.cpp b/src/main.cpp index c07192d..f88dca4 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -7,6 +7,7 @@ #include "bme280.h" #include "config.h" #include "time.h" +#include "mqtt.h" #ifndef SERIAL_BAUD #define SERIAL_BAUD 74880 @@ -74,6 +75,7 @@ void setup() uweather_time_init(); uweather_update_init(); + uweather_mqtt_init(); } @@ -82,5 +84,6 @@ void loop() uweather_web_handle(); uweather_update_handle(); uweather_time_handle(); + uweather_mqtt_handle(); delay(10); } diff --git a/src/mqtt.cpp b/src/mqtt.cpp new file mode 100644 index 0000000..f284c39 --- /dev/null +++ b/src/mqtt.cpp @@ -0,0 +1,73 @@ +#include "mqtt.h" +#include +#include +#include "config.h" +#include +#include "sensors.h" + +#define MQTT_BUFFER_SIZE 200 +#define MQTT_REPORT_INTERVAL 60000 + +bool enabled = false; +WiFiClient wfclient; +PubSubClient mqtt(wfclient); +char buffer[MQTT_BUFFER_SIZE] = {}; +unsigned long last_millis = 0; + +void uweather_mqtt_init() +{ + last_millis = 0; + + // should we be running? + if (Config._data.mqtt_host[0] == '\0') { + enabled = false; + Serial.println("MQTT disabled, no host set"); + return; + } + + //mqtt.setServer(Config._data.mqtt_host, 1883); //TODO: configurable port + // server is an ip addr + IPAddress addr; + if (addr.fromString((const char*) Config._data.mqtt_host)) { + mqtt.setServer(addr, 1883); //TODO: configurable port + } else { + mqtt.setServer((const char*) Config._data.mqtt_host, 1883); + } + + Serial.printf("MQTT Host set to %s\n", Config._data.mqtt_host); + + enabled = true; +} + +void uweather_mqtt_handle() +{ + if (!enabled) return; + + unsigned long now = millis(); + + if (now - last_millis < MQTT_REPORT_INTERVAL) return; + last_millis = now; + + if (!mqtt.connected()) { + String client_id = String(random(now), HEX); + Serial.printf("Connecting to MQTT Host %s...", Config._data.mqtt_host); + if (mqtt.connect(client_id.c_str())) { + Serial.println(" connected"); + } else { + Serial.println(" unable to connect"); + return; + } + } + + const char* topic = "/"; + if (Config._data.mqtt_prefix[0] != '\0') { + topic = (const char*) Config._data.mqtt_prefix; + } + int result = sensors_print_json(buffer, MQTT_BUFFER_SIZE); + if (result > MQTT_BUFFER_SIZE || result < 0) { + Serial.printf("ERROR: MQTT_BUFFER_SIZE too small; needed %d bytes, but only had %d\n", result, MQTT_BUFFER_SIZE); + return; + } + Serial.printf("Publishing data to mqtt://%s topic: %s\n", Config._data.mqtt_host, topic); + mqtt.publish(topic, buffer); +} \ No newline at end of file diff --git a/src/mqtt.h b/src/mqtt.h new file mode 100644 index 0000000..abfd423 --- /dev/null +++ b/src/mqtt.h @@ -0,0 +1,7 @@ +#ifndef _UWEATHER_MQTT_H_ +#define _UWEATHER_MQTT_H_ + +void uweather_mqtt_init(); +void uweather_mqtt_handle(); + +#endif // _UWEATHER_MQTT_H_ include guard \ No newline at end of file diff --git a/src/sensors.cpp b/src/sensors.cpp new file mode 100644 index 0000000..3911839 --- /dev/null +++ b/src/sensors.cpp @@ -0,0 +1,28 @@ +#include "sensors.h" +#include "time.h" +#include "bme280.h" +#include "battery.h" + +int sensors_print_json(char* buffer, size_t len) { + uweather_handle_battery(); + unsigned long now = current_timestamp(); + char buff[5][10] = {}; + dtostrf(BME.readTemperature(), 2, 1, buff[0]); + dtostrf(BME.readPressure(), 2, 1, buff[1]); + dtostrf(BME.readHumidity(), 2, 1, buff[2]); + dtostrf(battery_get_voltage(),2, 1, buff[3]); + if (now) { + sprintf(buff[4], "%d", now); + } else { + strcpy(buff[4], "null"); + } + return snprintf(buffer, len, "{\"time\": %s, \"temperature\": %s, \"pressure\": %s, \"humidity\": %s, \"battery\": { \"voltage\": %s, \"is_charging\": %s, \"percent\": %d}}", + buff[4], + buff[0], + buff[1], + buff[2], + buff[3], + (Battery.is_charging ? "true":"false"), + battery_get_percent() + ); +} \ No newline at end of file diff --git a/src/sensors.h b/src/sensors.h new file mode 100644 index 0000000..b05b682 --- /dev/null +++ b/src/sensors.h @@ -0,0 +1,8 @@ +#ifndef _UWEATHER_SENSORS_H_ +#define _UWEATHER_SENSORS_H_ + +#include + +int sensors_print_json(char*, size_t); + +#endif // _UWEATHER_SENSORS_H_ include guard \ No newline at end of file diff --git a/src/web.cpp b/src/web.cpp index a346d68..d781783 100644 --- a/src/web.cpp +++ b/src/web.cpp @@ -6,8 +6,9 @@ #include #include "config.h" #include "version.h" -#include "battery.h" #include "time.h" +#include "mqtt.h" +#include "sensors.h" /** * How long to wait after the OK to shutdown before no longer @@ -82,27 +83,15 @@ void handle_firmware(HttpRequest& req, HttpResponse& res) void handle_weather_current(HttpRequest& req, HttpResponse& res) { - unsigned long now = current_timestamp(); - char buff[5][10] = {}; - dtostrf(BME.readTemperature(), 2, 1, buff[0]); - dtostrf(BME.readPressure(), 2, 1, buff[1]); - dtostrf(BME.readHumidity(), 2, 1, buff[2]); - dtostrf(battery_get_voltage(),2, 1, buff[3]); - if (now) { - sprintf(buff[4], "%d", now); - } else { - strcpy(buff[4], "null"); - } res.headers.set("Content-Type", "application/json"); - content.printf("{\"time\": %s, \"temperature\": %s, \"pressure\": %s, \"humidity\": %s, \"battery\": { \"voltage\": %s, \"is_charging\": %s, \"percent\": %d}}", - buff[4], - buff[0], - buff[1], - buff[2], - buff[3], - (Battery.is_charging ? "true":"false"), - battery_get_percent() - ); + char buff[250]; + int printed = sensors_print_json(buff, 250); + if (printed > 250 || printed < 0) { + res.code = 500; + client_error("Sensor result data too large", res); + return; + } + content.print(buff); } // Handle WiFi Scan @@ -199,6 +188,7 @@ void handle_config_set(HttpRequest& req, HttpResponse& res) result = Config.setNTPHost(value); } else if (strcmp("mqtt_host", key) == 0) { result = Config.setMQTTHost(value); + uweather_mqtt_init(); } else if (strcmp("mqtt_prefix", key) == 0) { result = Config.setMQTTPrefix(value); } else if (strcmp("enable_http", key) == 0) { @@ -301,7 +291,6 @@ void uweather_web_init(void) void uweather_web_handle(void) { if (web_is_shutdown) return; - uweather_handle_battery(); if (web_shutdown_at) { unsigned long now = millis(); if (now > web_shutdown_at) {