Last active
May 19, 2024 21:09
-
-
Save JarrettR/5246c3a52c57b3602e414561e33de9db to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <ArduinoJson.h> | |
#include <ArduinoOTA.h> | |
#include <DNSServer.h> | |
#include <ESP8266WebServer.h> | |
#include <ESP8266WiFi.h> | |
#include <PubSubClient.h> | |
#include <WiFiManager.h> | |
#include "Config.h" | |
#include "SerialCom.h" | |
#include "Types.h" | |
particleSensorState_t state; | |
uint8_t mqttRetryCounter = 0; | |
WiFiManager wifiManager; | |
WiFiClient wifiClient; | |
PubSubClient mqttClient; | |
WiFiManagerParameter custom_mqtt_server("server", "mqtt server", Config::mqtt_server, sizeof(Config::mqtt_server)); | |
WiFiManagerParameter custom_mqtt_user("user", "MQTT username", Config::username, sizeof(Config::username)); | |
WiFiManagerParameter custom_mqtt_pass("pass", "MQTT password", Config::password, sizeof(Config::password)); | |
uint32_t lastMqttConnectionAttempt = 0; | |
const uint16_t mqttConnectionInterval = 60000; // 1 minute = 60 seconds = 60000 milliseconds | |
uint32_t statusPublishPreviousMillis = 0; | |
const uint16_t statusPublishInterval = 30000; // 30 seconds = 30000 milliseconds | |
char identifier[24]; | |
#define FIRMWARE_PREFIX "esp8266-vindriktning-particle-sensor" | |
#define AVAILABILITY_ONLINE "online" | |
#define AVAILABILITY_OFFLINE "offline" | |
char MQTT_TOPIC_STATE[128]; | |
char pm25[24]; | |
bool shouldSaveConfig = false; | |
void saveConfigCallback() { | |
shouldSaveConfig = true; | |
} | |
void setup() { | |
Serial.begin(115200); | |
SerialCom::setup(); | |
// wifiManager.resetSettings(); | |
Serial.println("\n"); | |
Serial.println("Hello from esp8266-vindriktning-particle-sensor"); | |
Serial.printf("Core Version: %s\n", ESP.getCoreVersion().c_str()); | |
Serial.printf("Boot Version: %u\n", ESP.getBootVersion()); | |
Serial.printf("Boot Mode: %u\n", ESP.getBootMode()); | |
Serial.printf("CPU Frequency: %u MHz\n", ESP.getCpuFreqMHz()); | |
Serial.printf("Reset reason: %s\n", ESP.getResetReason().c_str()); | |
delay(3000); | |
snprintf(identifier, sizeof(identifier), "VINDRIKTNING-%X", ESP.getChipId()); | |
snprintf(MQTT_TOPIC_STATE, 127, "jrainimo/feeds/pm25-%s", identifier); | |
WiFi.hostname(identifier); | |
Config::load(); | |
setupWifi(); | |
setupOTA(); | |
mqttClient.setServer(Config::mqtt_server, 1883); | |
mqttClient.setKeepAlive(10); | |
mqttClient.setBufferSize(2048); | |
mqttClient.setCallback(mqttCallback); | |
Serial.printf("Hostname: %s\n", identifier); | |
Serial.printf("IP: %s\n", WiFi.localIP().toString().c_str()); | |
Serial.println("-- Current GPIO Configuration --"); | |
Serial.printf("PIN_UART_RX: %d\n", SerialCom::PIN_UART_RX); | |
mqttReconnect(); | |
} | |
void setupOTA() { | |
ArduinoOTA.onStart([]() { Serial.println("Start"); }); | |
ArduinoOTA.onEnd([]() { Serial.println("\nEnd"); }); | |
ArduinoOTA.onProgress([](unsigned int progress, unsigned int total) { | |
Serial.printf("Progress: %u%%\r", (progress / (total / 100))); | |
}); | |
ArduinoOTA.onError([](ota_error_t error) { | |
Serial.printf("Error[%u]: ", error); | |
if (error == OTA_AUTH_ERROR) { | |
Serial.println("Auth Failed"); | |
} else if (error == OTA_BEGIN_ERROR) { | |
Serial.println("Begin Failed"); | |
} else if (error == OTA_CONNECT_ERROR) { | |
Serial.println("Connect Failed"); | |
} else if (error == OTA_RECEIVE_ERROR) { | |
Serial.println("Receive Failed"); | |
} else if (error == OTA_END_ERROR) { | |
Serial.println("End Failed"); | |
} | |
}); | |
ArduinoOTA.setHostname(identifier); | |
// This is less of a security measure and more a accidential flash prevention | |
ArduinoOTA.setPassword(identifier); | |
ArduinoOTA.begin(); | |
} | |
void loop() { | |
ArduinoOTA.handle(); | |
SerialCom::handleUart(state); | |
mqttClient.loop(); | |
const uint32_t currentMillis = millis(); | |
if (currentMillis - statusPublishPreviousMillis >= statusPublishInterval) { | |
statusPublishPreviousMillis = currentMillis; | |
if (state.valid) { | |
printf("Publish state\n"); | |
publishState(); | |
} | |
} | |
if (!mqttClient.connected() && currentMillis - lastMqttConnectionAttempt >= mqttConnectionInterval) { | |
lastMqttConnectionAttempt = currentMillis; | |
printf("Reconnect mqtt\n"); | |
mqttReconnect(); | |
} | |
} | |
void setupWifi() { | |
wifiManager.setDebugOutput(false); | |
wifiManager.setSaveConfigCallback(saveConfigCallback); | |
wifiManager.addParameter(&custom_mqtt_server); | |
wifiManager.addParameter(&custom_mqtt_user); | |
wifiManager.addParameter(&custom_mqtt_pass); | |
WiFi.hostname(identifier); | |
wifiManager.autoConnect(identifier); | |
mqttClient.setClient(wifiClient); | |
// strcpy(Config::mqtt_server, custom_mqtt_server.getValue()); | |
// strcpy(Config::username, custom_mqtt_user.getValue()); | |
// strcpy(Config::password, custom_mqtt_pass.getValue()); | |
strcpy(Config::mqtt_server, "io.adafruit.com"); | |
strcpy(Config::username, "ADAFRUIT_USERNAME_HERE"); | |
strcpy(Config::password,"ADAFRUIT_KEY_HERE"); | |
if (shouldSaveConfig) { | |
Config::save(); | |
} else { | |
// For some reason, the read values get overwritten in this function | |
// To combat this, we just reload the config | |
// This is most likely a logic error which could be fixed otherwise | |
Config::load(); | |
} | |
} | |
void resetWifiSettingsAndReboot() { | |
wifiManager.resetSettings(); | |
delay(3000); | |
ESP.restart(); | |
} | |
void mqttReconnect() { | |
for (uint8_t attempt = 0; attempt < 3; ++attempt) { | |
if (mqttClient.connect(identifier, Config::username, Config::password)) { | |
break; | |
} | |
delay(5000); | |
} | |
} | |
bool isMqttConnected() { | |
return mqttClient.connected(); | |
} | |
void publishState() { | |
snprintf(pm25, 20, "%i", state.avgPM25); | |
mqttClient.publish(&MQTT_TOPIC_STATE[0], &pm25[0], true); | |
} | |
void mqttCallback(char* topic, uint8_t* payload, unsigned int length) { } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment