Skip to content

Instantly share code, notes, and snippets.

@JarrettR
Last active May 19, 2024 21:09
Show Gist options
  • Save JarrettR/5246c3a52c57b3602e414561e33de9db to your computer and use it in GitHub Desktop.
Save JarrettR/5246c3a52c57b3602e414561e33de9db to your computer and use it in GitHub Desktop.
#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