dasdas
All checks were successful
Test compiling project / test (push) Successful in 1m44s

This commit is contained in:
2023-10-08 01:43:41 +02:00
parent dd136784e6
commit 496e7833f8
5 changed files with 220 additions and 60 deletions

View File

@@ -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';

View File

@@ -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">

View File

@@ -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>

View File

@@ -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"

View File

@@ -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);