This commit is contained in:
@@ -7,7 +7,7 @@ window.addEventListener('DOMContentLoaded', (event) => {
|
||||
fetch(apiUrl)
|
||||
.then(response => response.json())
|
||||
.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';
|
||||
})
|
||||
.catch(error => {
|
||||
@@ -19,6 +19,49 @@ window.addEventListener('DOMContentLoaded', (event) => {
|
||||
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) => {
|
||||
const apiUrl = '/network_info';
|
||||
|
||||
|
||||
@@ -20,39 +20,39 @@
|
||||
</div>
|
||||
</nav>
|
||||
|
||||
|
||||
<fieldset id="form-settings">
|
||||
<legend>Settings</legend>
|
||||
<p>
|
||||
<label for="input__text">Sensor max height (e.g. 4m)</label>
|
||||
<input id="input__text" type="number" placeholder="Text Input">
|
||||
</p>
|
||||
<p>
|
||||
<label for="input__password">Water max height</label>
|
||||
<input id="input__password" type="number">
|
||||
</p>
|
||||
<p>
|
||||
<label for="input__webaddress">Water min height</label>
|
||||
<input id="input__webaddress" type="number">
|
||||
</p>
|
||||
<p>
|
||||
<label for="input__emailaddress">Email Address</label>
|
||||
<input id="input__emailaddress" type="number">
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<button class="button primary" style="width: 100%;">Submit</button>
|
||||
</p>
|
||||
</fieldset>
|
||||
<form action="/update_sensor_settings" method="post">
|
||||
<fieldset id="form-settings">
|
||||
<legend>Settings</legend>
|
||||
<p>
|
||||
<label for="range">Sensor Range in cm</label>
|
||||
<input id="range" name="range" type="number" placeholder="200">
|
||||
</p>
|
||||
<p>
|
||||
<label for="level_max">Water max height in cm</label>
|
||||
<input id="level_max" name="level_max" type="number">
|
||||
</p>
|
||||
<p>
|
||||
<label for="level_min">Water min height in cm</label>
|
||||
<input id="level_min" name="level_min" type="number">
|
||||
</p>
|
||||
<p>
|
||||
<label for="liters">Volume in liters</label>
|
||||
<input id="liters" name="liters" type="number">
|
||||
</p>
|
||||
<p>
|
||||
<button class="button primary" style="width: 100%;">Submit</button>
|
||||
</p>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
||||
<form action="/update_wifi_credentials" method="post">
|
||||
<fieldset id="form-settings">
|
||||
<legend>WiFi Settings</legend>
|
||||
<p>
|
||||
<!-- <p>
|
||||
<input type="checkbox" id="enable" name="enable" value="true">
|
||||
<label for="enable"> Enable WiFi</label><br>
|
||||
</p>
|
||||
|
||||
</p> -->
|
||||
|
||||
<p>
|
||||
<label for="ssid">SSID</label>
|
||||
<input id="ssid" name="ssid" type="text">
|
||||
|
||||
@@ -42,6 +42,29 @@
|
||||
</tbody>
|
||||
</table>
|
||||
</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>
|
||||
|
||||
|
||||
@@ -69,15 +92,11 @@
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>Uptime: </td>
|
||||
<td>132d</td>
|
||||
<td id="uptime">XXX</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>FW version: </td>
|
||||
<td>0.2</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Time/Date: </td>
|
||||
<td>1.1.202022</td>
|
||||
<td>Heap usage: </td>
|
||||
<td id="heap">XXX</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
13
readme.md
13
readme.md
@@ -8,4 +8,15 @@
|
||||
|
||||
Config fields:
|
||||
- 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"
|
||||
135
src/main.cpp
135
src/main.cpp
@@ -14,6 +14,7 @@
|
||||
#include "INA226.h"
|
||||
#include "Wire.h"
|
||||
|
||||
|
||||
#include <Preferences.h>
|
||||
|
||||
#define LED_1 4
|
||||
@@ -26,14 +27,17 @@
|
||||
// Define keys to prevent typos
|
||||
#define ssid_key "ssid"
|
||||
#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();
|
||||
|
||||
// Calibration variables
|
||||
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_low = false;
|
||||
@@ -43,12 +47,21 @@ bool current_low = false;
|
||||
uint8_t failed_connection_attempts = 0;
|
||||
|
||||
struct SensorData {
|
||||
int percentage;
|
||||
float voltage;
|
||||
float current;
|
||||
float water_height;
|
||||
float bus_voltage;
|
||||
float shunt_voltage;
|
||||
float shunt_current;
|
||||
};
|
||||
|
||||
struct WaterData{
|
||||
// Water level in cm
|
||||
float level;
|
||||
// Water volume in liters
|
||||
float liters;
|
||||
// Percentage
|
||||
float percentage;
|
||||
};
|
||||
|
||||
|
||||
struct NetworkData {
|
||||
String ip_address;
|
||||
bool link;
|
||||
@@ -65,11 +78,18 @@ NetworkData wifi_data;
|
||||
NetworkData ethernet_data;
|
||||
DeviceTelemetry telemetry;
|
||||
|
||||
SensorData current_data = SensorData { -1, -1, -1, -1 };
|
||||
SensorData shunt_data;
|
||||
WaterData water_data;
|
||||
|
||||
int64_t mac_address = ESP.getEfuseMac();
|
||||
|
||||
//#define INA226
|
||||
|
||||
// #ifdef INA226
|
||||
INA226 ina_sensor(0x40);
|
||||
// #else
|
||||
// INA233 ina_sensor();
|
||||
// #endif
|
||||
|
||||
Preferences prefs;
|
||||
|
||||
@@ -152,7 +172,7 @@ 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);
|
||||
display_percentage(water_data.percentage);
|
||||
} else {
|
||||
Log.verbose("Error detected");
|
||||
// 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);
|
||||
}
|
||||
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)
|
||||
{
|
||||
while (true) {
|
||||
// Get Values from sensor
|
||||
float bus_voltage = ina_sensor.getBusVoltage();
|
||||
float shunt_voltage = ina_sensor.getShuntVoltage_mV() - zero_value;
|
||||
float shunt_current = shunt_voltage / 4;
|
||||
float shunt_current = shunt_voltage / RESISTOR_VALUE;
|
||||
|
||||
// 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 mA_per_cm = (20. - 4.) / (sensor_range);
|
||||
|
||||
float mA_per_cm = (20 - 4) / (sensor_range * 100);
|
||||
|
||||
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);
|
||||
// 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 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;
|
||||
|
||||
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_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);
|
||||
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);
|
||||
}
|
||||
@@ -344,12 +391,52 @@ void setup()
|
||||
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) {
|
||||
StaticJsonDocument<128> doc;
|
||||
doc["percentage"] = current_data.percentage;
|
||||
doc["voltage"] = current_data.voltage;
|
||||
doc["current"] = current_data.current;
|
||||
doc["water_height"] = current_data.water_height;
|
||||
doc["bus_voltage"] = shunt_data.bus_voltage;
|
||||
doc["shunt_voltage"] = shunt_data.shunt_voltage;
|
||||
doc["current"] = shunt_data.shunt_current;
|
||||
|
||||
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;
|
||||
serializeJson(doc, output);
|
||||
|
||||
Reference in New Issue
Block a user