Thanks, the above is all the code that references that variable, but I will post the full project I was just saving you some scrolling through all the junk
//Include Libraries
#include <Arduino.h>
#include <FS.h> //Arduino ESP8266 Core - Handles filesystem functions (read/write config file)
#include <LCD_I2C.h>
#include <FastLED.h> //https://github.com/FastLED/FastLED - LED functionality
#include <Arduino.h>
#include <WiFiManager.h> //https://github.com/tzapu/WiFiManager (must be v2.0.8-beta or later) - Wifi Onboarding with Portal
#include <PubSubClient.h> //https://github.com/knolleary/pubsubclient Provides MQTT functions
#include <ArduinoJson.h> //https://github.com/bblanchon/ArduinoJson
#include <WebServer.h> //Used for HTTP callback to enable/disable discovery
#include <HTTPUpdateServer.h>
#include <ArduinoOTA.h> //https://github.com/jandrassy/ArduinoOTA
#include <ESPmDNS.h>
#include <Update.h>
#ifdef ESP32
#include <SPIFFS.h>
#endif
#define VERSION "Firebeetle 2 (ESP32)"
//Setup RGB LED for Feedback
// Only one led is connected. The led is connected on IO5
//#define NUM_LEDS 1
//#define DATA_PIN 5
#define LED_DATA_PIN 5
#define WIFIMODE 2 // 0 = Only Soft Access Point, 1 = Only connect to local WiFi network with UN/PW, 2 = Both
#define MQTTMODE 1 // 0 = Disable MQTT, 1 = Enable (will only be enabled if WiFi mode = 1 or 2 - broker must be on same network)
#define NUM_LEDS_MAX 1 // For initialization - recommend actual max 50 LEDs if built as shown
//Define PinOut
#define TDS_SUP_Pin A0
#define TDS_PREDI_Pin A1
#define TDS_OUT_Pin A4
#define TdsFactor 0.5 // tds = ec / 2
//CRGB leds[NUM_LEDS];
//PubSubClient
WiFiClient espClient;
PubSubClient client(espClient);
//WebServer
WebServer server(80);
//WebServer server;
HTTPUpdateServer httpUpdater;
//const char* serverIndex = "<form method='POST' action='/update' enctype='multipart/form-data'><input type='file' name='update'><input type='submit' value='Update'></form>";
const char* host = "TDSMonitor-webupdate";
const char* mqtt_server = "10.0.0.8";
//const char* mqtt_port = "1883";
const char* mqtt_client = "TDSMonitor";
const char* mqtt_pub_topic_supTDS = "Aquarium/TDSMonitor/Sensor/supTDS";
const char* mqtt_pub_topic_prediTDS = "Aquarium/TDSMonitor/Sensor/prediTDS";
const char* mqtt_pub_topic_outTDS = "Aquarium/TDSMonitor/Sensor/outTDS";
const char* mqtt_sub_topic = "Aquarium";
const char* mqtt_supTDS_stat = "homeassistant/stat/TDSMonitor/supTDS";
const char* mqtt_prediTDS_stat = "homeassistant/stat/TDSMonitor/prediTDS";
const char* mqtt_outTDS_stat = "homeassistant/stat/TDSMonitor/outTDS";
const char* mqtt_IP_stat = "homeassistant/stat/TDSMonitor/ipaddress";
//Auto-discover enable/disable option
bool auto_discovery = false; //default to false and provide end-user interface to allow toggling
//Arduino OTA
bool ota_flag = true; // Must leave this as true for board to broadcast port to IDE upon boot
uint16_t ota_boot_time_window = 2500; // minimum time on boot for IP address to show in IDE ports, in millisecs
uint16_t ota_time_window = 20000; // time to start file upload when ota_flag set to true (after initial boot), in millsecs
uint16_t ota_time_elapsed = 0; // Counter when OTA active
uint16_t ota_time = ota_boot_time_window;
//Define device name
String deviceName = "TDSMonitor";
String wifiHostName = "TDSMonitor";
String otaHostName = "TDSMonitorOTA";
String mqttClient = "TDSMonitor";
// ===============================
// MQTT Variables
// ===============================
// MQTT will only be used if a server address other than '0.0.0.0' is entered via portal
byte mqttAddr_1 = 0;
byte mqttAddr_2 = 0;
byte mqttAddr_3 = 0;
byte mqttAddr_4 = 0;
int mqttPort = 0;
String mqttUser = "myusername";
String mqttPW = "mypassword";
uint16_t mqttTelePeriod = 60;
uint32_t mqttLastUpdate = 0;
String mqttTopicSub ="TDSMonitor"; //v0.41 (for now, will always be same as pub)
String mqttTopicPub = "TDSMonitor"; //v0.41
bool mqttEnabled = false; //Will be enabled/disabled depending on whether a valid IP address is defined in Settings (0.0.0.0 disables MQTT)
bool mqttConnected = false; //Will be enabled if defined and successful connnection made. This var should be checked upon any MQTT action.
bool prevCarStatus = false; //v0.44 for forcing MQTT update on state change
bool forceMQTTUpdate = false; //v0.44 for forcing MQTT update on state change
//Variables for creating unique entity IDs and topics (HA discovery)
byte macAddr[6]; //Device MAC address (array is in reverse order)
String strMacAddr; //MAC address as string and in proper order
char uidPrefix[] = "TDSMonitor"; //Prefix for unique ID generation
char devUniqueID[30]; //Generated Unique ID for this device (uidPrefix + last 6 MAC characters)
//---- Captive Portal -------
//flag for saving data in captive portal
bool shouldSaveConfig = false;
//callback notifying us of the need to save config
void saveConfigCallback () {
shouldSaveConfig = true;
}
//---------------------------
//VARIABLES FOR PORTAL USE (JSON vars)
char device_name[18]; //v0.41
char wifi_hostname[18]; //v0.41
char ota_hostname[18]; //v0.41
char mqtt_addr_1[4];
char mqtt_addr_2[4];
char mqtt_addr_3[4];
char mqtt_addr_4[4];
char mqtt_port[6];
char mqtt_user[65];
char mqtt_pw[65];
char mqtt_tele_period[4];
char mqtt_topic_sub[18]; //v0.41
char mqtt_topic_pub[18]; //v0.41
char calkValue_SUP[4];
char calkValue_PREDI[4];
char calkValue_OUT[4];
String home_page_message = "";
WiFiManager wifiManager;
WiFiManager wm;
String localIP;
char mqtt_tds_SUP[50];
char mqtt_tds_PREDI[50];
char mqtt_tds_OUT[50];
char mqtt_tds_SUP2[50];
char mqtt_tds_PREDI2[50];
char mqtt_tds_OUT2[50];
//Define TDS Global Variables
float tdstemp = 25;
float tdsAref = 5.0;
float tdsAdcRange = 1024.0;
float temperature;
//Define Supply TDS Variables
float tdsValue_SUP = 0;
float kValue_SUP = 1.0;
float analogValue_SUP;
float voltage_SUP;
float ecValue_SUP;
float ecValue25_SUP;
int kValueAddress_SUP[4];
int prevtdsValue_SUP;
//Define PRE-DI TDS Variables
float tdsValue_PREDI = 0;
float kValue_PREDI = 1.0;
float analogValue_PREDI;
float voltage_PREDI;
float ecValue_PREDI;
float ecValue25_PREDI;
int kValueAddress_PREDI[8];
int prevtdsValue_PREDI;
//Define Output TDS Variables
float tdsValue_OUT = 0;
float kValue_OUT = 1.0;
float analogValue_OUT;
float voltage_OUT;
float ecValue_OUT;
float ecValue25_OUT;
int kValueAddress_OUT[12];
int prevtdsValue_OUT;
char w_tdsValue_SUP[8];
char w_tdsValue_PREDI[8];
char w_tdsValue_OUT[8];
char SUP_kValue[4];
char PREDI_kValue[4];
char OUT_kValue[4];
//==========================
// LED Setup & Portal Options
//==========================
// Defaults values - these will be set/overwritten by portal or last saved vals on reboot
int numLEDs = 30;
byte activeBrightness = 100;
byte sleepBrightness = 5;
uint32_t maxOperationTimePark = 60;
uint32_t maxOperationTimeExit = 5;
String ledEffect_m1 = "Out-In";
bool showStandbyLEDs = true;
CRGB LEDs[NUM_LEDS_MAX];
CRGB ledColorOn_m1 = CRGB::White;
CRGB ledColorOff = CRGB::Black;
CRGB ledColorStandby = CRGB::Blue;
CRGB ledColorWake = CRGB::Green;
CRGB ledColorActive = CRGB::Yellow;
CRGB ledColorParked = CRGB::Red;
CRGB ledColorBackup = CRGB::Red;
//************************** Just Some basic Definitions used for the Up Time Logger ************//
long Day=0;
int Hour =0;
int Minute=0;
int Second=0;
int HighMillis=0;
int Rollover=0;
unsigned long previousMillis = 0;
unsigned long interval = 10000;
int TransmitInterval = interval;
// constants do not change:
int CurrentRSSI=100;
/*
void RGB_LED_Setup(){
// Configure an array of (one) leds without SPI
FastLED.addLeds<NEOPIXEL, DATA_PIN>(leds, NUM_LEDS);
}
void RGB_LED(){
leds[0] = CRGB::Black;
FastLED.show();
}
*/
//OTHER GLOBAL VARIABLES
bool blinkOn = false;
int intervalDistance = 0;
bool carDetected = false;
bool isAwake = false;
bool coldStart = true;
byte carDetectedCounter = 0;
byte carDetectedCounterMax = 3;
byte nocarDetectedCounter = 0;
byte nocarDetectedCounterMax = 10;
byte outOfRangeCounter = 0;
uint32_t startTime;
bool exitSleepTimerStarted = false;
bool parkSleepTimerStarted = false;
//Initial distances for default load (only used for initial onboarding)
byte uomDistance = 0; // 0=inches, 1=centimeters
int wakeDistance = 3048; // wake/sleep distance (~10ft)
int startDistance = 1829; // Start countdown distance (~6')
int parkDistance = 610; // Final parked distacce (~2')
int backupDistance = 457; // Flash backup distance (~18")
//===============================
// Web pages and handlers
//===============================
// Main Settings page
// Root / Main Settings page handler
void handleRoot() {
String mainPage = "<html>\
<head>\
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\
<title>TDS Monitor - Main</title>\
<style>\
body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; }\
</style>\
</head>\
<body>\
<h1>Controller Settings (VAR_DEVICE_NAME)</h1><br>\
Changes made here will be used <b><i>until the controller is restarted</i></b>, unless the box to save the settings as new boot defaults is checked.<br><br>\
To test settings, leave the box unchecked and click 'Update'. Once you have settings you'd like to keep, check the box and click 'Update' to write the settings as the new boot defaults.<br><br>\
If you want to change wifi settings or the device name, you must use the 'Reset All' command.<br><br>\
<form method=\"post\" enctype=\"application/x-www-form-urlencoded\" action=\"/postform/\">\
<table>\
<tr>\
<b><u>MQTT Settings</u></b>:<br>\
ONLY enter this information if you already have an MQTT broker configured. <u><i>To disable or remove MQTT functionality, set the IP address to 0.0.0.0</i></u><br>\
Any changes to MQTT require that you check the box to update boot settings below, which will reboot the controller. If a successful connection to your MQTT broker is made, \
a retained message of \"connected\" will be published to the topic \"homeassistant/stat/your_topic/mqtt\".<br><br>";
mainPage += "<table>\
<tr>\
<td><label for=\"mqttaddr1\">Broker IP Address:</label></td>\
<td><input type=\"number\" min=\"0\" max=\"255\" step=\"1\" name=\"mqttaddr1\" style=\"width: 50px\;\" value=\"";
mainPage += String(mqttAddr_1);
mainPage += "\">.<input type=\"number\" min=\"0\" max=\"255\" step=\"1\" name=\"mqttaddr2\" style=\"width: 50px\;\" value=\"";
mainPage += String(mqttAddr_2);
mainPage += "\">.<input type=\"number\" min=\"0\" max=\"255\" step=\"1\" name=\"mqttaddr3\" style=\"width: 50px\;\" value=\"";
mainPage += String(mqttAddr_3);
mainPage += "\">.<input type=\"number\" min=\"0\" max=\"255\" step=\"1\" name=\"mqttaddr4\" style=\"width: 50px\;\" value=\"";
mainPage += String(mqttAddr_4);
mainPage += "\"></td></tr>\
<tr>\
<td><label for=\"mqttport\">MQTT Broker Port:</label></td>\
<td><input type=\"number\" min=\"0\" max=\"65535\" step=\"1\" name=\"mqttport\" style=\"width: 65px\;\" value=\"";
mainPage += String(mqttPort);
mainPage += "\"></td></tr>\
<tr>\
<td><label for=\"mqttuser\">MQTT User Name:</label></td>\
<td><input type=\"text\" name=\"mqttuser\" maxlength=\"64\" value=\"";
mainPage += mqttUser;
mainPage += "\"></td></tr>\
<tr>\
<td><label for=\"mqttpw\">MQTT Password:</label></td>\
<td><input type=\"password\" name=\"mqttpw\" maxlength=\"64\" value=\"";
mainPage += mqttPW;
mainPage += "\"></td></tr>\
<tr>\
<td><label for=\"mqtttopic\">MQTT Topic: stat/</label></td>\
<td><input type=\"text\" name=\"mqtttopic\" maxlength=\"16\" value=\"";
mainPage += mqttTopicPub;
mainPage += "\"> (16 alphanumeric chars max - no spaces, no symbols)</td></tr>\
<tr>\
<td><label for=\"mqttperiod\">Telemetry Period:</label></td>\
<td><input type=\"number\" min=\"60\" max=\"600\" step=\"1\" name=\"mqttperiod\" style=\"width: 50px\;\" value=\"";
mainPage += String(mqttTelePeriod);
mainPage += "\"> seconds (60 min, 600 max)</td></tr>\
<tr>\
<td><label for=\"discovery\">MQTT Discovery:</label></td>\
<td><a href=\"http://";
mainPage += localIP;
mainPage += "/discovery\">Configure Home Assistant MQTT Discovery</a>";
mainPage += "</td></tr>\
<td><label for=\"calibration\">Sensor Calibration:</label></td>\
<td><a href=\"http://";
mainPage += localIP;
mainPage += "/calibration\">Calibrate TDS Sensors</a>";
mainPage += "</td></tr>\
</table><br>\
<input type=\"checkbox\" name=\"chksave\" value=\"save\">Save all settings as new boot defaults (controller will reboot)<br><br>\
<input type=\"submit\" value=\"Update\">\
</form>\
<br>\
<h2>Controller Commands</h2>\
Caution: Restart and Reset are executed immediately when the button is clicked.<br>\
<table border=\"1\" cellpadding=\"10\">\
<tr>\
<td><button id=\"btnrestart\" onclick=\"location.href = './restart';\">Restart</button></td><td>This will reboot controller and reload default boot values.</td>\
</tr><tr>\
<td><button id=\"btnreset\" style=\"background-color:#FAADB7\" onclick=\"location.href = './reset';\">RESET ALL</button></td><td><b>WARNING</b>: This will clear all settings, including WiFi! You must complete initial setup again.</td>\
</tr><tr>\
<td><button id=\"btnupdate\" onclick=\"location.href = './update';\">Firmware Upgrade</button></td><td>Upload and apply new firmware from local file.</td>\
</tr></table><br>\
Current version: VAR_CURRRENT_VER\
</body>\
</html>";
mainPage.replace("VAR_DEVICE_NAME", deviceName);
mainPage.replace("VAR_CURRRENT_VER", VERSION);
server.send(200, "text/html", mainPage);
}
// Settings submit handler - Settings results
void handleForm() {
if (server.method() != HTTP_POST) {
server.send(405, "text/plain", "Method Not Allowed");
} else {
String saveSettings;
mqttAddr_1 = server.arg("mqttaddr1").toInt();
mqttAddr_2 = server.arg("mqttaddr2").toInt();
mqttAddr_3 = server.arg("mqttaddr3").toInt();
mqttAddr_4 = server.arg("mqttaddr4").toInt();
mqttPort = server.arg("mqttport").toInt();
mqttUser = server.arg("mqttuser");
mqttPW = server.arg("mqttpw");
mqttTelePeriod = server.arg("mqttperiod").toInt();
mqttTopicSub = server.arg("mqtttopic");
mqttTopicPub = server.arg("mqtttopic");
saveSettings = server.arg("chksave");
String message = "<html>\
</head>\
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\
<title>TDS Monitor - Current Settings</title>\
<style>\
body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; }\
</style>\
</head>\
<body>\
<H1>Settings updated!</H1><br>\
<H3>Current values are:</H3>";
//example of message return types
//message += "Device Name: " + deviceName + "<br>";
//message += "Num LEDs: " + server.arg("leds") + "<br>";
//message += "Active Brightness: " + server.arg("activebrightness") + "<br>";
//message += "Standby Brightness: " + server.arg("sleepbrightness") + "<br><br>";
//message += "<b>LED active On Times</b><br><br>";
//message += "Park Time: " + server.arg("ledparktime") + " secs.<br>";
//message += "Exit Time: " + server.arg("ledexittime") + " secs.<br><br>";
//message += "Effect: " + server.arg("effect1") + "<br><br>";
message += "<b>MQTT Settings</b><br><br>";
if ((mqttAddr_1 == 0) && (mqttAddr_2 == 0) && (mqttAddr_3) == 0 && (mqttAddr_4 == 0)) {
message += "MQTT: <b><u>Disabled</u></b> ";
if (saveSettings != "save") {
message += "(If you just changed MQTT settings, you must save as new boot defaults for this to take effect)<br>";
}
} else {
message += "MQTT Server: " + server.arg("mqttaddr1") + "." + server.arg("mqttaddr2") + "." + server.arg("mqttaddr3") + "." + server.arg("mqttaddr4") + "<br>";
message += "MQTT Port: " + server.arg("mqttport") + "<br>";
message += "MQTT User: " + server.arg("mqttuser") + "<br>";
message += "MQTT Password: ***********<br>";
message += "MQTT Topic: homeassistant/stat/" + server.arg("mqtttopic") + "<br>";
message += "Telemetry Period: " + server.arg("mqttperiod") + " seconds<br>";
if (saveSettings != "save") {
message += "<br>(If you just changed MQTT settings, you must save as new boot defaults for this to take effect)<br>";
}
}
message += "<br>";
if (saveSettings == "save") {
message += "<br>";
message += "<b>New settings saved as boot defaults.</b> Controller will now reboot.<br>";
message += "You can return to the settings page after boot completes (lights will briefly turn blue then red/green to indicate completed boot).<br>";
} else {
//Wake up system so new setting can be seen/tested... even if car present
carDetectedCounter = carDetectedCounterMax + 1;
}
message += "<br><a href=\"http://";
message += localIP;
message += "/discovery\">Configure Home Assistant MQTT Discovery</a><br>";
message += "<br><a href=\"http://";
message += localIP;
message += "\">Return to settings</a><br>";
message += "</body></html>";
server.send(200, "text/html", message);
delay(1000);
if (saveSettings == "save") {
updateSettings(true);
} else {
updateSettings(false);
}
}
}
// Firmware update handler
void handleUpdate() {
String updFirmware = "<html>\
</head>\
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\
<title>TDS Monitor - Firmware Update</title>\
<style>\
body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; }\
</style>\
</head>\
<body>\
<H1>Firmware Update</H1>\
<H3>Current firmware version: ";
updFirmware += VERSION;
updFirmware += "</H3><br>";
updFirmware += "Notes:<br>";
updFirmware += "<ul>";
updFirmware += "<li>The firmware update will begin as soon as the Update Firmware button is clicked.</li><br>";
updFirmware += "<li>Your current settings will be retained.</li><br>";
updFirmware += "<li><b>Please be patient!</b> The update will take a few minutes. Do not refresh the page or navigate away.</li><br>";
updFirmware += "<li>If the upload is successful, a brief message will appear and the controller will reboot.</li><br>";
updFirmware += "<li>After rebooting, you'll automatically be taken back to the main settings page and the update will be complete.</li><br>";
updFirmware += "</ul><br>";
updFirmware += "</body></html>";
updFirmware += "<form method='POST' action='/update2' enctype='multipart/form-data'>";
updFirmware += "<input type='file' accept='.bin,.bin.gz' name='Select file' style='width: 300px'><br><br>";
updFirmware += "<input type='submit' value='Update Firmware'>";
updFirmware += "</form><br>";
updFirmware += "<br><a href=\"http://";
updFirmware += localIP;
updFirmware += "\">Return to settings</a><br>";
updFirmware += "</body></html>";
server.send(200, "text/html", updFirmware);
}
void updateSettings(bool saveBoot) {
// This updates the current local settings for current session only.
// Will be overwritten with reboot/reset/OTAUpdate
if (saveBoot) {
updateBootSettings(saveBoot);
} else {
//Update FastLED with new brightness values if changed
if (isAwake) {
FastLED.setBrightness(activeBrightness);
} else {
FastLED.setBrightness(sleepBrightness);
}
}
}
void updateBootSettings(bool restart_ESP) {
// Writes new settings to SPIFFS (new boot defaults)
char t_led_count[4];
char t_led_brightness_active[4];
char t_led_brightness_sleep[4];
char t_led_park_time[4];
char t_led_exit_time[4];
char t_uom_distance[4];
char t_wake_mils[6];
char t_start_mils[6];
char t_park_mils[6];
char t_backup_mils[6];
char t_color_standby[4];
char t_color_wake[4];
char t_color_active[4];
char t_color_parked[4];
char t_color_backup[4];
char t_led_effect[16];
int eff_len = 16;
char t_mqtt_addr_1[4];
char t_mqtt_addr_2[4];
char t_mqtt_addr_3[4];
char t_mqtt_addr_4[4];
char t_mqtt_port[6];
char t_mqtt_user[65];
char t_mqtt_pw[65];
char t_mqtt_tele_period[4];
int user_len = 65;
int user_pw = 65;
//v0.41 new values
char t_device_name[18];
char t_mqtt_topic_sub[18];
char t_mqtt_topic_pub[18];
int dev_name_len = 18;
int topic_len = 18;
char t_kValue_SUP[4];
char t_kValue_PREDI[4];
char t_kValue_OUT[4];
Serial.println("Attempting to update boot settings");
//#endif
//Convert values into char arrays
sprintf(t_led_count, "%u", numLEDs);
sprintf(t_led_brightness_active, "%u", activeBrightness);
sprintf(t_led_brightness_sleep, "%u", sleepBrightness);
sprintf(t_led_park_time, "%u", maxOperationTimePark);
sprintf(t_led_exit_time, "%u", maxOperationTimeExit);
sprintf(t_uom_distance, "%u", uomDistance);
sprintf(t_wake_mils, "%u", wakeDistance);
sprintf(t_start_mils, "%u", startDistance);
sprintf(t_park_mils, "%u", parkDistance);
sprintf(t_backup_mils, "%u", backupDistance);
ledEffect_m1.toCharArray(t_led_effect, eff_len);
sprintf(t_mqtt_addr_1, "%u", mqttAddr_1);
sprintf(t_mqtt_addr_2, "%u", mqttAddr_2);
sprintf(t_mqtt_addr_3, "%u", mqttAddr_3);
sprintf(t_mqtt_addr_4, "%u", mqttAddr_4);
sprintf(t_mqtt_port, "%u", mqttPort);
sprintf(t_mqtt_tele_period, "%u", mqttTelePeriod);
sprintf(t_kValue_SUP, "%u", kValue_SUP);
sprintf(t_kValue_PREDI, "%u", kValue_PREDI);
sprintf(t_kValue_OUT, "%u", kValue_OUT);
mqttUser.toCharArray(t_mqtt_user, user_len);
mqttPW.toCharArray(t_mqtt_pw, user_pw);
deviceName.toCharArray(t_device_name, dev_name_len);
mqttTopicSub.toCharArray(t_mqtt_topic_sub, topic_len);
mqttTopicPub.toCharArray(t_mqtt_topic_pub, topic_len);
#ifdef ARDUINOJSON_VERSION_MAJOR >= 6
DynamicJsonDocument json(1024);
#else
DynamicJsonBuffer jsonBuffer;
JsonObject& json = jsonBuffer.createObject();
#endif
json["mqtt_addr_1"] = t_mqtt_addr_1;
json["mqtt_addr_2"] = t_mqtt_addr_2;
json["mqtt_addr_3"] = t_mqtt_addr_3;
json["mqtt_addr_4"] = t_mqtt_addr_4;
json["mqtt_port"] = t_mqtt_port;
json["mqtt_tele_period"] = t_mqtt_tele_period;
json["mqtt_user"] = t_mqtt_user;
json["mqtt_pw"] = t_mqtt_pw;
json["calkValue_SUP"] = t_kValue_SUP;
json["calkValue_PREDI"] = t_kValue_PREDI;
json["calkValue_OUT"] = t_kValue_OUT;
//v0.41
json["device_name"] = t_device_name;
json["mqtt_topic_sub"] = t_mqtt_topic_sub;
json["mqtt_topic_pub"] = t_mqtt_topic_pub;
if (SPIFFS.begin()) {
File configFile = SPIFFS.open("/config.json", "w");
if (!configFile) {
Serial.println("failed to open config file for writing");
//#endif
}
serializeJson(json, Serial);
serializeJson(json, configFile);
configFile.close();
//end save
Serial.println("Boot settings saved. Rebooting controller.");
//#endif
}
SPIFFS.end();
if (restart_ESP) { //Needed so initial onboarding doesn't cause second reboot
ESP.restart();
}
}
void handleReset() {
String resetMsg = "<HTML>\
</head>\
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\
<title>Controller Reset</title>\
<style>\
body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; }\
</style>\
</head>\
<body>\
<H1>Controller Resetting...</H1><br>\
<H3>After this process is complete, you must setup your controller again:</H3>\
<ul>\
<li>Connect a device to the controller's local access point: ESP_ParkingAsst</li>\
<li>Open a browser and go to: 192.168.4.1</li>\
<li>Enter your WiFi information and set other default settings values</li>\
<li>Click Save. The controller will reboot and join your WiFi</li>\
</ul><br>\
Once the above process is complete, you can return to the main settings page by rejoining your WiFi and entering the IP address assigned by your router in a browser.<br>\
You will need to reenter all of your settings for the system as all values will be reset to original defaults<br><br>\
<b>This page will NOT automatically reload or refresh</b>\
</body></html>";
server.send(200, "text/html", resetMsg);
delay(1000);
SPIFFS.begin();
SPIFFS.format();
SPIFFS.end();
wifiManager.resetSettings();
delay(1000);
ESP.restart();
}
void handleRestart() {
String restartMsg = "<HTML>\
</head>\
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\
<title>Controller Restart</title>\
<style>\
body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; }\
</style>\
</head>\
<body>\
<H1>Controller restarting...</H1><br>\
<H3>Please wait</H3><br>\
After the controller completes the boot process (lights will flash blue, followed by red/green for approx. 2 seconds), you may click the following link to return to the main page:<br><br>\
<a href=\"http://";
restartMsg += localIP;
restartMsg += "\">Return to settings</a><br>";
restartMsg += "</body></html>";
server.send(200, "text/html", restartMsg);
delay(1000);
ESP.restart();
}
// =====================================
// Home Assistant MQTT Discovery - v0.45
// =====================================
void handleDiscovery() {
//Main page for enabling/disabling Home Assistant MQTT Discovery
String discMsg = "<HTML>\
</head>\
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\
<title> TDS Monitor - MQTT Discovery</title>\
<style>\
body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; }\
</style>\
</head>\
<body>\
<H1>Home Assistant MQTT Discovery</H1><br><br>\
This feature can be used to add or remove the TDS Monitor device and MQTT entities to Home Assistant without manual YAML editing.<br><br>";
discMsg += "<u><b>Prerequisites and Notes</b></u>";
discMsg += "<ul><li>It is <b><i>strongly recommended</i></b> that you read the  ";
discMsg += "<a href=\"https://github.com/Resinchem/ESP-Parking-Assistant/wiki/08-MQTT-and-Home-Assistant\" target=\"_blank\" rel=\"noopener noreferrer\">MQTT Documentation</a> before using this feature.</li>";
discMsg += "<li>You must have successfully completed the MQTT setup, rebooted and estabished a connection to your broker before these options will work.</li>";
discMsg += "<li>The Home Assistant MQTT integration must be installed, discovery must not have been disabled nor the default discovery topic changed.</li>";
discMsg += "<li>The action to enable/disable will occur immediately in Home Assistant without any interaction or prompts.</li>";
discMsg += "<li>If you have already manually created the Home Assistant MQTT entities, enabling discovery will create duplicate entities with different names.</li></ul>";
discMsg += "<H3>Enable Discovery</H3>";
discMsg += "This will immediately create a device called <b>VAR_DEVICE_NAME</b> in your Home Assistant MQTT Integration.<br>";
discMsg += "It will also create the following entities for this device:\
<ul>\
<li>Supply TDS</li>\
<li>Pre-DI TDS</li>\
<li>Output TDS</li>\
<li>IP Address</li>\
<li>MAC Address</li></ul><br>";
discMsg += "<button id=\"btnenable\" onclick=\"location.href = './discoveryEnabled';\">Enable Discovery</button>";
discMsg += "<br><hr>";
discMsg += "<H3>Disable Discovery</H3>";
discMsg += "This will <b>immediately</b> delete the device and all entities created MQTT Discover for this device.<br>\
If you have any automations, scripts, dashboard entries or other processes that use these entities, you will need to delete or correct those items in Home Assistant.<br><br>";
discMsg += "<button id=\"btndisable\" onclick=\"location.href = './discoveryDisabled';\">Disable Discovery</button><br><br>";
discMsg += "<br><a href=\"http://";
discMsg += localIP;
discMsg += "\">Return to settings</a><br>";
discMsg += "</body></html>";
discMsg.replace("VAR_DEVICE_NAME", deviceName);
server.send(200, "text/html", discMsg);
}
void enableDiscovery() {
String discMsg = "<HTML>\
</head>\
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\
<title> TDS Monitor MQTT Discovery</title>\
<style>\
body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; }\
</style>\
</head>\
<body>\
<H1>Home Assistant MQTT Discovery</H1><br>";
if (mqttEnabled) {
byte retVal = haDiscovery(true);
if (retVal == 0) {
discMsg += "<b><p style=\"color: #5a8f3d;\">MQTT Discovery topics successfully sent to Home Assistant.</p></b><br>";
discMsg += "If the Home Assistant MQTT integration has been configured correctly, you should now find a new device, <b>VAR_DEVICE_NAME</b>, under the MQTT integration.";
discMsg += "<p style=\"color: #1c5410;\">\
<ul>\
<li>You can change the name of the device or any entities, if desired, via Home Assistant</li>\
<li>To remove (permanently delete) the created device and entities, disable MQTT Discovery</li>\
<li>If you disable MQTT Discover and then reenable it, the device and entities will be recreated with their original names.</li>\
</ul></p><br>";
discMsg += "If you do not see the new device under your Home Assistant MQTT integration, please use a utility (e.g. MQTT Explorer or similar) to see if the controller is successfully connecting to your broker.<br>\
You should see an MQTT connected message, along with the IP and MAC addresses of your controller under the topic specified on the main settings page.<br><br>";
discMsg += "For additional troubleshooting tips, please see the <a href=\"https://github.com/Resinchem/ESP-Parking-Assistant/wiki/08-MQTT-and-Home-Assistant\" target=\"_blank\" rel=\"noopener noreferrer\">MQTT Documentation</a><br><br>\
It is recommended that you disable MQTT Discovery in the Parking Assistant app until you resolve any MQTT/Home Assistant issues.<br><br>";
} else if (retVal == 1) {
//Unable to connect or reconnect to broker
discMsg += "<b><p style=\"color: red;\">The Parking Assistant was unable to connect or reconnect to your MQTT broker!</p></b><br>";
discMsg += "Please be sure your broker is running and accessible on the same network and that you have completed the following:";
discMsg += "<ul>\
<li>Entered the proper MQTT broker settings and the correct User Name and Password</li>\
<li>Checked the box to save settings as new boot defaults</li>\
<li>Rebooted the controller</li>\
</ul><br>";
discMsg += "Please use a utility (e.g. MQTT Explorer or similar) to test if the controller is successfully connecting to your broker.<br>\
You should see an MQTT connected message, along with the IP and MAC addresses of your controller under the topic specified on the main settings page.<br><br>\
Until you successfully see these topics in your broker, you will not be able to utilize MQTT Discovery.<br><br>";
discMsg += "<p style=\"color: red;\">No Home Assistant devices or entities were created.</p><br><br>";
} else {
//Unknown error or issue
discMsg += "<b><p style=\"color: red;\">An unknown error or issue occurred!</p></b><br>";
discMsg += "Please be sure your broker is running and accessible on the same network and that you have completed the following:";
discMsg += "<ul>\
<li>Entered the proper MQTT broker settings and the correct User Name and Password</li>\
<li>Checked the box to save settings as new boot defaults</li>\
<li>Rebooted the controller</li>\
</ul><br>";
discMsg += "Please use a utility (e.g. MQTT Explorer or similar) to test if the controller is successfully connecting to your broker.<br>\
You should see an MQTT connected message, along with the IP and MAC addresses of your controller under the topic specified on the main settings page.<br><br>\
Until you successfully see these topics in your broker, you will not be able to utilize MQTT Discovery and may need to manually create the Home Assistant entities.<br><br>";
discMsg += "For additional troubleshooting tips, please see the <a href=\"https://github.com/Resinchem/ESP-Parking-Assistant/wiki/08-MQTT-and-Home-Assistant\" target=\"_blank\" rel=\"noopener noreferrer\">MQTT Documentation</a><br><br>";
discMsg += "<p style=\"color: red;\">No Home Assistant devices or entities were created.</p><br><br>";
}
} else {
discMsg += "<b><p style=\"color: red;\">MQTT is not enabled or was unable to connect to your broker!</p></b><br>";
discMsg += "Before attempting to enable MQTT Discovery, please be sure you have completed the following:";
discMsg += "<ul>\
<li>Entered the proper MQTT broker settings and the correct User Name and Password</li>\
<li>Checked the box to save settings as new boot defaults</li>\
<li>Rebooted the controller</li>\
</ul><br>";
discMsg += "Please use a utility (e.g. MQTT Explorer or similar) to see if the controller is successfully connecting to your broker.<br>\
You should see an MQTT connected message, along with the IP and MAC addresses of your controller under the topic specified on the main settings page.<br><br>\
Until you successfully see these topics in your broker, you will not be able to enable MQTT Discovery.<br>";
}
discMsg += "<br><a href=\"http://";
discMsg += localIP;
discMsg += "\">Return to settings</a><br>";
discMsg += "</body></html>";
discMsg.replace("VAR_DEVICE_NAME", deviceName);
server.send(200, "text/html", discMsg);
//send baseline TDS reading
sprintf(mqtt_tds_SUP, "%.0f",tdsValue_SUP);
client.publish(mqtt_supTDS_stat, mqtt_tds_SUP);
Serial.println("Supply TDS Baseline Telemetry Sent Successfully!");
Serial.println("");
sprintf(mqtt_tds_PREDI, "%.0f", tdsValue_PREDI);
client.publish(mqtt_prediTDS_stat, mqtt_tds_PREDI);
Serial.println("Pre-DI TDS Baseline Telemetry Sent Successfully!");
Serial.println("");
sprintf(mqtt_tds_OUT, "%.0f", tdsValue_OUT);
client.publish(mqtt_outTDS_stat, mqtt_tds_OUT);
Serial.println("Output TDS Baseline Telemetry Sent Successfully!");
Serial.println("");
}
void disableDiscovery() {
String discMsg = "<HTML>\
</head>\
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\
<title> TDS Monitor MQTT Discovery</title>\
<style>\
body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; }\
</style>\
</head>\
<body>\
<H1>Home Assistant MQTT Discovery</H1><br>";
if (mqttEnabled) {
byte retVal = haDiscovery(false);
if (retVal == 0) {
discMsg += "<b><p style=\"color: #5a8f3d;\">MQTT Removal topics successfully sent to Home Assistant.</p></b><br>";
discMsg += "The device <b>VAR_DEVICE_NAME</b> should now be deleted from Home Assistant, along with the following entities:\
<ul>\
<li>Supply TDS</li>\
<li>Pre-DI TDS</li>\
<li>Output TDS</li>\
<li>IP Address</li>\
<li>MAC Address</li></ul><br>";
} else if (retVal == 1) {
//Unable to connect or reconnect to broker
discMsg += "<b><p style=\"color: red;\">The Parking Assistant was unable to connect or reconnect to your MQTT broker!</p></b><br>";
discMsg += "Please be sure your broker is running and accessible on the same network and that you have completed the following:";
discMsg += "<ul>\
<li>Entered the proper MQTT broker settings and the correct User Name and Password</li>\
<li>Checked the box to save settings as new boot defaults</li>\
<li>Rebooted the controller</li>\
</ul><br>";
discMsg += "Please use a utility (e.g. MQTT Explorer or similar) to test if the controller is successfully connecting to your broker.<br>\
You should see an MQTT connected message, along with the IP and MAC addresses of your controller under the topic specified on the main settings page.<br><br>\
Until you successfully see these topics in your broker, you will not be able to utilize MQTT Discovery.<br><br>";
discMsg += "<p style=\"color: red;\">No Home Assistant devices or entities were removed.</p><br><br>";
} else {
//Unknown error or issue
discMsg += "<b><p style=\"color: red;\">An unknown error or issue occurred!</p></b><br>";
discMsg += "Please be sure your broker is running and accessible on the same network and that you have completed the following:";
discMsg += "<ul>\
<li>Entered the proper MQTT broker settings and the correct User Name and Password</li>\
<li>Checked the box to save settings as new boot defaults</li>\
<li>Rebooted the controller</li>\
</ul><br>";
discMsg += "Please use a utility (e.g. MQTT Explorer or similar) to test if the controller is successfully connecting to your broker.<br>\
You should see an MQTT connected message, along with the IP and MAC addresses of your controller under the topic specified on the main settings page.<br><br>\
Until you successfully see these topics in your broker, you will not be able to utilize MQTT Discovery and may need to manually create the Home Assistant entities.<br><br>";
discMsg += "For additional troubleshooting tips, please see the <a href=\"https://github.com/Resinchem/ESP-Parking-Assistant/wiki/08-MQTT-and-Home-Assistant\" target=\"_blank\" rel=\"noopener noreferrer\">MQTT Documentation</a><br><br>";
discMsg += "<p style=\"color: red;\">No Home Assistant devices or entities were removed.</p><br><br>";
}
} else {
discMsg += "<b><p style=\"color: red;\">MQTT is not enabled or was unable to connect to your broker!</p></b><br>";
discMsg += "Before attempting to use MQTT Discovery, please be sure you have completed the following:";
discMsg += "<ul>\
<li>Entered the proper MQTT broker settings and the correct User Name and Password</li>\
<li>Checked the box to save settings as new boot defaults</li>\
<li>Rebooted the controller</li>\
</ul><br>";
discMsg += "Please use a utility (e.g. MQTT Explorer or similar) to see if the controller is successfully connecting to your broker.<br>\
You should see an MQTT connected message, along with the IP and MAC addresses of your controller under the topic specified on the main settings page.<br><br>\
Until you successfully see these topics in your broker, you will not be able to enable MQTT Discovery.<br>";
}
discMsg += "<br><a href=\"http://";
discMsg += localIP;
discMsg += "\">Return to settings</a><br>";
discMsg += "</body></html>";
discMsg.replace("VAR_DEVICE_NAME", deviceName);
server.send(200, "text/html", discMsg);
}
// Settings submit handler - Settings results
void calibration() {
String saveCalibration;
sprintf(w_tdsValue_SUP, "%.0f", tdsValue_SUP);
sprintf(w_tdsValue_PREDI, "%.0f", tdsValue_PREDI);
sprintf(w_tdsValue_OUT, "%.0f", tdsValue_OUT);
saveCalibration = server.arg("calsave");
String calSensors = "<html>\
</head>\
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\
<title>TDS Monitor - Sensor Calibration</title>\
<style>\
body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; }\
</style>\
</head>\
<body>\
<H1>Calibrate TDS Sensor</H1><br>\
<H3>Current values are:</H3>";
//these are labels
calSensors += "<b>TDS Sensors</b><br>";
calSensors += "Current Supply TDS: ";
calSensors += w_tdsValue_SUP;
calSensors += "ppm";
calSensors += "<br>";
calSensors += "Current Pre-DI TDS: ";
calSensors += w_tdsValue_PREDI;
calSensors += "ppm";
calSensors += "<br>";
calSensors += "Current Output TDS: ";
calSensors += w_tdsValue_OUT;
calSensors += "ppm";
calSensors += "<br>";
calSensors += "<form method=\"post\" enctype=\"application/x-www-form-urlencoded\" action=\"/postcalibration/\">\
<table>\
<tr>\
<td><label for=\"calkValue_SUP\">Calibrated Supply TDS Value:</label></td>\
<td><input type=\"number\" min=\"1\" max=\"1000\" step=\"1\" name=\"calkValue_SUP\" style=\"width: 50px\;\" value=\"";
calSensors += String(kValue_SUP);
calSensors += "\"> ppm<br>\
<tr>\
<td><label for=\"calkValue_PREDI\">Calibrated Pre-DI TDS Value:</label></td>\
<td><input type=\"number\" min=\"1\" max=\"1000\" step=\"1\" name=\"calkValue_PREDI\" style=\"width: 50px\;\" value=\"";
calSensors += String(kValue_PREDI);
calSensors += "\"> ppm<br>\
<tr>\
<td><label for=\"calkValue_OUT\">Calibrated Output TDS Value:</label></td>\
<td><input type=\"number\" min=\"1\" max=\"1000\" step=\"1\" name=\"calkValue_OUT\" style=\"width: 50px\;\" value=\"";
calSensors += String(kValue_OUT);
calSensors += "\"> ppm<br></td></tr>\"";
calSensors += "<br>";
calSensors += "<br><a href=\"http://";
calSensors += localIP;
calSensors += "/discovery\">Configure Home Assistant MQTT Discovery</a><br>";
calSensors += "<br><a href=\"http://";
calSensors += localIP;
calSensors += "\">Return to settings</a><br>";
calSensors += "</td></tr>\
</table><br>\
<input type=\"checkbox\" name=\"calsave\" value=\"save\">Store Calibration and Replace Defaults? (put sensor in reference solution before submitting calibration)<br><br>\
<input type=\"submit\" value=\"Submit Calibration\">\
</form>\
<br>\
<h2>Controller Commands</h2>\
Caution: Restart and Reset are executed immediately when the button is clicked.<br>\
<table border=\"1\" cellpadding=\"10\">\
<tr>\
<td><button id=\"btnrestart\" onclick=\"location.href = './restart';\">Restart</button></td><td>This will reboot controller and reload default boot values.</td>\
</tr><tr>\
<td><button id=\"btnreset\" style=\"background-color:#FAADB7\" onclick=\"location.href = './reset';\">RESET ALL</button></td><td><b>WARNING</b>: This will clear all settings, including WiFi! You must complete initial setup again.</td>\
</tr><tr>\
<td><button id=\"btnupdate\" onclick=\"location.href = './update';\">Firmware Upgrade</button></td><td>Upload and apply new firmware from local file.</td>\
</tr></table><br>\
Current version: VAR_CURRRENT_VER\
</body>\
</html>";
calSensors.replace("VAR_DEVICE_NAME", deviceName);
calSensors.replace("VAR_CURRRENT_VER", VERSION);
server.send(200, "text/html", calSensors);
delay(1000);
if (saveCalibration == "save") {
updateSettings(true);
} else {
updateSettings(false);
}
}
// Settings submit handler - Settings results
void handleCalibration() {
if (server.method() != HTTP_POST) {
server.send(405, "text/plain", "Method Not Allowed");
} else {
String saveCalibration;
kValue_SUP = server.arg("calkValue_SUP").toInt();
kValue_PREDI = server.arg("calkValue_PREDI").toInt();
kValue_OUT = server.arg("calkValue_OUT").toInt();
saveCalibration = server.arg("calsave");
String calform = "<html>\
</head>\
<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">\
<title>TDS Monitor - Current Settings</title>\
<style>\
body { background-color: #cccccc; font-family: Arial, Helvetica, Sans-Serif; Color: #000088; }\
</style>\
</head>\
<body>\
<H1>Settings updated!</H1><br>\
<H3>Current values are:</H3>";
calform += "<b>Calibration Settings</b><br><br>";
if ((kValue_SUP == 0) && (kValue_PREDI == 0) && (kValue_OUT == 0 )) {
calform += "TDS: <b><u>Not Calibrated</u></b> ";
if (saveCalibration != "save") {
calform += "(If you just calibrated your TDS, you must save as new boot defaults for this to take effect)<br>";
}
} else {
calform += "Supply TDS Calibrated to: " + server.arg("calkValue_SUP") + "ppm" + "<br>";
calform += "Pre-DI TDS Calibrated to: " + server.arg("calkValue_PREDI") + "ppm" + "<br>";
calform += "Output TDS Calibrated to: " + server.arg("calkValue_OUT") + "ppm" + "<br>";
calibrateTDSprobe();
if (saveCalibration != "save") {
calform += "<br>(If you just calibrated your TDS, you must save as new boot defaults for this to take effect)<br>";
calibrateTDSprobe();
}
}
calform += "<br>";
if (saveCalibration == "save") {
calform += "<br>";
calform += "<b>New settings saved as boot defaults.</b> Controller will now reboot.<br>";
calform += "You can return to the settings page after boot completes (lights will briefly turn blue then red/green to indicate completed boot).<br>";
calibrateTDSprobe();
} else {
//Wake up system so new setting can be seen/tested... even if car present
carDetectedCounter = carDetectedCounterMax + 1;
}
calform += "<br><a href=\"http://";
calform += localIP;
calform += "/discovery\">Configure Home Assistant MQTT Discovery</a><br>";
calform += "<br><a href=\"http://";
calform += localIP;
calform += "/calibration\">Calibrate TDS Sensors</a><br>";
calform += "<br><a href=\"http://";
calform += localIP;
calform += "\">Return to settings</a><br>";
calform += "</body></html>";
server.send(200, "text/html", calform);
delay(1000);
if (saveCalibration == "save") {
updateSettings(true);
} else {
updateSettings(false);
}
}
}
void calibrateTDSprobe() {
char *cmdReceivedBufferPtr;
static boolean ecCalibrationFinish = 0;
static boolean enterCalibrationFlag = 0;
float KValueTemp_SUP,rawECsolution_SUP;
rawECsolution_SUP = strtod(cmdReceivedBufferPtr,NULL)/(float)(TdsFactor);
rawECsolution_SUP = rawECsolution_SUP*(1.0+0.02*(temperature-25.0));
Serial.println("Calibrating TDS Sensors: Supply, Pre-DI, and Output......");
Serial.print("rawECsolution:");
Serial.print(rawECsolution_SUP);
Serial.print(" ecvalue:");
Serial.println(ecValue_SUP);
KValueTemp_SUP = rawECsolution_SUP/(133.42*voltage_SUP*voltage_SUP*voltage_SUP - 255.86*voltage_SUP*voltage_SUP + 857.39*voltage_SUP); //calibrate in the buffer solution, such as 707ppm(1413us/cm)@25^c
if((rawECsolution_SUP>0) && (rawECsolution_SUP<2000) && (KValueTemp_SUP>0.25) && (KValueTemp_SUP<4.0))
{
Serial.println();
Serial.print("Calibration Successful");
Serial.print(KValueTemp_SUP);
calkValue_SUP = KValueTemp_SUP;
updateSettings(true);
} else {
updateSettings(false);
Serial.print("Calibration Failed");
}
}
// Not found or invalid page handler
void handleNotFound() {
String message = "File Not Found or invalid command.\n\n";
message += "URI: ";
message += server.uri();
message += "\nMethod: ";
message += (server.method() == HTTP_GET) ? "GET" : "POST";
message += "\nArguments: ";
message += server.args();
message += "\n";
server.send(404, "text/plain", message);
}
// ===================================
// SETUP MQTT AND CALLBACKS
// ===================================
bool setup_mqtt() {
byte mcount = 0;
IPAddress mymqttServer = IPAddress(mqttAddr_1, mqttAddr_2, mqttAddr_3, mqttAddr_4);
client.setServer(mymqttServer, mqttPort);
client.setBufferSize(512);
client.setCallback(callback);
Serial.print("Connecting to MQTT broker.");
//#endif
while (!client.connected( )) {
Serial.print(".");
//#endif
client.connect(mqttClient.c_str(), mqttUser.c_str(), mqttPW.c_str());
if (mcount >= 60) {
Serial.println();
Serial.println("Could not connect to MQTT broker. MQTT disabled.");
//#endif
// Could not connect to MQTT broker
return false;
}
delay(500);
mcount++;
}
Serial.println();
Serial.println("Successfully connected to MQTT broker.");
//#endif
client.subscribe(("cmnd/" + mqttTopicSub + "/#").c_str());
client.publish(("homeassistant/stat/" + mqttTopicPub + "/mqtt").c_str(), "connected", true);
//Publish current IP and MAC addresses
client.publish(("homeassistant/stat/" + mqttTopicPub + "/ipaddress").c_str(), localIP.c_str(), true);
client.publish(("homeassistant/stat/" + mqttTopicPub + "/macaddress").c_str(), strMacAddr.c_str(), true);
mqttConnected = true;
//send baseline TDS reading
sprintf(mqtt_tds_SUP, "TDS-SUP: %.0f", tdsValue_SUP);
client.publish(mqtt_pub_topic_supTDS, mqtt_tds_SUP);
Serial.println("Supply TDS Telemetry Sent Successfully!");
Serial.println("");
sprintf(mqtt_tds_PREDI, "TDS-PRE_DI: %.0f", tdsValue_PREDI);
client.publish(mqtt_pub_topic_prediTDS, mqtt_tds_PREDI);
Serial.println("Pre-DI TDS Telemetry Sent Successfully!");
Serial.println("");
sprintf(mqtt_tds_OUT, "TDS-OUT: %.0f", tdsValue_OUT);
client.publish(mqtt_pub_topic_outTDS, mqtt_tds_OUT);
Serial.println("Output TDS Telemetry Sent Successfully!");
Serial.println("");
client.publish("Aquarium","TDS Monitor Connected!");
client.subscribe("Aquarium");
Serial.println("MQTT Connected - Connection Mesage Sent!");
//send baseline TDS reading
sprintf(mqtt_tds_SUP, "%.0f", tdsValue_SUP);
client.publish(mqtt_supTDS_stat, mqtt_tds_SUP);
Serial.println("Supply TDS Telemetry Sent Successfully!");
Serial.println("");
sprintf(mqtt_tds_PREDI, "%.0f", tdsValue_PREDI);
client.publish(mqtt_prediTDS_stat, mqtt_tds_PREDI);
Serial.println("Pre-DI TDS Telemetry Sent Successfully!");
Serial.println("");
sprintf(mqtt_tds_OUT, "%.0f", tdsValue_OUT);
client.publish(mqtt_outTDS_stat, mqtt_tds_OUT);
Serial.println("Output TDS Telemetry Sent Successfully!");
Serial.println("");
return true;
}
void callback(char* topic, byte* payload, unsigned int length) {
payload[length] = '\0';
String message = (char*)payload;
/*
* Add any commands submitted here
* Example:
* if (strcmp(topic, "cmnd/matrix/mode")==0) {
* MyVal = message;
* Do something
* return;
* };
*/
}
void readConfigFile() {
if (SPIFFS.begin()) {
Serial.println("mounted file system");
//#endif
if (SPIFFS.exists("/config.json")) {
//file exists, reading and loading
Serial.println("reading config file");
//#endif
File configFile = SPIFFS.open("/config.json", "r");
if (configFile) {
Serial.println("opened config file");
//#endif
size_t size = configFile.size();
// Allocate a buffer to store contents of the file.
std::unique_ptr<char[]> buf(new char[size]);
configFile.readBytes(buf.get(), size);
DynamicJsonDocument json(1024);
auto deserializeError = deserializeJson(json, buf.get());
serializeJson(json, Serial);
if ( ! deserializeError ) {
Serial.println("\nparsed json");
//#endif
// Read values here from SPIFFS (v0.42 - add defaults for all values in case they don't exist to avoid potential boot loop)
strcpy(mqtt_addr_1, json["mqtt_addr_1"]|"0");
strcpy(mqtt_addr_2, json["mqtt_addr_2"]|"0");
strcpy(mqtt_addr_3, json["mqtt_addr_3"]|"0");
strcpy(mqtt_addr_4, json["mqtt_addr_4"]|"0");
strcpy(mqtt_port, json["mqtt_port"]|"0");
strcpy(mqtt_tele_period, json["mqtt_tele_period"]|"60");
strcpy(mqtt_user, json["mqtt_user"]|"mqttuser");
strcpy(mqtt_pw, json["mqtt_pw"]|"mqttpwd");
strcpy(device_name, json["device_name"]|"TDSMonitor"); // Default needed if upgrading to v0.41, because value won't exist in config
strcpy(mqtt_topic_sub, json["mqtt_topic_sub"]|"tdsmonitor"); // Default needed if upgrading to v0.41, because value won't exist in config
strcpy(mqtt_topic_pub, json["mqtt_topic_pub"]|"tdsmonitor"); // Default needed if upgrading to v0.41, because value won't exist in config
strcpy(calkValue_SUP, json["calkValue_SUP"]|"1.0");
strcpy(calkValue_PREDI, json["calkValue_PREDI"]|"1.0");
strcpy(calkValue_OUT, json["calkValue_OUT"]|"1.0");
//Need to set wifihostname here
deviceName = String(device_name);
} else {
Serial.println("failed to load json config");
//#endif
}
configFile.close();
}
}
SPIFFS.end();
} else {
Serial.println("failed to mount FS");
//#endif
}
}
void setup_Wifi() {
delay(10);
Serial.println("Booting");
Serial.println("Connecting to WiFi");
WiFi.mode(WIFI_STA);
WiFiManager wm;
bool res;
res = wm.autoConnect("TDS Monitor", "password");
if(!res) {
Serial.println("Failed to connect");
}
else {
Serial.println("WiFi Connection Success!");
client.publish(mqtt_IP_stat, localIP.c_str());
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
randomSeed(micros());
localIP = WiFi.localIP().toString();
Serial.println("");
Serial.println("WiFi connected");
Serial.print("IP address: ");
Serial.print(WiFi.localIP());
Serial.println("");
}
}
void resetWiFiSettings(){
//Wifi Reset Button if held for 10 seconds, reset wifi settings
pinMode(27, INPUT_PULLUP);
pinMode(2, OUTPUT);
int wifiReset = digitalRead(27);
if (wifiReset == HIGH) {
digitalWrite(2, LOW);
} else {
digitalWrite(2, HIGH);
delay(10000);
digitalWrite(2, LOW);
delay(150);
digitalWrite(2, HIGH);
delay(150);
digitalWrite(2, LOW);
delay(150);
digitalWrite(2, HIGH);
delay(150);
digitalWrite(2, LOW);
delay(150);
digitalWrite(2, HIGH);
delay(150);
digitalWrite(2, LOW);
delay(150);
digitalWrite(2, HIGH);
delay(150);
digitalWrite(2, LOW);
delay(150);
Serial.println("WiFi Reset...TDS Monitor Restarting");
delay(150);
wm.resetSettings();
delay(150);
//Restarts device after wiping wifi settings
ESP.restart();
}
}
void wifiReconnect() {
// Loop until we're reconnected
while (WiFi.status() != WL_CONNECTED) {
Serial.print("Attempting to Re-Establish WiFi Connection...");
if (WiFi.status() == WL_CONNECTED) {
Serial.println("WiFi Connection Re-Established!");
client.publish(mqtt_IP_stat, localIP.c_str());
} else {
Serial.print("failed, rc=");
Serial.print(WiFi.status());
Serial.println(" try again in 5 seconds");
// Wait 5 seconds before retrying
delay(5000);
setup_Wifi();
}
}
}
// ===============================
// LED and Display Functions
// ===============================
void blinkLEDs(CRGB color) {
if (blinkOn) {
fill_solid(LEDs, numLEDs, color);
} else {
fill_solid(LEDs, numLEDs, CRGB::Black);
}
blinkOn = !blinkOn;
}
void updateOutIn(int curDistance) {
byte numberToLight = 1;
fill_solid(LEDs, numLEDs, CRGB::Black);
//Get number of LEDs to light up on each end, based on interval
numberToLight = (startDistance - curDistance) / intervalDistance;
if (numberToLight ==0 ) numberToLight = 1; //Assure at least 1 light if integer truncation results in 0
for (int i=0; i < numberToLight; i++) {
LEDs[i] = ledColorActive;
LEDs[(numLEDs-1) - i] = ledColorActive;
}
}
void updateInOut(int curDistance) {
byte numberToLight = 1;
byte startLEDLeft = 0;
byte startLEDRight = 0;
fill_solid(LEDs, numLEDs, CRGB::Black);
//Get number of LEDs to light up on each end, based on interval
numberToLight = ((startDistance - curDistance) / intervalDistance);
if (numberToLight ==0 ) numberToLight = 1; //Assure at least 1 light if integer truncation results in 0
//Find center LED(s) - single of odd number, two if even number of LEDS
startLEDLeft = (numLEDs / 2);
startLEDRight = startLEDLeft;
if ((startLEDLeft % 2) == 0) {
startLEDLeft --;
}
for (int i=0; i < numberToLight; i++) {
LEDs[(startLEDLeft - i)] = ledColorActive;
LEDs[(startLEDRight + i)] = ledColorActive;
}
}
void updateFullStrip(int curDistance) {
byte numberToLight = 1;
fill_solid(LEDs, numLEDs, CRGB::Black);
//Get number of LEDs to light up from start of LED strip, based on interval
numberToLight = (startDistance - curDistance) / intervalDistance;
if (numberToLight ==0 ) numberToLight = 1; //Assure at least 1 light if integer truncation results in 0
for (int i=0; i < numberToLight; i++) {
LEDs[i] = ledColorActive;
}
}
void updateFullStripInv(int curDistance) {
byte numberToLight = 1;
fill_solid(LEDs, numLEDs, CRGB::Black);
//Get number of LEDs to light up from end of LED strip, based on interval
numberToLight = (startDistance - curDistance) / intervalDistance;
if (numberToLight ==0 ) numberToLight = 1; //Assure at least 1 light if integer truncation results in 0
for (int i=0; i < numberToLight; i++) {
LEDs[((numLEDs - i)- 1)] = ledColorActive;
}
}
void updateSolid(int curDistance) {
fill_solid(LEDs, numLEDs, CRGB::Black);
if ((curDistance > startDistance) && (curDistance <= wakeDistance)) {
fill_solid(LEDs, numLEDs, ledColorWake);
} else if ((curDistance > parkDistance) && (curDistance <= startDistance)) {
fill_solid(LEDs, numLEDs, ledColorActive);
} else if ((curDistance > backupDistance) && (curDistance <= parkDistance)) {
fill_solid(LEDs, numLEDs, ledColorParked);
}
}
void updateSleepMode() {
fill_solid(LEDs, numLEDs, CRGB::Black);
FastLED.setBrightness(sleepBrightness);
if (showStandbyLEDs) {
LEDs[0] = ledColorStandby;
LEDs[numLEDs - 1] = ledColorStandby;
}
}
void updateOTA() {
fill_solid(LEDs, numLEDs, CRGB::Black);
//Alternate LED colors using red and green
FastLED.setBrightness(activeBrightness);
for (int i=0; i < (numLEDs-1); i = i + 2) {
LEDs[i] = CRGB::Red;
LEDs[i+1] = CRGB::Green;
}
FastLED.show();
}
// ==============================
// MQTT Functions and Procedures
// ==============================
void createDiscoveryUniqueID() {
//Generate UniqueID from uidPrefix + last 6 chars of device MAC address
//This should insure that even multiple devices installed in same HA instance are unique
strcpy(devUniqueID, uidPrefix);
int preSizeBytes = sizeof(uidPrefix);
int preSizeElements = (sizeof(uidPrefix) / sizeof(uidPrefix[0]));
//Now add last 6 chars from MAC address (these are 'reversed' in the array)
int j = 0;
//for (int i = 2; i >= 0; i--) {
for (int i = 3; i < 6; i++) {
sprintf(&devUniqueID[(preSizeBytes - 1) + (j)], "%02X", macAddr[i]); //preSizeBytes indicates num of bytes in prefix - null terminator, plus 2 (j) bytes for each hex segment of MAC
j = j + 2;
}
//devUniqueID would now contain something like "TDSMonitor02BE4F" which can be used for topics/payloads
// End result is a unique ID for this device (e.g. rctdevE350CA)
Serial.print("Unique ID: ");
Serial.println(devUniqueID);
}
byte haDiscovery (bool enable) {
char topic[128];
//if (auto_discovery) {
char buffer1[512];
char buffer2[512];
char buffer3[512];
char buffer4[512];
char buffer5[512];
char uid[128];
if (mqttEnabled) {
createDiscoveryUniqueID();
if (enable) {
//Add device and entities
if (!client.connected()) {
if (!mqttReconnect_soft()) {
return 1;
}
}
//Should have valid MQTT Connection at this point
DynamicJsonDocument doc(2048);
Serial.println("Discovering new devices...");
Serial.println("Adding TDS Sensor...Supply TDS");
//Create supTDS Sensor with full device details
//topic
strcpy(topic, "homeassistant/sensor/");
strcat(topic, "TDSMonitor");
strcat(topic, "supTDS/config");
//Create unique_id based on devUniqueID
strcpy(uid, "TDSMonitor");
strcat(uid, "supTDS");
//JSON payload
doc.clear();
doc["name"] = "Supply TDS";
doc["obj_id"] = "mqtt_TDSmonitor_supTDS";
doc["dev_cla"] = "volatile_organic_compounds_parts";
doc["uniq_id"] = uid;
doc["stat_t"] = "homeassistant/stat/TDSMonitor/supTDS";
doc["unit_of_meas"] = "ppm";
doc["ic"] = "mdi:water-pump";
JsonObject devicesupTDS = doc.createNestedObject("device");
devicesupTDS["ids"] = "tdsmonitor";
devicesupTDS["name"] = "TDS Monitor";
devicesupTDS["mf"] = "DeezNutzInc";
devicesupTDS["mdl"] = "TDS Monitor Elite";
devicesupTDS["sw"] = "1.89";
devicesupTDS["hw"] = "1.0";
devicesupTDS["cu"] = "http://" + localIP + "/config"; //web interface for device, with discovery toggle
serializeJson(doc, buffer1);
//Publish discovery topic and payload (with retained flag)
client.publish(topic, buffer1, true);
//Create prediTDS Sensor
Serial.println("Adding TDS Sensor...Pre-DI TDS");
//Create unique Topic based on devUniqueID
strcpy(topic, "homeassistant/sensor/");
strcat(topic, "TDSMonitor");
strcat(topic, "prediTDS/config");
//Create unique_id based on decUniqueID
strcpy(uid, "TDSMonitor");
strcat(uid, "prediTDS");
//Create JSON payload per HA documentation
doc.clear();
doc["name"] = "Pre-DI TDS";
doc["obj_id"] = "mqtt_TDSmonitor_prediTDS";
doc["dev_cla"] = "volatile_organic_compounds_parts";
doc["uniq_id"] = uid;
doc["stat_t"] = "homeassistant/stat/TDSMonitor/prediTDS";
doc["unit_of_meas"] = "ppm";
doc["ic"] = "mdi:toilet";
JsonObject deviceprediTDS = doc.createNestedObject("device");
deviceprediTDS["ids"] = "tdsmonitor";
deviceprediTDS["name"] = "TDS Monitor";
serializeJson(doc, buffer2);
//Publish discovery topic and payload (with retained flag)
client.publish(topic, buffer2, true);
//outTDS Sensor
Serial.println("Adding TDS Sensor...Output TDS");
//Create unique Topic based on devUniqueID
strcpy(topic, "homeassistant/sensor/");
strcat(topic, "TDSMonitor");
strcat(topic, "outTDS/config");
//Create unique_id based on decUniqueID
strcpy(uid, "TDSMonitor");
strcat(uid, "outTDS");
//Create JSON payload per HA documentation
doc.clear();
doc["name"] = "Output TDS";
doc["obj_id"] = "mqtt_TDSmonitor_outTDS";
doc["dev_cla"] = "volatile_organic_compounds_parts";
doc["uniq_id"] = uid;
doc["stat_t"] = "homeassistant/stat/TDSMonitor/outTDS";
doc["unit_of_meas"] = "ppm";
doc["ic"] = "mdi:water-check";
JsonObject deviceoutTDS = doc.createNestedObject("device");
deviceoutTDS["ids"] = "tdsmonitor";
deviceoutTDS["name"] = "TDS Monitor";
serializeJson(doc, buffer3);
//Publish discovery topic and payload (with retained flag)
client.publish(topic, buffer3, true);
//IP Address Diagnostic Sensor
Serial.println("Adding IP Diagnostic Sensor...");
//Create unique Topic based on devUniqueID
strcpy(topic, "homeassistant/sensor/");
strcat(topic, "TDSMonitor");
strcat(topic, "IP/config");
//Create unique_id based on decUniqueID
strcpy(uid, "TDSMonitor");
strcat(uid, "IP");
//Create JSON payload per HA documentation
doc.clear();
doc["name"] = "IP Address";
doc["uniq_id"] = uid;
doc["ent_cat"] = "diagnostic";
doc["stat_t"] = "homeassistant/stat/TDSMonitor/ipaddress";
JsonObject deviceIP = doc.createNestedObject("device");
deviceIP = doc.createNestedObject("device");
deviceIP["ids"] = "tdsmonitor";
deviceIP["name"] = "TDS Monitor";
serializeJson(doc, buffer4);
//Publish discovery topic and payload (with retained flag)
client.publish(topic, buffer4, true);
Serial.println("All Devices Added!");
//Create MAC Address as Diagnostic Sensor
//topic
strcpy(topic, "homeassistant/sensor/");
strcat(topic, "TDSMonitor");
strcat(topic, "MAC/config");
//Unique ID
strcpy(uid, "TDSMonitor");
strcat(uid, "MAC");
//JSON Payload
doc.clear();
doc["name"] = deviceName + " MAC Address";
doc["uniq_id"] = uid;
doc["ent_cat"] = "diagnostic";
doc["stat_t"] = "homeassistant/stat/TDSMonitor/macaddress";
JsonObject deviceMAC = doc.createNestedObject("device");
deviceMAC["ids"] = "tdsmonitor";
deviceMAC["name"] = "TDS Monitor";
serializeJson(doc, buffer5);
client.publish(topic, buffer5, true);
return 0;
} else {
//Remove all entities by publishing empty payloads
if (!client.connected()) {
if (!mqttReconnect_soft()) {
return 1;
}
}
//Must use original topic, so recreate from original Unique ID
//This will immediately remove/delete the device/entities from HA
Serial.println("Removing discovered devices...");
//supTDS Sensor
strcpy(topic, "homeassistant/sensor/");
strcat(topic, "TDSMonitor");
strcat(topic, "supTDS/config");
client.publish(topic, "");
//prediTDS Sensor
strcpy(topic, "homeassistant/sensor/");
strcat(topic, "TDSMonitor");
strcat(topic, "prediTDS/config");
client.publish(topic, "");
//outTDS Sensor
strcpy(topic, "homeassistant/sensor/");
strcat(topic, "TDSMonitor");
strcat(topic, "outTDS/config");
client.publish(topic, "");
//IP Diagnostics Sensor
strcpy(topic, "homeassistant/sensor/");
strcat(topic, "TDSMonitor");
strcat(topic, "IP/config");
client.publish(topic, "");
//MAC Address Sensor
strcpy(topic, "homeassistant/sensor/");
strcat(topic, "TDSMonitor");
strcat(topic, "MAC/config");
client.publish(topic, "");
Serial.println("All Devices Removed...");
return 0;
}
} else {
//MQTT not enabled... should never hit this as it is checked before calling
return 90;
}
//catch all
return 99;
}
void mqttReconnect() {
int retries = 0;
// Loop until we're reconnected
while (!client.connected()) {
if(retries <150)
{
Serial.print("Attempting to Re-Establish MQTT Connection...");
//#endif
if (client.connect(mqttClient.c_str(), mqttUser.c_str(), mqttPW.c_str()))
{
Serial.println("TDS Monitor Re-connected After Failure!");
//#endif
// ... and resubscribe
client.subscribe("Aquarium/#");
}
else
{
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
//#endif
retries++;
// Wait 5 seconds before retrying
delay(5000);
}
}
if ((retries > 149) && (mqttEnabled))
{
ESP.restart();
}
}
}
bool mqttReconnect_soft() {
//Attempt MQTT reconnect. If fails, return false instead of forcing ESP Reboot
int retries = 0;
while (!client.connected()) {
if(retries < 10)
{
Serial.print("Attempting to Re-Establish MQTT Connection...");
//#endif
if (client.connect(mqttClient.c_str(), mqttUser.c_str(), mqttPW.c_str()))
{
Serial.println("TDS Monitor Re-connected After Failure!");
//#endif
// ... and resubscribe
client.subscribe("Aquarium/#");
return true;
}
else
{
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 5 seconds");
//#endif
retries++;
// Wait 3 seconds before retrying
delay(3000);
yield();
}
}
if ((retries > 9) && (mqttEnabled))
{
return false;
}
}
}
void setup_TDS(){
//Supply TDS Setup
pinMode(TDS_SUP_Pin,INPUT);
pinMode(TDS_PREDI_Pin,INPUT);
pinMode(TDS_OUT_Pin,INPUT);
readKValues();
}
void readKValues(){
kValue_SUP = 1.0; // default value: K = 1.0
kValue_PREDI = 1.0; // default value: K = 1.0
kValue_OUT = 1.0; // default value: K = 1.0
}
void update_TDS(){
analogValue_SUP = analogRead(TDS_SUP_Pin);
voltage_SUP = analogValue_SUP/tdsAdcRange*tdsAref;
ecValue_SUP=(133.42*voltage_SUP*voltage_SUP*voltage_SUP - 255.86*voltage_SUP*voltage_SUP + 857.39*voltage_SUP)*kValue_SUP;
ecValue25_SUP = ecValue_SUP / (1.0+0.02*(temperature-25.0)); //temperature compensation
tdsValue_SUP = ecValue25_SUP * TdsFactor;
analogValue_PREDI = analogRead(TDS_PREDI_Pin);
voltage_PREDI = analogValue_PREDI/tdsAdcRange*tdsAref;
ecValue_PREDI=(133.42*voltage_PREDI*voltage_PREDI*voltage_PREDI - 255.86*voltage_PREDI*voltage_PREDI + 857.39*voltage_PREDI)*kValue_PREDI;
ecValue25_PREDI = ecValue_PREDI / (1.0+0.02*(temperature-25.0)); //temperature compensation
tdsValue_PREDI = ecValue25_PREDI * TdsFactor;
analogValue_OUT = analogRead(TDS_OUT_Pin);
voltage_OUT = analogValue_OUT/tdsAdcRange*tdsAref;
ecValue_OUT=(133.42*voltage_OUT*voltage_OUT*voltage_OUT - 255.86*voltage_OUT*voltage_OUT + 857.39*voltage_OUT)*kValue_OUT;
ecValue25_OUT = ecValue_OUT / (1.0+0.02*(temperature-25.0)); //temperature compensation
tdsValue_OUT = ecValue25_OUT * TdsFactor;
}
void calculate_TDS(){
temperature = tdstemp;
update_TDS();
if(tdsValue_SUP == prevtdsValue_SUP) {
Serial.print("Supply TDS reading hasnt changed (Current/Last Read): ");
Serial.print(tdsValue_SUP, 0); Serial.print("ppm");
Serial.print(" : ");
Serial.print(prevtdsValue_SUP); Serial.println("ppm");
delay(100);
} else {
prevtdsValue_SUP = tdsValue_SUP;
Serial.print("SUP TDS: "); Serial.print(tdsValue_SUP, 0); Serial.println("ppm");
sprintf(mqtt_tds_SUP, "%.0f", tdsValue_SUP);
client.publish(mqtt_supTDS_stat, mqtt_tds_SUP);
sprintf(mqtt_tds_SUP2, "TDS-SUP: %.0f", tdsValue_SUP);
client.publish(mqtt_pub_topic_supTDS, mqtt_tds_SUP2);
Serial.println("Supply TDS Telemetry Sent Successfully!");
delay(100);
}
if(tdsValue_PREDI == prevtdsValue_PREDI) {
Serial.print("Pre-DI TDS reading hasnt changed (Current/Last Read): ");
Serial.print(tdsValue_PREDI, 0); Serial.print("ppm");
Serial.print(" : ");
Serial.print(prevtdsValue_PREDI); Serial.println("ppm");
delay(100);
} else {
prevtdsValue_PREDI = tdsValue_PREDI;
Serial.print("PRE-DI TDS: "); Serial.print(tdsValue_PREDI, 0); Serial.println("ppm");
sprintf(mqtt_tds_PREDI, "%.0f", tdsValue_PREDI);
client.publish(mqtt_prediTDS_stat, mqtt_tds_PREDI);
sprintf(mqtt_tds_PREDI2, "TDS-PRE_DI: %.0f", tdsValue_PREDI);
client.publish(mqtt_pub_topic_prediTDS, mqtt_tds_PREDI2);
Serial.println("Pre-DI TDS Telemetry Sent Successfully!");
delay(100);
}
if(tdsValue_OUT == prevtdsValue_OUT) {
Serial.print("Output TDS reading hasnt changed (Current/Last Read): ");
Serial.print(tdsValue_OUT, 0); Serial.print("ppm");
Serial.print(" : ");
Serial.print(prevtdsValue_OUT); Serial.println("ppm");
delay(100);
} else {
prevtdsValue_OUT = tdsValue_OUT;
Serial.print("OUT TDS: "); Serial.print(tdsValue_OUT, 0); Serial.println("ppm");
sprintf(mqtt_tds_OUT, "%.0f", tdsValue_OUT);
client.publish(mqtt_outTDS_stat, mqtt_tds_OUT);
sprintf(mqtt_tds_OUT2, "TDS-OUT: %.0f", tdsValue_OUT);
client.publish(mqtt_pub_topic_outTDS, mqtt_tds_OUT2);
Serial.println("Output TDS Telemetry Sent Successfully!");
delay(100);
}
delay(3000);
}
void setup() {
// Serial monitor
Serial.begin(115200);
Serial.println("Booting...");
//#endif
//RGB_LED_Setup();
// -------------
// SETUP FASTLED
// -------------
FastLED.addLeds<WS2812B, LED_DATA_PIN, GRB>(LEDs, NUM_LEDS_MAX);
FastLED.setDither(false);
FastLED.setCorrection(TypicalLEDStrip);
FastLED.setBrightness(activeBrightness);
setup_Wifi();
//mqttConnect();
client.setCallback(callback);
resetWiFiSettings();
setup_TDS();
MDNS.begin(host);
//Get MAC address when joining wifi and place into char array
WiFi.macAddress(macAddr);
//Call routing (or embed here) to create initial Unique ID
createDiscoveryUniqueID();
//Handle web callbacks for enabling or disabling discovery (using this method is just one of many ways to do this)
// Default Wifi to station mode - fixes issue #16
// Local AP will be handed by WifiManager for onboarding
WiFi.mode(WIFI_STA);
// -----------------------------------------
// Captive Portal and Wifi Onboarding Setup
// -----------------------------------------
//clean FS, for testing - uncomment next line ONLY if you wish to wipe current FS
//SPIFFS.format();
// *******************************
// read configuration from FS json
// *******************************
Serial.println("mounting FS...");
//#endif
readConfigFile();
// The extra parameters to be configured (can be either global or just in the setup)
// After connecting, parameter.getValue() will get you the configured value
// id/name placeholder/prompt default length
WiFiManagerParameter custom_text("<p>Each parking assistant must have a unique name. Letters and numbers only, no spaces, 16 characters max. See the wiki documentation for more info.</p>");
WiFiManagerParameter custom_dev_id("devName", "Unique Device Name", "parkasst", 16, " 16 chars/alphanumeric only");
//set config save notify callback
wifiManager.setSaveConfigCallback(saveConfigCallback);
//set static ip
//wifiManager.setSTAStaticIPConfig(IPAddress(10, 0, 1, 99), IPAddress(10, 0, 1, 1), IPAddress(255, 255, 255, 0));
//add all your parameters here
wifiManager.addParameter(&custom_text);
wifiManager.addParameter(&custom_dev_id);
//reset settings - for testing
//wifiManager.resetSettings();
//sets timeout until configuration portal gets turned off
//useful to make it all retry or go to sleep
//in seconds
wifiManager.setTimeout(360);
//fetches ssid and pass and tries to connect
//if it does not connect it starts an access point with the specified name "ESP_ParkingAsst"
//If not supplied, will use ESP + last 7 digits of MAC
//and goes into a blocking loop awaiting configuration. If a password
//is desired for the AP, add it after the AP name (e.g. autoConnect("MyApName", "12345678")
if (!wifiManager.autoConnect("TDS Monitor")) { //
Serial.println("failed to connect and hit timeout");
//#endif
delay(3000);
//reset and try again, or maybe put it to deep sleep
ESP.restart();
delay(5000);
}
//Get custom device name and set wifi and OTA host name, mqttclient and
if (shouldSaveConfig) {
strcpy(device_name, custom_dev_id.getValue());
}
deviceName = String(device_name);
//Use device name to define host names and mqttclient name
wifiHostName = deviceName;
otaHostName = deviceName + "OTA";
mqttClient = deviceName;
//if you get here you have connected to the WiFi
WiFi.hostname(wifiHostName.c_str());
Serial.println("connected to your wifi...yay!");
//#endif
//If callback was excuted, flag was set to save parameters
if (shouldSaveConfig) {
updateBootSettings(false); //don't reboot
delay(1000);
readConfigFile(); //Load settings
}
Serial.println("local ip");
Serial.println(WiFi.localIP());
//#endif
localIP = WiFi.localIP().toString();
WiFi.macAddress(macAddr); //Array for Unique ID gen
strMacAddr = WiFi.macAddress(); //String for MQTT
// ----------------------------
mqttAddr_1 = (String(mqtt_addr_1)).toInt();
mqttAddr_2 = (String(mqtt_addr_2)).toInt();
mqttAddr_3 = (String(mqtt_addr_3)).toInt();
mqttAddr_4 = (String(mqtt_addr_4)).toInt();
kValue_SUP = (String(calkValue_SUP)).toFloat();
kValue_PREDI = (String(calkValue_PREDI)).toFloat();
kValue_OUT = (String(calkValue_OUT)).toFloat();
//Disable MQTT if IP = 0.0.0.0
if ((mqttAddr_1 == 0) && (mqttAddr_2 == 0) && (mqttAddr_3 == 0) && (mqttAddr_4 == 0)) {
mqttPort = 0;
mqttEnabled = false;
mqttConnected = false;
} else {
mqttPort = (String(mqtt_port)).toInt();
mqttTelePeriod = (String(mqtt_tele_period)).toInt();
mqttUser = String(mqtt_user);
mqttPW = String(mqtt_pw);
mqttTopicSub = String(mqtt_topic_sub);
mqttTopicPub = String(mqtt_topic_pub);
mqttEnabled = true;
}
//------------------------------
// Setup handlers for web calls
//------------------------------
server.on("/", handleRoot);
server.on("/postform/", handleForm);
server.onNotFound(handleNotFound);
server.on("/update", handleUpdate);
server.on("/restart", handleRestart);
server.on("/reset", handleReset);
server.on("/discovery", handleDiscovery);
server.on("/discoveryEnabled", enableDiscovery);
server.on("/discoveryDisabled", disableDiscovery);
server.on("/calibration", calibration);
server.on("/postcalibration/", handleCalibration);
server.on("/otaupdate",[]() {
//Called directly from browser address (//ip_address/otaupdate) to put controller in ota mode for uploadling from Arduino IDE
server.send(200, "text/html", "<h1>Ready for upload...<h1><h3>Start upload from IDE now</h3>");
ota_flag = true;
ota_time = ota_time_window;
ota_time_elapsed = 0;
});
//Firmware Update Handler
httpUpdater.setup(&server, "/update2");
httpUpdater.setup(&server);
server.begin();
Serial.println("Setup complete - starting main loop");
//#endif
//PROBABLY DONT NEED BUT KEEP TIL WORKING
server.on("/discovery_on",[]() {
server.send(200, "text/html", "<h1>Discovery ON...<h1><h3>Home Assistant MQTT Discovery enabled</h3>");
delay(200);
auto_discovery = true;
byte retVal = haDiscovery(true);
});
server.on("/discovery_off",[]() {
server.send(200, "text/html", "<h1>Discovery OFF...<h1><h3>Home Assistant MQTT Discovery disabled. Previous entities removed.</h3>");
delay(200);
auto_discovery = false;
byte retVal = haDiscovery(false);
});
// =====================
// MQTT Setup
// =====================
if (mqttEnabled) {
//Attempt to connect to MQTT broker - if fails, disable MQTT
if (!setup_mqtt()) {
mqttEnabled = false;
}
}
//-----------------------------
// Setup OTA Updates
//-----------------------------
ArduinoOTA.setHostname(otaHostName.c_str());
ArduinoOTA.onStart([]() {
String type;
if (ArduinoOTA.getCommand() == U_FLASH) {
type = "sketch";
} else { // U_FS
type = "filesystem";
}
// NOTE: if updating FS this would be the place to unmount FS using FS.end()
});
ArduinoOTA.begin();
}
void loop() {
if (WiFi.status() != WL_CONNECTED) {
wifiReconnect();
}
//RGB_LED();
calculate_TDS();
resetWiFiSettings();
server.handleClient();
//Handle OTA updates when OTA flag set via HTML call to http://ip_address/otaupdate
if (ota_flag) {
updateOTA(); //Show update on LED strip
uint32_t ota_time_start = millis();
while (ota_time_elapsed < ota_time) {
ArduinoOTA.handle();
ota_time_elapsed = millis()-ota_time_start;
delay(10);
}
ota_flag = false;
updateSleepMode();
}
uint32_t currentMillis = millis();
int16_t distance = 0;
/*
******** UPDATE WITH SOMETHING LIKE IF STATE CHANGE FOR TDS
//v0.44 - force MQTT update if car state changes
if (carDetected != prevCarStatus) {
prevCarStatus = carDetected;
forceMQTTUpdate = true;
}
*/
//Put system to sleep if parking or exit time elapsed
uint32_t elapsedTime = currentMillis - startTime;
if (((elapsedTime > (maxOperationTimePark * 1000)) && (parkSleepTimerStarted)) || ((elapsedTime > (maxOperationTimeExit * 1000)) && (exitSleepTimerStarted ))) {
updateSleepMode();
isAwake = false;
startTime = currentMillis;
exitSleepTimerStarted = false;
parkSleepTimerStarted = false;
}
//Handle MQTT calls (if enabled)
if (mqttEnabled) {
#if defined(MQTTMODE) && (MQTTMODE == 1 && (WIFIMODE == 1 || WIFIMODE == 2))
if (!client.connected())
{
mqttReconnect();
}
client.loop();
#endif
}
//Update MQTT Stats per tele period
if (mqttEnabled) {
if (((currentMillis - mqttLastUpdate) > (mqttTelePeriod * 1000)) || (forceMQTTUpdate)) {
mqttLastUpdate = currentMillis;
forceMQTTUpdate = false;
if (!client.connected()) {
mqttReconnect();
}
//Keep to use with own criteria
/*
// Publish MQTT values
char outMsg[6];
byte carStatus = 0;
float measureDistance = 0;
if (carDetected) carStatus = 1;
sprintf(outMsg, "%1u",carStatus);
client.publish(("homeassistant/stat/" + mqttTopicPub + "/cardetected").c_str(), outMsg, true);
sprintf(outMsg, "%2.1f", measureDistance);
client.publish(("homeassistant/stat/" + mqttTopicPub + "/parkdistance").c_str(), outMsg, true);
*/
}
}
//Show/Refresh LED Strip
FastLED.show();
delay(200);
}
Would be keen to see more info on this AJAX, ill do some research