Added min/max LCD, add NVS storage, add button3 Longpress

This commit is contained in:
Carsten Schmiemann 2018-08-30 02:05:09 +02:00
parent 222feef353
commit 69b5cfebc1
6 changed files with 204 additions and 107 deletions

Binary file not shown.

42
data/about.html Normal file
View file

@ -0,0 +1,42 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Carstens Battery Analyzer</title>
<link href="css/bootstrap.min.css" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-md-12">
<h3>
Power Analyzer - V0.29 Beta
</h3>
<ul class="nav">
<li class="nav-item">
<a class="nav-link active" href="index.html">Messwerte</a>
</li>
<li class="nav-item">
<a class="nav-link" href="graph.html">Graph</a>
</li>
<li class="nav-item">
<a class="nav-link disabled" href="about.html">About</a>
</li>
</ul>
</div>
Power Analyzer on ESP32, libraries used ArduinoINA219, Wire, TaskScheduler, <br>LiquidCrystal_I2C, ESPAsyncWifiManager, ESP Async WebServer, FS, ESP8266FtpServer, NVS, SPIFFS
</div>
</div>
<div><center>Build by Carsten Schmiemann (2018), Akku <span id="battery"></span> V, Status: <span id="run"></span></center></div>
<script src="js/jquery.min.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="js/scripts.js"></script>
</body>
</html>

81
data/graph.html Normal file
View file

@ -0,0 +1,81 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Carstens Battery Analyzer</title>
<link href="css/bootstrap.min.css" rel="stylesheet">
<link href="css/style.css" rel="stylesheet">
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-md-12">
<h3>
Power Analyzer - V0.29 Beta
</h3>
<ul class="nav">
<li class="nav-item">
<a class="nav-link active" href="index.html">Messwerte</a>
</li>
<li class="nav-item">
<a class="nav-link" href="graph.html">Graph</a>
</li>
<li class="nav-item">
<a class="nav-link disabled" href="about.html">About</a>
</li>
</ul>
</div>
</div>
</div>
<div id="chartContainer" style="width:100%; height:300px;"></div>
<div><center>Build by Carsten Schmiemann (2018), Akku <span id="battery"></span> V, Status: <span id="run"></span></center></div>
<script type="text/javascript" src="https://canvasjs.com/assets/script/jquery-1.11.1.min.js"></script>
<script type="text/javascript" src="https://canvasjs.com/assets/script/canvasjs.min.js"></script>
<script type="text/javascript">
window.onload = function() {
var dataPoints = [];
function getDataPointsFromCSV(csv) {
var dataPoints = csvLines = points = [];
csvLines = csv.split(/[\r?\n|\r|\n]+/);
for (var i = 0; i < csvLines.length; i++)
if (csvLines[i].length > 0) {
points = csvLines[i].split(",");
dataPoints.push({
x: parseFloat(points[0]),
y: parseFloat(points[1])
});
}
return dataPoints;
}
$.get("/datalog.csv", function(data) {
var chart = new CanvasJS.Chart("chartContainer", {
title: {
text: "Power Analyzer Graphics",
},
data: [{
type: "line",
dataPoints: getDataPointsFromCSV(data)
}]
});
chart.render();
});
}
</script>
<script src="js/jquery.min.js"></script>
<script src="js/bootstrap.min.js"></script>
<script src="js/scripts.js"></script>
</body>
</html>

View file

@ -59,7 +59,7 @@
<span id="voltage"></span> V
</td>
<td>
<span id="shuntvoltage_V_min"></span> / <span id="shuntvoltage_V_max"></span>
<span id="busvoltage_V_min"></span> / <span id="busvoltage_V_max"></span>
</td>
</tr>
<tr class="table-active">

View file

@ -12,7 +12,7 @@
platform = espressif32
board = nodemcu-32s
framework = arduino
lib_deps = ArduinoINA219, Wire, EEPROM, TaskScheduler, LiquidCrystal_I2C, ESPAsyncWifiManager, ESP Async WebServer, FS, ESP8266FtpServer
lib_deps = ArduinoINA219, Wire, TaskScheduler, LiquidCrystal_I2C, ESPAsyncWifiManager, ESP Async WebServer, FS, ESP8266FtpServer
board_build.partitions = partitions.csv
monitor_port = COM6
monitor_speed = 115200

View file

@ -7,7 +7,7 @@
#include <TaskScheduler.h>
#include <LiquidCrystal_I2C.h>
#include <INA219.h>
#include <EEPROM.h>
#include <Preferences.h>
#include <ESPAsyncWebServer.h>
#include <ESPAsyncWiFiManager.h>
#include <SPIFFS.h>
@ -21,6 +21,7 @@ AsyncWebServer server(80);
DNSServer dns;
FtpServer ftpSrv;
Scheduler task;
Preferences nvs;
//Konstanten
#define R_SHUNT 0.001
@ -28,7 +29,7 @@ Scheduler task;
#define V_BUS_MAX 26
#define I_MAX_EXPECTED 60
#define i2c_address 1
#define led_lowbat_pin 25
#define led_error_pin 25
#define led_run_pin 26
#define button1_pin 14
#define button2_pin 17
@ -57,23 +58,17 @@ Task t2(1750, TASK_FOREVER, &lcd_header);
Task t3(10000, TASK_FOREVER, &read_bat);
Task t4(300, TASK_FOREVER, &read_button);
Task t5(30000, TASK_FOREVER, &data_logging);
//Task t3(60000, TASK_FOREVER, &eeprom_save);
//Globale Variablen
float shuntvoltage_V = 0, shuntvoltage_mV = 0, busvoltage_V = 0, busvoltage_mV = 0, current_A = 0, current_mA = 0, power_W = 0, power_mW = 0;
float shuntvoltage_V_max = 0, current_A_max = 0, power_W_max = 0, shuntvoltage_V_min = 0, current_A_min = 0, power_W_min = 0;
float busvoltage_V_max = 0, current_A_max = 0, power_W_max = 0, busvoltage_V_min = 0, current_A_min = 0, power_W_min = 0;
float Ah = 0, mAh = 0, Wh = 0, mWh = 0;
float battery_voltage, battery_average;
int i_header = 0;
bool button1, button2, button3;
bool lcd_light = true, wifi_enabled = true, test_mode = false;
bool measuring_run = false, measuring_init = false, reset_actual = false, reset_minmax =false, battery_low = false;
unsigned long lastread = 0;
unsigned long tick;
unsigned long previousMillisReadData = 0;
unsigned long previousMillisDisplay = 0;
unsigned long data_timestamp = 0;
byte i2c_MasterCommand = 0;
bool button1, button2, button3, button3long;
bool lcd_light = true, lcd_minmax = false, wifi_enabled = true, test_mode = false;
bool measuring_run = false, measuring_init = false, reset_actual = false, reset_minmax = false, battery_low = false;
unsigned long lastread = 0, tick, previousMillisReadData = 0, previousMillisDisplay = 0, data_timestamp = 0, button3timer = 0;
//Custom LCD Characters
byte grad[8] = {
@ -111,7 +106,7 @@ byte batterie[8] = {
void setup() {
//Setup GPIO
pinMode(led_lowbat_pin, OUTPUT);
pinMode(led_error_pin, OUTPUT);
pinMode(led_run_pin, OUTPUT);
pinMode(button1_pin, INPUT_PULLUP);
pinMode(button2_pin, INPUT_PULLUP);
@ -151,7 +146,7 @@ void setup() {
})
.onError([](ota_error_t error) {
lcd.setCursor(3,3);
lcd.print("Done.");
digitalWrite(led_error_pin, HIGH);
if (error == OTA_AUTH_ERROR) lcd.print("Auth Failed");
else if (error == OTA_BEGIN_ERROR) lcd.print("Begin Failed");
else if (error == OTA_CONNECT_ERROR) lcd.print("Connect Failed");
@ -162,48 +157,32 @@ void setup() {
ArduinoOTA.setPassword("powerlyzer");
ArduinoOTA.begin();
//Init LCD and Custom Chars
//Init LCD, Custom Chars and test LEDs
lcd.init();
lcd.backlight();
lcd.createChar(0, grad);
lcd.createChar(1, sollwert);
lcd.createChar(2, batterie);
digitalWrite(led_lowbat_pin, 255);
digitalWrite(led_run_pin, 255);
digitalWrite(led_error_pin, HIGH);
digitalWrite(led_run_pin, HIGH);
delay(1000);
//Bootscreen
lcd.clear();
lcd.setCursor(4,0);
lcd.print("Power Analyzer");
lcd.setCursor(7,1);
//lcd.print("Tracker");
lcd.setCursor(6,2);
lcd.print("V0.29 Beta");
lcd.print("V0.31 Beta");
lcd.setCursor(7,3);
lcd.print("CS,2018");
lcd.write(1);
//End Test Output PWM
digitalWrite(led_lowbat_pin, 0);
digitalWrite(led_run_pin, 0);
//End Test LEDs
delay(5000);
digitalWrite(led_error_pin, LOW);
digitalWrite(led_run_pin, LOW);
lcd.clear();
/*
//Load Setpoint from EEPROM
lcd.setCursor(0,0);
lcd.print("Loading Setup from");
lcd.setCursor(0,1);
lcd.print("EEPROM...");
EEPROM.get(0, ee_setpoint);
setpoint = ee_setpoint;
delay(800);
lcd.setCursor(16,1);
lcd.print("Done");
delay(200);
*/
//Init Wi-Fi
lcd.setCursor(0,0);
if (digitalRead(button3_pin)) {
@ -247,7 +226,7 @@ void setup() {
})
.onError([](ota_error_t error) {
lcd.setCursor(3,3);
lcd.print("Done.");
digitalWrite(led_error_pin, HIGH);
if (error == OTA_AUTH_ERROR) lcd.print("Auth Failed");
else if (error == OTA_BEGIN_ERROR) lcd.print("Begin Failed");
else if (error == OTA_CONNECT_ERROR) lcd.print("Connect Failed");
@ -276,7 +255,7 @@ void setup() {
lcd.setCursor(16,1);
lcd.print("Test");
test_mode = true;
delay(500);
delay(1000);
}
//Init Task Scheduler
@ -288,6 +267,7 @@ void setup() {
task.addTask(t3);
task.addTask(t4);
task.addTask(t5);
//Init Filesystem and Webserver
SPIFFS.begin();
server.on("/meas/run", HTTP_GET, web_measuring_run);
@ -300,27 +280,35 @@ void setup() {
server.serveStatic("/img", SPIFFS, "/img");
server.serveStatic("/", SPIFFS, "/").setDefaultFile("index.html");
server.begin();
ftpSrv.begin("power","analyzer");
//Init FTP Server
ftpSrv.begin("power","analyzer");
delay(500);
lcd.setCursor(16,2);
lcd.print("Done");
delay(500);
//Finished initilization
lcd.setCursor(0,3);
lcd.print("Done. Starting up...");
delay(1500);
//Display IP address
if (wifi_enabled) {
lcd.clear();
lcd.setCursor(6,1);
lcd.setCursor(4,1);
lcd.print("IP address");
lcd.setCursor(6,2);
lcd.setCursor(4,2);
lcd.print(WiFi.localIP());
delay(1500);
}
//Load Default Screen
lcd_init();
//Fetch stored values
nvs.begin("usage", true);
Ah = nvs.getFloat("Ah");
Wh = nvs.getFloat("Wh");
nvs.end();
//Enable Tasks
t1.enable();
t2.enable();
@ -332,23 +320,25 @@ void setup() {
void loop() {
//Exec TaskScheduler
task.execute();
//Service Handler
ftpSrv.handleFTP();
ArduinoOTA.handle();
//High Precision Measuring
unsigned long currentMillis = millis();
if ((unsigned long)(currentMillis - previousMillisReadData) >= 250) {
previousMillisReadData = millis();
if (test_mode) {
if (digitalRead(button1_pin)) {
shuntvoltage_V += 1;
busvoltage_V += 1;
power_W += 1;
current_A += 1;
Ah += 1;
Wh += 1;
}
if (digitalRead(button2_pin)) {
shuntvoltage_V -= 1;
busvoltage_V -= 1;
power_W -= 1;
current_A -= 1;
Ah -= 1;
@ -361,6 +351,14 @@ void loop() {
}
void lcd_print() {
if (lcd_minmax) {
lcd.setCursor(1,1);
lcd.print(String(current_A_min) + String(" / ") + String(current_A_max) + String(" A"));
lcd.setCursor(1,2);
lcd.print(String(power_W_min) + String(" / ") + String(power_W_max) + String(" A"));
lcd.setCursor(1,3);
lcd.print(String(busvoltage_V_min) + String(" / ") + String(busvoltage_V_max) + String(" A"));
} else {
lcd.setCursor(0,1);
if (current_A < 100 && current_A >= 10) {lcd.print(" ");} else if (current_A < 10 && current_A >= 0) {lcd.print(" ");};
if (current_A > -100 && current_A <= -10) {lcd.print(" ");} else if (current_A > -10 && current_A < 0) {lcd.print(" ");};
@ -376,6 +374,7 @@ void lcd_print() {
lcd.setCursor(11,1);
if (Ah < 1000 && Ah > 100) {lcd.print(" ");} else if (Ah < 100 && Ah >= 10) {lcd.print(" ");} else if (Ah < 10) {lcd.print(" ");};
if (Ah > -100 && Ah <= -10) {lcd.print(" ");} else if (Ah > -10 && Ah < 0) {lcd.print(" ");};
lcd.print(Ah);
lcd.setCursor(11,2);
@ -384,6 +383,7 @@ void lcd_print() {
lcd.setCursor(14,3);
if (battery_voltage > 3.4) {lcd.print(battery_voltage);} else {lcd.print("LOW ");}
}
}
void lcd_init() {
@ -437,53 +437,9 @@ void lcd_header() {
}
}
//Flash Battery Low LED
if (battery_low && digitalRead(led_lowbat_pin)) {
digitalWrite(led_lowbat_pin,LOW);
} else if (battery_low && digitalRead(led_lowbat_pin) == false) { digitalWrite(led_lowbat_pin,HIGH); }
}
/*void eeprom_save() {
if (ee_setpoint != setpoint) {
EEPROM.put(0, setpoint);
ee_setpoint = setpoint;
lcd.setCursor(0,2);
lcd.print(" ");
lcd.setCursor(2,2);
lcd.print("EEProm written.");
}
}*/
void i2c_receive(int howMany){
i2c_MasterCommand = Wire.read();
}
void i2c_respond(){
int returnValue = 0;
switch(i2c_MasterCommand){
case 0: // No new command was received
Wire.write("Invalid Request");
break;
case 10:
returnValue = busvoltage_V;
break;
case 20:
returnValue = current_A;
break;
case 30:
returnValue = power_W;
}
byte buffer[2];
buffer[0] = returnValue >> 8;
buffer[1] = returnValue & 255;
Wire.write(buffer, 2);
i2c_MasterCommand = 0;
if (battery_low && digitalRead(led_error_pin)) {
digitalWrite(led_error_pin, LOW);
} else if (battery_low && digitalRead(led_error_pin) == false) { digitalWrite(led_error_pin, HIGH); }
}
void readCurrent() {
@ -510,8 +466,8 @@ void readCurrent() {
Wh += (power_W * tick)/3600000.0;
mWh = Wh * 1000;
if (shuntvoltage_V_max < shuntvoltage_V) {
shuntvoltage_V_max = shuntvoltage_V;
if (busvoltage_V_max < busvoltage_V) {
busvoltage_V_max = busvoltage_V;
}
if (current_A_max < current_A) {
current_A_max = current_A;
@ -519,8 +475,8 @@ void readCurrent() {
if (power_W_max < power_W) {
power_W_max = power_W;
}
if (shuntvoltage_V_min > shuntvoltage_V) {
shuntvoltage_V_min = shuntvoltage_V;
if (busvoltage_V_min > busvoltage_V) {
busvoltage_V_min = busvoltage_V;
}
if (current_A_min > current_A) {
current_A_min = current_A;
@ -534,22 +490,29 @@ void readCurrent() {
Wh = 0;
data_timestamp = 0;
reset_actual = false;
shuntvoltage_V_max = 0;
busvoltage_V_max = 0;
current_A_max = 0;
power_W_max = 0;
shuntvoltage_V_min = 0;
busvoltage_V_min = 0;
current_A_min = 0;
power_W_min = 0;
}
if (measuring_run && measuring_init == false) {
shuntvoltage_V_max = 0;
busvoltage_V_max = 0;
current_A_max = 0;
power_W_max = 0;
shuntvoltage_V_min = shuntvoltage_V;
busvoltage_V_min = busvoltage_V;
current_A_min = current_A;
power_W_min = power_W;
measuring_init = true;
}
if (measuring_run == false && measuring_init) {
nvs.begin("usage", false);
nvs.putFloat("Ah", Ah);
nvs.putFloat("Wh", Wh);
nvs.end();
measuring_init = false;
}
lastread = newtime;
ina219.recalibrate();
ina219.reconfig();
@ -564,7 +527,7 @@ void read_bat() {
}
if (battery_voltage > 3.6 && battery_low) {
battery_low = false;
digitalWrite(led_lowbat_pin,LOW);
digitalWrite(led_error_pin,LOW);
lcd.backlight();
}
}
@ -584,10 +547,16 @@ void read_button() {
}
if (digitalRead(button3_pin)) {
button3 = false;
button3long = false;
}
else {
button3 = true;
button3timer = millis();
if (millis() - button3timer > 900) {
button3long = true;
}
}
if (button1 && test_mode == false) {
reset_actual = true;
}
@ -601,13 +570,18 @@ void read_button() {
} else {
digitalWrite(led_run_pin,false);
}
if (button3 && lcd_light) {
if (button3 && button3long && lcd_light) {
lcd_light = false;
lcd.noBacklight();
} else if (button3 && lcd_light == false) {
} else if (button3 && button3long && lcd_light == false) {
lcd_light = true;
lcd.backlight();
}
if (button3 && lcd_minmax == false) {
lcd_minmax = true;
} else if (button3 && lcd_minmax) {
lcd_minmax = false;
}
}
void web_measuring_stop(AsyncWebServerRequest *request) {
@ -633,7 +607,7 @@ void web_get_values(AsyncWebServerRequest *request) {
else {
web_status = "Stopped";
}
request->send( 200, "application/json", "{\"voltage\":" + String(busvoltage_V) + ", \"current\":" + String(current_A) + ", \"power\":" + String(power_W) + ", \"Ah\":" + String(Ah) + ", \"Wh\":" + String(Wh) + ", \"battery\": " + String(battery_voltage) + ", \"run\":\"" + String(web_status) + "\", \"shuntvoltage_V_max\":" + String(shuntvoltage_V_max) + ", \"shuntvoltage_V_min\":" + String(shuntvoltage_V_min) + ", \"current_A_max\":" + String(current_A_max) + ", \"current_A_min\":" + String(current_A_min) + ", \"power_W_max\":" + String(power_W_max) + ", \"power_W_min\":" + String(power_W_min) + "}");
request->send( 200, "application/json", "{\"voltage\":" + String(busvoltage_V) + ", \"current\":" + String(current_A) + ", \"power\":" + String(power_W) + ", \"Ah\":" + String(Ah) + ", \"Wh\":" + String(Wh) + ", \"battery\": " + String(battery_voltage) + ", \"run\":\"" + String(web_status) + "\", \"busvoltage_V_max\":" + String(busvoltage_V_max) + ", \"busvoltage_V_min\":" + String(busvoltage_V_min) + ", \"current_A_max\":" + String(current_A_max) + ", \"current_A_min\":" + String(current_A_min) + ", \"power_W_max\":" + String(power_W_max) + ", \"power_W_min\":" + String(power_W_min) + "}");
}
void data_logging() {