better formatting
All checks were successful
Test compiling project / test (push) Successful in 1m42s

This commit is contained in:
2023-10-07 20:08:31 +02:00
parent 9c6f83d4f0
commit 5bd085ba63

View File

@@ -1,13 +1,13 @@
#include <Arduino.h>
#include "SPIFFS.h"
#include <WiFi.h>
#include <Arduino.h>
#include <AsyncTCP.h>
#include <ESPAsyncWebServer.h>
#include <ETH.h>
#include <WiFi.h>
#include "AsyncJson.h"
#include <ArduinoJson.h>
#include <ArduinoLog.h>
#include "AsyncJson.h"
#include <ArduinoOTA.h>
@@ -42,26 +42,24 @@ bool current_low = false;
uint8_t failed_connection_attempts = 0;
struct SensorData
{
int percentage;
float voltage;
float current;
float water_height;
struct SensorData {
int percentage;
float voltage;
float current;
float water_height;
};
struct NetworkData
{
String ip_address;
bool link;
float rssi;
String network_name;
struct NetworkData {
String ip_address;
bool link;
float rssi;
String network_name;
};
NetworkData wifi_data;
NetworkData ethernet_data;
SensorData current_data = SensorData{-1, -1, -1, -1};
SensorData current_data = SensorData { -1, -1, -1, -1 };
int64_t mac_address = ESP.getEfuseMac();
@@ -74,321 +72,266 @@ AsyncWebServer server(80);
void display_percentage(int percentage)
{
digitalWrite(LED_RED, 0);
digitalWrite(LED_RED, 0);
if (percentage > 20)
{
digitalWrite(LED_1, 1);
}
else
{
digitalWrite(LED_1, 0);
}
if (percentage > 40)
{
digitalWrite(LED_2, 1);
}
else
{
digitalWrite(LED_2, 0);
}
if (percentage > 60)
{
digitalWrite(LED_3, 1);
}
else
{
digitalWrite(LED_3, 0);
}
if (percentage > 80)
{
digitalWrite(LED_4, 1);
}
else
{
digitalWrite(LED_4, 0);
}
if (percentage > 95)
{
digitalWrite(LED_5, 1);
}
else
{
digitalWrite(LED_5, 0);
}
if (percentage > 1) {
digitalWrite(LED_1, 1);
} else {
digitalWrite(LED_1, 0);
}
if (percentage > 20) {
digitalWrite(LED_2, 1);
} else {
digitalWrite(LED_2, 0);
}
if (percentage > 40) {
digitalWrite(LED_3, 1);
} else {
digitalWrite(LED_3, 0);
}
if (percentage > 60) {
digitalWrite(LED_4, 1);
} else {
digitalWrite(LED_4, 0);
}
if (percentage > 80) {
digitalWrite(LED_5, 1);
} else {
digitalWrite(LED_5, 0);
}
delay(3000);
}
void display_error_code(byte err_code)
{
digitalWrite(LED_RED, 1);
digitalWrite(LED_1, bitRead(err_code, 0));
digitalWrite(LED_2, bitRead(err_code, 1));
digitalWrite(LED_3, bitRead(err_code, 2));
digitalWrite(LED_4, bitRead(err_code, 3));
digitalWrite(LED_5, bitRead(err_code, 4));
digitalWrite(LED_RED, 1);
digitalWrite(LED_1, bitRead(err_code, 0));
digitalWrite(LED_2, bitRead(err_code, 1));
digitalWrite(LED_3, bitRead(err_code, 2));
digitalWrite(LED_4, bitRead(err_code, 3));
digitalWrite(LED_5, bitRead(err_code, 4));
}
bool is_error()
{
return voltage_high || voltage_low || current_high || current_low;
return voltage_high || voltage_low || current_high || current_low;
}
void printSuffix(Print *_logOutput, int logLevel)
void printSuffix(Print* _logOutput, int logLevel)
{
_logOutput->print(CR);
_logOutput->print(CR);
}
void print_prefix(Print *_logOutput, int logLevel)
void print_prefix(Print* _logOutput, int logLevel)
{
_logOutput->print("WATERMETER - C");
_logOutput->print(xPortGetCoreID());
_logOutput->print(" - ");
_logOutput->print(pcTaskGetName(xTaskGetCurrentTaskHandle()));
_logOutput->print(" - ");
_logOutput->print("WATERMETER - C");
_logOutput->print(xPortGetCoreID());
_logOutput->print(" - ");
_logOutput->print(pcTaskGetName(xTaskGetCurrentTaskHandle()));
_logOutput->print(" - ");
}
void display_task(void *parameter)
void display_task(void* parameter)
{
while (true)
{
if (!is_error())
{
// We have no error, refresh status display and wait half a second
display_percentage(current_data.percentage);
delay(1000);
while (true) {
if (!is_error()) {
// We have no error, refresh status display and wait half a second
display_percentage(current_data.percentage);
delay(1000);
} else {
Log.verbose("Error detected");
// We have an error, display error code for 3 seconds and then water level for 3 seconds
if (voltage_low) {
display_error_code(1);
} else if (voltage_high) {
display_error_code(2);
} else if (current_low) {
display_error_code(3);
} else if (current_high) {
display_error_code(4);
}
delay(3000);
display_percentage(current_data.percentage);
}
}
else
{
Log.verbose("Error detected");
// We have an error, display error code for 3 seconds and then water level for 3 seconds
if (voltage_low)
{
display_error_code(1);
}
else if (voltage_high)
{
display_error_code(2);
}
else if (current_low)
{
display_error_code(3);
}
else if (current_high)
{
display_error_code(4);
}
delay(3000);
display_percentage(current_data.percentage);
delay(3000);
}
void wifi_task(void* parameter)
{
Log.verbose("Starting WiFi Task");
while (true) {
if (prefs.getString(ssid_key, "") == "" || failed_connection_attempts > 5) {
wifi_data.link = false;
if (failed_connection_attempts > 5) {
Log.verbose("Failed to connecto to currently saved SSID, starting SoftAP");
} else {
Log.verbose("No SSID saved, starting SoftAP");
}
String ap_ssid = "Watermeter-" + String(mac_address);
WiFi.softAP(ap_ssid, "");
Log.verbose("[WIFI_TASK] Waiting for SSID now...");
String old_ssid = prefs.getString(ssid_key, "xxx");
while (prefs.getString(ssid_key, "") == "" || prefs.getString(ssid_key, "") == old_ssid) {
delay(1000);
}
failed_connection_attempts = 0;
} else {
if (WiFi.isConnected() && WiFi.SSID() == prefs.getString(ssid_key, "")) {
failed_connection_attempts = 0;
wifi_data.rssi = WiFi.RSSI();
wifi_data.link = true;
wifi_data.network_name = WiFi.SSID();
wifi_data.ip_address = WiFi.localIP().toString();
Log.verbose("RSSI: %F, IP Address, %p, SSID: %s", float(WiFi.RSSI()), WiFi.localIP(), prefs.getString(ssid_key, "NOSSID"));
delay(5000);
} else {
Log.verbose("Connecting to %s using password %s", prefs.getString(ssid_key, ""), prefs.getString(wifi_password_key, ""));
WiFi.mode(WIFI_STA);
WiFi.begin(prefs.getString(ssid_key, ""), prefs.getString(wifi_password_key, ""));
failed_connection_attempts++;
delay(5000);
}
}
}
}
}
void wifi_task(void *parameter)
void ethernet_task(void* parameter)
{
Log.verbose("Starting WiFi Task");
while (true)
{
if (prefs.getString(ssid_key, "") == "" || failed_connection_attempts > 5)
{
wifi_data.link = false;
if (failed_connection_attempts > 5)
{
Log.verbose("Failed to connecto to currently saved SSID, starting SoftAP");
}
else
{
Log.verbose("No SSID saved, starting SoftAP");
}
String ap_ssid = "Watermeter-" + String(mac_address);
WiFi.softAP(ap_ssid, "");
Log.verbose("[WIFI_TASK] Waiting for SSID now...");
String old_ssid = prefs.getString(ssid_key, "xxx");
while (prefs.getString(ssid_key, "") == "" || prefs.getString(ssid_key, "") == old_ssid)
{
delay(1000);
}
failed_connection_attempts = 0;
Log.verbose("Connecting Ethernet");
ETH.begin(0, 17, 23, 18);
ETH.setHostname("watermeter");
while (true) {
ethernet_data.link = ETH.linkUp();
ethernet_data.rssi = ETH.linkSpeed();
ethernet_data.ip_address = ETH.localIP().toString();
delay(60 * 1000);
}
else
{
if (WiFi.isConnected() && WiFi.SSID() == prefs.getString(ssid_key, ""))
{
failed_connection_attempts = 0;
wifi_data.rssi = WiFi.RSSI();
wifi_data.link = true;
wifi_data.network_name = WiFi.SSID();
wifi_data.ip_address = WiFi.localIP().toString();
}
Log.verbose("RSSI: %F, IP Address, %p, SSID: %s", float(WiFi.RSSI()), WiFi.localIP(), prefs.getString(ssid_key, "NOSSID"));
delay(5000);
}
else
{
Log.verbose("Connecting to %s using password %s", prefs.getString(ssid_key, ""), prefs.getString(wifi_password_key, ""));
WiFi.mode(WIFI_STA);
WiFi.begin(prefs.getString(ssid_key, ""), prefs.getString(wifi_password_key, ""));
failed_connection_attempts++;
delay(5000);
}
void collect_internal_telemetry_task(void* parameter)
{
while (true) {
float heap_usage = (float(ESP.getFreeHeap()) / float(ESP.getHeapSize())) * 100;
uint64_t uptime_seconds = millis() / 1000;
Log.verbose("Current heap usage: %F", heap_usage);
Log.verbose("Current uptime: %d", uptime_seconds);
delay(60000);
}
}
}
void ethernet_task(void *parameter)
void read_sensor_task(void* parameter)
{
Log.verbose("Connecting Ethernet");
ETH.begin(0, 17, 23, 18);
ETH.setHostname("watermeter");
while (true)
{
ethernet_data.link = ETH.linkUp();
ethernet_data.rssi = ETH.linkSpeed();
ethernet_data.ip_address = ETH.localIP().toString();
delay(60 * 1000);
}
}
while (true) {
float bus_voltage = ina_sensor.getBusVoltage();
float shunt_voltage = ina_sensor.getShuntVoltage_mV() - zero_value;
float shunt_current = shunt_voltage / 4;
void collect_internal_telemetry_task(void *parameter)
{
float mA_per_cm = (20 - 4) / (sensor_range * 100);
while (true)
{
float heap_usage = (float(ESP.getFreeHeap()) / float(ESP.getHeapSize())) * 100;
uint64_t uptime_seconds = millis() / 1000;
float min_water_level_mA_over_zero = (min_water_level_cm * mA_per_cm);
float max_water_level_mA_over_zero = (max_water_level_cm * mA_per_cm);
Log.verbose("Current heap usage: %F", heap_usage);
Log.verbose("Current uptime: %d", uptime_seconds);
float min_water_level_mA = 4 + min_water_level_mA_over_zero;
float max_water_level_mA = 4 + max_water_level_mA_over_zero;
delay(60000);
}
}
// Over Zero always revers to zero water level
float shunt_current_over_zero = shunt_current - min_water_level_mA;
void read_sensor_task(void *parameter)
{
while (true)
{
float bus_voltage = ina_sensor.getBusVoltage();
float shunt_voltage = ina_sensor.getShuntVoltage_mV() - zero_value;
float shunt_current = shunt_voltage / 4;
int percentage = round((shunt_current_over_zero / max_water_level_mA_over_zero) * 100);
float mA_per_cm = (20 - 4) / (sensor_range * 100);
current_low = shunt_current < 3.8;
current_high = shunt_current > 20.2;
voltage_low = bus_voltage < 23;
voltage_high = bus_voltage > 25;
Log.verbose("Bus current: %F", bus_voltage);
Log.verbose("Shunt current: %F", shunt_current);
Log.verbose("Shunt voltage: %F", shunt_voltage);
Log.verbose("Value percentage: %F", percentage);
float min_water_level_mA_over_zero = (min_water_level_cm * mA_per_cm);
float max_water_level_mA_over_zero = (max_water_level_cm * mA_per_cm);
current_data = SensorData { percentage, bus_voltage, shunt_current, shunt_current_over_zero };
float min_water_level_mA = 4 + min_water_level_mA_over_zero;
float max_water_level_mA = 4 + max_water_level_mA_over_zero;
// Over Zero always revers to zero water level
float shunt_current_over_zero = shunt_current - min_water_level_mA;
int percentage = round((shunt_current_over_zero / max_water_level_mA_over_zero) * 100);
current_low = shunt_current < 3.8;
current_high = shunt_current > 20.2;
voltage_low = bus_voltage < 23;
voltage_high = bus_voltage > 25;
Log.verbose("Bus current: %F", bus_voltage);
Log.verbose("Shunt current: %F", shunt_current);
Log.verbose("Shunt voltage: %F", shunt_voltage);
Log.verbose("Value percentage: %F", percentage);
current_data = SensorData{percentage, bus_voltage, shunt_current, shunt_current_over_zero};
delay(20000);
}
delay(20000);
}
}
void setup()
{
prefs.begin("waterlevel", false);
Serial.begin(115200);
prefs.begin("waterlevel", false);
Serial.begin(115200);
Log.begin(LOG_LEVEL_VERBOSE, &Serial);
Log.setSuffix(printSuffix);
Log.setPrefix(print_prefix);
Log.begin(LOG_LEVEL_VERBOSE, &Serial);
Log.setSuffix(printSuffix);
Log.setPrefix(print_prefix);
Log.verbose("Init LEDs");
pinMode(LED_1, OUTPUT);
pinMode(LED_2, OUTPUT);
pinMode(LED_3, OUTPUT);
pinMode(LED_4, OUTPUT);
pinMode(LED_5, OUTPUT);
pinMode(LED_RED, OUTPUT);
display_error_code(17);
Log.verbose("Init LEDs");
pinMode(LED_1, OUTPUT);
pinMode(LED_2, OUTPUT);
pinMode(LED_3, OUTPUT);
pinMode(LED_4, OUTPUT);
pinMode(LED_5, OUTPUT);
pinMode(LED_RED, OUTPUT);
display_error_code(17);
Log.verbose("Beginning SPIFFS");
SPIFFS.begin(true);
Log.verbose("SPIFFS initialized");
display_error_code(19);
Log.verbose("Beginning SPIFFS");
SPIFFS.begin(true);
Log.verbose("SPIFFS initialized");
display_error_code(19);
Log.verbose("Begin INA");
ina_sensor.begin(33, 32);
display_error_code(20);
ina_sensor.setMaxCurrentShunt(0.02, 4, false);
ina_sensor.setBusVoltageConversionTime(7);
ina_sensor.setShuntVoltageConversionTime(7);
ina_sensor.setAverage(4);
display_error_code(21);
Log.verbose("Begin INA");
ina_sensor.begin(33, 32);
display_error_code(20);
ina_sensor.setMaxCurrentShunt(0.02, 4, false);
ina_sensor.setBusVoltageConversionTime(7);
ina_sensor.setShuntVoltageConversionTime(7);
ina_sensor.setAverage(4);
display_error_code(21);
display_error_code(22);
display_error_code(22);
/////////////////////////////// ROUTES ///////////////////////////////
Log.verbose("Route Setup");
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request)
{ request->send(SPIFFS, "/status.html", "text/html", false); });
/////////////////////////////// ROUTES ///////////////////////////////
Log.verbose("Route Setup");
server.on("/", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(SPIFFS, "/status.html", "text/html", false); });
server.on("/settings", HTTP_GET, [](AsyncWebServerRequest *request)
{ request->send(SPIFFS, "/settings.html", "text/html", false); });
server.on("/settings", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(SPIFFS, "/settings.html", "text/html", false); });
server.on("/export", HTTP_GET, [](AsyncWebServerRequest *request)
{ request->send(SPIFFS, "/data_export.html", "text/html", false); });
server.on("/export", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(SPIFFS, "/data_export.html", "text/html", false); });
server.on("/logic.js", HTTP_GET, [](AsyncWebServerRequest *request)
{ request->send(SPIFFS, "/logic.js", "application/javascript", false); });
server.on("/logic.js", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(SPIFFS, "/logic.js", "application/javascript", false); });
server.on("/update_wifi_credentials", HTTP_POST, [](AsyncWebServerRequest *request)
{
int params = request->params();
server.on("/update_wifi_credentials", HTTP_POST, [](AsyncWebServerRequest* request) {
int params = request->params();
if (request->hasParam(ssid_key, true) && request->hasParam(wifi_password_key, true))
{
Log.verbose("Updating SSID config");
AsyncWebParameter *ssid_param = request->getParam(ssid_key, true);
AsyncWebParameter *password_param = request->getParam(wifi_password_key, true);
prefs.putString(ssid_key, ssid_param->value().c_str());
prefs.putString(wifi_password_key, password_param->value().c_str());
}
else
{
for (int i = 0; i < params; i++)
{
AsyncWebParameter *p = request->getParam(i);
if (p->isFile())
{ // p->isPost() is also true
if (request->hasParam(ssid_key, true) && request->hasParam(wifi_password_key, true)) {
Log.verbose("Updating SSID config");
AsyncWebParameter* ssid_param = request->getParam(ssid_key, true);
AsyncWebParameter* password_param = request->getParam(wifi_password_key, true);
prefs.putString(ssid_key, ssid_param->value().c_str());
prefs.putString(wifi_password_key, password_param->value().c_str());
} else {
for (int i = 0; i < params; i++) {
AsyncWebParameter* p = request->getParam(i);
if (p->isFile()) { // p->isPost() is also true
Log.verbose("POST[%s]: %s\n", p->name().c_str(), p->value().c_str());
}
else if (p->isPost())
{
} else if (p->isPost()) {
Log.verbose("POST[%s]: %s\n", p->name().c_str(), p->value().c_str());
}
else
{
} else {
Log.verbose("GET[%s]: %s\n", p->name().c_str(), p->value().c_str());
}
}
request->send(400, "text/plain", "Missing parameters"); // TODO add proper error messages
}
request->send(SPIFFS, "/settings.html", "text/html", false); // TODO add proper return templating
});
}
request->send(400, "text/plain", "Missing parameters"); // TODO add proper error messages
}
request->send(SPIFFS, "/settings.html", "text/html", false); // TODO add proper return templating
});
server.on("/sensor_data", HTTP_GET, [](AsyncWebServerRequest *request)
{
server.on("/sensor_data", HTTP_GET, [](AsyncWebServerRequest* request) {
StaticJsonDocument<128> doc;
doc["percentage"] = current_data.percentage;
doc["voltage"] = current_data.voltage;
@@ -399,8 +342,7 @@ void setup()
serializeJson(doc, output);
request->send(200, "application/json", output); });
server.on("/network_info", HTTP_GET, [](AsyncWebServerRequest *request)
{
server.on("/network_info", HTTP_GET, [](AsyncWebServerRequest* request) {
StaticJsonDocument<256> doc;
doc["wifi"]["ip"] = wifi_data.ip_address;
doc["wifi"]["rssi"] = wifi_data.rssi;
@@ -416,17 +358,15 @@ void setup()
serializeJson(doc, output);
request->send(200, "application/json", output); });
server.on("/chota.css", HTTP_GET, [](AsyncWebServerRequest *request)
{ request->send(SPIFFS, "/chota.css", "text/css", false); });
server.on("/chota.css", HTTP_GET, [](AsyncWebServerRequest* request) { request->send(SPIFFS, "/chota.css", "text/css", false); });
display_error_code(23);
display_error_code(23);
display_error_code(24);
display_error_code(24);
Log.verbose("OTA Setup");
ArduinoOTA
.onStart([]()
{
Log.verbose("OTA Setup");
ArduinoOTA
.onStart([]() {
String type;
if (ArduinoOTA.getCommand() == U_FLASH)
type = "sketch";
@@ -435,12 +375,9 @@ void setup()
// NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end()
Log.verbose("Start updating %s", type); })
.onEnd([]()
{ Log.verbose("\nEnd"); })
.onProgress([](unsigned int progress, unsigned int total)
{ Serial.printf("Progress: %u%%\r", (progress / (total / 100))); })
.onError([](ota_error_t error)
{
.onEnd([]() { Log.verbose("\nEnd"); })
.onProgress([](unsigned int progress, unsigned int total) { Serial.printf("Progress: %u%%\r", (progress / (total / 100))); })
.onError([](ota_error_t error) {
Serial.printf("Error[%u]: ", error);
if (error == OTA_AUTH_ERROR) Log.verbose("Auth Failed");
else if (error == OTA_BEGIN_ERROR) Log.verbose("Begin Failed");
@@ -448,23 +385,23 @@ void setup()
else if (error == OTA_RECEIVE_ERROR) Log.verbose("Receive Failed");
else if (error == OTA_END_ERROR) Log.verbose("End Failed"); });
display_error_code(26);
digitalWrite(LED_RED, 0);
display_error_code(26);
digitalWrite(LED_RED, 0);
xTaskCreate(display_task, "DisplayTask", 10000, NULL, 1, NULL);
xTaskCreate(read_sensor_task, "ReadSensorTask", 2048, NULL, 1, NULL);
xTaskCreate(collect_internal_telemetry_task, "InternalTelemetryTask", 2048, NULL, 1, NULL);
xTaskCreate(ethernet_task, "EthernetTask", 4096, NULL, 1, NULL);
xTaskCreate(wifi_task, "WiFiTask", 10000, NULL, 1, NULL);
delay(1000);
Log.verbose("Starting webserver");
server.begin();
display_error_code(25);
ArduinoOTA.begin();
xTaskCreate(display_task, "DisplayTask", 10000, NULL, 1, NULL);
xTaskCreate(read_sensor_task, "ReadSensorTask", 2048, NULL, 1, NULL);
xTaskCreate(collect_internal_telemetry_task, "InternalTelemetryTask", 2048, NULL, 1, NULL);
xTaskCreate(ethernet_task, "EthernetTask", 4096, NULL, 1, NULL);
xTaskCreate(wifi_task, "WiFiTask", 10000, NULL, 1, NULL);
delay(1000);
Log.verbose("Starting webserver");
server.begin();
display_error_code(25);
ArduinoOTA.begin();
}
void loop()
{
ArduinoOTA.handle();
delay(1000);
ArduinoOTA.handle();
delay(1000);
}