This post is a dump of stuff I’ve done in the last period working on DC monitoring.
First, I’ve made some changes and additions to the OLED display, in conjunction with the button pressing.
OLED default behaviour is On and cycling through views of different pages of data.
If a button is pressed on GPIO0 then the display and changing page will become dependant on button presses, and be Off by default (after 10 seconds of no button). I made a couple of graphics for charging and discharging too.
I could’ve remade the video after the radio unexpectedly turned on, but it was Ivor Cutler, so left it as it was.
Second, the problems a couple of users have had with inaccurate voltage readings when using the buck reg of my own design was due mostly to the complete lack of filtering at the voltage divider. The same noisy problem travelled into the current readings so it was all shambles really. I’ve worked out the filters on current and voltage channels to cancel out the noise of the buck, and noise more generally I hope. The buck operated at around 400kHz and appeared easy enough to filter out.

This shows a very simple filter arrangement dependant on the fuses themselves, which have a rated resistance. In the video above one can see the TR5 fuse holders I’d used to work out a suitable combination of R and C. I checked also that the charging of the capacitor wasn’t blowing the fuse, there was a condition where the charging of a large cap was blowing a 50mA fuse. I did this check at 32V, and settled on 150mA fuses.
An alternative filter is depicted downstream of the shunt monitor, I’ve not done that, but will be possible in future PCBs just in case.
Third, the variant of emonESP used has had an upgrade, which most importantly could solve the WiFi dropping out issue. I’ve copied openEVSE code to put the web pages into progmem which means flashing requires one file, and can completely upgrade the firmware+web server in one flash, or OTA, or with a file dropped into the web-interface (note the security implications of this!).
I’ve finally got fluent at navigating the excellent code by J.Poulter and also the program VS Code I must say is fantastic, and makes navigation much easier because of the Find and Go To tools. I don’t know another editor which does this so well.
(I think right-click and view image to zoom in).
This shows a bunch of settings I’ve imagined will be useful to battery monitors and general board-hacking.
Imagined being a key word… I’ve tested all of it but in practice I guess things can be added and others taken away. I have one test set up here but time will tell.
What else… Peukert!
Thanks to another user making me aware of this, I’ve implemented State of Charge monitoring using the Peukert exponent, or coefficient, to give an idea of the true usable amount of energy remaining in the battery. This is in addition to counting coulombs. Using the Peukert coefficient gives a more accurate idea because it factors in the changing efficiency of discharge against the rate of discharge (or charge). Meaning the faster one takes energy from a battery the less usable energy there will be in total, as the increased internal resistance of the battery will dissipate more greatly.
Still lacking from this firmware is monitoring of the temperature of the environment and batteries, and factoring in of the age of the batteries, all of which would add to accuracy. Age could be adjusted for manually in the settings by decreasing the capacity.
Example code:
#include <stdio.h>
#include "soc.h"
#include <math.h>
#include <stdint.h>
#include <stdbool.h>
#include <time.h>
#include <unistd.h>
// test input data
double Current_B = 5; // amps
// initial SoC for test:
double state_of_charge = 1.00 ; // 1 = 100% percent
// battery data.
double Hr = 20.0; // rated time in hours
double k = 1.3; // approx. Peukert exponent for flooded lead-acid.
double C = 100.0; // capacity of battery at rated time (Ah)
char log_buffer[200];
int period = 5;
time_t current_time;
int main()
{
printf("run.\r\n");
time_t current_time = time(NULL);
current_time -= period; // for sensible start data.
while(1) {
uint32_t previous_time = current_time;
current_time = time(NULL); // seconds.
double Ah_period = (Current_B * (current_time-previous_time)) / 3600.0; // Coulomb counting.
double soc_diff = Ah_period / effective_capacity_fromfull(); // state of charge difference this period.
state_of_charge -= soc_diff; // update state of charge.
double _time_until_discharged = time_until_discharged_fromfull() * 3600 * state_of_charge;
sprintf(log_buffer, "state_of_charge(%%):%.6f\r\n", state_of_charge*100);
printf("%s",log_buffer);
sprintf(log_buffer, "_time_until_discharged(seconds):%.1f\r\n", _time_until_discharged);
printf("%s",log_buffer);
sleep(period);
}
} // end main
//-------------------------
// Battery monitoring.
//-------------------------
double time_until_discharged_fromfull(void) { // returns time until discharged from ideal battery condition.
// http://www.smartgauge.co.uk/peukert2.html
// T = (Hr*(C/Hr)^n)/(I^n)
double Peukert_capacity = Hr * pow((C/Hr), k);
double _time_until_discharged = Peukert_capacity / (pow(Current_B, k));
return _time_until_discharged;
}
double effective_capacity_fromfull(void) { // returns eff. cap. in Ah.
// http://www.smartgauge.co.uk/technical1.html
// http://www.smartgauge.co.uk/peukert3.html
double _effective_capacity = time_until_discharged_fromfull() * Current_B;
return _effective_capacity;
}
output:
$ make && ./soc
gcc -o soc soc.c
run.
state_of_charge(%):99.993056
_time_until_discharged(seconds):71995.0
state_of_charge(%):99.986111
_time_until_discharged(seconds):71990.0
state_of_charge(%):99.979167
_time_until_discharged(seconds):71985.0
state_of_charge(%):99.972222
_time_until_discharged(seconds):71980.0
state_of_charge(%):99.965278
_time_until_discharged(seconds):71975.0
state_of_charge(%):99.958333
_time_until_discharged(seconds):71970.0
See http://www.smartgauge.co.uk for some good learning material on this, I had to develop on their basics to get the above code, which simply adds a real-time adjusted ‘time until discharged’ based on the updated SoC.
This code has not been checked by anyone else.
Helpful and fun having a couple of these recently to test with!
Over n out.