commit d918bfe08e653c46c0d1fda880d9b78bdad269d8 Author: Ollo Date: Mon Nov 15 19:03:27 2021 +0100 Initial version diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..89cc49c --- /dev/null +++ b/.gitignore @@ -0,0 +1,5 @@ +.pio +.vscode/.browse.c_cpp.db* +.vscode/c_cpp_properties.json +.vscode/launch.json +.vscode/ipch diff --git a/PM1006.code-workspace b/PM1006.code-workspace new file mode 100644 index 0000000..7bd3d03 --- /dev/null +++ b/PM1006.code-workspace @@ -0,0 +1,21 @@ +{ + "folders": [ + { + "path": "." + } + ], + "settings": { + "files.associations": { + "*.tcc": "cpp", + "bitset": "cpp", + "algorithm": "cpp", + "istream": "cpp", + "limits": "cpp", + "streambuf": "cpp", + "functional": "cpp", + "string": "cpp", + "typeinfo": "cpp", + "cmath": "cpp" + } + } +} diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..f554e39 --- /dev/null +++ b/Readme.md @@ -0,0 +1,35 @@ +## Filesystem +### Configuration +Use the config-example.json from the host folder and create here a config.json file. +### HowTo upload +Start Platform.io +Open a new Atom-Terminal and generate the filesystem with the following command : +```pio run -t buildfs``` +Upload this new generated filesystem with: +```pio run -t uploadfs``` + +### Command pio +Can be found at ```~/.platformio/penv/bin/pio``` + +# Hardware +ESP8266 version ESP12 was used. + +The prototype was based on the Witty board +``` +REST | TXD +ADC LDR | RXD +CH_PD | GPIO05 +GPIO16 | BTN GPIO04 +GPIO14 | GPIO00 +GPIO12 RGB-G | GPIO02 +GPIO13 RGB-B | RGB-R GPIO15 +VCC | GND + USB +``` + +The following pins are used: +* GPIO4 PM1006 particle sensor +* GPIO2 WS2812 stripe out of three LEDs, replacing the orignal LEDs at front + +# Sources +* [https://github.com/amkuipers/witty Witty pinout] \ No newline at end of file diff --git a/data/homie/.gitignore b/data/homie/.gitignore new file mode 100644 index 0000000..d344ba6 --- /dev/null +++ b/data/homie/.gitignore @@ -0,0 +1 @@ +config.json diff --git a/data/homie/ui_bundle.gz b/data/homie/ui_bundle.gz new file mode 100644 index 0000000..13983d4 Binary files /dev/null and b/data/homie/ui_bundle.gz differ diff --git a/host/Readme.md b/host/Readme.md new file mode 100644 index 0000000..5303e87 --- /dev/null +++ b/host/Readme.md @@ -0,0 +1,63 @@ +# Configuration +## File +Generate a file as, described in +http://homieiot.github.io/homie-esp8266/docs/develop-v3/configuration/json-configuration-file/ + +## Upload +* Start ESP +* Login to Wifi, opened by the ESP +* Use the script to upload the configuration file +* restart the ESP + +# Remote Upload + +This script will allow you to send an OTA update to your device: +***upload-via-mqtt.sh*** + +## Installation + +Requirements are: +* paho-mqtt + +## Usage of underlying tool + +The python script can be used, manually, too: +```text +usage: ota_updater.py [-h] -l BROKER_HOST -p BROKER_PORT [-u BROKER_USERNAME] + [-d BROKER_PASSWORD] [-t BASE_TOPIC] -i DEVICE_ID + firmware + +ota firmware update scirpt for ESP8226 implemenation of the Homie mqtt IoT +convention. + +positional arguments: + firmware path to the firmware to be sent to the device + +arguments: + -h, --help show this help message and exit + -l BROKER_HOST, --broker-host BROKER_HOST + host name or ip address of the mqtt broker + -p BROKER_PORT, --broker-port BROKER_PORT + port of the mqtt broker + -u BROKER_USERNAME, --broker-username BROKER_USERNAME + username used to authenticate with the mqtt broker + -d BROKER_PASSWORD, --broker-password BROKER_PASSWORD + password used to authenticate with the mqtt broker + -t BASE_TOPIC, --base-topic BASE_TOPIC + base topic of the homie devices on the broker + -i DEVICE_ID, --device-id DEVICE_ID + homie device id +``` + +* `BROKER_HOST` and `BROKER_PORT` defaults to 127.0.0.1 and 1883 respectively if not set. +* `BROKER_USERNAME` and `BROKER_PASSWORD` are optional. +* `BASE_TOPIC` has to end with a slash, defaults to `homie/` if not set. + +### Example: + +```bash +python ota_updater.py -l localhost -u admin -d secure -t "homie/" -i "device-id" /path/to/firmware.bin +``` + +### Source +https://github.com/homieiot/homie-esp8266/blob/develop/scripts/ota_updater diff --git a/host/ota_updater.py b/host/ota_updater.py new file mode 100755 index 0000000..a8c13fc --- /dev/null +++ b/host/ota_updater.py @@ -0,0 +1,174 @@ +#!/usr/bin/env python + +from __future__ import division, print_function +import paho.mqtt.client as mqtt +import base64, sys, math +from hashlib import md5 + +# The callback for when the client receives a CONNACK response from the server. +def on_connect(client, userdata, flags, rc): + if rc != 0: + print("Connection Failed with result code {}".format(rc)) + client.disconnect() + else: + print("Connected with result code {}".format(rc)) + + client.subscribe("{base_topic}{device_id}/$state".format(**userdata)) # v3 / v4 devices + client.subscribe("{base_topic}{device_id}/$online".format(**userdata)) # v2 devices + + + print("Waiting for device to come online...") + + +# The callback for when a PUBLISH message is received from the server. +def on_message(client, userdata, msg): + # decode string for python2/3 compatiblity + msg.payload = msg.payload.decode() + + if msg.topic.endswith('$implementation/ota/status'): + status = int(msg.payload.split()[0]) + + if userdata.get("published"): + if status == 206: # in progress + # state in progress, print progress bar + progress, total = [int(x) for x in msg.payload.split()[1].split('/')] + bar_width = 30 + bar = int(bar_width*(progress/total)) + print("\r[", '+'*bar, ' '*(bar_width-bar), "] ", msg.payload.split()[1], end='', sep='') + if (progress == total): + print() + sys.stdout.flush() + elif status == 304: # not modified + print("Device firmware already up to date with md5 checksum: {}".format(userdata.get('md5'))) + client.disconnect() + elif status == 403: # forbidden + print("Device ota disabled, aborting...") + client.disconnect() + + elif msg.topic.endswith('$fw/checksum'): + checksum = msg.payload + + if userdata.get("published"): + if checksum == userdata.get('md5'): + print("Device back online. Update Successful!") + else: + print("Expecting checksum {}, got {}, update failed!".format(userdata.get('md5'), checksum)) + client.disconnect() + else: + if checksum != userdata.get('md5'): # save old md5 for comparison with new firmware + userdata.update({'old_md5': checksum}) + else: + print("Device firmware already up to date with md5 checksum: {}".format(checksum)) + client.disconnect() + + elif msg.topic.endswith('ota/enabled'): + if msg.payload == 'true': + userdata.update({'ota_enabled': True}) + else: + print("Device ota disabled, aborting...") + client.disconnect() + + elif msg.topic.endswith('$state') or msg.topic.endswith('$online'): + if (msg.topic.endswith('$state') and msg.payload != 'ready') or (msg.topic.endswith('$online') and msg.payload == 'false'): + return + + # calcluate firmware md5 + firmware_md5 = md5(userdata['firmware']).hexdigest() + userdata.update({'md5': firmware_md5}) + + # Subscribing in on_connect() means that if we lose the connection and + # reconnect then subscriptions will be renewed. + client.subscribe("{base_topic}{device_id}/$implementation/ota/status".format(**userdata)) + client.subscribe("{base_topic}{device_id}/$implementation/ota/enabled".format(**userdata)) + client.subscribe("{base_topic}{device_id}/$fw/#".format(**userdata)) + + # Wait for device info to come in and invoke the on_message callback where update will continue + print("Waiting for device info...") + + if ( not userdata.get("published") ) and ( userdata.get('ota_enabled') ) and \ + ( 'old_md5' in userdata.keys() ) and ( userdata.get('md5') != userdata.get('old_md5') ): + # push the firmware binary + userdata.update({"published": True}) + topic = "{base_topic}{device_id}/$implementation/ota/firmware/{md5}".format(**userdata) + print("Publishing new firmware with checksum {}".format(userdata.get('md5'))) + client.publish(topic, userdata['firmware']) + + +def main(broker_host, broker_port, broker_username, broker_password, broker_ca_cert, base_topic, device_id, firmware): + # initialise mqtt client and register callbacks + client = mqtt.Client() + client.on_connect = on_connect + client.on_message = on_message + + # set username and password if given + if broker_username and broker_password: + client.username_pw_set(broker_username, broker_password) + + if broker_ca_cert is not None: + client.tls_set( + ca_certs=broker_ca_cert + ) + + # save data to be used in the callbacks + client.user_data_set({ + "base_topic": base_topic, + "device_id": device_id, + "firmware": firmware + }) + + # start connection + print("Connecting to mqtt broker {} on port {}".format(broker_host, broker_port)) + client.connect(broker_host, broker_port, 60) + + # Blocking call that processes network traffic, dispatches callbacks and handles reconnecting. + client.loop_forever() + + +if __name__ == '__main__': + import argparse + + parser = argparse.ArgumentParser( + description='ota firmware update scirpt for ESP8226 implemenation of the Homie mqtt IoT convention.') + + # ensure base topic always ends with a '/' + def base_topic_arg(s): + s = str(s) + if not s.endswith('/'): + s = s + '/' + return s + + # specify arguments + parser.add_argument('-l', '--broker-host', type=str, required=False, + help='host name or ip address of the mqtt broker', default="127.0.0.1") + parser.add_argument('-p', '--broker-port', type=int, required=False, + help='port of the mqtt broker', default=1883) + parser.add_argument('-u', '--broker-username', type=str, required=False, + help='username used to authenticate with the mqtt broker') + parser.add_argument('-d', '--broker-password', type=str, required=False, + help='password used to authenticate with the mqtt broker') + parser.add_argument('-t', '--base-topic', type=base_topic_arg, required=False, + help='base topic of the homie devices on the broker', default="homie/") + parser.add_argument('-i', '--device-id', type=str, required=True, + help='homie device id') + parser.add_argument('firmware', type=argparse.FileType('rb'), + help='path to the firmware to be sent to the device') + + parser.add_argument("--broker-tls-cacert", default=None, required=False, + help="CA certificate bundle used to validate TLS connections. If set, TLS will be enabled on the broker conncetion" + ) + + # workaround for http://bugs.python.org/issue9694 + parser._optionals.title = "arguments" + + # get and validate arguments + args = parser.parse_args() + + # read the contents of firmware into buffer + fw_buffer = args.firmware.read() + args.firmware.close() + firmware = bytearray() + firmware.extend(fw_buffer) + + # Invoke the business logic + main(args.broker_host, args.broker_port, args.broker_username, + args.broker_password, args.broker_tls_cacert, args.base_topic, args.device_id, firmware) diff --git a/host/spelling.sh b/host/spelling.sh new file mode 100755 index 0000000..ec98d73 --- /dev/null +++ b/host/spelling.sh @@ -0,0 +1,11 @@ +#!/bin/bash + +whereis -b codespell | grep "/codespell" >> /dev/null +if [ $? -ne 0 ]; then + echo "codespell needs to be installed" + exit 1 +fi +codespell -w ../src/* +codespell -w ../include/* +codespell ../Readme.md +exit 0 diff --git a/host/upload-via-mqtt.sh b/host/upload-via-mqtt.sh new file mode 100755 index 0000000..949eda2 --- /dev/null +++ b/host/upload-via-mqtt.sh @@ -0,0 +1,25 @@ +#!//bin/bash + +if [ $# -ne 3 ]; then + echo "Homie prefex and device index must be specified:" + echo "$0 " + echo "e.g." + echo "$0 192.168.0.2 test/ MyDeviceId" + exit 1 +fi + +mqttHost=$1 +mqttPrefix=$2 +homieId=$3 +firmwareFile=../.pio/build/nodemcuv2/firmware.bin + +if [ ! -f $firmwareFile ]; then + echo "the script $0 must be started in host/ sub directory" + exit 2 +fi + +echo "Waiting for $homieId ..." +mosquitto_sub -h $mqttHost -t "${mqttPrefix}${homieId}/#" -R -C 1 +python ota_updater.py -l $mqttHost -t "$mqttPrefix" -i "$homieId" $firmwareFile + +exit 0 diff --git a/include/HomieSettings.h b/include/HomieSettings.h new file mode 100644 index 0000000..29337e2 --- /dev/null +++ b/include/HomieSettings.h @@ -0,0 +1,18 @@ +/** + * @file HomieSettings.h + * @author your name (you@domain.com) + * @brief Air quality sensor + * @version 0.1 + * @date 2021-11-05 + * + * @copyright Copyright (c) 2021 + * + */ + +#ifndef HOMIE_SETTINGS +#define HOMIE_SETTINGS + +#define HOMIE_FIRMWARE_NAME "Vindriktning" +#define HOMIE_FIRMWARE_VERSION "1.1.0" + +#endif diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..7c1a999 --- /dev/null +++ b/platformio.ini @@ -0,0 +1,21 @@ +;PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:nodemcuv2] +platform = espressif8266 +board = d1_mini +framework = arduino +build_flags = -D PIO_FRAMEWORK_ARDUINO_LWIP2_LOW_MEMORY +; the latest development branch (convention V3.0.x) +lib_deps = https://github.com/homieiot/homie-esp8266.git#develop + EspSoftwareSerial + NeoPixel + adafruit/Adafruit BMP280 Library @ ^2.4.2 + diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..69ee2fe --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,333 @@ +/** + * @file main.cpp + * @author Ollo + * @brief + * @version 0.1 + * @date 2021-11-05 + * + * @copyright Copyright (c) 2021 + * + */ + +/****************************************************************************** + * INCLUDES + ******************************************************************************/ +#include +#include +#include "HomieSettings.h" +#include +#include +#include +#include + +/****************************************************************************** + * DEFINES + ******************************************************************************/ + +#define GPIO_WS2812 D4 /**< GPIO2 */ +#define SENSOR_PM1006_RX D2 /**< GPIO4 */ +#define SENSOR_PM1006_TX -1 /**< Unused */ +#define WITTY_RGB_R D8 /**< GPIO15 */ +#define WITTY_RGB_G D6 /**< GPIO12 */ +#define WITTY_RGB_B D7 /**< GPIO13 */ +#define PM1006_BIT_RATE 9600 +#define PM1006_MQTT_UPDATE 5000 /**< Check the sensor every 10 seconds; New measurement is done every 20seconds by the sensor */ +#define PIXEL_COUNT 3 +#define GPIO_BUTTON SENSOR_PM1006_RX /**< Button and software serial share one pin on Witty board */ +#define SENSOR_I2C_SCK D5 /**< GPIO14 - I2C clock pin */ +#define SENSOR_I2C_SDI D1 /**< GPIO5 - I2C data pin */ + +#define PM1006_BIT_RATE 9600 +#define PM1006_MQTT_UPDATE 5000 /**< Check the sensor every 10 seconds; New measurement is done every 20seconds by the sensor */ + +#define SEALEVELPRESSURE_HPA (1013.25) + +#define LOG_TOPIC "log\0" +#define MQTT_LOG_ERROR 1 +#define MQTT_LOG_WARNING 10 +#define MQTT_LOG_INFO 20 +#define MQTT_LOG_DEBUG 90 + +#define getTopic(test, topic) \ + char *topic = new char[strlen(Homie.getConfiguration().mqtt.baseTopic) + strlen(Homie.getConfiguration().deviceId) + 1 + strlen(test) + 1]; \ + strcpy(topic, Homie.getConfiguration().mqtt.baseTopic); \ + strcat(topic, Homie.getConfiguration().deviceId); \ + strcat(topic, "/"); \ + strcat(topic, test); + +#define NUMBER_TYPE "Number" +#define NODE_PARTICE "particle" +#define NODE_TEMPERATUR "temp" +#define NODE_PRESSURE "pressure" +#define NODE_ALTITUDE "altitude" +/****************************************************************************** + * TYPE DEFS + ******************************************************************************/ + +/****************************************************************************** + * FUNCTION PROTOTYPES + ******************************************************************************/ + +void log(int level, String message, int code); + +/****************************************************************************** + * LOCAL VARIABLES + ******************************************************************************/ + +bool mConfigured = false; +bool mConnected = false; + +HomieNode particle(NODE_PARTICE, "particle", "Particle"); /**< Measuret in micro gram per quibik meter air volume */ +HomieNode temperatureNode(NODE_TEMPERATUR, "Room Temperature", "Room Temperature"); +HomieNode pressureNode(NODE_PRESSURE, "Pressure", "Room Pressure"); +HomieNode altitudeNode(NODE_ALTITUDE, "Altitude", "Room altitude"); + +HomieSetting i2cEnable("i2c", "BMP280 sensor present"); + +static SoftwareSerial pmSerial(SENSOR_PM1006_RX, SENSOR_PM1006_TX); +Adafruit_BMP280 bmp; // connected via I2C + +Adafruit_NeoPixel strip(PIXEL_COUNT, GPIO_WS2812, NEO_GRB + NEO_KHZ800); + +// Variablen +uint8_t serialRxBuf[80]; +uint8_t rxBufIdx = 0; +int spm25 = 0; +int last = 0; +unsigned int mButtonPressed = 0; + +/****************************************************************************** + * LOCAL FUNCTIONS + *****************************************************************************/ + +/** + * @brief Get the Sensor Data from software serial + * + * @return int PM25 value + */ +int getSensorData() { + uint8_t rxBufIdx = 0; + uint8_t checksum = 0; + + // Sensor Serial aushorchen + while ((pmSerial.available() && rxBufIdx < 127) || rxBufIdx < 20) + { + serialRxBuf[rxBufIdx++] = pmSerial.read(); + delay(15); + } + + // calculate checksum + for (uint8_t i = 0; i < 20; i++) + { + checksum += serialRxBuf[i]; + } + + /* Debug Print of received bytes */ + String dbgBuffer = String("PM1006: "); + for (uint8_t i = 0; i < 20; i++) + { + dbgBuffer += String(serialRxBuf[i], 16); + } + dbgBuffer += String("check: " + String(checksum, 16)); + log(MQTT_LOG_DEBUG, String(dbgBuffer), 1); + + // Header und Prüfsumme checken + if (serialRxBuf[0] == 0x16 && serialRxBuf[1] == 0x11 && serialRxBuf[2] == 0x0B /* && checksum == 0 */) + { + return (serialRxBuf[5] << 8 | serialRxBuf[6]); + } + else + { + return (-1); + } +} + +/** + * @brief Handle events of the Homie platform + * @param event + */ +void onHomieEvent(const HomieEvent &event) +{ + switch (event.type) + { + case HomieEventType::MQTT_READY: + mConnected=true; + digitalWrite(WITTY_RGB_R, LOW); + if (!i2cEnable.get()) { /** keep green LED activated to power I2C sensor */ + digitalWrite(WITTY_RGB_G, LOW); + } + digitalWrite(WITTY_RGB_B, LOW); + strip.fill(strip.Color(0,0,128)); + strip.show(); + break; + case HomieEventType::READY_TO_SLEEP: + break; + case HomieEventType::OTA_STARTED: + break; + case HomieEventType::OTA_SUCCESSFUL: + ESP.restart(); + break; + default: + break; + } +} + +void bmpPublishValues() { + temperatureNode.setProperty(NODE_TEMPERATUR).send(String(bmp.readTemperature())); + pressureNode.setProperty(NODE_PRESSURE).send(String(bmp.readPressure() / 100.0F)); + altitudeNode.setProperty(NODE_ALTITUDE).send(String(bmp.readAltitude(SEALEVELPRESSURE_HPA))); +} + +/** + * @brief Main loop, triggered by the Homie API + * All logic needs to be done here. + * + * The ranges are defined as followed: + * - green: 0-35 (good+low) + * - orange: 36-85 (OK+medicore) + * - red: 86-... (bad+high) + * + * source @link{https://github.com/Hypfer/esp8266-vindriktning-particle-sensor/issues/16#issuecomment-903116056} + */ +void loopHandler() +{ + static long lastRead = 0; + if ((millis() - lastRead) > PM1006_MQTT_UPDATE) { + int pM25 = getSensorData(); + if (pM25 >= 0) { + particle.setProperty("particle").send(String(pM25)); + if (pM25 < 35) { + strip.fill(strip.Color(0, 255, 0)); /* green */ + } else if (pM25 < 85) { + strip.fill(strip.Color(255, 127, 0)); /* orange */ + } else { + strip.fill(strip.Color(255, 0, 0)); /* red */ + } + } + strip.show(); + + /* Read BOSCH sensor */ + bmpPublishValues(); + + lastRead = millis(); + } + // Feed the dog -> ESP stay alive + ESP.wdtFeed(); +} + +/****************************************************************************** + * GLOBAL FUNCTIONS + *****************************************************************************/ + +void setup() +{ + SPIFFS.begin(); + Serial.begin(115200); + Serial.setTimeout(2000); + pinMode(WITTY_RGB_R, OUTPUT); + pinMode(WITTY_RGB_G, OUTPUT); + pinMode(WITTY_RGB_B, OUTPUT); + digitalWrite(WITTY_RGB_R, LOW); + digitalWrite(WITTY_RGB_G, LOW); + digitalWrite(WITTY_RGB_B, LOW); + + Homie_setFirmware(HOMIE_FIRMWARE_NAME, HOMIE_FIRMWARE_VERSION); + Homie.setLoopFunction(loopHandler); + Homie.onEvent(onHomieEvent); + i2cEnable.setDefaultValue(false); + memset(serialRxBuf, 0, 80); + + pmSerial.begin(PM1006_BIT_RATE); + Homie.setup(); + + particle.advertise("particle").setName("Particle").setDatatype(NUMBER_TYPE).setUnit("micro gram per quibik"); + temperatureNode.advertise(NODE_TEMPERATUR).setName("Degrees") + .setDatatype("float") + .setUnit("ºC"); + pressureNode.advertise(NODE_PRESSURE).setName("Pressure") + .setDatatype("float") + .setUnit("hPa"); + altitudeNode.advertise(NODE_ALTITUDE).setName("Altitude") + .setDatatype("float") + .setUnit("m"); + + + strip.begin(); + /* activate I2C for BOSCH sensor */ + Wire.begin(SENSOR_I2C_SDI, SENSOR_I2C_SCK); + + mConfigured = Homie.isConfigured(); + digitalWrite(WITTY_RGB_G, HIGH); + if (mConfigured) + { + if (i2cEnable.get()) { + strip.fill(strip.Color(0,128,0)); + strip.show(); + /* Extracted from library's example */ + if (!bmp.begin()) { + Serial.println(F("Could not find a valid BMP280 sensor, check wiring or " + "try a different address!")); + while (1) delay(10); + } + + /* Default settings from datasheet. */ + bmp.setSampling(Adafruit_BMP280::MODE_NORMAL, /* Operating Mode. */ + Adafruit_BMP280::SAMPLING_X2, /* Temp. oversampling */ + Adafruit_BMP280::SAMPLING_X16, /* Pressure oversampling */ + Adafruit_BMP280::FILTER_X16, /* Filtering. */ + Adafruit_BMP280::STANDBY_MS_500); /* Standby time. */ + } + strip.fill(strip.Color(0,0,0)); + for (int i=0;i < (PIXEL_COUNT / 2); i++) { + strip.setPixelColor(0, strip.Color(0,0,128)); + } + strip.show(); + digitalWrite(WITTY_RGB_B, HIGH); + } else { + strip.fill(strip.Color(128,0,0)); + for (int i=0;i < (PIXEL_COUNT / 2); i++) { + strip.setPixelColor(0, strip.Color(0,0,128)); + } + strip.show(); + } +} + +void loop() +{ + Homie.loop(); + /* use the pin, receiving the soft serial additionally as button */ + if (digitalRead(GPIO_BUTTON) == LOW) { + mButtonPressed++; + } else { + mButtonPressed=0U; + } + + if (mButtonPressed > 10000U) { + mButtonPressed=0U; + if (SPIFFS.exists("/homie/config.json")) { + printf("Resetting config\r\n"); + SPIFFS.remove("/homie/config.json"); + SPIFFS.end(); + } else { + printf("No config present\r\n"); + } + } +} + + +void log(int level, String message, int statusCode) +{ + String buffer; + StaticJsonDocument<200> doc; + doc["level"] = level; + doc["message"] = message; + doc["statusCode"] = statusCode; + serializeJson(doc, buffer); + if (mConnected) + { + getTopic(LOG_TOPIC, logTopic) + + Homie.getMqttClient().publish(logTopic, 2, false, buffer.c_str()); + delete logTopic; + } +}