This commit is contained in:
@@ -7,7 +7,7 @@ window.addEventListener('DOMContentLoaded', (event) => {
|
|||||||
fetch(apiUrl)
|
fetch(apiUrl)
|
||||||
.then(response => response.json())
|
.then(response => response.json())
|
||||||
.then(data => {
|
.then(data => {
|
||||||
document.getElementById('voltage').textContent = roundToTwo(data.voltage)+ ' V' || 'N/A';
|
document.getElementById('voltage').textContent = roundToTwo(data.bus_voltage)+ ' V' || 'N/A';
|
||||||
document.getElementById('current').textContent = roundToTwo(data.current)+ ' mA' || 'N/A';
|
document.getElementById('current').textContent = roundToTwo(data.current)+ ' mA' || 'N/A';
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
@@ -19,6 +19,49 @@ window.addEventListener('DOMContentLoaded', (event) => {
|
|||||||
setInterval(fetchData, 5000); // fetch every 5 seconds
|
setInterval(fetchData, 5000); // fetch every 5 seconds
|
||||||
});
|
});
|
||||||
|
|
||||||
|
window.addEventListener('DOMContentLoaded', (event) => {
|
||||||
|
// URL of your API
|
||||||
|
const apiUrl = '/telemetry';
|
||||||
|
|
||||||
|
function fetchData() {
|
||||||
|
// Fetching data from the API
|
||||||
|
fetch(apiUrl)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
document.getElementById('uptime').textContent = roundToTwo(data.uptime_seconds)+ ' s' || 'N/A';
|
||||||
|
document.getElementById('heap').textContent = roundToTwo(data.heap_percent)+ ' %' || 'N/A';
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error("There was an error fetching data from the API", error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchData(); // fetch immediately on page load
|
||||||
|
setInterval(fetchData, 5000); // fetch every 5 seconds
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener('DOMContentLoaded', (event) => {
|
||||||
|
// URL of your API
|
||||||
|
const apiUrl = '/water_data';
|
||||||
|
|
||||||
|
function fetchData() {
|
||||||
|
// Fetching data from the API
|
||||||
|
fetch(apiUrl)
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
document.getElementById('level').textContent = roundToTwo(data.water_height)+ ' cm' || 'N/A';
|
||||||
|
document.getElementById('liters').textContent = roundToTwo(data.liters)+ ' l' || 'N/A';
|
||||||
|
document.getElementById('percentage').textContent = roundToTwo(data.percentage)+ ' %' || 'N/A';
|
||||||
|
})
|
||||||
|
.catch(error => {
|
||||||
|
console.error("There was an error fetching data from the API", error);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fetchData(); // fetch immediately on page load
|
||||||
|
setInterval(fetchData, 5000); // fetch every 5 seconds
|
||||||
|
});
|
||||||
|
|
||||||
window.addEventListener('DOMContentLoaded', (event) => {
|
window.addEventListener('DOMContentLoaded', (event) => {
|
||||||
const apiUrl = '/network_info';
|
const apiUrl = '/network_info';
|
||||||
|
|
||||||
|
|||||||
@@ -20,38 +20,38 @@
|
|||||||
</div>
|
</div>
|
||||||
</nav>
|
</nav>
|
||||||
|
|
||||||
|
<form action="/update_sensor_settings" method="post">
|
||||||
<fieldset id="form-settings">
|
<fieldset id="form-settings">
|
||||||
<legend>Settings</legend>
|
<legend>Settings</legend>
|
||||||
<p>
|
<p>
|
||||||
<label for="input__text">Sensor max height (e.g. 4m)</label>
|
<label for="range">Sensor Range in cm</label>
|
||||||
<input id="input__text" type="number" placeholder="Text Input">
|
<input id="range" name="range" type="number" placeholder="200">
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<label for="input__password">Water max height</label>
|
<label for="level_max">Water max height in cm</label>
|
||||||
<input id="input__password" type="number">
|
<input id="level_max" name="level_max" type="number">
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<label for="input__webaddress">Water min height</label>
|
<label for="level_min">Water min height in cm</label>
|
||||||
<input id="input__webaddress" type="number">
|
<input id="level_min" name="level_min" type="number">
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
<label for="input__emailaddress">Email Address</label>
|
<label for="liters">Volume in liters</label>
|
||||||
<input id="input__emailaddress" type="number">
|
<input id="liters" name="liters" type="number">
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<button class="button primary" style="width: 100%;">Submit</button>
|
<button class="button primary" style="width: 100%;">Submit</button>
|
||||||
</p>
|
</p>
|
||||||
</fieldset>
|
</fieldset>
|
||||||
|
</form>
|
||||||
|
|
||||||
<form action="/update_wifi_credentials" method="post">
|
<form action="/update_wifi_credentials" method="post">
|
||||||
<fieldset id="form-settings">
|
<fieldset id="form-settings">
|
||||||
<legend>WiFi Settings</legend>
|
<legend>WiFi Settings</legend>
|
||||||
<p>
|
<!-- <p>
|
||||||
<input type="checkbox" id="enable" name="enable" value="true">
|
<input type="checkbox" id="enable" name="enable" value="true">
|
||||||
<label for="enable"> Enable WiFi</label><br>
|
<label for="enable"> Enable WiFi</label><br>
|
||||||
</p>
|
</p> -->
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
<label for="ssid">SSID</label>
|
<label for="ssid">SSID</label>
|
||||||
|
|||||||
@@ -42,6 +42,29 @@
|
|||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
<!--Sensor card-->
|
||||||
|
<div class="card">
|
||||||
|
<header>
|
||||||
|
<h4>Water information</h4>
|
||||||
|
</header>
|
||||||
|
<table class="tg">
|
||||||
|
<thead></thead>
|
||||||
|
<tbody>
|
||||||
|
<tr>
|
||||||
|
<td>Waterlevel: </td>
|
||||||
|
<td id="level">WAITING</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Water volumen: </td>
|
||||||
|
<td id="liters">WAITING</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>Percentage: </td>
|
||||||
|
<td id="percentage">WAITING</td>
|
||||||
|
</tr>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
||||||
@@ -69,15 +92,11 @@
|
|||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Uptime: </td>
|
<td>Uptime: </td>
|
||||||
<td>132d</td>
|
<td id="uptime">XXX</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>FW version: </td>
|
<td>Heap usage: </td>
|
||||||
<td>0.2</td>
|
<td id="heap">XXX</td>
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<td>Time/Date: </td>
|
|
||||||
<td>1.1.202022</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
|
|||||||
11
readme.md
11
readme.md
@@ -9,3 +9,14 @@
|
|||||||
Config fields:
|
Config fields:
|
||||||
- ssid
|
- ssid
|
||||||
- wifi_password
|
- wifi_password
|
||||||
|
|
||||||
|
- range
|
||||||
|
- level_min
|
||||||
|
- level_max
|
||||||
|
- liters
|
||||||
|
|
||||||
|
|
||||||
|
#define level_sensor_range_key "range"
|
||||||
|
#define water_level_min_key "level_min"
|
||||||
|
#define water_level_max_key "level_max"
|
||||||
|
#define liters_key "liters"
|
||||||
133
src/main.cpp
133
src/main.cpp
@@ -14,6 +14,7 @@
|
|||||||
#include "INA226.h"
|
#include "INA226.h"
|
||||||
#include "Wire.h"
|
#include "Wire.h"
|
||||||
|
|
||||||
|
|
||||||
#include <Preferences.h>
|
#include <Preferences.h>
|
||||||
|
|
||||||
#define LED_1 4
|
#define LED_1 4
|
||||||
@@ -26,14 +27,17 @@
|
|||||||
// Define keys to prevent typos
|
// Define keys to prevent typos
|
||||||
#define ssid_key "ssid"
|
#define ssid_key "ssid"
|
||||||
#define wifi_password_key "wifi_password"
|
#define wifi_password_key "wifi_password"
|
||||||
|
#define level_sensor_range_key "range"
|
||||||
|
#define water_level_min_key "level_min"
|
||||||
|
#define water_level_max_key "level_max"
|
||||||
|
#define liters_key "liters"
|
||||||
|
|
||||||
|
#define RESISTOR_VALUE 4
|
||||||
|
|
||||||
extern "C" int rom_phy_get_vdd33();
|
extern "C" int rom_phy_get_vdd33();
|
||||||
|
|
||||||
// Calibration variables
|
// Calibration variables
|
||||||
float zero_value = 0.03; // Measured shunt voltage with nothing connected, used to fix measuring offset
|
float zero_value = 0.03; // Measured shunt voltage with nothing connected, used to fix measuring offset
|
||||||
float max_water_level_cm = 200;
|
|
||||||
float min_water_level_cm = 0;
|
|
||||||
float sensor_range = 2.0;
|
|
||||||
|
|
||||||
bool voltage_high = false;
|
bool voltage_high = false;
|
||||||
bool voltage_low = false;
|
bool voltage_low = false;
|
||||||
@@ -43,12 +47,21 @@ bool current_low = false;
|
|||||||
uint8_t failed_connection_attempts = 0;
|
uint8_t failed_connection_attempts = 0;
|
||||||
|
|
||||||
struct SensorData {
|
struct SensorData {
|
||||||
int percentage;
|
float bus_voltage;
|
||||||
float voltage;
|
float shunt_voltage;
|
||||||
float current;
|
float shunt_current;
|
||||||
float water_height;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct WaterData{
|
||||||
|
// Water level in cm
|
||||||
|
float level;
|
||||||
|
// Water volume in liters
|
||||||
|
float liters;
|
||||||
|
// Percentage
|
||||||
|
float percentage;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
struct NetworkData {
|
struct NetworkData {
|
||||||
String ip_address;
|
String ip_address;
|
||||||
bool link;
|
bool link;
|
||||||
@@ -65,11 +78,18 @@ NetworkData wifi_data;
|
|||||||
NetworkData ethernet_data;
|
NetworkData ethernet_data;
|
||||||
DeviceTelemetry telemetry;
|
DeviceTelemetry telemetry;
|
||||||
|
|
||||||
SensorData current_data = SensorData { -1, -1, -1, -1 };
|
SensorData shunt_data;
|
||||||
|
WaterData water_data;
|
||||||
|
|
||||||
int64_t mac_address = ESP.getEfuseMac();
|
int64_t mac_address = ESP.getEfuseMac();
|
||||||
|
|
||||||
|
//#define INA226
|
||||||
|
|
||||||
|
// #ifdef INA226
|
||||||
INA226 ina_sensor(0x40);
|
INA226 ina_sensor(0x40);
|
||||||
|
// #else
|
||||||
|
// INA233 ina_sensor();
|
||||||
|
// #endif
|
||||||
|
|
||||||
Preferences prefs;
|
Preferences prefs;
|
||||||
|
|
||||||
@@ -152,7 +172,7 @@ void display_task(void* parameter)
|
|||||||
while (true) {
|
while (true) {
|
||||||
if (!is_error()) {
|
if (!is_error()) {
|
||||||
// We have no error, refresh status display and wait half a second
|
// We have no error, refresh status display and wait half a second
|
||||||
display_percentage(current_data.percentage);
|
display_percentage(water_data.percentage);
|
||||||
} else {
|
} else {
|
||||||
Log.verbose("Error detected");
|
Log.verbose("Error detected");
|
||||||
// We have an error, display error code for 3 seconds and then water level for 3 seconds
|
// We have an error, display error code for 3 seconds and then water level for 3 seconds
|
||||||
@@ -166,7 +186,7 @@ void display_task(void* parameter)
|
|||||||
display_error_code(4);
|
display_error_code(4);
|
||||||
}
|
}
|
||||||
delay(3000);
|
delay(3000);
|
||||||
display_percentage(current_data.percentage);
|
display_percentage(water_data.percentage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -243,33 +263,60 @@ void collect_internal_telemetry_task(void* parameter)
|
|||||||
void read_sensor_task(void* parameter)
|
void read_sensor_task(void* parameter)
|
||||||
{
|
{
|
||||||
while (true) {
|
while (true) {
|
||||||
|
// Get Values from sensor
|
||||||
float bus_voltage = ina_sensor.getBusVoltage();
|
float bus_voltage = ina_sensor.getBusVoltage();
|
||||||
float shunt_voltage = ina_sensor.getShuntVoltage_mV() - zero_value;
|
float shunt_voltage = ina_sensor.getShuntVoltage_mV() - zero_value;
|
||||||
float shunt_current = shunt_voltage / 4;
|
float shunt_current = shunt_voltage / RESISTOR_VALUE;
|
||||||
|
|
||||||
float mA_per_cm = (20 - 4) / (sensor_range * 100);
|
// Get values from storage
|
||||||
|
float sensor_range = prefs.getFloat(level_sensor_range_key, 200);
|
||||||
|
float max_water_level = prefs.getFloat(water_level_max_key, sensor_range);
|
||||||
|
float min_water_level = prefs.getFloat(water_level_min_key, 0);
|
||||||
|
float max_liters = prefs.getFloat(liters_key, 10000.);
|
||||||
|
|
||||||
float min_water_level_mA_over_zero = (min_water_level_cm * mA_per_cm);
|
float mA_per_cm = (20. - 4.) / (sensor_range);
|
||||||
float max_water_level_mA_over_zero = (max_water_level_cm * mA_per_cm);
|
|
||||||
|
|
||||||
|
// Get mA over 0cm/4mA for max/min water level
|
||||||
|
float min_water_level_mA_over_zero = (min_water_level * mA_per_cm);
|
||||||
|
float max_water_level_mA_over_zero = (max_water_level * mA_per_cm);
|
||||||
|
|
||||||
|
// Levels which represent raw sensor value, with 4mA added
|
||||||
float min_water_level_mA = 4 + min_water_level_mA_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;
|
float max_water_level_mA = 4 + max_water_level_mA_over_zero;
|
||||||
|
|
||||||
// Over Zero always revers to zero water level
|
Log.verbose("max_water_level_mA: %F", max_water_level_mA);
|
||||||
|
Log.verbose("min_water_level_mA_over_zero: %F", min_water_level_mA_over_zero);
|
||||||
|
|
||||||
|
// Current over the 0 level of the water
|
||||||
float shunt_current_over_zero = shunt_current - min_water_level_mA;
|
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);
|
// cm over zero water level
|
||||||
|
float cm_over_zero = shunt_current_over_zero / mA_per_cm;
|
||||||
|
|
||||||
|
// Raw unrounded percentage in decimal
|
||||||
|
float percentage_raw = (shunt_current_over_zero / (max_water_level_mA_over_zero - min_water_level_mA_over_zero));
|
||||||
|
float percentage_rounded = round(percentage_raw*100*100)/100;
|
||||||
|
|
||||||
|
// Tank volume in liters
|
||||||
|
float liters_raw = max_liters * percentage_raw;
|
||||||
|
int liters = round(liters_raw);
|
||||||
|
|
||||||
current_low = shunt_current < 3.8;
|
current_low = shunt_current < 3.8;
|
||||||
current_high = shunt_current > 20.2;
|
current_high = shunt_current > 20.2;
|
||||||
voltage_low = bus_voltage < 23;
|
voltage_low = bus_voltage < 23;
|
||||||
voltage_high = bus_voltage > 25;
|
voltage_high = bus_voltage > 25;
|
||||||
Log.verbose("Bus current: %F", bus_voltage);
|
|
||||||
Log.verbose("Shunt current: %F", shunt_current);
|
Log.verbose("Shunt current: %F", shunt_current);
|
||||||
Log.verbose("Shunt voltage: %F", shunt_voltage);
|
Log.verbose("Shunt voltage: %F", shunt_voltage);
|
||||||
Log.verbose("Value percentage: %F", percentage);
|
Log.verbose("Bus voltage: %F", bus_voltage);
|
||||||
|
Log.verbose("cm_over_zero: %F", cm_over_zero);
|
||||||
|
|
||||||
current_data = SensorData { percentage, bus_voltage, shunt_current, shunt_current_over_zero };
|
shunt_data.bus_voltage = bus_voltage;
|
||||||
|
shunt_data.shunt_voltage = shunt_voltage;
|
||||||
|
shunt_data.shunt_current = shunt_current;
|
||||||
|
|
||||||
|
water_data.level = cm_over_zero;
|
||||||
|
water_data.liters = liters;
|
||||||
|
water_data.percentage = percentage_rounded;
|
||||||
|
|
||||||
delay(20000);
|
delay(20000);
|
||||||
}
|
}
|
||||||
@@ -344,12 +391,52 @@ void setup()
|
|||||||
request->send(SPIFFS, "/settings.html", "text/html", false); // TODO add proper return templating
|
request->send(SPIFFS, "/settings.html", "text/html", false); // TODO add proper return templating
|
||||||
});
|
});
|
||||||
|
|
||||||
|
server.on("/update_sensor_settings", HTTP_POST, [](AsyncWebServerRequest* request) {
|
||||||
|
int params = request->params();
|
||||||
|
|
||||||
|
if (request->hasParam(level_sensor_range_key, true) && request->hasParam(water_level_min_key, true) && request->hasParam(water_level_max_key, true) && request->hasParam(liters_key, true)) {
|
||||||
|
Log.verbose("Updating Sensor config");
|
||||||
|
AsyncWebParameter* range_param = request->getParam(level_sensor_range_key, true);
|
||||||
|
AsyncWebParameter* level_min_param = request->getParam(water_level_min_key, true);
|
||||||
|
AsyncWebParameter* level_max_param = request->getParam(water_level_max_key, true);
|
||||||
|
AsyncWebParameter* liters_param = request->getParam(liters_key, true);
|
||||||
|
|
||||||
|
prefs.putFloat(level_sensor_range_key, range_param->value().toFloat());
|
||||||
|
prefs.putFloat(water_level_min_key, level_min_param->value().toFloat());
|
||||||
|
prefs.putFloat(water_level_max_key, level_max_param->value().toFloat());
|
||||||
|
prefs.putFloat(liters_key, liters_param->value().toFloat());
|
||||||
|
} else {
|
||||||
|
Log.verbose("!!!! FAIL lo");
|
||||||
|
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()) {
|
||||||
|
Log.verbose("POST[%s]: %s\n", p->name().c_str(), p->value().c_str());
|
||||||
|
} 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
|
||||||
|
});
|
||||||
|
|
||||||
server.on("/sensor_data", HTTP_GET, [](AsyncWebServerRequest* request) {
|
server.on("/sensor_data", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
StaticJsonDocument<128> doc;
|
StaticJsonDocument<128> doc;
|
||||||
doc["percentage"] = current_data.percentage;
|
doc["bus_voltage"] = shunt_data.bus_voltage;
|
||||||
doc["voltage"] = current_data.voltage;
|
doc["shunt_voltage"] = shunt_data.shunt_voltage;
|
||||||
doc["current"] = current_data.current;
|
doc["current"] = shunt_data.shunt_current;
|
||||||
doc["water_height"] = current_data.water_height;
|
|
||||||
|
String output;
|
||||||
|
serializeJson(doc, output);
|
||||||
|
request->send(200, "application/json", output); });
|
||||||
|
|
||||||
|
server.on("/water_data", HTTP_GET, [](AsyncWebServerRequest* request) {
|
||||||
|
StaticJsonDocument<128> doc;
|
||||||
|
doc["percentage"] = water_data.percentage;
|
||||||
|
doc["water_height"] = water_data.level;
|
||||||
|
doc["liters"] = water_data.liters;
|
||||||
|
|
||||||
String output;
|
String output;
|
||||||
serializeJson(doc, output);
|
serializeJson(doc, output);
|
||||||
|
|||||||
Reference in New Issue
Block a user