NordicOffGrid´ Logo
Off-grid solcellssystem.
I Nordiskt klimat!
 by Bosse
By AutonomTech.se Frittliv webbplats

 Webbsidan är senast uppdaterad:  

Batterimonitor

NordicOffGrid Ultra-precise Battery System Monitor
Batterimonitor för driftsövervakning av off-grid solcellssystem

Webbsidan skapad 2022-04-10
ESP32-batterimonitor
ESP32-batterimonitor: Battery 24hr operational graph

Batterimonitor typ "tankmätare" för batterier där man summerar ström / effekt till batteribanken över tid till Ah/Wh urladdad status från 100% SOC fulladdat. Utifrån känd C20-batterikapacitet kan man då även försöka ange en relevant SOC-status för laddnivån som 0-100% SOC.
Är en väldigt viktig grundläggande funktion i ett off-grid solcellssystem för batteridriften!
NordicOffGrid Batterimonitor övervakar många fler parameterar för driften än Ah/Wh så utgör en driftsövervakning av off-grid solcellssystemet, med även historisk data och statistik!
Gör även om rå mätdata till information, s.k. aggregerad data, med mer info över driften.
Det jag gör här blir mer som en "Battery System Monitor" (BSM) än en ren batterimonitor, med autonom proaktiv förbrukarstyrning för skonsam hantering av batteridriften!
Batterimonitorn kommer visa data och drifsstatistik med inställningsmöjligheter dels på en strömsnål LCD 16x2 teckendisplay, dels via local console on a network (LAN) dvs Webbsidor från webbserver i ESP32 via WiFi, vilka kan visas i webbläsare i mobilen, på laptop eller dator.
Batterimonitorn används i projektet: PWM-solladd­regulator
"Att mäta är att veta" myntades redan på 1800-talet av Werner von Siemens!
Kommer uppdatera här efterhand som jag utvecklar Batterimonitorn.

Beskrivning av grundfunktion:

Genom att mäta den ström / effekt som laddas ur/i batterierna över tiden fås den strömmängd som påverkar hur mycket av batterikapaciteten som för tillfället lånats ur batterierna. Med 1A ström urladdning under 1h har 1Ah laddats ur batterierna, och motsvarande med 12W effekt urladdning under 1h har 12Wh laddats ur. Men då strömmen normalt varierar mycket över tid måste den mätas väldigt ofta och för varje sådant kort tidsintervall summeras ihop till den totala strömmängden.
För att få en bra noggrannhet över lite längre tid så måste både ström / effekt mätas väldigt noga och med stort dynamiskt omfång samt de korta tidsintervallen måste också kunna mätas med hög precision. Stort dynamiskt omfång betyder att man måste både kunna mäta väldigt små strömmar och de stora som systemet är max dimensionerat för, då även väldigt små strömmar blir en signifikant strömmängd över en längre tid.
En ström på bara 10mA (0,010A) blir på en vecka till 1,7Ah.
Sedan tillkommer problem med att batteri­verknings­graden är lägre än 100%, att den varierar med hur fulladdade batterierna är samt med om driften hela tiden växlar mellan kortare ur/i-laddningar eller längre kontinuerliga ur/i-laddningar. Samt verknings­graden påverkas även av hur hög ström ur/i-laddningen sker med, det som kallas för Peukert´s law, och batterier har en viss självurladdning också. Detta är även olika för olika batterityper, där vanliga blybatterier har rätt stor inverkan av detta, blykol-batterier betydligt mindre och LiFePO4 ännu mindre.
Så för en bra batterimonitor-funktion bör det tas hänsyn till dessa förluster samt man måste även ha en väldigt stabil bra synkronisering mot 100% SOC fulladdad batteribank för att mot fulladdad batteribank kalibrera bort den drift / onoggranhet som ofrånkomligen summeras över tid.
Det enda säkra tillståndet att nollställa / kalibera batterimonitorn mot är 100% SOC fulladdade batterier! Så är en oerhört viktig funktion att få stabil med hög noggrannhet, som även sköter sig helautomatiskt själv utan inställningar av användaren.
Idealet för en batterimonitor är att den själv kan utvärdera dessa olika parametrar dynamiskt under drift, då de varier över dels tid, dels med temperatur samt dels med hur driften är. Så för bra noggrann långtidsstabil drift kan man inte ha fasta inställningsvärden för dessa, värden som dessutom är svåra för användaren att avgöra!
Så min ambition är att försöka utveckla en batterimonitor som hanterar detta själv, sedan får vi se hur långt jag lyckas nå med det. Är svårt så hela vägen når jag nog inte!
Mina analyser visar att batterimonitorn då måste ha tillgång till information om hur solladdregulatorn arbetar för stunden med batteriladdningen, direkt från regulatorn. Är inget som den själv kan utvärdera tillräckligt bra via sina egna mätvärden. Så jag tänker bygga en hybrid PWM-solladdregulator med integrerad batterimonitor. (Och solladdregulatorn i sin tur behöver veta strömmen in-/ut-ur batteribanken för bäst laddstyrning, så en hybrid är välmotiverat.)
2022-10-26
En frågeställning är dock hur får man till allt helt rätt när man har både sol och andra laddare samtidigt?

Peukert´s Law: 2022-10-14

I denna batterimonitor kommer jag inte alls ha med Peukert´s law för Ah- och SOC-beräkningar, samt kommer som första början räkna mot blybatteriernas nominella C20-kapacitet så får resten bara bli en extra marginal för åldrande vid moderata strömuttag.
Jag och en del andra som tittat rätt mycket på detta med batterimonitor är inne på att för batterimonitor i ett off-grid solcellssystem bör man inte alls ta med Peukert´s law så för SOC-beräkningarna, då det blir ett missbruk av den och Peukert´s law inte alls beskriver det driftsfallet eller en verklig förlust av batterikapacitet vid sådan växlande battericykling!

Växlande urladdning Peukert´s law
Växlande urladdning blybatteri, Peukert´s law

Peukert´s law gäller bara för en urladdning med konstant ström i ett svep från 100% SOC till "0% SOC" som bestäms av att urladdningen avbryts vid 10,5V batterispänning för 12V blybatteri. Så Peukert´s law gäller inte alls när man som i ett off-grid solcellssystem har ständigt växlande laddning / urladdning som det blir där!
Därmed är det väldigt osäkert vad den bidrar till i en batterimonitor? Bör ge helt fel resultat!
Är väldigt svårt att hitta kunskap kring hur blybatterier beter sig ur Peukert´s law synvinkel med en växlande daglig laddning från solceller och urladdning där emellan.
Peukert´s relation describes how the capacity is related to the total time to discharge the battery to 10.5 volts. Simply put, the reason you get less amp hours out when the amps are higher is that the higher amps drag down the volts more than a lower amp load, so the 10.5 volts endpoint is reached sooner. It is not because some of the electrons [capacity] in the battery get lost or wasted when you draw current out faster. [källa]
Så Peukert´s Law beskriver inte en förlust i batterikapacitet, utan bara hur mycket av kapaciteten som kan urladdas i ett svep för olika strömmar innan man når 10,5V batterispänning!
Vilket då är helt ointressant för en batterimonitor, inte minst i ett off-grid solcellssystem!
Handlar om tillfälliga polarisations-effekter som sänker batterispänningen under urladdning, mer vid högre ström, som återställs vid vila eller minskar signifikant vid låg ström, mer ju lägre!

Växlande urladdning Peukert´s law
Växlande urladdning blybatteri, Peukert´s law

Som exempel, låter man ett blybatteri som laddats ur till 0% SOC enligt Peukert´s law vila 24h så hämtar det sig och är inte längre urladdat till 0% SOC, utan en signifikant del av kapaciteten återkommer igen under vilan.
Och det är ju precis så driften sker i off-grid solcellssystem, där solcellsladdning i detta sammanhang kan ses som "supervila" för blybatterierna! Så vid ständig växlande laddning / urladdning får man inte alls de förluster i kapacitet som Peukert´s law beskriver när ett blybatteri laddas ur helt i ett svep!
It is a common misunderstanding that the energy not delivered by the battery due to Peukert´s law is "lost" (as heat for example). In fact, once the load is removed, the battery voltage will recover and more energy can again be drawn out of the battery. This is because the law applies specifically to batteries discharged at constant current down to the cutoff voltage. The battery will no longer be able to deliver that current without falling below the cutoff voltage, so it is considered discharged at that point, despite significant energy still remaining in the battery.
What happens is that the chemical process (diffusion) responsible for transporting active chemicals around the battery progresses at a finite rate, so draining the battery quickly causes the voltage to reach the cutoff level prematurely before all the active material in the battery is used up. Given time, the active material will diffuse through the cell (for example, sulfuric acid in a lead-acid battery will diffuse through the porous lead plates and separators) and be available for further reaction.
What Peukert really meant: When energy is drawn, battery voltage falls. As an example were a battery able to sustain 5 amps for 20 hours (before falling below 10.6 volts) it can be rated as being 100 amp hours.
When a heavier load (say 50 amps) is connected across that battery, its voltage falls more rapidly. After (say) 60 minutes, it is likely below 10.6 volts. The battery is consequently unable to sustain that discharge rate. But its energy has been depleted by 50 amp hours. No more – nor less.
A lead acid battery reacts very slowly. Once that 50 amp load is removed it slowly recovers. Off-load voltage will be 12.2-12.3 volts. It may still be able to supply 50 amps, but this time for only 30 minutes. Delivered available capacity is now 75%. The 25% remaining is still available, but now at five or so amps.
So, what Peukert really meant is that rate of discharge does not affect overall capacity. That which it affects is only its usable capacity when loaded above its rated current. In other words its rated capacity (energy) is still available, but only at its intended (rated) current. Some see that as "available capacity".
[källa]

Växlande urladdning Peukert´s law
Blybatterikapacitet 5dygns dålig-väder-reserv.
Ger medelurladdningsström 0,8A/100Ah (C20).
Discharge Rate = 20h / (5 * 24h) = 0.167
Peukert´s k=1.25 är högt för AGM & BlyKol.
Peukert Kalkylator1 / Peukert Kalkylator2

Men riktigt vad man får tillgång till för extra kapacitet vid moderata urladdningsströmmar vet jag inte, då jag hittat absolut noll kunskap kring det för denna växlande driften i ett off-grid solcellssystem. Så i ett senare skede ska jag troligen försöka utvärdera det ur blybatterispänningen vid lägre SOC när strömmen är som lägst nattetid utan solcellsladdning. Men då främst för åldrandet.

2023-08-02
Beräknat för 5 dygns dåligt-väder-reserv (C120) medelström skulle man då ur 100Ah C20 blybatterikapacitet kunna ladda ur 156Ah vid Peukerts exponent 1.25, vilket känns helt orealistiskt mycket! Det skulle innebära att vid C20´s 20h urladdning skulle bara 64% av det aktiva elektrodmaterialet delta i omvandlingen från laddat till urladdat kemiskt tillstånd, vilket känns helt osannolikt lite! Beskrivs även i en forskningsrapport: "The classical Peukert´s equation is not applicable at small discharge currents as according to this equation, at the discharge current decrease, the capacity released by the cells tends to infinity."
En annan forskningsrapport tittar på "Adapting the Peukert Equation to Batteries Discharged at Pulse Currents" och kom fram till "Therefore, the methodology proposed here may extend Peukert´s law to batteries in which the discharge current is not constant."
"Peukert´s law has always been applied to the discharge of batteries at constant currents. Today, however, there are more and more applications in which batteries are used with pulse currents (e.g. wireless sensors, electric vehicles, [off-grid PV-systems])."
Dvs Peukert´s law gäller inte för urladdning med varierande strömstyrka eller vid ständig växling mellan laddning och urladdning i solcellssystem (precis som jag bedömt).
En person med Victron SmartShunt batterimonitor tyckte den visade 76% SoC med Peukert exponent 1.25 kändes hög, då urladdade Ah motsvarade 50% SoC räknat mot fritidsblybatteriernas C20-kapacitet. Så han provade att ändra till Peukert exponent 1.00 och då visade SmartShunt 50% SoC. Ändrad tillbaka till 1.25 visades åter 76% SoC! Så Victron SmartShunt använder Peukert exponent för att räkna ut användbar batterikapacitet vs strömbelastning, vilket då vid låga strömmar (<C20-urladdning) blir en högre kapacitet än blybatteriets C20-kapacitet!
I detta fallet med 50Ah urladdat / 100Ah C20 har Victron SmartShunt för den låga strömbelastningen räknat fram 208Ah användbar kapacitet ur 100Ah C20-kapacitet, vilket är helt orimligt att det skulle stämma med verkligheten bedömer jag! Den ovan nämda forskningsrapportet säger samma: "The classical Peukert´s equation is not applicable at small discharge currents"!
De 208Ah ur 100Ah/C20 i SmartShunt-fallet motsvarar en Discharge Rate = 0.053 i Peukert-beräkningen dvs C20 / 0.053 = C377 urladdning i snitt (typ 15 dygns dåligt-väder-reserv).
Detta stärker också min bedömning att inte använda Peukert´s Law i batterimonitorer!
Även Mastervolt använder Peukert´s Law i sina batterimonitorer: "Peukert´s Law describes the effect of different discharge values on the capacity of a battery, i.e. that battery capacity is reduced at higher discharge rates. All Mastervolt battery monitors take this equation into account so you will always know the correct status of your batteries."
Balmar SG200 batterymonitor använder Peukert´s Law, men bara för Time-To-Go beräkningarna: "Changing the PEUKERT Value will not effect Charge Termination, only TIME REMAINING Calculations".
Simarine verkar också använda sig av Peukert´s Law via: "The nominal battery capacity for the next C ratings: C/20, C/10, and C/5. If you don´t know all the ratings, fill in just those ratings that you know. It is highly recommended to fill at least two C ratings (one is not enough for precise calculations).
Studer Battery Status Processor BSP 1200 använder också Peukert´s Law: "The capacity varies according to the discharge current. With this parameter one can set the Peukert exponent that goes along with the nominal capacity and nominal discharge time."
Trots detta är det min övertygelse att Peukert´s Law inte är tillämpbar för en batterimonitor, speciellt inte i ett off-grid solcellssystem! Finns tillräckligt med vetenskapliga rapporter och fakta som stödjer att Peukert´s Law inte gäller för fluktuerande strömurladdningar samt inte beskriver några kapacitetsförluster för kvarvarande batterikapacitet efter viss urladdning, anser jag!
Vid lite efterforskning finns det en Kinetic Battery Model (KiBaM) för drift i typ off-grid solcellssystem. Det finns en ur KiBaM vidareutvecklad modell "addressing four characteristics of operation: charging, discharging, rest after charge, and rest after discharge" Comprehensive Model for Real Battery Simulation Responsive to Variable Load (4-KiVM) som såifall kanske kunde användas i en batterimonitor i motsats till Peukert´s law. Referens till "The KiBaM battery model" finns i Wikipedia artikeln Recovery effect.
Mer: Battery Aging, Battery Charging and the Kinetic Battery Model: A First Exploration
A realistic model for battery state of charge prediction in energy management simulation tools, baserad på the Kinetic Battery Model.
HOMER uses the Kinetic Battery Model to determine the amount of energy that can be absorbed by or withdrawn from the storage bank each time step. (Visualiserar principen!)

Jag har av dessa anledningar inte heller med Peukert´s law i min Kalkylator små Solelsystem II då jag under min drift sedan 2007 i mitt off-grid solcellssystem inte kunnat se någon inverkan av det som Peukert´s law beskriver!
Jag hade med den från början men har under åren verkligen letat väldigt noga efter inverkan av Peukert's law i min off-grid drift och inte kunnat hitta några spår av den. Då har jag i och för sig rätt måttliga strömmar, men ska man klara 5dygns dåligt-väder-reserv kan höga urladdningsströmma bara förekomma väldigt korta tider av den totala driftstiden, så bör vara i stort samma för alla. Precis under en kortvarig hög urladdningsström borde man kunna notera en effekt av Peukert´s law, men sedan hämtar sig blybatterierna från den s.k "Recovery effect" / "Relaxation effect" (i stort helt vid driften i ett off-grid solcellssystem vad jag kunnat få fram).

Bogart Engineering med sin TriMetric batterimonitor beskriver tydligt varför de inte använder Peukert´s law i sin batterimonitor, och det utifrån över 25 års erfarenhet av att utveckla batterimonitorer.
När jag läser på Victrons webbsida om Peukert exponent för deras BMV 700-serie batterimonitorer får jag uppfattningen att Victron till stor del har missförstått vad Peukert´s Law står för och vad för effekt i blybatterier den beskriver då Victron bl.a. skriver "The capacity of a battery depends on the rate of discharge. The faster the rate of discharge, the less capacity will be available.", vilket känns lite märkligt ihop med batterimonitor i off-grid solcellssystem (även om Peukert´s Law missuppfattas rätt ofta, så förståeligt om även deras ingenjörer gjort så)!
Peukert´s exponent ökar även med blybatteriernas åldrande, så den kommer ju aldrig vara korrekt över tid, och som sagt beskriver inget fenomen användbart för en batterimonitor så som jag och en del andra uppfattat det. Samt den är många gånger svår att få tag på för sina blybatterier, men går att räkna fram om de har minst två kapaciteter angivna typ C5 / C10 / C20 / C100.
De delar av Peukerts effekt som eventuellt påverkar lite även vid cyklisk drift kommer då till stor del med som del av den utvärderade batteriverkningsgraden i batterimonitorn. Så med sådan funktion kan jag verkligen inte se något behov av Peukert´s exponent i batterimonitorn!

Utökad funktion: 2022-06-30 / 2023-04-18

För oss lite mer intresserade kunde det vara intressant med mer information än bara Ah och SOC från en batterimonitor, typ hur mycket ström som använts direkt från solcellerna och hur mycket som plockats ur batteribanken. Hur mycket av strömförbrukning som just nu kommer från solcellerna respektive batteribanken samt ström / effekt ut till utgående förbrukning.
Och vid off-grid för fritidsboende att man kunde nollställa och mäta för en boendeperiod där hur mycket av strömmen som solcellerna resp. batteribanken levererat samt systemet förbrukat, både för boendeperioden och senaste dygnet (24h). Ur det kunde systemet även mer smart beräkna hur länge till batteribankens dåligt-väder-reserv räcker utifrån senaste 24h drift.
Har man 5 dygns dåligt-väder-reserv i batteribanken och solcellerna levererar 75% av förbrukad ström i molnig väder så räcker den reserven då i 20 dygn som exempel.
Kanske även en prognos baserat på senaste timmens förbrukning, men baserat på momentan förbrukning som flera batterimonitorer idag gör känns rätt meningslöst.
Bra att få info om, men lite krävande att själv försöka uppskatta!
Även detta görs lättas genom en samverkan mellan solladdregulator och batterimonitor.
Jag tänker även försöka lagra data kortare tid lokalt i ESP32 (typ 24h till 7? dygn, samt viss nyckeldata kanske ett år och annan 30dygn) samt regelbundet koppla upp den mot egen webbplats inhyrd på webbhotell och lagra långtidsdata där. Så kan jag hålla koll på batteridriften även via Internet varifrån jag vill. Får se under utvecklingen hur mycket sparad data som verkar vettigt!
Sedan hade även någon form av "Battery state of health estimation (SOH)" varit bra, som även kunde larma om något batteri börjar bli dåligt, men får nog ses som överkurs.
Har dock lite funderingar på att övervaka float-ström när solladdregulatorn reglerar den, hålla koll på lägsta batterispänning nattetid samt kanske mäta batteribankens impedans när PWM-regulatorn strömpulsar fulladdad batteribank. Bör kunna ge viss insikt om batteribankens status om någon av de börjar avvika från de normalt uppmätta värdena över lite längre tid!
Även kanske jämföra olika tidsfiltrerade batteriverkningsgrads-mätningar, typ 1/1, 1/10, 1/100 & 1/1000 och se om det blir en tydlig plötslig förändring i batteriverkningsgrad över tid som då kan indikera utvecklingen av problem i blybatterierna! Borde kunna vara ett bra mått!

Hårdvara att bygga på:

Har nu detaljstuderat databladen för INA260 (datasheet) och INA226 (datasheet) och de har verkligen flera riktigt bra funktioner för att kunna bygga en batterimonitor med hög precision! Mer om INA260/INA226.
Dels kan man sätta ADC (Analogue to Digital Converter) conversion time till mellan 140µs och 8.244ms där längre tid ger en mer exakt avläsning, dels kan man låta dem beräkna medelvärdena för mellan 1 till 1024st mätningar, vilket också ger möjlighet till noggrannare mätning av ström och effekt. INA226 använder extern strömshunt med mätområdet ≤36V, ±81,9mV, 16-bit, som då ger möjlighet till externt RC-filter av signalen från strömshunten så ingen data missas mellan samplingarna typ kraftiga korta strömpulser. INA260 har intern 2mΩ strömshunt för ±15A och ≤36V 16-bit mätområde inom -40°C to +85°C. The device operates from a single 2.7V to 5.5V supply, drawing 310 µA (typical), så är strömsnåla också!
Innebär att med maxvärdena 8.244ms och 1024st mätningar fås nya exakta medelvärdesbildade aggregerade data 1ggr/8,64s och som snabbast ca 1ggr/140µs, som INA260/226 då arbetar självständigt med att samla in. Kretsarna har även en signalutgång som indikerar exakt när nya aggregerade mätvärden är tillgängliga, så man kan synka av läsningen av ström/effekt från INA260/226 hos ESP32-mikro-processorkortet med den, vilket görs via s.k. interrupt.
Den utsignalen skulle under långvarig standby-drift även kunna användas till att väcka upp ESP32 mikroprocessorkortet (källa2) ifrån strömsnål light-sleep och läsa av strömförbrukningen med upp till 1ggr/8,64s intervall och vara i light-sleep däremellan, som strömsnål batterimonitor! Men 2x (U+I) 1.1ms conversion time och 1024 averages, 1ggr/2,25s, är nog vettigt så kan responstiden på knapptryckning under light-sleep bli max 2,25s. Då borde kanske ca 22ms RC-filter bli lagom? Typ 4,12kΩ * 4,7µF, R82 50V (RC=19ms), så bör INA226´s 830kΩ ingångsresistans inverka minimalt på mätresultaten.
2023-02-16
Är bara INA226 spänningsmätning VBUS som har 830kΩ ingångsresistans, strömmätningens ingångar IIN+/IIN- har en Input bias current på typ 10µA, men uppmätt ca 35µA i drift!
Så går inte att göra en RC-filtrering på samma lätta sätt där som för VBUS!
Med 4,7µF/4,2kΩ (20ms RC) fick jag 341mA mätt med 500mA genom strömshunten! Utan 4,2kΩ mättes 501,7mA genom 60A/60mV shunten (LSB=1,8mA / 2,5µV).

Multiple INA226´s with INA226_WE library (limit: 4 INA226).
Kanske kan kombinera interrupt med ISR och light sleep wakeup på samma GPIO?
Låter möjligt: ESP32 using interrupt to momentarily wake from Light Sleep - bug?
Går att göra via ONLOW_WE / ONHIGH_WE attachInterrupt(pin, ISR, ONLOW_WE); där WE=Wakeup Enabled, dvs Interrupt och Wakeup från sleep på samma digitala ingång.
Kan göras som deferred interrupt via Queue API med tidsstämpling på 1µs upplösning för effektiv interrupt-hantering och exakt Ah-/Wh-summering / integrering.
Och ESP32 i sin tur har en 64-bitars tidmätning som mäter tiden med 1µs upplösning (0,000001s) och som bara startar om (overflow) 1ggr/292år så man kan mäta tiden mellan ström- och effekt-mätningarna med riktigt hög precision, vilken används för att summera ihop ström (A) och effekt (W) till Ah och Wh för värdena i batterimonitorn.
Ihop med batterier som trivs/tål att float-laddas 100% SOC längre tid (typ blybatterier) kan jag då även göra så batterimonitorn regelbundet automatisk nollströmskalibrerar sig under drift, vilket också ökar långtidsstabiliteten och precisionen. Har jag inte sett någon batterimonitor nu på marknaden har (möjligen BALMAR SG200). Kanske nollströmskalibrera sig mot den ström som är självurladdningen, då det egentligen är en strömförbrukning som inte ström­shunten kan registrera och inte bör komma med i ∑Ah / ∑Wh.
Ska bli spännande det här!

Mobil 4G Router Teltonika RUT241: 2022-07-30

Teltonika RUT241
Teltonika RUT241

Införskaffat den 4G-router jag ska använda för att överföra driftsdata från off-grid sol­cells­systemet till min webbplats server. Valet föll på en Teltonika RUT241 4G/LTE(Cat 4), 3G, 2G industriell router med bra rykte om stabil till­för­lit­lig drift, med bra temperatur­drifts­om­råde på -40°C - +75°C, drifts­spänning 9VDC - 30VDC samt chassit är i aluminium för bästa värme­över­föring och kylning. Drar uppkopplad mot 4G utan datatrafik 1,2W matad från 12V enligt wiki, <2,5Ah/dygn. Har rimligt pris för prestandan tycker jag!
"RUT241 is an excellent fit in various IoT and M2M solutions that require easy setup, reliable network, and remote accessibility.
Kommer använda extern rundstrålande puck-antenn placerad uppe i takluckan i husvagnen, då alla väggar av aluminiumplåt skärmar av rätt mycket där det är dålig mottagning.
RUT241 är en ny version av RUT240, beskriven som: "Teltonika RUT241 är en ny uppgraderad version av den klassiska industriella LTE-routern RUT240. De är nära identiska förutom styrkretsen som uppgraderats till Mediatek MT7628 som har väsentligt bättre tillgänglighet och något snabbare prestanda [580MHz vs 400MHz]." Samt dubbelt så mycket RAM-minne som RUT240, så plats för uppgradering till mer krävande OS i framtiden.

Teltonika RUT241 vs RUT240
Teltonika RUT241 vs RUT240

ESP32 WIFI uppkopplad till RUT241: 2022-08-03

Har kopplat upp RUT241 här hemma nu och tycker WIFI känns helt OK! Har placerat RUT241 ute i köket med en armerad betongvägg i vägen in till vardagsrummet där jag sitter längst in nu. Får full signalstyrka på mobilen där ifrån RUT241 samt min ESP32 som är lite kinkig kopplade upp och synkade med tidsserver på Internet utan problem via RUT241 här längst in i vardagsrummet vid datorn.
ESP32 kopplar upp snabbare till RUT241 än till min bredbands-router som finns i hallen precis utanför dörröppningen in till vardagsrummet och således med bättre kontaktväg så utan armerad betongvägg i vägen. Och den är ändå bra.
I mobilen får inte min bredbands-router riktigt full signalstyrka hela tiden här inne i vardagsrummet, så RUT241 verkar ge något bättre WIFI. Här är ändå 14st andra routrar från grannar som sänder ut WIFI jag ser i mobilen, så är väl ingen perfekt miljö här precis tänker jag.
Har låtit ESP32 koppla upp och synka mot tidsserver via RUT241 8-9ggr nu och fungerar bra hela tiden. 2022-12-16 Nu har min ESP32 bootat och hämtat tid från NTP-server >1000ggr!
Så känns riktigt lovande för husvagnen och mitt kommande PWM-regulator + batterimonitor ESP32 projekt.
Lär ju få tillgång till WIFI även utanför husvagnen, vilket blir som en extra bonus då jag är fullt nöjd med bra Internet inne i husvagnen.
Jag får nu WIFI-signalstyrka RSSI -59dBm i ESP32, vilken anses som:
-50 to -67dBm – At Good signal strength for Web browsing, voice/video calls.
Wireless dBm table

Teltonika RUT241 4G-router i glesbygd: 2022-08-28

Teltonika RUT241
Teltonika 4G Signal strength 3(5)

Tog med Teltonika RUT241 till husvagnen för test av funktion där. Är en ofta svag långsam intermittent mobil-uppkoppling där via mobilen, så en bra referensplats för funktion i bergig skogig Östgötsk glesbygd. Testade även hur ESP32 kan koppla upp och synka sin RTC mot tidsserver på Internet via RUT241´s wifi, och det skedde fint stabilt samt snabbt!

Teltonika RUT241
Teltonika 4G Signal strength

Fick -81dB signalstyrka med puck-antenn på soffbordet där nära mobilen samt pendlade mellan 2-3 (5) streck på RUT241´s indikator. Uppe i taklucka låg den på 3 streck signalstyrka större delen av tiden. Samt fick ned 4-8Mbit/s och upp 0,5-2Mbit/s med snitt runt 6Mbit/s ned och 0,7Mbit/s upp, en 5-10ggr snabbare än med mobilen direkt mot 4G! Är ofta låg kapacitet så hos basstationer ute i glesbygd, som brukar vara rätt hårt belastade så här vid 17:30-tiden på dygnet. Men den mest avgörande skillnaden var att RUT241 behöll sin uppkoppling stabilt med 2-3 streck i signalstyrka, där mobilen tappar den av och till lite längre perioder.
Och wifi räckte bra långt utanför husvagnen med bra signalstyrka 8-10m bort, trots husvagnens utsida av Al-plåt. Så jag känner mig helt nöjd med funktionen, som känns bättre än en del framhållit på Internet för föregångaren RUT240!

Adafruit Proto-Screwshield Arduino R3: 2022-12-01

Proto-Screwshield R3
Adafruit Proto-Screwshield Arduino R3

Lödde ihop ett Proto-Screwshield R3 för utvecklingsfasen när jag testar fram funktionen. Är smidigt och enkelt att arbeta med, att slippa löda in anslutningstrådar från givare, strömförsörjning, etc. till WeMOS ESP32 D1 R32 Uno.
"The next generation Proto-ScrewShield is a dual-purpose prototyping shield. Not only does it have a large 0.1" grid prototyping area but it also extends the Arduino pins to sturdy, secure, and dependable screw terminal blocks. You even get a few bonus terminals for extra GND and four ´free´ terminals for whatever connections you wish! New! As of June 23, 2014 we now have an R3 update to this design - we now have a stacking header for the ICSP 2x3 pins and breakout the SCL and SDA pins. It now works much better with R3 UNO´s, Mega, Leonardo, as well as stacking nicely with any shield.
The stack-able wing design allows you slip this under any shield and still get easy access to the "analog" & "digital" ports of the Arduino. The ScrewShield can be stacked above or below pretty much every other shield.
"

Solid-state relay AC/DC: 2022-12-04

För att styra strömmatningen till Teltonika RUT241 4G Router behöver jag solid-state-relay / load-switch / power-switch funktion som kan styra strömmen ON/OFF på high-side med 3.3V signal från ESP32. Hittade denna hos Electrokit, men finns nog billigare: LCA717 DIP-6 Solid-state relay AC/DC.
What is a Load Switch?
Load switches (TI)
Load switches Low quiescent current, 0-3A (TI)

Batteriverkningsgrad: 2022-12-11

Lite idéer / tankar dök upp kring hur den ska mätas / utvärderas... Kanske som funktion av hur djup en battericykling varit (max DOD) samt kanske hur lång tid den varat innan 100% SOC fulladdat igen? Kan den även vara beroende av batteritemperatur? Får mäta och se när jag har batterimonitorn i skarp drift med den första inledande funktionen för batteri­verkningsgrad och coulomb­verkningsgrad.
Är nog en sådan funktion som kunde använda ML (machine learning) i framtiden?
ML | What is Machine Learning?, GeeksForGeeks
Se även TinyML ESP32 Arduino, TensorFlow.

Grundkoden med menyer & NTP tid klar: 2022-12-13

Blev idag klar med grundkoden för alla menyer, WiFi samt för synkning av RTC (Real Time Clock) med NTP tidsserver på Internet. Sparade en kopia av den som bas för framtida ESP32-projekt. Detta är en mycket stor del av den totala kodningen men bara så viktig med det smidiga användargränssnitt den ger via 16x2 LCD displayen. Samt välutvecklat i FreeRTOS så det med väldigt lite kodning lätt läggs till nya menyer, både som editerar dataparameterar samt som visar driftsdata eller Datum / Tid från RTC, etc.
Har även varit ett lärosteg för mig att börja använda FreeRTOS för effektiv realtidsfunktion! Så hela funktionen är uppbyggd kring ett antal FreeRTOS-tasks, och Arduino loop() raderad.

ID för varje ESP32, macAdress: 2022-12-14

När driftsdata ska skickas till en webbserver på Internet kan ESP32´s MAC-adress användas som ID för respektive ESP32, då det ska vara unikt för varje individ. Så kan data skickas från flera olika ESP32-batterimonitorer utan risk att blandas ihop!
WiFi.macAddress() - Espressif MAC-adress, Convert MAC Address to String

ESP32 Async web server SSE: 2022-12-18

ESP32 Async webbserver (SSE)
ESP32 Async webbserver (SSE), mobil.
Flyttar senare Grafisk dashboard överst.
När all ESP32 funktion är på plats.

Nu kodat färdig för en Async Webbserver med webbsida i ESP32 som skickar datauppdateringar direkt till webbsidan via Server-Sent Events (SSE). SSE är effektivt, strömsnålt och elegant!
Har använt infon och en del kod från: ESP32 Web Server using Server-Sent Events.
Samt från ESP32 WiFiMulti: Connect to the Strongest Wi-Fi Network (from a list of networks)
Med biblioteket: ESPAsyncWebServer-esphome installerat inifrån PlatformIO, ett "Asynchronous HTTP and WebSocket Server Library for ESP8266 and ESP32".
ESPAsyncWebServer-esphome Readme user manual!!!
Var förvånadsvärt enkelt och smärtfritt samt gick mycket snabbare än jag hade förväntat mig! Fungerade direkt.
Är lite snabbt kodat så är inte slutligt utförande / design, samt skickar just nu bara fuskade slumtalsvärden för att se funktionen.
Fungerar jättebra mot wifi-routern här hemma samt mot Teltonika RUT241! ESP32 skickar webbsidan via wifi till routern som i sin tur skickar den vidare via sin wifi ut till mobil / dator.
Så på plats i ett off-grid boende / husvagn kan man kolla sin solcells-batteri driftsstatus inom hela området som routerns wifi når, vilket bör bli ett större områden än för en app via Bluetooth.
ESP32 skickar först hela webbsidan till webbläsaren och sedan bara den data som uppdateras där direkt till webbsidan via Server Sent Events (SSE), vilket är jätteeffektivt och strömsnålt även när flera olika enheter är uppkopplade mot webbsidan samtidigt.
Jag har valt att skicka nya data 1ggr/s så upplevs visningen stabil.
I mobilen kan man välja fullskärmsläge som då ser ut precis som en app, så blir lika snyggt med webbsidan på så sätt utan något beroende av någon extern tjänst eller kontakt med mobilnätet.
Jag väljer att använda en webbsida istället för app, dels för att jag redan har bra kunskap i att koda webbsidor, dels att driftsdatan då kan visas på en mängd olika enheter med webbläsare.
Så vill man ha en stor display kan man bara köpa en billig enkel surfplatta och montera hos sig, samt går ju även att visa på en smart-TV om man har en sådan.
Ska senare koda den som en progressive web app! (Web app manifests | Installing web apps)
Och smidigt att visa driftsdata så direkt från ESP32 mikrokontrollern!
Ska visas mer info där efterhand som projektet framskrider, som en dashboard.
Men nästa steg är att skriva koden för ström-energi-sensorn INA226 och koppla in den mot mitt lilla experimentella off-grid solcellssystem här hemma är tanken. Ska bli intressant!
ESP32 Useful WiFi Library Functions, Arduino
Espressif: ESP32 WiFi API Reference, Networking APIs
HTML vs Body: How to Set Width and Height for Full Page Size
HTML vs Body in CSS (2018)

ESP32 Async webbserver (SSE)
ESP32 Async webbserver (SSE), dator.
Ska bli en till canvas grafisk dashboard.
När full funktion så flyttas de överst.
Ser liknande ut på liggande mobilskärm.

ESP32 Async web server kraschar: 2022-12-21

Har nu kört med ESP32 Async web server SSE några dagar och det visar sig att ESP32-koden kraschar oregelbundet rätt glest (typ 5-10min) när en eller flera webbläsare är uppkopplad aktivt mot ESP32-webbservern och får Server Side Events skickade till sig. Bara då!
ESP32 bootar då om i en oändlig loop utan att lyckas starta om, förutom typ efter 80st gånger som vid debug-utskriften nedan (ResetBootCountRTC in RTC memory: 80).
Trodde först de orsakades av lite svag strömmatning via USB då LCD-displayens LED-bakgrundsbelysning blinkar lite när WiFi kortvarigt drar lite högre ström.
Men dels får jag Reset reason: 4, ESP_RST_PANIC, vilket inte är orsakat av spänningsmatning, dels blev det ingen skillnad när jag monterade in en kondensator för stabilisering av 5V på ESP32!
Och sedan hittad jag hur det gick att få ut mer debug-info i serial-monitor.
Så får där nu följande när det händer:
-------
Reset reason: 4, ESP_RST_PANIC
ResetBootCountRTC in RTC memory: 80
Total booting / resets: 2855

assert failed: tcpip_api_call IDF/components/lwip/lwip/src/api/tcpip.c:497 (Invalid mbox)
(Ser ut som ett av Espressiv-IDF biblioteken är orsak - kan det då fixas med någon inställning för webbservern, eller annat kodmässigt?)

Backtrace:0x40083b71:0x3ffb4c700x4008dadd:0x3ffb4c90 0x40093119:0x3ffb4cb0 0x400fadf1:0x3ffb4de0 0x401493f1:0x3ffb4e10 0x40149c15:0x3ffb4e50 0x400e095e:0x3ffb4e90 0x400d476b:0x3ffb4eb0 0x400d4854:0x3ffb4f20

ELF file SHA256: 0000000000000000

Rebooting...
ets Jun 8 2016 00:22:57

rst:0xc (SW_CPU_RESET),boot:0x13 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
-------
Så får dels läsa på mer i ESPAsyncWebServer-esphome Readme user manual, dels se om jag kan få felutskrift för heap corruption diagnostics, om det kan vara en orsak.
Espressif: Heap Memory Debugging
Samt i övrigt gå igenom min kod mer grundligt, ihop med att leta lite mer info på Internet.
Har sett indikation på lösning med att skicka SSE lite mer sällan än nuvarande 1ggr/s?
Vad jag förstått körs allt ESP32-internt kring WiFi / Bluetooth stöd i Core0, så att jag lagt mina funktioner för ESP32-webbserver också i Core0 kanske leder till någon krock av något slag, så får även testa att byta till Core1!

Efter att slagit på mer debug-info kom följande fram:
> assert [RX:' '] [RX:'failed: tcpip_api_call IDF/comp'] failed: tcpip_api_call IDF/comp [RX:'o'] o [RX:'nents/lwip/lwip/src/api/tcpip.c'] nents/lwip/lwip/src/api/tcpip.c [RX:':'] : [RX:'497 (Invalid mbox)\r\n
> \r\n
> \r\n
> Backtra'] 497 (Invalid mbox)

Så problemet ligger tydligen i tcpip...
Edit: Det mesta pekar på att det var ett spänningsfall av strömspik när SSE-data skickas via WiFi / Webbserver, då en 470µF kondensator kopplad till 3,3V på ESP32-kortet för att buffra för dessa fick kodkrasher med det felmeddelandet att försvinna!
Därmed är per se inte min kod det direkta problemet, men får testa ändå med att koda om lite för bättre mer renodlad kod samt lägga i Core1 och se om det kan påverka. Har ändrat så SSE bara exekveras 1ggr/3s (från 1ggr/s) och det verkar lite stabilare!
Samt även läsa på mer i ESPAsyncWebServer-esphome Readme user manual för att se om det är saker i min kod som kan förbättras för ESP32-webbservern. Kanske typ finns någon buffert man kan dimensionera upp?
2022-12-22
Testat en del olika samt läst på nu och blivit något klokare.
Provade att lägga in en vTaskDelay() på 2ms mellan varje av de 11st events.send(), men det gjorde ingen skillnad.
Provade att ändra frekvensen för SSE från 1ggr/s till 1ggr/3s och det blev märkbart stabilare men kraschade ändå någon gång per timme.
Provade att bara låta sända 4st events.send() data mot 11st hittills och då fick jag ingen krasch under flera timmar.
Provade då att öka till 6st events.send() data och då fick jag en krasch under drygt två timmar, när jag hade webbsidan aktiv i två olika webbläsare samtidigt som SSE-data skickades till.
Har något luddigt minnesfragment av att jag läst att vid behov av många datavärden bör man välja att skicka dessa i en JSON fil istället, så ska nog prova det som alternativ.
Även mätt tiden det tog att skicka de 11st events.send() data och blev 12-20ms, så tänkte att med id = millis() fanns risken att två kunde få samma id och det kanske krashade då. Så även provat med id=micros() för att utesluta det, men blev ingen skillnad.
Men jag kan med 6st events.send() data gå vidare nu och koda för energi/ström-sensorn INA226 och installera den mot blybatteriet för lite riktiga mätvärden. Är så nyfiken på att få den sensor i drift och känna pulsen på den!
Och därefter koda om för data via JSON-fil.
Funderar även på ESP32 Webbserver byggt på WebSocket för att kunna få en tvåvägskommunikation så jag kan justera inställningsvärden från webbsidan och aktivera funktioner i ESP32, via Remote Control.
2022-12-22
Kört i flera timmar med bara 6st events.send() data skickade samt ett webbläsarfönster anslutet till ESP32 utan någon krasch!
2022-12-23
Provade att flytta de 11st events.send() data från den Deferred-Interrupt-Task med höga FreeRTOS Priority=7 där jag lagt dem tillfälligt till en nykodad Task_WebServerESP32 med låga FreeRTOS Priority=2 i Core0 som tänkt, och då med den lägre prioriteten fungerade det mycket stabilare.
Så sannolikt krockar en så hög FreeRTOS prioritet för webb-/WiFi-kommunikation med Espressif-IDF bibliotekskods prioritet i core0! Men måste ändå vara en bug/svaghet där, då den kraschar så hårt att ESP32 fastnar i en ändlös reboot och kräver manuell fysisk reset.

Canvas dashboard sneak-peek
ESP32 Async webbserver (SSE) webbsida
Canvas dashboard sneak-peek

Kunde köra två webbläsarfönster anslutna till ESP32-webbservern som uppdaterades med 11st events.send() data under ett par timmar utan krasch. Och med två datorer + en mobil med total 4st webbläsarfönster mot ESP32-webbservern klarade den drygt 15min innan krasch, vilket inte gick alls tidigare. Syns även på RAM-minnes hanteringen som ser mer stabil ut nu!
Så är på rätt spår. Har även checkat att det inte är något minnesläckage!
Sedan flyttade jag allt eget med wifi / webbserver till core1 så blev det ytterligare stabilare samt några andra småmodifieringar.
Så tydligt krockade den hög task-prioriteten med de task Espressif lagt för wifi i core0 så webbservern blockerade det. Har även prova att lägga in en 100ms vTaskDelay() efter hälften av events.send() som delegerar processorkraften i FreeRTOS till andra uppgifter de 100ms.
Har även tittat över alla ESP32 FreeRTOS Task stack size för mina kodade Tasks och optimerat dem.
Nu även kopplat den SSE-skickade datan till den canvas-grafik dashboard jag har på ESP32-webbsidan så mätvärden och mätare uppdateras där, vilket känns riktigt häftigt och coolt! Visar en sneak-peek av dashboard-grafiken och kommer visa hela när jag har den i full drift.
De två olika felmeddelande jag får vid krasch nu är:
assert failed: tcpip_api_call IDF/components/lwip/lwip/src/api/tcpip.c:497 (Invalid mbox)
Guru Meditation Error: Core 0 panic´ed (LoadProhibited). Exception was unhandled.
Där "LoadProhibited" = The error LoadProhibited means that the CPU tried to load a variable form an illegal address.
2022-12-28
Ändrade alla globala variabler till static typedef så de bara blir globala inom min fil, vilket är det normala inom C/C++ för att slippa namnkrock med variabler i inlänkade bibliotek. Verkar som det löste mina misstankar om en klassisk C/C++ bug typ pekarefel eller dylikt som jag hade isolerat till att finnas i en av mina Task. Har i vart fall inte fått något mer sådant felmeddelande.
Men får ändå enstaka glesa kraschar så inte helt stabilt ännu, även om jag oftast kan exekvera fler timmar i sträck.
Ska kolla upp att jag verkligen använder Mutex för exklusiv åtkomst till data / resurser på alla ställen i koden det behövs för att undvika krockar mellan min olika asynkront exekverande FreeRTOS-Tasks! Och om jag inte hittar något där så ta bort alla String-class variabler jag använt (Php-kodvana) och ersätta med klassisk C/C++ char[]-array istället, vilket är mycket effektivare samt antytts någon stans att String kan vålla dessa krascher ihop med webbserver-biblioteket ESPAsyncWebServer-esphome jag använder. Så hoppas få det helt stabilt så!
Lite intressant läsning kring C++ kodning:
Static local variables, Learn C++
Sharing global constants across multiple files (using inline variables)
Why (non-const) global variables are evil
2022-12-29
Fick "Guru Meditation Error: Core 1 panic´ed (LoadProhibited). Exception was unhandled." igen när jag aktiverade en av tryckknapparna, och misstänker det har något att göra med missad Mutex kring min DisplayHandler(), Task_DisplayViewHandler() samt Task_LCDButtonsHandler(), eller Mutex kring Serial.print() då det händer när jag aktiverar menyn för att Serial.printa info om FreeRTOS Task stack size!
Nya versioner av espressif/arduino-esp32 (ESP32 Arduino 2.0.6 based on ESP-IDF 4.4.3) och av platformio/platform-espressif32, 5.3.0 med bl.a. "Fixed issue where esp32 won´t reconnect to WiFi AP if the AP was restarted." som jag tackar för just nu när jag håller på med WiFi och async webbserver!
Har även upptäckt att med PlatformIO längre tid passiv i bakgrunden med öppen Serie-Monitor ansluten till ESP32 så kraschar ESP32-webbservern ibland, men stänger jag Serie-Monitor så undviks det! Verkar som Serie-Monitor blir inaktiv då.

ESP32 Async webbserver (SSE) + LCD
ESP32 Async webbserver (SSE), mobil.
Fullskärmsläge på mobilen liknar en App.
LCD-display på ESP32 med driftsdata.

2022-12-31
Har nu fin långtidsstabilitet med ESP32-webbservern med en uppkopplad webbläsare / webbsida samt med att jag sänkt uppdateringsfrekvensen till 1ggr/2s. Den sänkta uppdateringsfrekvensen beror troligen på att mitt Olimex LCD-shield arbetar så enormt långsamt då det saknar en buffert för inkommande texter så min kod får vänta på den riktigt långsamma skrivning av varje tecken till själva displayen med drygt 640ms för att skriva alla de 2x16 tecknen (20ms/tecken) vid I2C busshastighet 80kHz som är max den klarar.
Vid data till flera webbläsarfönster får jag fortfarande krascher med felmeddelandet: "assert failed: tcpip_api_call IDF/components/lwip/lwip/src/api/tcpip.c:497 (Invalid mbox)". Nämns dock något om ESP32 reset WiFi stack samt How can I increase wifi task stack size?, ESP32: Increase wifi task stack size to support advanced logging, 4WAY_HANDSHAKE_TIMEOUT.
Espressif: Optimization of Internal RAM, Fatal Errors, Guru Meditation Errors
Verkar vara någon buffert / stack size som inte räcker till, men inte lyckats hitta någon bra info om det trots mycket sökande på Internet!


2023-01-18
Har nu hittat både CONFIG_ASYNC_TCP_STACK stack-size och CONFIG_ASYNC_TCP_QUEUE_SIZE event-queue-size för AsyncTCP.cpp i AsyncTCP-esphome-biblioteket:
me-no-dev / AsyncTCP
Sending big blocks of data triggers async_tcp task watchdog, i AsyncTCP.cpp:
event-queue-size:
static inline bool _init_async_event_queue(){
  if(!_async_queue){
    _async_queue = xQueueCreate(512, sizeof(lwip_event_packet_t *)); // 32 default
    if(!_async_queue){
    return false;
    }
  }
  return true;
}
Att öka event-queue-size från default 32 till 512 gjorde att jag kunde öka gränsen för antal events.avgPacketsWaiting() jag tillåter samt köra det helt stabilt även när jag hetsar med 5ggr snabbare sändningsfrekvens via SSE till webbsidorna, även när jag uppdaterar mot två samtidiga webbsidor! Kan med interrupt via tryckknapp uppdatera ca 5ggr/s och fungerar ändå stabil!
Kanske inte skulle behöva kö-övervakningen alls nu, men när jag nu kodat den funktionen känns den bra att ha där. Nu med ökad gräns behöver den i stort aldrig ingripa.
Beskrivs även här: AsyncWebServer giving wdt reset.
Där tipsas även om EspExceptionDecoder för felsökning.
Är ju synd bara att de inte kodat en funktion i AsyncTCP.cpp så man kan justera både dess stack-size och event-queue-size inifrån sin egen kod!
Och i AsyncTCP.h #define CONFIG_ASYNC_TCP_STACK_SIZE 8192 * 2, som jag även ska prova att öka.
Ökade till 16384 * 2 men det tar mycket RAM-minne, så går tillbaka igen till default. Märkte ingen skillnad vid en snabb test.
Lite mer att läsa:
Using server.serveStatic causes WDT crashes
ESPAsyncWebServer Fork
The combination I currently using Wenserver

Känns inuitivt som att det skulle fixa sig genom att gå över till WebSocket istället för nuvarande SSE med den datamängd jag skickar!
Eller annars använda antingen JSON-data eller Protocol Buffers (Protobuf) (is a free and open-source cross-platform data format used to serialize structured data) för datan.
Går vidare med att koda för och koppla in INA226 energi-/ström-sensorn nu, så får test med WebSocket komma senare. Blir en intressant start på nya året!
2023-01-01
Har haft problem med ESPAsyncWebServer template processing engine då den ersätter template-namn mellan två %-tecken, typ %VOLTAGE% med datan från en C/C++-variable i ESP32-koden. Blir problem dels när man använder % som längdmått i CCS typ width=100%;, samt dels även som enhet i sin html-text! Har ägnat flera dagar åt att hitta en möjlig fix till detta och löste det idag äntligen :-)
Provade att införa #define TEMPLATE_PLACEHOLDER '$' i min kod, men fungerade inte då det inte rår på ESPAsyncWebServer biblioteket.
Hittade tips om att build_flags = -TEMPLATE_PLACEHOLDER='$' i platformio.ini filen skulle fixa det, men inte!
Infogade #define TEMPLATE_PLACEHOLDER '$' i min kod så fick jag upp ett felmeddelande om att symbolen i WebResponseImpl.h var redefinierad och kunde då klicka upp den filen där den ursprungliga #define fanns, så editerade jag den där till #define TEMPLATE_PLACEHOLDER '$'! Och det fungerade!
Där finns även #define TEMPLATE_PARAM_NAME_LENGTH 32, så default kan max 32 tecken användas.
Och även där är en allvarlig bug i denna kodfunktionen, för den tar inledande %-tecken och de följande 32 tecknen och ersätter fast inte hittat avslutande %-tecken. Egentligen är det nog huvudproblemet, och ett grovt kodningsfel tycker jag!
Genom att behålla #define TEMPLATE_PLACEHOLDER '$' i min kod så kommer jag bli uppmärksam på ny uppdatering av ESPAsyncWebServer / WebResponseImpl.h vid kompilering och får då editera där igen. Men oförändrad blir det inga felmeddelande så.
Känns rätt klantigt att använda "%"-tecken för denna funktion, liksom att inte infört ett lätt sätt att själv i sin kod kunna välja lämpligt tecken! Jag provad även att i den egna processor() funktion man gör för utbytet att returnera den var-String man får där ihop med %-tecken, så skulle ju det vid width=100%; ersättas med ursprunglig kod och ingen skada skedd, men då reprocessar den hela den koden från början för varje template-name-processing så hamnade då i en oändlig loop! Också rätt märklig kodfunktion som slösar processorkraft! Borde ju fungerat!
Han som kodat detta bad redan 2018 om ursäkt för den funktionen, men ändå är det nu drygt 4 år senare inte åtgärdat! Ger ett lite dåligt intryck av biblioteket som trots det är det mest använda och mest aktuellt uppdaterade Async Web Server SSE bibliotekt vad jag ser.
Ska senare kolla in WebSockets och då även kanske testa PlatformIO biblioteket WebSocket Server and Client for Arduino ESP32.
2023-01-03
Har nu visat driftsdata (slumptals-fejkade än så länge) från min ESP32 batterimonitor (och blivande PWM-regulator) aktivt uppdaterat via WiFi mot mobilen två timmar i ett streck med stabil funktion från webbservern i ESP32 mikrokontrollern!
Så känns tillräckligt stabilt nu för att gå vidare med att koppla in energi-/ström-sensorn INA226 och fixa programkoden för den samt ansluta till min lilla experiments-solcellsanläggning här hemma.
Server Side Events (SSE) är en elegant smidig teknik, men med detta kodbiblioteket känns den inte riktigt stabil för en "större" datamängd som här, så ska senare testa med WebSockets istället. Men går nu först vidare med att koppla in INA226!
Är så jäkla nyfiken på att testa den smarta INA226: 36V, 16-bit, ultra-precise I2C output current / voltage / power monitor w/alert!

ESP32 Async webbserver (SSE) + LCD
ESP32 Async webbserver (SSE), mobil.
Fullskärmsläge på mobilen liknar en App.
LCD-display på ESP32 med driftsdata.

2023-01-05
Nu verkar jag fått min ESP32-webbserver att arbeta helt stabilt utan kodkrascher, både med 1ggr/s uppdateringfrekvens av SSE-data till webbsidan och av LCD-displayen, genom fem ytterligare åtgärder. Har även provat med 2st webbsidor på datorn och 1st i mobilen nu.

  1. Införde en Mutex för DisplayHandler-funktionen så bara en instans av den kan vara aktiv åt gången via anrop från olika FreeRTOS Tasks. Fast den i sig utnyttjar Mutex för I2C-seriebussen så belastar det RAM-minnet med flera aktiva instanser av DisplayHandler inlästa där helt i onödan, samt tar även processorkraft. Syntes tydligt på heap-minnet!
  2. Införde adaptiva funktioner i koden som minskar uppdateringsfrekvensen av SSE-skickade data till webbsidan samt av uppdateringen av LCD-displayen så fort det blir för mycket kö i de Queue-dataflödena. Gjorde stor märkbar skillnad, samt innebär att jag nu normalt kan uppdatera båda 1ggr/s, som väldigt glest tillfälligt görs långsammare individuellt för de olika enheterna. För SSE-skickade data var detta extra kritiskt när en nedstängd webbserver väcks upp igen!
  3. Ändrade WiFi.useStaticBuffers(true); till true (set the buffers memory allocation to dynamic = false), då dynamisk minnesbuffert verkade fragmentera heap-minnet och efter lång driftstid kraschade exekveringen med felmeddelande att heap-allocation inte gick.
  4. Bytte ut den 10µF kondensator jag kopplat till 3,3V på ESP32-kortet till en 470µF kondensator för att buffra för de korta lite högre strömspikar WiFi-kommunikationen drar, vilket gjorde stor skillnad. Nu försvann helt det väldigt glesa kodkrascherna när jag hade ett webbläsarfönster öppet mot ESP32-webbservern, och de mer frekventa krascherna vid 2-3 uppkopplad webbläsarfönster försvann också, så var helt klart spänningsdippar som störde mikroprocessorn! Det luriga är att jag fick inga Brownout-resets utan ESP_RST_PANIC (Panic Handler), så Brownout´s detekterar tydligen inte så korta spänningsdrop!
  5. I min Task där jag skickar alla SSE-data events.send() till webbsidan införde jag ckeck för events.avgPacketsWaiting() så inte de köar upp för mycket väntande Packets i webbservern utan väntar då med att skicka nya, vilket även skonade RAM/Heap-utnyttjandet signifikant. Med events.count() får man även antal webbsidor som servas för stunden!
    Var ett litet dektivjobb att hitta, då det inte tas med i de enkla exemplen för webbserver-kod till ESP32 jag hittat på Internet!
    Har testat vid svag WiFi-signal och arbetar helt stabilt nu även när det kan ta 10-15s mellan att SSE-data via events.send() når webbläsaren! Tidigare kraschade kod-exekveringen då!
    Köandet ökar inte vid 3st anslutna webbläsarfönster mot 1st, så är inte skickad datamängd som ger kö utan tydligen antal anrop till events.send(). Har läst att vid större mängd data blir det bättre att packa in dem i en JSON-fil och skicka med ett anrop till events.send(), så ska prova det senare. Även sett info om att WebSockets skulle vara bättre / effektivare vid denna typ av dataskickande till webbsida, bl.a. för att den kan även skicka binär data (typ float/int tal) mot SSE som bara tar textsträngar, så även det ska jag prova senare.
    Men då jag fått det stabilt nu installerar jag först effekt/ström-sensor INA226 så jag får igång riktig mätning mot batteriet i mitt lilla experiment off-grid solcellssystem här hemma!
2023-01-07
Har lagt in en WiFi.onEvent() som aktiverar server.begin() så att webbservern helt säkert återstartas direkt när WiFi har återanslutit och fått IP efter varit nedkopplad. Tidigare kunde webbserverns återstartande vara lite segt, som ibland t.o.m. kraschade kodexekveringen.
Gör att även efter automatisk WiFi-Reconnect med WiFi.setAutoReconnect(true) så återstartas webbservern direkt!
WiFi.onEvent() är riktigt snabb så WiFi.onEvent(ARDUINO_EVENT_WIFI_STA_GOT_IP); aktiveras innan wifiMulti.run() exekverat färdigt med sin anslutning till WiFi! Märks även när jag nu testat med att min ESP32-kod fått stänga ned WiFi och sedan återstarta en mängd gånger, att webbservern återansluter väldigt snabbt och SSE-data kan uppdateras direkt i webbläsaren efter WiFi-Reconnect! Samt har varit 100% stabilt!
Så ytterligare en pusselbit i att få en riktigt långtidsstabil ESP32 webbserver kod-funktion.
Info och kodtips från: Reconnect to Wi-Fi Network After Lost Connection (Wi-Fi Events)
ESP32 C/C++ kod:
WiFi.onEvent(WiFiGotIP, WiFiEvent_t::ARDUINO_EVENT_WIFI_STA_GOT_IP);
void WiFiGotIP(WiFiEvent_t event, WiFiEventInfo_t info){
  server.begin();
}

Funktionens parametrar: ESP32 Arduino: Getting WiFi Event information.
2023-01-11
Mätt upp via oscilloskop hur snabbt jag kan växla en GPIO-utgång 1-0-1 på mitt ESP32-kort. Är förberedelse inför att kunna utvärdera en Deferred interrupt processing jag snart ska implementera för INA226. Tog 100ns (10MHz), vilket jag är nöjd med!
Så kan göra sådana utvärderingar då med 100ns upplösning!
När jag sedan mäter med interrupt så måste jag göra det via oscilloskop såhär, då signalen kommer utifrån från INA226.
Gör detta med direkt portmanipulation:
GPIO.out_w1tc = ((uint32_t)1 << 18); // Set PIO 18 to 0
GPIO.out_w1ts = ((uint32_t)1 << 18); // Set PIO 18 to 1
GPIO.out_w1tc = ((uint32_t)1 << 18); // Set PIO 18 to 0

Mätte även upp hur exakt den FreeRTOS-Task jag exekverar 1ggr/1000ms blir i sin frekvens samt den tid själva Task-exekveringen tar varje gång. Styrs då av vTaskDelayUntil( &xLastWakeTime, 1000 / portTICK_PERIOD_MS ) samt exekveringen innefattar bl.a. 2st xQueueSend() som initierar exekvering av två andra Task.
Den önskade 1ggr/1000ms exekveringsfrekvensen mäts till 1ggr/1000,01ms stabilt med Std-Dev 4,78µs över 50 mätningar, så det är ju imponerande bra!
Oscilloskopet mäter upp en exekveringsfrekvens på 999,99mHz!

Samt själva exekveringen tar 0,6 - 0,7ms, så xQueueSend()-data till andra Task är också snabbt, då jag gör lite andra småsaker också under Task-exekveringen. Detta går ju att mäta inne i koden också med microsekund-upplösning. Men man ser tydligare hur tiden varierar på oscilloskopet.
Så en duty-cycle för exekveringen på 0,06% - 0,07% i denna Task!
Inte så hård belastning på processorn precis :-)
Gör detta för att få insikt i hur exekveringen och koden arbetar, för eventuellt senare optimering om det behövs! Ökar även min kunskap om hur det jag gör verkligen fungerar.

ESP32 PIO portmanipulation
ESP32 PIO portmanipulation
ESP32 Task frekvens & exekvering
ESP32 Task frekvens & exekvering
ESP32 Task frekvens & exekvering
ESP32 Task frekvens & exekvering

2023-01-16
Kodat Interrupt och WakeUp från light sleep på samma GPIO:
För INA226 effekt/ström-sensorn så dess Alert-interrupt signal både kan indikera nya mätvärden att läsa av samt samtidigt väcka upp ESP32 via GPIO från light sleep när i energisparläge. Görs med attachInterrupt(19, ISR, ONLOW_WE);, där WE=WakeUp Enabled. Var svårt att hitta info om, men nu fungerar det emulerat via en tryckknapp på bread-board. Så nästa steg är att koppla ihop med INA226!
2023-01-18
Har nu hittat både CONFIG_ASYNC_TCP_STACK stack-size och CONFIG_ASYNC_TCP_QUEUE_SIZE event-queue-size för AsyncTCP.cpp i AsyncTCP-esphome-biblioteket:
me-no-dev / AsyncTCP
Sending big blocks of data triggers async_tcp task watchdog, i AsyncTCP.cpp:
event-queue-size:
static inline bool _init_async_event_queue(){
  if(!_async_queue){
    _async_queue = xQueueCreate(512, sizeof(lwip_event_packet_t *)); // 32 default
    if(!_async_queue){
    return false;
    }
  }
  return true;
}
Att öka event-queue-size från default 32 till 512 gjorde att jag kunde öka gränsen för antal events.avgPacketsWaiting() jag tillåter samt köra det helt stabilt även när jag hetsar med 5ggr snabbare sändningsfrekvens via SSE till webbsidorna, även när jag uppdaterar mot två samtidiga webbsidor! Kan med interrupt via tryckknapp uppdatera ca 5ggr/s och fungerar ändå stabil!
Kanske inte skulle behöva kö-övervakningen alls nu, men när jag nu kodat den funktionen känns den bra att ha där. Nu med ökad gräns behöver den i stort aldrig ingripa.
Beskrivs även här: AsyncWebServer giving wdt reset.
Där tipsas även om EspExceptionDecoder för felsökning.
Är ju synd bara att de inte kodat en funktion i AsyncTCP.cpp så man kan justera både dess stack-size och event-queue-size inifrån sin egen kod!
Och i AsyncTCP.h #define CONFIG_ASYNC_TCP_STACK_SIZE 8192 * 2, som jag även ska prova att öka.
Ökade till 16384 * 2 men det tar mycket RAM-minne, så går tillbaka igen till default. Märkte ingen skillnad vid en snabb test.
Lite mer att läsa:
Using server.serveStatic causes WDT crashes
ESPAsyncWebServer Fork
The combination I currently using Wenserver
2023-01-20

Nedladdningsprestanda webbsida
Document, html, överfört 41,23 kB, storlek 41,12kB, 266ms

Har nu kodat ett menysystem färdigt till 5st webbsidor i ESP32, så nu är där en hel webbplats. Huvud­webbsidan är nu 41,23 kB i överförd storlek som tar ca 150-300ms att ladda ned för webbläsaren. Jag tycker det är imponerande hanterat av ESP32 prestandamässigt!
Är gjort som en modern s.k. "responsive hamburger menu" med en inline <svg></svg> hamburger-icon kod från CSS-Tricks.
Har delat upp webbkoden i separata CSS, JavaScript & Html char-variabler kodblock som är gemensamma för alla webbsidorna, som kopieras in via processor-funktionen i ESPAsyncWebServer-esphome. Sparar på så sätt flash-minne samt slipper redundant kod så blir enklare att uppdatera koden för webbsidorna.
Är fortfarande gott om plats i ESP32 där kompilatorn rapporterar:
RAM: [= ] 14.4% (used 47196 bytes from 327680 bytes)
Flash: [=== ] 28.9% (used 908177 bytes from 3145728 bytes)
Samt i aktiv drift mäter jag i ESP32:
FreeSketchSpace(%): 75
FreeHeap(%): 57 (52% när SSE skickas till webbsida)
SdkVersion: v4.4.3
ChipModel: ESP32-D0WDQ6
ChipRevision: 1
Har även lagt in <svg></svg> för en icon för aktivering av full-screen mode uppe till höger.
Koden hämtad från Arrows fullscreen Icon Svg Code. Finns även Arrows Maximize Icon SVG.
Här är alla FontAwesomeIcons SVG Icons | SVG Code Generator.

Har även lagt till en SVG-FavIcon: Use inline SVG as favicon där <svg></svg>-koden URL-encodes via URL-encoder for SVG.
Nu som första start använder jag Speedometer2 SVG Icon Code men tänker senare skapa en egen SVG-FavIcon.
Html-kodas såhär i <head>-sektionen:
<link rel="icon" href="data:image/svg+xml,[YOUR URL-ENCODED SVG HERE]" type="image/svg+xml" />

Meny ESP32 Async webbserver (SSE)
Meny ESP32 Async webbserver (SSE), mobil.

2023-01-21
Har kopplat in INA226 till ESP32 med INA226_WE biblioteket och dess Conversion-Ready-Alarm Interrupt signal triggar min ISR och dess deferred interrupt processing Task med en väldigt hög repetitiv precision på 1129695±2µs! Mätt via 64-bit esp_timer_get_time()!
En otrolig tidsnoggrannhet upplever jag, men kommer ändå summera Ah med den mätta tiden!
Har då satt INA226 till 1.1ms conversion time och 512 samples för medelvärdesbildning och det är spänning + ström som läses av så 1,1ms * 512 * 2 = 1126ms mellan att INA226 ska ha färdiga nya mätvärden att läsa av, plus ca 4ms overhead på det tydligen.
INA226 mäter därmed ström och spänning 512ggr/1,129695s dvs 453ggr/s, 1ggr/2,2ms!
Ihop med 19ms RC-filter fångas även de allra snabbaste och korta pulser upp i mätningarna!
Så INA226 styr på så sätt nu "pulsen" för min kods exekvering.

Har ingen ström ansluten till INA226 ännu så den mäter nu 3,286V, 0,000A & 0,000W, då spänningsmätningen är kopplad till 3,3V matningsspänningen. Mätdatan 3,286V ligger exakt stabilt på den spänningen och strömmen är 0,000A hela tiden, riktigt imponerande!
Mätt med min digitala multimeter får jag 3,285V.
Ser ut att bli riktigt bra förutsättningar för en hög noggrannhet i batterimonitorn med detta!
Så stämmer med hur jag noga valt komponenter.

Att medelvärdesbilda så här över 1,1s ger väldigt stabila värden att visa och att reglera på!
Blir spännande att se hur stabila mätvärden jag får inkopplat mot blybatteriet senare.
Är möjligt sedan när jag ska reglera laddningen att jag behöver läsa av strömmen lite oftare, men får prova då. Med 588µs conversion time och 256 samples får jag 0,588ms * 256 * 2 = 301ms intervall, som nog kan vara bra att sikta mot om jag behöver snabbare respons för strömmen.
Men samtidigt är den medelvärdesbildade strömmätningen så extremt stabil brusfri att man kan göra en snabbare och mer exakt reglering på den, så tror ändå det räcker med 1ggr/1,1s avläsning. Vid en linjärt förändrad ström över tid så skulle man kunna ta 2ggr förändringen sedan senaste medelvärdesbildade mätvärde, då det skulle motsvara nuvarande momentant värde, så kan experimentera med att ta 1,5-2ggr strömförändringen så i PWM-regleringen. Sedan är en ren PWM-reglering smidig då en ändring i duty-cycle / pulskvot direkt motsvarar en strömändring, så går att matematiskt räkna fram väldigt nog hur mycket pulskvoten behöver ändras för att justera en viss avvikelse i strömregleringen! Och strömreglering i sig mot blybatterier har mycket snabbare respons än spänningsreglering, så det blir en bra bas för regleringen.
Kan se att min nuvarande rent spänningsreglerande PWM-regulator agerar rätt långsamt pga det för stabil reglering mot blybatterierna, då de är rätt spänningströga!
Ska även ha en ström+ reglering för extra snabb noggrann laddreglering, min specialare.

Fri SRAM ligger fortfarande kvar på 52% under aktiv exekvering med SSE-data till webbsida, så en försumbar inverkan på ESP32 prestandan liksom en minimal försumbar tid att hämta mätvärden över I2C. Totala aktiva exekveringstiden för mina FreeRTOS Task´s är kvar på ca 1%.

Och jag lyckas få ihop detta med använt I2C Olimex Shield-LCD 16x2 som har svårt att samsas med annan enhet på samma I2C. Har gjort lite smart kodande där som adaptivt håller koll på detta och skyddar och optimerar Olimex Shield-LCD´s I2C-kommunikation.
Och det går inte ut över INA226´s I2C-kommunikation, så känner mig väldigt nöjd så!
2023-01-22
Testad att sätta ESP32 i light-sleep strömsparläge mellan varje INA226-avläsning, som väcks upp av interrupt från INA226 för ny avläsning av mätdata och sedan light-sleep igen. Nu med 1,1s cykeltid får jag då 10% aktiv drift (för uppdatering av LCD med nya datan) och 90% light-sleep energisparläge. I light-sleep drar ESP32 ca 15mA från 5V USB, samt ca 52mA i aktiv drift utan WiFi och med WiFi i snitt runt 75mA grovt. Fungerade jättebra!
I sådan drift blir strömförbrukning ca 19mA i snitt, vilket känns rätt OK. Vid drift från 12V via DC-DC-konverter bör det bli lägre, beroende på effektiviteten hos DC-DC-konvertern.
2023-01-23
Gjort nu att i strömsparläge med light-sleep så väntar koden adaptivt in en uppdatering av LCD, vilket då tar 2-5% av cykeltiden. Så medelströmförbrukningen då blir vid 5% 0,05x52mA + 0,95x15mA = 17mA från 5V USB. Samt lagt in att när någon av de fyra tryckknapparna är nedtryckt går den ur strömsparläge. Fungerar bra.
It is common to use the idle hook function to place the microcontroller CPU into a power saving mode. The Idle Task Hook - får titta in på detta för light-sleep strömsparfunktion!

INA226 breakout-boardet har en 100mOhm strömshunt, så ställt in INA226 för 100mOhm och 1A mätområde nu under inledande testande. Då mäter den med 0,00125V / 0,00003A upplösning (1 LSB step size). Med ström via 1k+3,3V matningsspänning mäter den då stabilt 3,28625V, 0,00366A samt 0,012W, utan att siffrorna ändras sig alls, dvs utan något som helst brus! Någon gång glest ibland växlar den till 3,28750V dvs 1 LSB upp. Mätvärdena är då medelvärdena av 512st avläsningar av strömshunten, spänningen samt effekten under 1,1s. Medelvärdesbildningen i INA226 så ger väldigt stabila mätvärden samtidigt som avläsning 512ggr/1,1s internt i INA226 fångar upp snabba förändringar i batteribankens ström / spänning för noggrann Ah/Wh-mätning!
Håller jag med två fuktiga fingrar över 1k-motståndet ökar strömvärdet till 0,00369A med just +0,03mA minsta mätsteget (1 LSB step size).
Så med 100A 0,5mOhm strömshunt blir mätupplösningen 3mA i mitt off-grid solcellssystem!
Senare ska jag ta bort strömshunten på INA226 breakout-boardet och koppla mot extern strömshunt 60A / 60mV som jag har i mitt lilla experiment off-grid solcellssystem här hemma.

Mätt med digitalt minnes-oscilloskop för: Interrupt → ISR → ISR Deferred Handling Task

ESP32 deferred interrupt processing
ESP32 deferred interrupt processing
With: I2C Wire.setClock(80000); (Hz)
The I2C LCD-display sets this limit in speed
Only latency that vary is the Mutex lock I2C
due to interference with I2C LCD-display communication
ESP32 deferred interrupt processing
ESP32 deferred interrupt processing
Interrupt frequency (INA226): 1/1129695±2µs (1/1,1s)

Finns lite att läsa på hos espressif kring snabbheten för Interrupt och kod:
High-Level Interrupts
Interrupt allocation
Maximizing Execution Speed

ESP32 Interrupt - ISR latency
ESP32 Interrupt → ISR latency är ca 1,82µs
Rätt långsamt för en 240MHz 32-bit processor
Men väldigt stabil tidsmässigt

Med portYIELD_FROM_ISR() / taskYIELD_FROM_ISR() context switch (ger samma funktion) i ISR fås en bra realtidsfunktion med extremt liten variation i de ca 25µs Deferred ISR Interrupt Latency, ESP32 Interrupt ISR → Deferred Task interrupt processing latency! En extrem skillnad mot utan Yield() då latencyn varierar slumpmässigt ≤1ms!
Mätt med digitalt minnes-oscilloskop för: Interrupt → ISR → ISR Deferred Handling Task.
void IRAM_ATTR ISR_INA226Batt(void)
{
 auto InterruptTime = esp_timer_get_time();
 BaseType_t xHigherPriorityTaskWoken = pdFALSE;
 xQueueSendToBackFromISR(DeferredInterruptQueue, &InterruptTime, &xHigherPriorityTaskWoken);
 if( xHigherPriorityTaskWoken )
 {
  portYIELD_FROM_ISR(); // same as taskYIELD_FROM_ISR()
 }
}
Beskrivning av ISR context switch samt FreeRTOS: Why to call taskYIELD_FROM_ISR() method within the isrHandler. "Calling either xQueueSendFromISR() or xQueueReceiveFromISR() within an interrupt service routine can potentially cause a task to leave the Blocked state which then necessitates a context switch if the unblocked task has a higher priority than the interrupted task.
A context switch is performed transparently (within the API functions) when either xQueueSend() or xQueueReceive() cause a task of higher priority than the calling task to exit the Blocked state. This behavior is desirable from a task, but not from an interrupt service routine. Therefore, xQueueSendFromISR() and xQueueReceiveFromISR(), rather than performing the context switch themselves, instead return a value indicative of whether a context switch is required. If a context switch is required, the application writer can use taskYIELD_FROM_ISR() to perform the context switch at the most appropriate time, normally at the end of the interrupt handler.
"
Utan Yield() varierar ESP32 Interrupt ISR → Deferred Task interrupt processing latency mellan 52µs till 900µs.
Beror troligen på att FreeRTOS portTICK_PERIOD_MS är 1ms i ESP32, dvs FreeRTOS tick rate = 1000Hz som är så ofta FreeRTOS kan växla mellan Task under sin Preemptive Multitasking. Min ISR Deferred Interrupt Task har här priority 7 (medelhög).
ESP32 FreeRTOS max Task priority är: 24. Low priority numbers denote low priority tasks. The idle task has priority zero (tskIDLE_PRIORITY).
Max latency utan Yield() för ISR → deferred interrupt processing kan därmed sannolikt bli ≤1000µs = portTICK_PERIOD_MS för en deferred Task med högre prioritet än övriga Tasks.

ESP32 ISR - deferred interrupt processing  latency, Min
ESP32 Interrupt ISR → Deferred Task interrupt processing latency, Minimum ca 25µs

ESP32 deferred interrupts processing
ESP32 deferred interrupt processing - time to sent data to INA226

ESP32 deferred interrupts processing
ESP32 deferred interrupt processing - time reading 4x data from INA226

2023-01-28
Har idag kodat in en finite-state machine i form av en C++ class i mitt ESP32 batterimonitor / PWM-regulator hobbyprojekt. Blev riktigt bra och trevlig!

Styr och håller koll på vilka driftslägen den arbetar i samt sköter om växlingen mellan olika driftslägen på ett strukturerat robust sätt, så jag smidigt kan sköta det från en central kod-funktion.
Blir nu mycket tydligare i programkoden vad som görs samt väldigt mycket enklare att implementera en avancerad robust funktion kring detta! Som att stänga ned i light-sleep kräver att det görs i ett antal steg för bra stabil funktion i mitt projekt, och då tar finite-state machinen hand om den processen bl.a. att stänga ned WiFi först.
Och behöver jag framöver optimera en sådan process eller föra in nya driftslägen så blir det väldigt smidig med en gemensam central kod / class som tar hand om det.

Nu har jag för WiFi / Webbserverns drift samt för CPU-diftsläge / strömsparläge med olika CPU-klockning samt light-sleep. Kommer senare även att ha för PWM-regulatorn och dess olika laddfaser för blybatterierna.
Kan då även från olika delar i koden fråga finite-state machinen om aktuellt driftsläge för de olika funktionerna.

Är väl något man gjort intuitivt förut också, men inte såhär formaliserat och tydligt, vilket blev mycket bättre och kraftfullare :-)
Så känns som detta projektet tog ett tydligt steg framåt idag!
Även lagt in ny LCD-meny för dels att nolla datan för ESP32 Hard- / WDT-resets, dels för Ah/Wh.
Samt lött in en 470µF/16V/105°C och en 2.2µF/50V R82 kondensator mot den pyttelilla som finns invid ESP32-shipets 3,3V matning, för att hantera när ESP32 sänder data via WiFi.
2023-01-29
Nu summerar ESP32 Ah/Wh både vid CPU 240MHz och i Light-Sleep energisparläge. Lagt in en Serial.print() som visar miljarddelar av en Ah/Wh för att lätt kunna följa summeringen över tid där med den lilla 0,00366A ström (1kΩ) 3,28500V jag mäter just nu.
Får utskrivet vid Light-Sleep / 240MHz typ:
Serial.print(): INA226 Interrupt Time: 45232715734µs, TimeDiff (µs): 2261571 / 1129689, 0.046016466Ah, 0.153235674Wh, 99.959991% vid ström 0,00366A och spänning 3,28500V.
Ger 0.046016466Ah / 0,00366A = 12,57h samma som 45232,715734s / 3600 = 12,57h så OK!
Har då infört en C++ BatteriMonitor class som tar hand om denna loggning.
Har även optimerat funktionen vid drift med Light-Sleep så INA226 växlar till AVERAGE_1024 från AVERAGE_512 annars som ihop med 1,1ms conversion-time ger 2,2s resp. 1,1s cykeltid, samt gjort lite annan kod tydligare. Med 2,2s cykeltid blir Light-Sleep driften extra strömsnål.
Processorn väcks upp ur Light-Sleep via INA260-interrupt och efter avlästa mätvärden, uträknade Ah/Wh och uppdaterad LCD sätts i Light-Sleep igen. Så är då i Light-Sleep >95% av tiden när i energisparläge typ nattdrift, där den då drar 15mA från 5V USB.
2023-01-30
Mätte med ESP32+INA226 i frysen (-18°C) och då blev 0,00000A i rumstemperatur -0,00012A nedkyld vid 1A mätområde, så en hyfsat liten inverkan. Mätningen strulade lite så vet inte hur säkert resultatet blev. Motsvarar då -12mA vid 100A mätområde, ca 2Ah/vecka i felvisning så ifall. Men jag har tänkt att automatiskt regelbundet nollström-kalibrera mot aktiv float-laddström vid 100% SOC fulladdat så även batteribankens självurladdning kommer med, så då blir påverkan försumbar.
Är tänkt att göra en förenklad ML (Machine Learning) hur det varierar med batteritemperaturen, en sorts kalibreringstabell-funktion vs batteritemperatur, för extra precision i Ah-räknandet. Senare kanske via TinyML / Tensorflow om det verkar kunna ge någon fördel.
Även tänkt utvärdera batteriverkningsgrad på liknande sätt, vs temperatur, urladdningsdjup, tid sedan senaste fulladdat, etc.
2023-01-31
Köpt DollaTek 10st MP1584EN ultra liten DC-DC 3A ström step-down omvandlare efter tips om att DC-DC-omvandlare baserade på MP1584 har låg tomgångsström (quiescent current). Testat nu och utan utgående ström drar de låga 0,24mA matad med 12,5V, och ut 7,03V belastade med 22Ω / 0,304A drar den 0,182A. Blir 7,03 x 0,304 / (12,5 x 0,182) = 0,94 dvs 94% verkningsgrad vid så låg belastning! Känns lovande för låg strömförbrukning för ESP32 i drift matad via denna! Bör kunna bli ca 10mA i strömsparläge typ nattdrift med bara loggning av strömförbrukning från/till batterierna aktiv med >95% i light-sleep som drar 15mA från 5V USB. Målet har varit <15mA för strömsnål vinterdrift. Får se hur den och ESP32 trivs ihop.
Driftstemperatur: -45°C till 85°C, Storlek: 22mm gånger 17mm.
Finns även hos svenska Invize: Spänningsomvandlare step-down 3A MP1584
2023-02-01
Ändrat så vid night-mode strömsparläge med light-sleep sänks CPU-frekvensen från 240MHz till 80MHz. Med 10, 20 & 40MHz fungerade inte Serial.print() OK, troligen för ESP32 inte hinner skriva databuffertern innan satt i light-sleep. Övriga koden fungerade helt OK även vid 10MHz!
Men är OK med 80MHz som då ger omkring 0,05x40mA + 0,95x15mA = 16mA från 5V USB. Bör kunna bli ca 10mA i snitt via DC-DC-konverter från 12V, klart under målet <15mA.
Har mätt nu och drar ca 11mA från 12,5V vid 7,0V ut vid night-mode strömsparläge med light-sleep, så är nöjd med det! Går kanske att trimma ned till 6,5-6V, men får bli senare testande vart den gränsen går.
Kodat så bara de ändrade mätvärdena skickas över via SSE (Server Side Events) till webbsidan, vilket både belastar SSE mindre samt gav lägre strömförbrukning. Då även kodat in en liten punkt som blinkar på webbsidan i takt med uppdateringarna, så man ser att SSE är aktiv även om inga siffervärden ändras. Den punktens events() uppdaterar även canvas-grafiken.
2023-02-03
Kodat in att menyinställningarna för strömshunt (mV/A, typ 60mV/60A) nu även ändrar inställningarna i INA226 via ina226.setResistorRange(Ω,A), så därmed kodmässigt klart för inkoppling mot blybatteriet i mitt lilla experiment off-grid solcellssystem.
Även installerat breadboard och ESP32 på en gemensam bottenplatta med fasta kopplingsplintar för att säkert kunna dra elledningarna till batteriet. Blir inte så bra direkt från breadboard!
2023-02-04
Kört och loggat min lilla testström lite längre idag, här i strömsparläge / light-sleep:
INA226 Interrupt Time: 26808049418, TimeDiff (us): 2262446, -2.735489130Ah, -8.853511810Wh, SOC 97.621315%. Kodfunktionen för Ah / Wh & SOC är på plats!
2023-02-05
Optimerat Task_LCDbuttonsHandler() för snabbare respons på knapptryckning samt mindre inverkan på övrig kodexekvering. Blev även en renare, tydligare och kortare kod kring I2C.
2023-02-16
Är bara INA226 spänningsmätning VBUS som har 830kΩ ingångsresistans, strömmätningens ingångar IIN+/IIN- har en Input bias current på typ 10µA, men uppmätt ca 35µA i drift!
Så går inte att göra en RC-filtrering på samma lätta sätt där som för VBUS!
Med 4,7µF/4,12kΩ (20ms RC) fick jag 341mA mätt med 500mA genom strömshunten! Utan 4,2kΩ mättes 501,7mA genom 60A/60mV shunten (LSB=1,8mA / 2,5µV).
Missat där så blev lite feltänk! Få fundera på hur jag kan göra istället för att inte missa strömmätningen mellan 2,2ms samplings intervallen! Vill få med även korta strömspikar!
Har nu 22Ω och 4,7µF för strömingångarna som skydd, vilket bara ger 0,10ms tidskonstant.
2023-02-20
Kopplat in min ESP32-batterimonitor till mitt lille experiment off-grid solcellssystem här hemma i lägenhet nu i testdrift.
Så jag kan testa i riktigt driftsmiljö och utveckla den vidare mot färdig funktion med verklig driftsdata för mer skarp drift.
Visar sig då ett elektriskt fenomen som gör att de snabba superkorta strömpulserna från min Battery Reconditioner (9kHz, >50A) ger fel strömvärden vid avläsning av spänningsfallet över 60A/60mV strömshunten. Det då även en så grov strömshunt innehar lite induktans så spänningen vid snabba strömpulser visar inte bara den resistiva spänningen över shunten utan en induktiv sådan också som blir som en falsk strömsignal! Så kondensatorn i strömmätningens RC-filter på 22Ω / 4,7µF laddas upp så det vid strömmar på 100-200mA fås 5-10ggr högre mätt ström, samt vid 800mA ca 2ggr högre!
Utan djupare analys trodde jag att de skulle ta ut sig över en cykel med inverkan av den mikroinduktansens strömtröghet, men gör uppenbarligen inte så!
Så ska försöka få lite hjälp med mer djup kunskap kring det från folk som kan elteorier mer på djupet än jag kan och kanske få tips eller tankar som gör att jag kan arbeta vidare med att nå en lösning även på det. Men kändes lite motigt tillfälligt nu.
Funderar lite kring om LC- eller LRC-lågpassfilter skulle kunna lösa det?
Men känns ändå jäkla skoj att kommit såhär lång nu!
Vid kontinuerlig jämn DC-ström mäter den med väldig hög precision!
Lite input kring detta:
- Kalkylator för låg-/högpassfilter
- LC Filter Calculator – How LC filters work
- LC low pass calculator
- Basic Knowledge of LC Filters
- Transient Robustness for Current Shunt Monitor, Tips?
- TI: INA226 - pulse current measurement
- INA226: 1uA measure current resolution for INA226
- INA226: Measurement resolution and ADC error, 1 LSB Shunt Voltage: 2.5µV
- INA226: Current measurement error with PWM motor driver
- INA240 -4 to 80V, bidirectional, ultra-precise current sensor with enhanced PWM rejection
- ESP32 corrupt heap when handling multiple simultaneous requests, Websockets has been updated / fixed, but SSE (which has similarities with websockets) not. As stated I use Server Sent Events so possible an issue still exists in SSE. (2018, ESPAsyncWebServer)
2023-02-23
Mätt upp strömförbrukningen till: 35mA/12,5V WiFi/webbserver + LCD-bakgrundsbelysning + ESP32 240MHz awake, 33mA vid 1/3-del "Soft" LCD-bakgrundsbelysning mode.
Drar 9mA i snitt med Wifi-OFF, släckt LCD-bakgrundsbelysning, ESP32 80MHz samt light-sleep som väcks upp av INA226-interrupt bara för att kort läsa av nya mätvärden och uppdatera LCD-display 1ggr/2,2s, vid 7,0V från DC-DC omvandlaren. Under själva light-sleep drar den 7mA.
Känner mig nöjd med 9mA då det är <<15mA som var målet!
2023-02-26
Mätt upp strömvärden i off-grid solcellsdrift via de tre olika källorn PWM-display / DMM (True RMS spänning över strömshunt) & INA226 (över strömshunt 60A/60mV), när PWM-regulatorn strömpulsar med drygt 8A pulser 30Hz (ca 7% duty-cycle) samt en Battery Reconditioner strömpulsar >50A 9kHz extremt korta strömpulser genom strömshunten in i blybatteriet:
Mätn1: PWM: 0,3A / DMM: 0,55A / INA226: 1,483A
Mätn2: PWM: 0,2A / DMM: 0,48A / INA226: 1,459A
Vid Batteri: 13,87V = PV Throttle, INA226 mätt ca 20W.
Så är något i min mättekniska utformning kring INA226 som måste fixas för att hantera sådan kraftigt strömpulsad mätning OK!
När ingen strömpulsning förekommer mäter alla tre källorna lika strömvärde!
OBS! PWM-regulatorns egen strömmätning från solpanelen visar också stort fel gentemot DMM True RMS mätvärdet, och då inkluderar det även ESP32´s egenförbrukning på 9mA samt Battery Reconditioner´s på ca 20mA!

Canvas dashboard sneak-peek
ESP32 Async webbserver (SSE) webbsida.
PV off-grid Operational status dashboard sneak-peek.

2023-03-02
Fått strömmätningen med kraftiga strömpulser att fungera nu genom att spänningen över 60A/60mV strömshunten filtreras i ett LRCL-filter vid ingångarna till INA226. Nu stämmer strömvärdena från INA226 med DMM True RMS spänningsmätningar (mV med 2 decimaler) över strömshunten. Ska utvärdera och analysera mätningarna mer noga framöver. Jag kan inte ännu riktigt förklara el-teoretiskt varför det fungerar så och därmed inte heller optimera komponentvärdena för det. Men troligen är det inte mer känsligt än för ett RC-filter, då det ser ut att visa rätt med båda de helt olika strömpulserna! Har gått på min analyserande intuition vad som borde kunna fixa detta!
Visar en liten sneak-peek från mitt grafiska dashboard för "PV off-grid Operational status" i verkligt drift nu i mitt lilla experimentella off-grid solcellssystem vid mobil-laddning.

2023-03-07
Presentation av projektstatus i ett par Facebook-grupper:


Nu har jag mitt ESP32-mikrokontroller baserade batterimonitor projekt i drift sedan en dryg vecka här hemma i mitt lilla experiment off-grid solcellssystem i lägenheten :-)
Känns riktigt skoj att kommit så långt, men är lite svårare än jag tänkt och tar rätt mycket tid att utveckla!
Laddar mobilen här 9 månader/år för att få lite verklig drift, övrig tid på vintern räcker inte strömmen till. Så är mobil-säsong nu igen.
Skoj då att kunna följa driften så detaljerat nu :-)

Med 60A/60mV strömshunt här kan den mäta med en upplösning på 1,8mA (LSB). Med 100A/50mV strömshunt i mitt riktiga off-grid solcellssystem blir det med 3,0mA LSB, så bra precision.
Med INA226 "ultra-precise I2C output current / voltage / power monitor" med väldigt hög precision samt hög noggrannhet över lång tid och stort temperaturområde (så jag inte trodde det var tekniskt möjligt med den prestandan) så bör jag få en riktigt fin precision hos batterimonitorns mätningar, även över hyfsat lång tid.

INA226 får göra upprepat i kontinuerlig följ 512st mätningar av spänning / ström / effekt under 1,1s som den då medelvärdesbildar och sätter en interruptsignal till ESP32 att det finns nya mätvärde att hämta från dess buffert. Så ESP32 hämta varje 1,1s nya sådana fint aggregerade data till sina beräkningar. Får på så sätt både väldigt stabila data som ändå tar med snabba förändringar i ström / spänning 512ggr/1,1s!
I ESP32 mäter jag tid med 1µs upplösning, så beräkningen / summering av Ah och Wh sker med väldigt hög precision så också.

Jag har en Battery Reconditioner till batteriet som via strömshunten strömpulsar med väldigt korta skarpa pulser på >50A i 9kHz för att motverka sulfatering samt PWM-regulatorn strömpulsar med >8A 30Hz när den begränsar laddströmmen för att anpassa laddningen till batteriet.
Jag har nu lyckats få till att jag ändå kan mäta så små strömmar som några mA utan att mätningen störs ut av de höga strömpulserna, och samtidigt mäta strömmängden de höga strömpulserna ger. Ska senare utvärdera lite bättre hur bra det blivit, men ser så här långt riktigt bra ut. Min NASA BM1 batterimonitor jag har i mitt off-grid solcellssystem idag störs helt klart av det strömpulsandet och mäter inte riktigt rätt då. Samt den är inte riktigt temperaturstabil eller långtidsstabil heller, men har ändå haft väldigt bra nytta av den under många år.

Har även en webbserver kodad i ESP32 med webbsidor som visar driftsdata, statistik och info på fem olika webbsidor, som jag då via WiFi kan se i webbläsaren på mobilen eller på en dator, som man ser i mobilen på fotot.

Men är rätt mycket jobb kvar ändå till helt färdigt.
Att göra en egen batterimonitor såhär innebär att jag kan visa precis den driftsdata och statistik jag vill se, samt som det ser ut nu kan jag få en väldigt hög precision i mätningarna.
Ska senare även försöka att skicka data via WiFi / Internet till en webbsida jag har på webbhotell, där jag kan samla driftsdata över längre tid, samt som jag då kan se hemifrån eller vart jag än befinner mig.

Men några gånger har jag nästan varit på väg att ge upp då det dykt upp svårigheter som kändes omöjliga att lösa för mig, men jag lyckats med till slut ändå :-)
Samt är mycket nytt att lära för mig, då detta är mitt första ESP32-projekt samt första gången jag använder FreeRTOS i kodandet! Tror dock jag tagit mig igenom de värsta svårigheterna så nu...

Jag gör detta som ett hobbyprojekt till mig själv för bättre funktion i mitt off-grid solcellssystem i husvagnen och är bara självlärd inom elektronik, C++ kodning samt ESP32-mikrokontroller.
Samt gör det även lite för att ha något tekniskt att engagera mig i och få stimulans från som pensionär.
För de som är nyfikna kan man se mer på min webbsida för projektet:
https://www.nordicoffgrid.se/datalogging/batterymonitor.php

ESP32 batterimonitor - utvecklingsplattform
ESP32 batterimonitor - utvecklingsplattform i off-grid solcellssystem skarp drift.

2023-03-08
Texas Instruments benämner sin sensor INA226 jag använder för "ultra-precise I2C output current / voltage / power monitor". Så ihop med den precision jag kan får ut ur ESP32 så får jag kanske då en ultra-precise batterimonitor som kan mäta sig väl mot de som finns på marknaden.

Det jag via min ESP32-batterimonitor nu följt laddningen i mitt 44Ah blykolbatteri här hemma senaste dygnet är riktigt intressant, där -2Ah urladdat (95% SOC) återladdades igår via bulk-, absorptions- och float-laddning i fullt solsken under dagen ger en väldigt detaljerad info om laddförloppet.
PWM-regulatorn skiftade från kontinuerlig float-laddning till bulk- / absorptions-laddning, då batterispänning sjönk till ca 12,3V vid mobilladdning, under <12,4V som är gränsen för det. Är det initiala spänningdroppet "coup de fouet" man får vid riktigt 100% SOC fulladdade blybatterier i bra kondition, så strömpuls-laddningen har verkligen hunnit fräschat upp blybatteriet efter ca 2,5 vintermånader utan att nått 100% SOC full laddnivå!
Riktigt skoj att kunna följa det så noga, vilket även gav mig ett par nya intressanta kunskaper kring blybatteriladdning.

Kunde bl.a. bekräfta ett antagande jag gjort utifrån ett flertal olika källor om nivån på 0,015C / 1,5% tail-current (1,5A/100Ah) som gräns där absorptions-laddningen bör avbrytas för optimal laddning, så man låter blybatterierna själva tala om när de fått lagom med absorptions-laddning.
Så kommer använda det i min egna PWM-solladdregulator.
Strömmen under 3h absorptions-laddning gick ned till <0,44A/44Ah (0,01C / 1%) utan tvekan där, så blir bra marginaler!
Samt vid 13,8V float-laddning stabiliserade sig den pulsade laddströmmen på ca 200mA (för högt). När solen sedan började gå ned så solcellsströmmen sjönk långsamt och stabilt så blev strömmen vid 13,4V ca 35mA, vilket känns mer lagom för standby-laddning.
Är så grovt och primitiv att köra med en fast tidsgräns för absorptions-laddning, och även med en adaptiv tidsfunktion mot batterispänningen precis när laddningen startar på morgonen blir en grov osäker styrning av blybatteriladdningen, om än något bättre.

Senare ska jag koda lite mer analytisk funktion så jag får ut än mer intressant data från den, som även ska kunna styra laddförloppet bättre.
Jag tycker hela den här branschen med 12/24/48V off-grid solcellssystem är lite seg i att utnyttja den moderna tekniken och skapa lite aktivare smartare laddhantering.
När man gick från oreglerad laddning till s.k. smarta batteriladdare för blybatterier var det ett stort steg, men lite synd utvecklingen verkar ha stannat där känner jag!
Man verkar helt ha nöjt sig med vanlig flerstegsladdning med fasta gränser!

På kvällen uppdaterades de grundbibliotek från Espressif man använder för ESP32 kodning inkl. Arduino v2.0.7, och var några buggfixar där som eventuellt åtgärdar några saker jag haft lite problem kring med WiFi / Webbservern.
Har även gjort lite code refactoring så jag nu fått in i stort all driftsstyrning via en Finite-State Machine (FSM) och därmed en bättre tydligare funktion. Innebär att alla de olika driftslägena, "states", nu styrs och växlas mellan av StateMachine-koden, så allt det är samlat på en plats och det blir inte redundant kod. Blir även mycket enklare att underhålla den delen av funktionaliteten samlad centralt på så sätt, samt mindre risk för buggar.
En tydlig förbättring blev att jag införde en Task_StateMachine() för asynkron växling av driftsläge, så t.ex. inte aktivering av WiFi / Webbserver blockerar responsen hos tryckknapparna. Task_StateMachine() kommunicerar med class StateMachine som har en synkron funktion.
Idag 14 Mars när jag aktiverade ESP32-batterymonitorn med en knapptryckning på morgonen kopplade den upp snabbt smidigt mot WiFi, vilket efter en natts drift tidigare ofta varit trögt och ibland misslyckats. Om det håller i sig är det ett signifikant framsteg mot stabil 24/7/365 drift!
Jag hade en svag intuitiv känsla att en asynkron Finite-State Machine (FSM) funktion skulle kunna ha den inverkan, så håller tummarna för det!
Förfinade även ESP32-webbsidornas meny-funktion lite, med att när man tryckt på ett menyval så fälls meny in snyggt mjukt igen tills webbläsaren hinner växla webbsida.
2023-03-15

Canvas dashboard sneak-peek
ESP32 Async webbserver (SSE) webbsida.
PV off-grid Operational status dashboard sneak-peek.

Även idag startade ESP32-batterymonitor upp WiFi snabbt och smidigt vid knapptryckning!
Samt flera gånger under gårdagen och kvällen.
Kan även se att när WiFi / Webbserver stängs ned frigör mycket SRAM nu (52% till 76% ledigt), vilket inte skett tidigare, så indikerar också tydliga förändringar i kodens funktion som känns positiva. Samt lägsta ledigt SRAM nu 129204b under dessa dygn och största allokerbart heap block 110580b stabilt. Är ca 161970b vid 52% ledigt SRAM.
Är stabilaste drift hittills under flera dygn såhär! Känns riktigt lovande!
Aktiv WiFi, webbserver och SSE-data till webbsida drar ca 35mA för sin drift, så rätt måttligt.
2023-03-16
Helt stabil snabb smidig uppkoppling mot WiFi nu tredje morgonen (24/3-drift) i drift också, när aktiverad med knapptryckning! Riktigt upplyftande, känns att jag går i mål med detta nu.
Samma många gånger under hela gårdagen, så ett riktigt bra framsteg för 24/7/365-drift!
Är sannolikt en kombination av WiFi-buggfixar i Platform-espressif32 v6.1.0 / ESP-IDF v5.0.1 / Arduino v2.0.7 samt min dynamiska Task_StateMachine() ihop med min code refactoring!
2023-03-17
Har två gånger fått kod-krascher när jag aktiverat WiFi / Webbserver med felmeddelandet:
"Guru Meditation Error: Core 0 panic´ed (IntegerDivideByZero). Exception was unhandled."
Har lite snabbt sökt men inte hittat orsaken i min kod. Ska göra det noggrannare senare!
Men ESP32 fixar Rebooting snabbt och bra direkt efter det, så inget som direkt påverkar stabil 24/7/365-drift annat än att <15min (<2hr) data förloras!
2023-03-18

24hr running statistics
Latest 24hr running statistics - Current

Har kodat "Senaste 24-timmars löpande stati­stik" för ström­men, med Akuell-, Medel­värd­es-, Max­värd­es- & Min­värd­es-ström över sen­as­te 24 timmarna löpande. Ska bli för de andra mätvärdena också. Får här tränga djupare in i C++, klasser och objektorientering m.m.!
Ger en bra överblick över senaste dygnets drift i off-grid solcellssystemet.
ESP-batterimonitorn fortsätter att arbeta stabilt över dygnet.
2023-03-19

24hr running statistics
Latest 24hr running statistics - Current

Hade haft Nordic­Off­Grid Batteri­mon­itorn i drift i dryga 24h när skärm­dumpen från mobilen togs idag. De senaste 24h har medel­ström­men då varit -5mA i det väldigt gråmulna vädret, samt Max +73mA och Min -82mA. Max ladd­ström mitt lilla ex­peri­ment sol­cells­sy­stem ger är ca 1A i bra soligt väder, så idag ca 7% av det som mest. Är mätt med en 60A/60mV ström­shunt.

Det löpande ström­medel­vär­det för 24h är beräknat på ca 80.000 ström­värd­en hanterade i ESP32 från INA226-sensorn, som i sin tur skapar varje sådant strömvärde som medelvärdet under 1,1s för 512st strömmätningar.
Så totalt baseras det löpande 24h strömmedelvärdet på ca 40.000.000 strömmätningar, vilket ger bra precision! Liknande gäller för Max- och Min-värdena. Max- och Min-värdena bygger på de under 1,1s medelvärdesbildade mätvärdena från 512st mätningar i INA226, så korta irrelevanta strömspikar filtreras bort på så sätt. Blir samma för batterispänning och övriga datamätvärden också.
Med så många mätvärden blir det viktigt med en bra effektiv algoritm för hur man hanterar det i programkoden, och jag har fixat en som både är väldigt snål på minne och CPU-belastning.

Med strömmedelvärdet för senaste 24h kommer jag göra en bra tidsprognos för hur länge kvarvarande batterikapacitet bör räcka, något helt annat än den prognos baserad på momentan-strömmen min NASA BM1 ger idag. Baserat på momentanström fås olika tidsprognos när 12V kylskåpskompressorn arbetar eller pausar i sin drift, helt oanvändbart! Med 24h tas även den lägre strömförbrukningen under natten med i prognosen.
Ger en bra överblick över senaste dygnets drift i off-grid solcellssystemet.
Blir mer som driftsövervakning av off-grid solcellssystemet än bara batterimonitor!
Ger på så sätt en tydligare överblick över driften av min Victron blykolbatteribank, samt kommer bättre kunna planera aktiv drift i lite längre dåligt solcellsväder.
Känns roligt med en batterimonitor med bra precision och bra info via aggregerad data :-)
2023-03-24

Time To Go
Time To Go för 24hr och 1hr medelström.
Time To Go
Time To Go för 24hr och 1hr medelström.
Time To Go
Time To Go för 24hr och 1hr medelström.
Stabila värden trots korta solglimtar!
Time To Go
Time To Go för 24hr och 1hr medelström.

Har idag kodat en "Time To Go" panel för en bra tidprognos över hur länge kvarvarande batterikapacitet bör räcka för driften vid urladdning, eller tid till fulladdat när solcellerna laddar upp batteribanken. Upp↑/ned↓-pilar visar laddning/urladdning.
Visar bara i hela dagar och timmar, då minuter blir för precist i förhållande till den långtidsprecision man får i ett sådant här system anser jag, och kanske än mer till hur noga man rent tekniskt kan synkronisera 100% SOC med verkligt fulladdad batteribank. Blir då inom ±30min som ↑↓1hr visas avrundat.
Tidprognosen visas dels för senaste löpande 24hr strömmedelvärde, dels för senaste 1hr strömmedelvärde. På så sätt får man en stabil bra uppfattning över hur man ligger till med driften av batteribanken och off-grid socellssystemet oavsett lite varierande ström över dygnet eller från kylskåpskompressors drift ON/OFF, från korta solglimtar, etc. "Time To Go" baserat på momentanström är värdelös!
Kanske blir det senare någon form av adaptiv funktion för 1hr visningen, som någon gav förslag på för anpassning till hur aktuell drift är.

24hr Average, Max & Min Current
Present, 24hr Average, Max & Min Current
24hr & 1hr running Average Current
24hr & 1hr running Average Current

Idag är det väder med ständigt korta solglimtar, men får då ändå en stabil fin prognos för hur lång återladdningstid som är kvar, istället för att den hoppar kraftigt fram och tillbaka efter hur den momentana strömmen är i systemet!
Strömmen varierade då 400-500% till 1000% snabbt upp och ned, så blir svårt att bilda sig en uppfattning på det momentana strömvärdet / tidsprognosen, men med 1hr medelvärde får man ändå stabila fina värden både för strömmen och återstående laddtid! Riktigt häftigt!

Ska även bli löpande 7dygns statistik och troligen även 30dygns, för än bättre info, insikt och överblick det ger över off-grid-systemets drift. I ett sunt dimensionerat off-grid solcellssystem med ≥5dygns dåligt-väder-reserv (Days Of Autonomy) utjämnar batteribanken normalt variationer i strömproduktion av verkligt väder över minst 1-2 veckors tid, så 7dygns strömstatistik är värdefullt i sådan drift.
Min vision med detta är även ett system som helt autonomt smart kan styra laster efter hur mycket ström den utvärderar att det finns att utnyttja över tid, typ 4G router, fläkt, belysning, etc.

2023-03-27

Upptid, datum/tid ESP32 / Client
Upptid samt datum/tid ESP32 / Client.

Skapat en TIME-panel för dels ESP32 Uptime, dels för datum/tid för ESP32 RTC samt Client tid, så kan se hur länge ESP32 varit igång sedan senaste bootning samt kan jämföra hur ESP32 RTC-tiden håller sig och är uppdaterad.
Har efter det fått ett par panic-reboot med felmeddelandet: "Guru Meditation Error: Core 0 panic´ed (LoadProhibited). Exception was unhandled.", som jag får felsöka!
The error LoadProhibited means that the CPU tried to load a variable form an illegal address.
Do you use String Class and do a lot off String constructions with String c = "a" + "b", or are you creating char arrays on the fly e.g. char d[ ] = "efg".
Arduino: ESP32 - Guru Meditation Error: Core 1 panic´ed (LoadProhibited): "My guess is that "lastData" returnedData = int(lastData[7]); has not been set and is still a null (0) pointer. You get an error when you try to read address 7."

Har lagt in att alla class StateMachine´s public variabler initieras i dess Constructor StateMachine(), kanske en möjlig orsak? En variabel, ESP_Time_us, som jag missat där används tidigt för just Uptime, kanske innan den hade initierats med något värde!

Optimerat för detta när bara IP förloras, så WiFi nu ska startas om och återansluta IP:
15:32:02.824 > INA226 Interrupt Time: 144809137, TimeDiff(us): 4592239, -0.038083Ah, 0.596590Wh, 99.913%, 0.96/0.52W
15:32:05.962 > [157673][V][WiFiGeneric.cpp:374] _arduino_event_cb(): STA IP Lost
15:32:05.968 > [157674][D][WiFiGeneric.cpp:931] _eventCallback(): Arduino Event: 9 - STA_LOST_IP
15:32:05.973 > WiFi.onEvent(): No WifiConnect, Event: 9
15:32:05.975 >
15:32:07.851 > INA226 Interrupt Time: 150549432, TimeDiff(us): 5740295, -0.038016Ah, 0.598343Wh, 99.914%, 1.10/0.54W
OBS! WiFi.status() != WL_CONNECTED blir nog inte True då, vilket jag nog förutsatt!?
Får fundera mer på det och söka kunskap om! Inträffar så väldigt sällan, så svårt att ha tur och fånga upp meddelandet såhär.Har modifierat nu så det bör återansluta WiFi / IP!
Hanterar nu dessa WiFi.onEvent(): RDUINO_EVENT_WIFI_STA_DISCONNECTED || ARDUINO_EVENT_WIFI_STA_LOST_IP || ARDUINO_EVENT_WIFI_STA_STOP för anrop av WiFiReconnect(), samt har tagit bort villkoret WiFi.status() != WL_CONNECTED för återanslutning.

2023-03-29
Har problem med att sällsynt ibland (typ <1ggr/dag) så blir det kodexekveringsfel, men bara med WiFi / webbserver ingång vad jag kan se. I nattmode med nedsläckt LCD-display och WiFi / webbserver har jag aldrigt noterat det, så minskar ned koden jag behöver leta i. Samtidgt vet jag då inte om det är min kod eller Espressif system-kod för WiFi eller webbserver-biblioteket?
Skulle jag kunna använda IDF Monitor ihop med Espressif Arduino-framework så skulle jag få ut det radnummer det inträffar vid samt i vilken kod-fil! Då hade det genast blivit mycket lättare att hitta och åtgärda (om det är i min kod-fil), så får söka efter om det är möjligt på något sätt!

Felmeddelande jag får i Verbose mode (DCORE_DEBUG_LEVEL=5):
Guru Meditation Error: Core 0 panic´ed (StoreProhibited). Exception was unhandled.
Core 0 register dump:
PC : 0x40094090 PS : 0x00060233 A0 : 0x80094506 A1 : 0x3ffe1c10
A2 : 0x3ffb8014 A3 : 0x3ffb8e1c A4 : 0xabba1234 A5 : 0x00000010 A6 : 0x00000003 A7 : 0x00000003 A8 : 0x00000003 A9 : 0x00000002
A10 : 0x3ffb8e18 A11 : 0x0000003c A12 : 0x00000059 A13 : 0x3ffb8e14
A14 : 0x3ffb8e48 A15 : 0x00000000 SAR : 0x0000001d EXCCAUSE: 0x0000001d
EXCVADDR: 0xabba1240 LBEG : 0x4008be5d LEND : 0x4008be6d LCOUNT : 0xfffffffe

Guru Meditation Error: Core 0 panic´ed (LoadProhibited). Exception was unhandled.
Core 0 register dump:
PC : 0x400ded89 PS : 0x00060030 A0 : 0x800deded A1 : 0x3ffe1d80
A2 : 0x3ffb85d4 A3 : 0xbaad5678 A4 : 0x3ffb85e0 A5 : 0x3ffb93c8
A6 : 0x0a0d0a0d A7 : 0x32343031 A8 : 0x800ded85 A9 : 0x3ffe1d60
A10 : 0x00000000 A11 : 0xbaad5678 A12 : 0x00000000 A13 : 0x3ffb857c
A14 : 0x00000000 A15 : 0x74000a0d SAR : 0x0000000a EXCCAUSE: 0x0000001c
EXCVADDR: 0xbaad567c LBEG : 0x4008a530 LEND : 0x4008a546 LCOUNT : 0xffffffff

Här finns felbeskrivning av LoadProhibited, StoreProhibited:
"These CPU exceptions happen when an application attempts to read from or write to an invalid memory location. The address which has been written/read is found in the EXCVADDR register in the register dump. If this address is zero, it usually means that the application has attempted to dereference a NULL pointer. If this address is close to zero, it usually means that the application has attempted to access a member of a structure, but the pointer to the structure is NULL. If this address is something else (garbage value, not in 0x3fxxxxxx - 0x6xxxxxxx range), it likely means that the pointer used to access the data is either not initialized or has been corrupted."
Så antagligen försöker min C++ programkod läsa/skriva till en variabel som inte längre existerar (ett klassiskt C++ kodfel), som kanske skulle behöva göras static för att behållas i programminnet typ Local variable scope.
Eftersom exekveringsfelet inträffar i Core 0 (där Espressif WiFi systemkod ligger, ihop med en del av mina FreeRTOS Task) skulle jag som felsökning kunna flytta alla mina Task till Core 1 temporärt. Följer då felet med till Core 1 så är det någon av mina Task. Då kan jag flytta en Task i taget tillbaks och när felet följer med tillbaka till Core 0 så vet jag vilken Task som orsakar det. Men hade varit lättare om det inträffade oftare!
Verkar dock som jag lyckats skapa något pekar- eller variable scope-fel i min senare kodning nu! Känns bara lite konstigt att det inträffar så sällan med många timmar emellan!
Nu senast LoadProhibited med EXCVADDR: 0x00000005.
Får även senare framöver titta på Get started with Arduino and ESP32-DevKitC: debugging and unit testing!
Även kanske om problemen fortsätter: Please build project in debug configuration to get more details about an exception, ihop med PlatformIO meny: PROJEKT TASKS - wemos_d1_uno32 - General - Monitor (kan det vara "IDF Monitor"?).
2023-03-30
Man ska inte använda färdiga kopplingssladdar till breadboards för strömförsörjningen till sin ESP32!
Har nu lokaliserat ett problem jag fick efter den senaste större kodförändringen till dålig kontakt och glappkontakt i just en sådan som går mellan min DC-DC-konverter och ESP32! Trodde naturligtvis jag fått till någon dum bugg i min kod, men hittade glappkontakt och sannolikt även dålig kontakt i den kopplingstråden. Sedan är det nog även något typ pekarfel i min C++ kod!
Samt efter de senaste kodförändringarna har ESP32 fått svårt att återansluta till WiFi / Webbserver, så något blev inte bra där!
Backar därför till senaste version jag märkt OK (2023-03-14), och där fungerar det bra igen. Så blir att återinföra förändringar sedan dess en i taget och checka när problemet uppstår. Går lätt via "Compare Selected" i PlatformIO / VSCode där jag får upp de två filer jag jämför sida vid sida med alla skillnader utmärkta, så bara kopiera kod mellan dem steg för steg via den pil-icon-kopieringsfunktionen som finns där. Blev två steg fram ett tillbaka nu, som det blir ibland!

VSCode "Compare Selected"
VSCode "Compare Selected"

2023-03-31
Haft version 2023-03-14 i drift idag i drygt 8h med aktiv WiFi / Webbserver utan något problem. Har då modifierat koden så jag på Serial.print bara får ut debug- och felinformation, så det är lätt att följa vad som händer. Så denna versionen verkar helt OK och stabil!
Är inget minnesläckage heller under den tiden med: Fri SRAM 52% (161660b), Lägst ledig heap: 135324b samt Största allokerbara heap 110580b.
Så noga under så lång tid har jag inte följt upp kodexekveringen förut, även om jag haft igång den i flera dygn tidigare. Men ville nu vara säker på att jag utgår från en stabilt fungerande kod för felsökningen av senare tillagd kod!
Känns skönt, för då ska det lättare gå att hitta buggen / buggarna i den kod jag successivt återinför steg för steg nu igen.
Även om det känns lite märkligt att ett typ pekarfel kan inträffa så glest som 3-4h eller längre tid med programkoden exekverandes 1ggr/1,1s! Men är delvis asynkrona kodloopar med FreeRTOS Task ihop med att lite olika kod exekveras beroende på mätt batteriström, så kanske någon kombination kan uppstå så sällan då? Samt har bara hänt när WiFi / Webbservern är aktiva, så är i någon kod som bara exekveras då så har mina aningar var jag ska se upp lite extra när koden återinförs steg för steg! Detta är lärpengar som ny på objektorienterad C++ kodning!
Får läsa på lite mer om det, som typ: Grundläggande objektorienterad programmering i C++: Klasser och objekt, Creating a class object in C++, References to the class object. Access to a class object by reference., DuckDuckGo: C++ "class" "object" new pointer vs reference, DuckDuckGo: C++ new reference "class" "object", Static Objects in C++, Static Members of a C++ Class.
Ser ut som att jag missuppfattat någon nyans där och bör modifiera min C++ OOP-kod?
W3school testing C++ OOP coding.
2023-04-01
Justerade C++ OOP-koden för alla class-object så den säkert inte allokeras i stack-minnet utan i heap, men blev samma kodkrascher ändå med koden för class RingBuffer24hr:
[746963][D][WiFiGeneric.cpp:931] _eventCGuru Meditation Error: Core 0 panic´ed (IntegerDivideByZero). Exception was unhandled.
Guru Meditation Error: Core 0 panic´ed (LoadStoreAlignment). Exception was unhandled. EXCVADDR: 0x401057be LBEG
Vid aktivering av strömsparläge light-sleep?
[747746][D][WiFiGeneric.cpp:931] _eventGuru Meditation Error: Core 0 panic´ed (IntegerDivideByZero). Exception was unhandled.
Kom efter: Uptime: 00y00m00d 00:12:26, med 12 minuters tid till aktivering av strömsparläge light-sleep!
2023-04-02

Upptid, datum/tid ESP32 / Client
Upptid samt datum/tid ESP32 / Client.

Återinförde all kod utom den som gör statistiska beräkningar inom class RingBuffer24hr och då fungerar det stabilt inklusive Time-displayen med Uptime och datum! Så kodbuggen finns i den koden för statistiska beräkningarna inom class RingBuffer24hr eller dess SSE-skickande till webbsidan. Så får gå igenom koden för varje sådan statistikdata där och införa en och en tills jag hittat kodfelet. En hyfsat rimlig uppgift!
Skönt jag fått stabil drift igen så långt med koden!
Konstaterar samtidigt så tomt det känns med bara rå mätdata med frånvaro av den omgjord till information s.k aggregerad data! Så min vision kring detta är helt rätt och värt arbetet!
Och efter Uptime: 00y00m00d 01:35:34 kom det igen:
Guru Meditation Error: Core 0 panic´ed (LoadProhibited). Exception was unhandled. EXCVADDR: 0x00000005 LBE
Kommer så jäkla sällan, så svårt att veta vilken kodförändring som orsakar det!

2023-04-03
Ska nog bara ha egen kod i Core 1 då man dels annars drabbas av komplexiteten av "ESP32 inter-processor communication" vad det gäller access till globala variabler med konflikt om man inte skapar exklusiv access via Semaphore-Mutex, dels kör Espressif all systemfunktion med WiFi på Core 0 som man riskerar att störa. Är risk det är bl.a. detta jag har haft problem med!
Provar nu att köra alla mina Task på Core 1.
Har tänkt att float- och int-variabler accessas inom en klockcykel så ingen risk för kollision där, men kan ju bli det när en global sådan variabel accessas samtidigt från de två olika CPU-kärnorna! Så ett lite feltänk pga oerfaren inom Multitasking- / Mulitecore-kodande!
Samt får nog även kolla att jag ger exklusiv access till globala double-variabler (s.k. none-atomic variables) då de tar två klockcykler att accessa, samt troligen samma till alla class-object instanser (eller bara dess funktioner()?) i min Multitasking-koddrift!
2023-04-04

Time To Go för 24hr och 1hr medelström.
Time To Go för 24hr och 1hr medelström.
Uptime 2023-04-07.
Uptime 2023-04-07.

Nu har jag återställt all kod samt, fixat några små buggar, optimerat lite kod samt gjort lite Code refactoring, ihop med att all min kod nu körs på Core 1. Och nu ser det ut att arbeta stabilt och bra utan kodkrasch, i vart fall i ett par 3-4 timmar pass.
Har även omprövat min tidigare åsikt och redovisar nu "Time To Go" antingen som ddhh eller hhmm, dvs gått ifrån att visa timme som minsta mått utan tar även minuter så man får lite mer upplösning på det. Man får se det som tid kvar till att batterimonitorn når 100% SOC, vilket kan skilja något från batteribankens verklighet.
Kommer framöver för 24hr Time-To-Go statistiskt analysera hela dess datamängd och få en lite bättre prognos som aldrig bör komma fram till en fulladdad tid mitt i natten! Blir även senare liknande för löpande 7 dygns statistik!

2023-04-07
Har fått in lite mer 24hr data, samt framförallt kunnat kör 1dygns och 17h stabil drift nu. Här ser man tydligt nyttan av 24hr Time-To-Go prognos över 1hr Time-To-Go prognos tidig morgon med bara en ytterst svag laddström ännu. Samt jag tycker det är smidigt med "24hr ΔCHARGE" som visar hur laddningen i batteribanken har förändrats under senast 24 timmarna, så man själv inte behöver memorera något sådant eller läsa av ur diagram. Ger en bra bild över utvecklingen av batteribankens laddstatus så man speciellt i sämre väder kan planera sin drift bättre.
Denna 24hr statistik baseras på 40.000.000 mätvärden / dygn av spänning, ström och effekt till/från batteribanken, så fångar även upp snabba förändringar för hög precision.
Är det VOLTAGE, POWER, DISCHARGE & SOC som också ska få sina 24hr data, vilket den mesta C++ OOP-koden redan är kodad för.
Ska senare bli en lika dan dashboard för "Latest 7days running statistics"!

NordicOffGrid™ PV Battery Dashboard
NordicOffGrid™ PV Battery Dashboard - Latest 24hr running statistics

2023-04-10

Upptid, datum/tid ESP32 / Client
Upptid & datum/tid ESP32 / Client.

Har nu passerat 5 dygns uptime, när detta skrivs 00y00m05d 06:43:11. Så det visar på hög exekveringsstabilitet. Det motsvar ca 412.000 programloopsexekveringar, så alla kombinationer borde ha hunnit uppstå då som kan leda till kodkrasch tänker jag.
Är lite av en milstolpe för 24/7/365-drift känner jag!
Är bara att koda vidare för att VOLTAGE, POWER, DISCHARGE & SOC också ska få sina 24hr data, vilket den mesta C++ OOP-koden redan är kodad för.

2023-04-12
Nu är "Dashboard - Latest 24hr running statistics" färdigkodad och i drift, vilket känns skoj! Hann dessförinnan nå drygt 7 dygns kontinuerlig drift som är rekordet hittills.
Kan även konstatera att objektorinterad programmering (OOP) är bara så bra och smidigt, samt att jag trivs bra med att koda i C/C++ som ger väldigt snabb prestanda och minnessnål kod!
I Computer Sweden´s De 10 mest populära programmeringsspråken i april 2023 ligger C på 2:a och C++ på 4:e plats i populäritet, så är populära hos många.

NordicOffGrid™ PV Battery Dashboard
NordicOffGrid™ PV Battery Dashboard - Latest 24hr running statistics

2023-04-16
Fick tips om IoTPlotter som "is a service which collects data from your IoT devices for long-term graph plotting and storage, completely free" där jag enkelt skulle kunna komma igång snabbt med att få upp data i diagram som jag når ifrån hela Internet. Som ett första steg innan jag kodat eget till mina egna webbsidor på Internet.
Men ska först göra ett snabbt test om jag inte lite enkelt kan skicka data till min egna webbsite.
Även fått tips att använda Grafana på egen server hemma för att visa aggregerad mätdata i olika dashboards som är lätta att tyda. Får kolla upp om det även går på min webbplats inhyrd på webbhotell! Grafana ser fint ut och har spanat in det för rätt länge sedan då Grafana kan ge fina grafiska dashboards.
Samt en som via Zabbix gjort egen monitoring från Victron-enheter i sin båt.
Själv skulle jag i framtiden vilja använda MQTT med en tidsdatabas typ InfluxDB + MQTT.
Samt för egen grafisk display ser LVGL - Light and Versatile Graphics Library trevligt ut.
2023-04-17
Testkört min kod som utvärderar batteribankens Coulomb(Ah) och Energy(Wh) verkningsgrad i batterimonitorn. Än så länge med manuell aktivering för fulladdat batteri vid en "Tail current" på ca 0,005C (0,5%) laddström vid 13,8V aktivt reglerad float-laddning.
Vid cykling 100%-98%-100% SOC blir Coulomb(Ah)-verkningsgraden 48% för mitt gamla blykol-startbatteri jag använder i experiment solcellssystemet här hemma. Utgör den cykling min mobil-laddning ger.
Är betydligt bättre verkningsgrad än jag trodde för den lilla marginella cyklingen. Vid automatisk mätning av verkningsgraden senare ska det bara göras för de urladdningscykler som batteriet nått <90% SOC för att ge vettiga värden är tanken.
Denna aktuella verkningsgradssiffra kommer jag använda på ett smart sätt i batterimonitorn för att få riktigt bra precision i dess mätningar, vilket då sker med en ständigt uppdaterad aktuell verkningsgradssiffra för batteribanken.
Ska bli spännande att mäta på mina Victron lead-carbon batterier i mitt riktiga off-grid solcellssystem inom några veckor!
Här med laddströmmen 0,157A för 44Ah batteriet under aktiv float-laddning är det 0,0036C dvs ca 1,4ggr marginal mot 0,005C för Tail current! Är också något jag kunde övervaka för stabil robust funktion / drift, och till en början följa upp när i skarp drift. Nu under några dygn mätt till >1,5ggr lägsta ström vid aktiv float-laddning!
Inspiration / referens:
AI-felsökning i 5G-mobilnätet med maskininlärning visar hur analys av stora datamängder ger fördel!
Batteribolaget: "Tur-och-retur-verkningsgrad (urladdning från 100% till 0% och tillbaka till 100% laddning) hos det genomsnittliga blybatteriet är 80%. Motsvarande för ett LFP-batteri (LiFePO4) är 92%. Laddningsprocessen hos bly-syra batterier blir särskilt ineffektivt när 80% laddningstillståndet har uppnåtts, vilket resulterar i 50% effektivitet eller till och med mindre i solcellssystem där flera dagars reservenergi krävs (batteritid i 70% till 100% laddat tillstånd)."
TAO Performance: A complete Energy Management System
UPS VRLA lead acid battery predictive maintenance.

NordicOffGrid™ PV Battery Dashboard
NordicOffGrid™ PV Battery Dashboard - Operational data
OBS! EFFIENCY siffrorna (99) & (97) är bara fake ännu.

2023-04-21
Nu vid 17-tiden blev en ny laddcykel klar vid Tail-current <0,005C (0,5%) och aktiv float-laddning i mitt gamla 44Ah blykol-startbatteri jag har i mitt lille experiment solcellssystem. Urladdade till 96% SOC laddnivå denna gången igår kväll vid laddning av urladdad mobil.
Fick då mätt av min ESP32 batterimonitor batteriverkningsgrad 75% nu mot 48% när jag cyklade till 98% SOC, vilket är riktigt bra för så minimal 4% DOD cykling. Det blykol-startbatteriet är från 2016, så indikerar att det är rimligt fräscht fortfarande märkligt nog men naturligtvis krävs det djupare urladdning för att avgöra det mer säkert.
Energiverkningsgraden 58% är inte helt OK mätt ännu, då jag har någon överledning / störning i hårdvaran vid låga effekter så den mäter fel där. Men vet ungefär vad jag ska ändra på hårdvarumässigt, dock valt att få programkoden rimligt färdig först.
Men programkoden verkar fungera fint som tänkt i att utvärdera batteriverkningsgrad!
(Siffrorna (99) / (97) är bara fake ännu, men ska bli något medelvärde över tid.)
Nästa steg är att lyckas koppla upp mot befintlig PWM-regulator så jag får en automatisk detektering av Tail-current 0,005C vid aktiv float-laddning för synkning mot 100% SOC fulladdad blybatteribank.

NordicOffGrid™ PV Battery Dashboard
NordicOffGrid™ PV Battery Dashboard - Operational data
OBS! EFFIENCY siffrorna (99) & (97) är bara fake ännu.

2023-04-27
Infört en synkningsrutin för 100% SOC mot fulladdad batteribank vid grundare urladdningar där inte batteriverkningsgrad beräknas. Kom på en smart algoritm där som ger en noggrann synkning av 100% SOC mot fulladdad batteribank, utan några kepiga svåra inställningar! Får fundera på om den kunde användas för all 100% SOC synkning?
Utvärdering av batteribankens coulomb-verkningsgrad (Ah) är intressant data att ta del av, men främst är det viktig data för hög precision i batterimonitorns mätning av SOC/Ah-laddningsnivå status i batteribanken! Coulomb-verkningsgraden blir löpande utvärderad så den fås för aktuellt driftsmönster och batteritemperatur för bästa precision. På så sätt får man hela tiden aktuell batteriverkningsgrad för den typ av drift / cykling man har för sin blybatteribank samt för batteritemperatur och inverkan från åldrande batterier.
För att kunna mäta batteriverkningsgrad rimligt exakt krävs det att batterimonitorn har en bra precision i att kunna synkronisera sitt 100% SOC fulladdat mätvärde med verkligt 100% SOC fulladdat batteri, och där har jag fått till bra funktion nu.
Samt under de första tio cyklingarna kalibrerar sig batterimonitorn mot batteribanken!
Blir en helt annan precision än om man som användare ska försöka mata in ett fast sådant värde själv för batteriverkningsgrad som inställning!
Ska man uppnå en bra långtidsstabiltet i mätningarna av batteribankens SOC/Ah-laddstatus vid längre tids partiell (PSOC) cykling krävs ett bra verkligt värde för batteriverkningsgraden för att det inte ska driva iväg, så en viktig funktion för det. Med båda LiFePO4 och AGM-blykol (lead-carbon) som tål mycket PSOC-cykling blir detta mer viktigt hos en batterimonitor än tidigare!
2023-05-08
I förrgår natt hade jag 230V 100W växelriktaren igång för att ladda ur lite så kom ned på 96% SOC laddnivå, och igår hann solen ladda det fullt igen. Hamnade då på 70,3% Coulomb­verknings­grad, vilket är jäkla bra för bara 4% DOD urladdning. I en vetenskaplig noggrann rapport mätte de upp ca 50% verkningsgrad vid cykling med 15-20% urladdning, och än sämre vid ännu grundare urladdningar hos ett fint kvalitetsblybatteri.
Så måste vara kombinationen blykolbatteri (mitt gamla Tudor High Tech Carbon Boost 2.0 startbatteri) och strömpulsad laddning från PWM-regulatorns som ger den bra verkningsgraden.

Är skoj att mäta upp och få data på, men den riktiga vinsten är i att med den datan kunna mäta urladdningsnivån (SOC / Ah-urladdning) i blybatteriet med högre precision då jag använder verkningsgraden i beräkningarna där! Här systemdata jag får ut (dock alla datavärden inte helt korrekt där då jag flera gånger laddat upp ny programkod som då stört mitt i mätningar).

Igår kväll/inatt laddade jag ur till 93% SOC så blev absorptions-laddning idag. Då denna PWM-regulator har en fast 3h absorptionstid så kom laddströmmen ned ända till 350mA (0,008C) innan växling till float-laddning, vilket är betydligt lägre än den 0,015C (1,5%, 0,66A/44Ah) Tail-current som är lämplig gräns att avbryta absorptions-laddningen vid för växling till float-laddning.
Om växling skett vid 0,015C Tail-current hade laddnivån då varit någon stans mellan 99,5-100% SOC, så absorptions-laddningen hade kommit väldigt nära 100% SOC fulladdat och bara några få 1/10-dels procent återstått att ladda via float-laddning!
Så blev en bra kvittens på att 0,015C (1,5%) Tail-current är en bra säker gräns att avbryta absorptions-laddningen vid, med god marginal mot hur låg laddströmmen kan bli under absorptions-laddningen. Visar även att 0,015C Tail-current hade avbrutit denna absorptions-laddning signifikant tidigare än dess nu fasta 3h gräns som ger lite onödig överladdning!
Ger ny intressant kunskap med en batterimonitor som mäter med så hög precision!
Så ger bra input till laddcykelstyrningen hos Nordic PV-controller.

NordicOffGrid™ PV Battery Dashboard
NordicOffGrid™ PV Battery Dashboard - Operational data.
Uppmätta verkningsgrader vid grund urladdning 1,5-7% DOD.
NordicOffGrid™ PV Battery Dashboard
NordicOffGrid™ PV Battery Dashboard - Latest running 24hr statistics.
Absorptions-laddning - Volt, Amp & SOC / Discharge stämmer med varandra vid 100% SOC batteri!
Tail-current 0,015C (1,5%) 44Ah = 0,66A då Absorptions-laddning ska avbrytas.
Här kör PWM-regulatorn med fast 3h absorptions laddtid så laddar onödigt länge.

2023-05-12
Är inte bara för mig det tar tid att utveckla mjukvaran / programkoden och testa av den noga för denna batterimonitorn!
I höst skulle Volvos nya elbil EX90 börja produceras, men så blir det inte:
"– Volvo Cars behöver ytterligare tid i mjukvaruutveckling och testning och justerar den planerade produktionsstarten. Produktionen beräknas nu påbörjas under första halvåret 2024, uppger bolaget i ett pressmeddelande.
Även andra tillverkar har haft kraftiga förseningar pga tid som mjukvaruutvecklingen tar!
Nu har jag inför fälttest i mitt riktiga off-grid solcellssystem kvar att införa en meny för reset av statistikdata, två mindre funktioner som behöver en lätt optimering samt att skapa det elektriska informationsutbytet mellan befintlig PWM-regulators driftsmode och batterimonitorn. Så förhållandevis lite kvar :-)
Och även att bygga ett exemplar till av hårdvaran, men det går rätt fort!
Mätningen / utvärderingen av batteriverkningsgrad fungerar bra nu:

NordicOffGrid™ PV Battery Dashboard
NordicOffGrid™ PV Battery Dashboard - Operational data.
Uppmätta verkningsgrader vid grund urladdning 1,5-7% DOD.

Hittade intressant data om nominal float-laddström för AGM-blybatterier hos Float Current Monitoring: a complete overview "Remote monitoring expertise for over four decades", samt även en lista med "Float Current behaviors to monitor"!
A good rule of thumb for VRLA is 10mA of float current for each 100Ah capacity (float at 13,5V). Vid 13,8V och +25°C gäller enligt dem:
Nominal AGM Float-current = 1.6mA/Ah ±33%, så 160±53mA/100Ah.
Eftersom AGM-blykol har något lägre laddspänning så gäller det nog för lite lägre float-spänning hos dem.

Även hittat en Ultra-High Precision Coulometry för cyklisk mätning / utvärdering av battericeller. What Coulombic Efficiency (CE) measurements mean and how they can be used to quantify cell performance.
Exploring Coulombic Inefficiency Per Hour (CIE/HR): "There´s no denying the usefulness and importance of Coulombic Efficiency. However, when comparing cells cycled under different conditions, to have a direct comparison, there´s a few things that must be considered since cell degradation depends on both time and cycle number. Things like reactions of electrolyte components will occur even if a cell is sitting on a shelf not being cycled.
The time dependence of reactions within a lithium-ion cell are challenging for meaningful comparisons of CE – which measures these reactions – where cycles take a different amount of time to complete; cells with cycles that take more time will experience more reactions per cycles. In this way, CE is understood to be a function of both cycle number and time.
"

Ger mig en tanke att jag kanske skulle addera till en antagen (uppmätt?) självurladdning för en bättre långtidsstabilitet i mätningen av SOC/Ah-laddnivå i batteribanken? Men utvärderar först från lite testdrift i mitt riktiga off-grid solcellssystem. Jag har inte någon data på blybatteriers cykliska drift från en ultra-precis batterimonitor och ej hittat någon sådan data på Internet.
Eller fångas det upp rimligt bra av mätningen av batteriverkningsgraden?
Båda dessa ger en kvittens på att jag är rätt på det med tankar kring att utvärdera olika dynamiska driftsparametrar för att få en indikation på när något blybatteri i batteribanken börjar få problem i sin batterikemi!

2023-05-16
Två intressanta rapporter som ger lite mer kunskapsinsikt kring blybattericykling i off-grid solcellssystem, samt kring hur valet av blybatteriverkningsgrad i batterimonitorn är beroende av ens egen battericykling i ett solcellssystem för att få en noggrann visning i batterimonitorn.
Dels: "Superkondensatorer kombinerat med blybatterier" (vilket man även har integrerat i blykol-batterikemin) som även har en del resonemang kring batteriverkningsgrad och Peukerts effekt.
Dels den jag läste redan för något år sedan och som även refereras till i rapporten ovan, där Trojan djupurladdnings flooded kvalitetsblybatterier cyklas med strömbelastningar aktuella i off-grid solcellssystem (C/30): "A Study of Lead-Acid Battery Efficiency Near Top-of-Charge and the Impact on PV System Design"

Det verkar vanligt att man anger 85% blybatteriverkningsgrad i en batterimonitor men för den typiska cyklingen i ett sunt dimensionerat off-grid solcellssystem blir det ofta signifikant fel enligt dessa rapporter!
"Notice also that the overall efficiency shows high values, with full charge represented by approximately 85% efficiency, a commonly used value for battery charge efficiency. More importantly, notice the dramatically lower efficiencies for the increments above about 80% state of charge, where most values are below 60% efficiency, and full charge is represented by less than 50% efficiency."
Så har man då den typiska grunda blybattericyklingen det blir i ett sunt dimensionerat off-grid solcellssystem så är 85% verkningsgrad på tok för högt för batterimonitorn, som med den då ger felvisning.
Nu tror jag att AGM-blybatterier är något lite bättre än öppna flooded blysyrabatterier på detta, men har inte sett några fakta på det.

Verkningsgraden hos ett blysyrabatteri varierar väldigt mycket beroende på omständigheterna.
Tre viktiga variabler är urladdningsdjup (DoD), temperatur och strömbelastning, men även typ av laddning har stor inverkan samt även åldrande.

Enligt rapporten ger en grund cykling på 3-4% DOD en blybatteriverkningsgrad (Ah) på 45-50% bara! När jag nu cyklat mitt gamla blykol-startbatteri i mitt lilla experiment solcellssystem med 3-4% DOD har min batterimonitor mätt upp en batteriverkningsgrad (Ah) på 70-73%! Dvs ca 1,55ggr / 55% bättre batteriverkningsgrad!
Sannolikt är det från kombinationen strömpulsad laddning via PWM-regulator (som är förstärkt av mig) samt att det är blykol-batteri. Men jag tror att det är den strömpulsade laddningen som bidrar mest till den bra blybatteriverkningsgraden!
Vid sådan grund blybattericykling ger strömpulsad laddning markant bättre batteriverkningsgrad, så det enligt mina erfarenheter i stort uppväger att PWM-regulatorn inte kan utnyttja de extra 15-25% ström som en MPPT-regulator får ut från solpanelerna under bulk-laddfasen då den typiska battericyklingen sker inom 70-100% SOC i ett off-grid solcellssystem.

Min batterimonitor jag utvecklar som ett hobbyprojekt utvärderar löpande batteriverkningsgraden vid den aktuella cyklingen man har i sitt batterisystem, så inverkan av olika urladdningsdjup (DoD), temperatur och strömbelastning samt även laddsätt kommer med från den verkliga driften. På så sätt räknar jag med att löpande kunna få riktigt bra precision i den, samt jag slipper en besvärlig inställning.
De delar av Peukerts effekt som eventuellt påverkar lite även vid cyklisk drift kommer då till stor del med som del av den utvärderade batteriverkningsgraden, så även den slipper jag ha som ett inställningsvärde.
Sedan varierar blybatteriverkningsgraden med hur djupt batteribanken cyklas, så är den utvärderad för rätt grund cykling i bra väder så kommer den inte stämma fullt ut för de mer sällsynta djupa urladdningarna i längre dåligt väder. Men bör ändå bli hyfsat bra, speciellt med tanke på att batteriverkningsgraden blir något högre vid djupare urladdningscykel så man kommer då att ha något större marginaler än batterimonitorn visar. Så utvärdering av blybatteriverkningsgraden vid grundare cykling kommer aldrig leda till någon kritisk överraskning för driften vid en mer sällsynt djupare urladdning i längre dåligt väder!
I princip skulle man kunna utvärdera den biten också efterhand som ens blybatteribank cyklas olika djupt, men just nu känner jag mig tveksam till om det är värt att komplicera programkoden med det samt att lägga energi på hur det skulle hanteras.

Incremental charge efficiency
Incremental Ah charge efficiency for Trojan 30XHS 100Ah battery at C/30

2023-05-25
En av marknadens mer avancerade och välutvecklade BMS för LiFePO4 TAO Performance BMS visar också sin driftsdata i en local dashboard via WiFi och webbläsare, precis som jag gör via webbservern i denna batterimonitorn!
Batterimonitorn använder två metoder för att synkronisera 100% SOC fulladdat till verkligt fulladdad blybatteribank, dels via tail-current under aktiv float-reglering, dels en annan speciell utvecklad mätmetod bara utifrån sina egna mätdata som blir lite som en reservmetod.
Denna reservmetod är nu testad en tid och fungerar riktigt bra! Ska optimera den lite ytterligare för att bli mer oberoende av batteribankens kapacitet (Ah) samt av hur aktuell drift är. Ger en hög precision i synkningen samt kräver inga inställningar för aktuell installation!
Tail-current metoden behövs fortfarande för att få en mer likartad utvärdering av batteriverkningsgrad, då det är blybatterierna som direkt själva talar om när de precis är 100% SOC fulladdade.

2023-06-03
Kämpar vidare med att uppnå full 365/7/24 driftsstabilitet!
Har haft fortsatt glesa kodkrascher när jag bläddrar runt aktivt mellan de olika webbsidorna med driftsdata från ESP32, där kodbiblioteket ESP32 ESPAsyncWebServer-esphome kraschar i sin programkod. Men i nattdrift med bara min egen kod i drift är det fullt stabilt!
Känns surt/motigt att det är välrenomerade kodbibliotek jag använder som skapar problem för stabil kodfunktion och inte mitt egna kodande. Interaktionen med kodbiblioteket är väldigt tydligt och rättfram, så känner mig säker på att jag inte gör fel där!
Har ökat CONFIG_ASYNC_TCP_QUEUE_SIZE från 512 till 1024 (från original 32) i AsyncTCP.h, men osäker på om det behövdes. Men har det så en tid nu som test. Gör det i xQueueCreate(1024, sizeof(lwip_event_packet_t *)) i AsyncTCP.ccp.
Har gjort en rutin som aktiverar events.close() på alla de olika instanserna där events.count() == 0 för att säkert stänga ned all SSE-kommunikation som inte är aktiv längre och behövs!
if (eventsStat.count() == 0U)
{
  eventsStat.close();
}
Det verkar göra nytta att rensa upp så! Har inte sett någon kodkrasch sedan dess relaterat till bläddrande bland ESP32-webbsidorna i webbläsaren på datorn! Men hittar inget skrivet alls om detta utan hittade close() när jag studerade alla funktioner som gick att applicera på en events från dess kodbibliotek. Har hört att vid vanlig webbsideskodning med SSE för Internet är det ett problem som uppstår ibland att inte all gammal oanvänd SSE-kommunikation rensas ut så och tillslut leder till kodkrasch då SSE blir överbelastat, att SSE anslutningarna aldrig stängs även när de borde ha stängts.
Events.close() leder till filen AsyncEventSource.cpp och inom webbutveckling finns EventSource close() method: The close() method of the EventSource interface closes the SSE connection, if one is made. Så känns som close() stänger en kvarlämnad SSE-anslutning.
Samt har optimerat free stack space för mina olika FreeRTOS Task så de har lite drygt 2000 bytes free stack under drift. Kör med god marginal nu under utvecklingen men tanken är att gå ned till ca 1000 bytes free stack space senare och slutgiltigt 500 bytes:
Task minimum free stack space (bytes):

1.TaskSetupESP32: (2628)
2.TaskDisplayViewHandler: 2032
3.TaskLCDbuttonsHandler: 2052
4.TaskWebServerESP32: 2080
5.TaskDeferredInterruptINA226: 2040
6.TaskStateMachine: 2072

Samt har även ändrat Task_DeferredInterruptIN226´s xQueueReceive() xTicksToWait från 1500 till 5000ms så den inte aktiveras för en mindre fördröjning av interrupt från INA226 pga eventuell krock med interrupt mot ESPAsyncWebServer. Har haft någon väldigt sällsynt kodkrasch som verkar vara kopplad till Task_DeferredInterruptIN226, typ 1ggr/10dygn när ESP32 webbsida visas med aktiv SSE.
Har även ändrat i TaskWebServerESP32 så att SSE-events bara max får utnyttja 450ms av 1100ms cykeltiden, mot tidigare 750ms. Ger mer ostörd tid för ESPAsyncWebServer, om det kanske är lite av problemet!
Känns dock som ett misstag att jag fortsatte med SSE (Server Side Events) för dataskickandet till webbsidorna så länge för första fälttestet i husvagnen, istället för att byta till WebSockets som jag senare fått uppfattningen är stabilare i sin funktion.
Behöver WebSockets dubbelriktade kommunikation för en webbsida med inställningar samt WebSocket kan skicka binär data.
Så når jag inte full stabiltet med dessa kodrefaktorings så får jag bita i det sura äpplet och byta till WebSockets nu, vilket jag annars gör senare efter lite test och utvärdering!
Är mer hype kring WebSocket så verkar vara mer välutvecklat därför, som bl.a. beskrivs i ESPAsyncWebServer manualen:
Limiting the number of web socket clients:
Browsers sometimes do not correctly close the websocket connection, even when the close() function is called in javascript. This will eventually exhaust the web server´s resources and will cause the server to crash. Periodically calling the cleanClients() function from the main loop() function limits the number of clients by closing the oldest client when the maximum number of clients has been exceeded. This can called be every cycle, however, if you wish to use less power, then calling as infrequently as once per second is sufficient.
void loop(){
  ws.cleanupClients();
}
cleanupClients() finns inte för SSE där!

2023-06-05
Så långt är det stabilt nu med förändringarna beskrivna ovan.
Fångade en komplett battericykling ned till 95% SOC och fick verkningsgrad utvärderad.
Blev hela 81,2% coulomb-verkningsgrad för så grund urladdning, så blykol-batteri ihop med strömpulsad laddning är helt klart en bra kombination. Ytterligare en urladdning till 97,3% SOC gav 73,4% coulomb-verkningsgrad. Jag har fortfarande en hårdvarumässig överhörning vid mätning av låga effekter, så energi-verkningsgraden blir inte rätt ännu.
Men har inte heller försökt att lösa det problemet ännu. Tror det är rätt enkelt.
Övriga data där blir mer intressant med lite fler cyklingar på rad utan kodkrasch!

2023-06-09
Hade återigen en syllsynt kodkrasch (typ <1ggr/vecka) när jag aktivt snabbt bläddrade runt bland webbsidorna från ESP32-webbservern, precis när en ny webbsida skulle visas. Nu efter 6 dygns OK funktion med mycket stresstestande. Finns inget bra sätt att felsöka så sällsynta händelser för mig. Men lite logiskt tänkande ledde till att kanske SSE anslutningen inte stängs korrekt när webbsidan stängs och avslutas, så ESP32-webbservern blir överbelastad av det (att kanske försöka skicka både SSE och ny webbsida samtidigt).
Så provat att lagt in sådan funktion nu i min webbsideskod som avslutar SSE innan webbsidan stängs. Kunde se i "Verktyg för webbutvecklare - Nätverk" i webbläsaren att utan den kodfunktionen kommer det ett Error-meddelande för förra visade webbsidans SSE-events vid sidväxling men nu med detta inlagt så försvinner det Error-meddelandet! Så känns helt rätt och kan nog faktiskt vara en orsak. Men inget jag sett något tips om eller beskrivning av - är så mycket jag själv måste lista ut kring att få SSE att fungera stabilt med webbsidorna och ESP32-webbservern!
Ser även en lite ytterligare distinkt funktion i aktiveringen av SSE på nya visade webbsidan, vilket även skett lite efter de övriga senaste förändringarna. Så en liten indirekt indikation på att kodförbättringen kanske gör nytta.
window.addEventListener("pagehide", (event) => {
  eventsource.close();
},false);
document.addEventListener("visibilitychange", (event) => {
  if (document.visibilityState === "hidden") {
    eventsource.close();
  }
},false);
Page Lifecycle API
Förhoppningsvis är det så stabilt nu att jag med denna koden kan starta fältprov i mitt riktiga off-grid solcellssystem bara jag byggt prototyp 2 färdig. Sedan är det att skicka driftsdata till webbsida på webbhotell samt att börja testa WebSocket som står på tur. Men ska först då vara off-grid aktivt lite och uppleva ESP32-batterimonitorns funktion i skarp drift.
Jag tror starkt på att ersätta SSE (Server Side Events) med WebSocket för mindre problem och mer prestanda i datautbytet mellan webbservern och webbsidan, men återstår att testa!

2023-06-14

TRMS vs Average
TRMS vs Average / Medelvärde - olika kurvform
CF: Crest Factor = Peak-value / RMS-value
D: Duty-cycle (Pulskvot)
TRMS vs Average
TRMS vs Average / Medelvärde - olika kurvform
TRMS vs Average
TRMS vs Average / Medelvärde

Att utvärdera att batterimonitorn mäter rätt strömvärde för ren kontinuerlig jämn DC likström är inte svårt, men vid olika pulsad ström blir det svårare! De mätinstrument jag har mäter TRMS och batterimontorn mäter medelvärde, vilka skiljer sig åt för olika kurvformer. Blir extra tydligt vid låga PWM-pulskvoter från PWM-regulatorn! Ska senare se om mitt digtala oscilloskop kan hjälpa mig där vid en mer slutlig utvärdering.
Men under några timmars mätning vid olika strömpulsande ser batterimonitorn ut att hålla en bra precision i strömmätningarna!
Även effektmätningen har blivit betydligt bättre efter en smärre förändring hårdvarumässigt och räknar med en signifikant förbättring när jag gör om hårdvaru-layouten så överhörning från strömpulsandet minimeras.
Nu när programkoden verkar fungera stabilt och bra fokuserar jag lite på att verifiera och förbättra hårdvaran när jag bygger protyp två nu!
Mer kunskap:
How to derive the RMS value of pulse and square waveforms
Digital Multimeters- Basic Guide, Fluke
Electronic Test Instruments: Measurement Theory

2023-06-16
Nu kört drift stabilt drygt 7dygn och gjort en massa stresstestande med en mängd aktiveringar av WiFi / Webbserver samt bläddrande mellan alla ESP32-webbsidorna! Har inte gått förut!
Så känns riktigt lovande för stabil 24/7/365-drift. Ser även att belastningen av SRAM-minnet är ytterligare stabilare nu under dessa 7+ dygn med 127096 bytes som lägsta ledigt samt i snitt ca 51% ledigt med visad aktiv webbsida!
Har haft problem med funktionen från det välrenommerade ESPAsyncWebServer-esphome biblioteket. Har dels fått hacka det lite, dels fått lista ut en del ej dokumenterade funktioner som krävs, samt fått koda en övervakning och reglering av webbserverns SSE-drift så den inte överbelastas i SSE-kommunikationen till webbsidorna som visar driftsdata.
Verkar som den senaste justeringen nu i webbsideskoden som stänger SSE precis innan webbsidan avslutas var det sista som behövdes för att kunna växla stabilt mellan webbsidorna!

NordicOffGrid™ PV Battery Dashboard
NordicOffGrid™ PV Battery Dashboard - Operational Data

2023-06-18
Fick färdigt den 2:a prototypen av ESP32-batterimonitorn idag som fungerade direkt. Testkört den en del men inte inkopplad i solcellssystem ännu. Är mer noga byggd samt med en bättre hårdvarulayout som bör förhindra överhörning från strömpulsande!
Ska göra en del mer laboratoriemässiga mätningar och analyser på ström- och effekt-mätningen på den först nu.
Sedan provköra i mitt lilla experiment solcellssystem och därefter installera i mitt riktiga off-grid solcellssystem.

ESP32 Ultra-precise Battery System Monitor
Prototyp 2, ESP32 Ultra-precise Battery System Monitor


2023-06-29
För att ytterligare minimera risken för problem mellan ESPAsyncWebServer-esphome biblioteket och min programkod har jag omslutit hela min ISR-funktions kod för INA226´s interrupt med en kritisk sektion portENTER_CRITICAL_ISR(&Mux) / portEXIT_CRITICAL_ISR(&Mux), vilken ger att "inside the critical section interrupts are disabled" källa1, källa2, källa3, källa4, atomic instruction.
Key of a critical section is that it´s not preempted. One will not get a context switch in a critical section with interrupts disabled! Vilket känns viktigt för denna ISR_INA226Batt()!
Critical sections are used as a valid protection method against simultaneous access in FreeRTOS - Critical Sections & Disabling Interrupts.
ESPAsyncWebServer-esphome lär ha interrupts för sin funktion så bör undvika störning av annat samtidigt interrupt på detta sätt, vilket jag sett extremt glesa händelser jag tolkar skulle kunna vara en interrupt "context switch" när min ISR-funktion ISR_INA226Batt() exekverar.
Men då detta har hänt typ 1ggr/2veckor tar det tid att verifiera en förbättring!
Samt det händer bara när ESPAsyncWebServern aktiveras och visar webbsidor.
Kan i vart fall inte se någon negativ effekt av portENTER_CRITICAL_ISR(&Mux) / portEXIT_CRITICAL_ISR(&Mux) i ISR för min kod-funktion!
Läs mer om Deferred interrupt context switch på webbsidan om Arduino ESP32 C/C++ kodning.
Är mycket med kodinteraktionen med RTOS att förstå sig på riktigt djupt och få känsla för!
Men samtidigt intressant och spännande att utforska.

2023-07-03
Gör nu en del mer laboratoriemässiga mätningar och analyser på ström- och effekt-mätningen på min 2:a prototyp. Ser att jag behöver justera hur jag kopplat hårdvaran då det finns lite mätavvikelse vid riktigt låga strömmar. Egentligen borde jag ha strömshunten på high-side (batteri-plus) men min nuvarande batterimonitor i off-grid solcellssystemet har den på low-side (batteri-minus), vilket är det vanliga hos batterimonitorer. Vill helst slippa en ombyggnad i elsystemet så försöker lite till med low-side! INA226 är annars mest anpassade för high-side vid dubbelriktad strömmätning.
Men mäter och provar lite olika små justeringar och lär mig INA226 i mer detalj ett tag. Får jag det tillräckligt bra nu med low-side så monterar jag in den i skarp drift i mitt off-grid solcellssystem, så fortsätter jag att optimera med protyp 1 här hemma i experiment solcellssystemet.

INA226
INA226 High- or- Low-side sensing application

2023-07-04
En liten enkel justering i hårdvarans INA226 inkoppling fixade helt mätavvikelsen vid låga strömmar och mäter nu 100% korrekt, med strömshunten ansluten low-side (batteri minus).
Är intressant att se att medan strömvisningen på labora­torie­nät­aggre­gatet fladdrar mellan 11mA till 24mA så visar ESP32 stabilt -13mA medelström mätt över 2,2s vid nattdrift. Är växlingarna mellan ESP32 light-sleep och kort full drift för avläsning av INA226-sensorn samt en blinkande LED som ger variationerna i strömförbrukning men som ligger absolut stilla som medelvärde!
Ger en väldigt behaglig stabil och precis strömvisning, samt strömvärde för beräkningar!
Har även validerat labora­torie­nät­aggre­gatets strömvisning med en bra multimeter.

2023-07-07
Köpt nytt blybatteri till mitt lilla experiment off-grid solcellssystem hemma i Lägenheten. Ska ersätta mitt gamla utrangerade 44Ah blykol-startbatteri från 2016-01-23, som inte är AGM och jag inte kan kolla syranivån i (så det inte händer en olycka med det). Det beter sig annars spännings-, ström-, laddnings- och verkningsgrads-mässigt väldigt fräscht vid mina grunda cyklingar (≥95% SoC) med värden som i stort hos ett nytt batteri. Strömpulsladdning rocks!
Det nya 12V UPLUS 90Ah Lead-Carbon (Bly-Kol) är ett "true deep cycle AGM technology" som ger ett bra kvalitetsintryck. "UPLUS Bly-Carbon batterier är utvecklade för elfordon och för att användas som ett förbrukningsbatteri i mobila och marina applikationer. Batterierna fungerar dock även bra som ett stand-by batteri." Så ska fungera väldigt bra med min drift här med mest väldigt grunda cyklingar från laddning av mobilen, nästan som standby-drift. Och samtidigt kunna fungera lite som reservkraft vid eventuellt strömavbrott.
Detta UPLUS 90Ah Lead-Carbon höll 12,60V vid leverans, vilket känns helt OK (≈90% SoC).
  • True deep cycle AGM technology-GREEN SOLUTION
  • Over 99.99% virgin lead for grid plate and active material
  • Heavy duty grid/paste design for deep cycle application
  • Maintenance free, non-spillable, valve-regulated
  • Double separator configuration: long cycle life &
    High energy density and super anti-vibration design
  • Low self-discharge for longer shelf life
SellPower Nordic AB som är generalagent för dessa i Sverige ger ett bra, seriöst kunnigt intryck och verkar noga med att bara ha kvalitetsprodukter i sitt sortiment, flera med en grön profil!
Har nu även fått ett par feedback av folk som jobbat med dem eller haft affärer ihop som säger att SellPower är väldigt seriösa och duktiga, vilket bekräftar min analys av SellPower!
Blir även bra att min fortsatta utveckling sker mot ett AGM-blykol batteri för djupurladdning till solcellssystem, så jag har rätt förutsättningar. Utökar även till dubbla solcellseffekten.

2023-07-10
Kopplat in prototyp II på mitt lilla experimentella off-grid solcellssystem i lägenheten och det fungerar fint! Förändringarna i hårdvarans layout för INA226 blev bra.
Känner av när PWM-regulatorn är i aktiv reglermode och PWM-strömpulsar s.k PV Throttle, precis som tänkt. Och i kombination med Tail-current <0,005C (0,5%) så synkar den 100% SoC mot fulladdat batteri bara så fint och exakt. Kan därmed få riktigt bra precision i uppmätning av batteri­verknings­grad och därmed även SoC / Ah-laddnivå! Vid aktiv strömbegränsande reglering ihop med 0,5% Tail-current så talar batteriet själv om när det är fulladdat.
Har därmed fått min PWM-solladdregulator och denna ESP32 batterimonitor att kommunicera med varandra, vilket behövs för riktigt bra funktion hos batterimonitorn.
PV Throttle dektekteringen fungerar från riktigt hög pulskvot, så fångar verkligen direkt PWM-strömpulsandet börjar. Så osäkerheten kring det är helt skingrad nu.
Har gjort lite speciell kodning kring detta som kvalitetssäkrar detekteringen av PV Throttling och 100% SoC fulladdad blybatteribank via Tail-current.
Men är 0,5% Tail-current ett säkert fast värde att gå på som alltid kan nås i ett blybatteri? I mitt nuvarande gamla utrangerade 44Ah blykol-startbatteri från 2016-01-23 här hemma når jag ända ned till åtminstone 0,25% Tail-current, så ger 2ggr säkerhet i detekteringen av 0,5% Tail-current!
Sedan kommer jag bygga in en övervakning av detta, så om den lägsta mätta Tail-current vid PV Throttle börjar närma sig eller överstiger 0,5% så kommer en kodfunktion justera upp den automatiskt för att säkra funktionen. En sorts inbyggd automatisk kvalitetssäkrande funktion.

ESP32 Ultra-precise Battery System Monitor
Prototyp II, Tänd Grön LED = PV Throttle ON
Och Ström < Tail-current => 100% SoC synkat


2023-07-14
Varit flera dygn utan att blivit fulladdat, men så idag blev blybatteriet 100% SoC fulladdat.
Kombinationen PV Throttle = ON och Tail-current <0,005C (0,5%) plus lite kvalitetssäkrande logik ger en riktig fin precision i avkänning av 100% SoC batteriladdnivå! Idag var det växlande soligt med moln så en svår instabil situation att detektera 100% SoC men batterimonitorn gjorde det väldigt stabilt med riktigt bra precision! Är imponerande utan att ha trimmat funktionen!
Så ett första bra steg i valideringen av den funktionen, som är så grundläggande!
Tyvärr blockerar jag utvärderingen av batteriverkningsgrad vid första 100% SoC synkningen, men såg ut att ha blivit väldigt hög verkningsgrad annars. Så är nästa spännande att se.

2023-07-15
Kodat 5st till LCD displayvyer, för SoC-data, TimeToGo 1hr/24hr, 24hr ΔCHARGE (Ah/Wh), Batteriverkningsgrad samt Cycled Discharge. Har nu totalt 21st LCD-displayvyer att bländra runt som en cirkel mellan, både som visar driftsdata och menyer för inställningar.
Kan nu även se den mesta driftsdatan via LCD-displayen av det som visas på webbsidorna.

LCD display views
LCD-display vyer över driftsdata


2023-07-16
Med prototyp II som mäter rätt även för små strömmar samt synkar 100% SoC till fulladdat batteri med hög precision utvärderades en Coulomb(Ah) verkningsgrad på hela 92% för 44Ah bly­kol­start­batteriet från 2016-01-23 strömpuls­laddat med låg ström <1A/44Ah=<0,023C. Är för 1st laddcykel över två dygn med -1,7Ah/44Ah urladdning.
Är sannolikt pga kombinationen blykol-batteri, ström­puls­ladd­ning och låg laddström, men ändå väldigt imponerande för det gamla blybatteriet! Intressant att kunna mäta nu!
Samt mätte en Energi(Wh) verkningsgrad på 87%.
Behövs dock mätningar över flera batteri­cyklingar innan man kan känna sig mer säker på dessa värden, men just nu prioriterar jag den sista justeringen i koden inför att installera i mitt riktiga off-grid sol­cells­system! Var dock skoj att se för en batteri­cykling såhär.

Prototyp II, 1st laddcykel över två dygn
Prototyp II, 1st laddcykel över två dygn -1,7Ah/44Ah => 92% Coulomb(Ah) verkningsgrad!
Samt 87% Energi(Wh) verkningsgrad.

2023-07-18
Har gjort lite kodrefaktoring, optimerat några kodfunktioner samt verifierat programkoden lite mer så den nu bör vara redo för skarpt fältprov i mitt riktiga off-grid solcellssytem! Några små verifieringar ytterligare av hårdvaran också bara samt uppdatering till samma hårdvarulayout i prototyp I som stannar här hemma i experiment off-grid solcellssystemet.
Är lättast att göra det när jag har de två prototyperna anslutna parallellt här hemma så jag kan jämföra mellan dem. Ska se om jag kan förenkla det filter jag har som gör att jag mäter strömmen för kraftigt snabbt strömpulsande rätt. Tror det men ändå lite osäker.
Har ju hittills mest lagt tiden på programkodningen, då det varit huvudutmaningen.

2023-07-19
Är jäkla spännande att få mätt batteriverkningsgraden för sitt blykolbatteri via batterimonitorn för varje battericykel (dock gammalt blykol­start­batteri från 2016-01-23 här hemma just nu)!
Både Coulomb(Ah) och Energy(Wh) verkningsgrad.

Förra battericykeln gav 92,0% Coulomb(Ah)-verkningsgrad cyklad -1,7Ah av 44Ah, till bara 97,7% SoC.
Då skedda återladdningen i bra solsken mot slutet av tiden under de två dygnen.
Återladdat med låg solcellsström <1A / 44Ah = <0,023C och mot slutet när regulatorn begränsar strömmen PWM-strömpuls­laddat.
Återladdningen vid så grund cykling sker i enbart float-laddning med min PWM-regulator.

Batteriet själv talar då om när det är fulladdat vid aktiv float-strömreglering och Tail-current <0,005C (0,5%). Samt ihop med lite kvalitetssäkrande kod så den detekteringen blir robust och stabil även i växlande solsken.
Har sett nu att detta ser ut att ske med riktigt bra repeterbar precision!
Så även batterimonitorns 100% SoC blir väldigt exakt synkad till full blybatteribank.
Här kan man se att Tail-current kommit ned ända på +0,123A vid aktiv PWM-reglering, mot 0,220A som är 0,005C / 0,5% för 44Ah batteriet.

Senaste battericykeln klar nu seneftermiddag återladdad stor del av tiden med riktigt låg ström i varierande väder med mycket molnigt slutade med 98,4% Coulomb(Ah)-verkningsgrad cyklad -1,3Ah av 44Ah, till bara 97,2% SoC.
Jag cyklar här normalt bara med laddning av min mobil.

Vid så grunda cyklingar brukar traditionella blybatterier ha urusel verkningsgrad under 50%!
Att jag får så hög här bör vara kombinationen väldigt låg laddström, PWM-strömpulsladdning och blykol-batteri.
(Samt det kräver egentligen verifiering från lite fler laddcykler för säkra siffror, och blir bättre uppmätt med urladdning <90% SoC.)

Planen är att ha denna batterimonitor inmonterad i mitt off-grid solcellssystem med Victron lead-carbon batterier senast under nästa vecka. Och där kommer då batteriverkningsgrad bara utvärderas för battericykler som går under 90% SoC!
Ska bli väldigt intressant att få mätt Victron lead-carbon´s batteriverkningsgrad under min normala aktiva drift där!
Tyvärr har jag varit rätt sjuk senaste månaderna så är en viss osäkerhet kring det om tidplanen håller.
Men programkoden (firmware) för detta är i alla fall äntligen färdig, debuggad och testad nu.

Prototyp II, 1st laddcykel över två dygn
Prototyp II, 1st laddcykel -1,3Ah av 44Ah => 98,4% Coulomb(Ah) verkningsgrad!
Samt 87% Energi(Wh) verkningsgrad.
Prototyp II, 1st laddcykel över två dygn
Prototyp II, 1st laddcykel -1,3Ah av 44Ah => 98,4% Coulomb(Ah) verkningsgrad!
Samt 87% Energi(Wh) verkningsgrad.

2023-07-21
Senaste laddcykel över ett dygn gav 100% Ah-batteriverkningsgrad (!) för -1,6Ah/44Ah cyklad urladdning och 96,5% SoC. Så antingen någon liten felmätning av pulsad ström eller möjligen att det skett lite ytterligare desulfatering, för 100% verkningrad har det absolut inte. Är extremt känsligt när man mäter såhär väldigt grunda urladdningar, så blir intressantare sedan för drift i mitt riktiga off-grid solcellssystem.
Lägsta Tail-current sjönk något ytterligare ned till omkring 105mA (≈0,0024C), vilket tyder på lite ytterligare gjord desulfatering i batteriet av strömpulsandet.
Är svårt att verifiera att batterimonitorn mäter pulsad ström med tillräckligt bra noggrannhet vid PWM-strömpulsad laddning! Ska se om jag kan verifiera det bättre med mitt digitala oscilloskop som jag tror kan mäta medelspänningen över strömshunten för pulsande ström.
För båda de senaste dygnens kompletta små laddcyklar har medelströmmen under 24h varit +8mA/+9mA, så en väldigt liten mängd "bortslösad" ström som förlust i blykolbatteriet!
Visar att blybatterier kan arbeta betydligt mer effektivt än de allmänt beskrivs som. Innebär sannolikt i stort noll gasning och bara lite ström till desulfatering, cellbalansering och förluster.
Strömpulsladdning ger extremt låg gasning som en av flera fördelar!
Har inget noterbart minnesläckage (memory leak) under 2-3 veckors drift:
ESP.getMinFreeHeap(): 132004 bytes (lägsta sedan start)
ESP.getMaxAllocHeap(): 110580 bytes (största fritt minnesblock)
ESP.getFreeHeap() / ESP.getHeapSize(): 50-51% Wifi+Webserver ON, 74% Wifi+Webserver OFF

2023-07-23
Kodat en adaptiv funktion som hanterar Tail-current gränsvärdet (0,005C / 0,5%) så det vid behov justeras upp automatisk efter blybatteriernas funktion så en robust stabil synkronisering av 100% SoC till fulladdat blybatteri alltid kan göras utifrån Tail-current.
Sedan finns det en reservmetod som också synkroniserar 100% SoC med bra precision, men inte tidsmässigt lika exakt för bra beräkning av batteriverkningsgrad.


2023-07-28
Mätt upp strömförbrukningen för Mobil 4G Router Teltonika RUT241 vid uppkopplad drift, som då drar ≈90mA i snitt från 12,5V. Motsvarar i 24/7-drift ca 2Ah/dygn, vilket känns överkomligt.
Optimerade / förenklade även filtret för strömsignalen för korrekt mätning av pulsad ström. Då jag hade både version I & II inkopplade samtidigt kunde jag jämföra och med modifieringen blev mätningen något lugnare men gav ändå i stort samma strömvärden. Jag bedömmer att det blev något bättre noggrannhet för små strömvärden under ca 150mA för 60A/60mV strömshunten.
Ska senare försöka göra än mer noga utvärdering via digitalt oscilloskop som kan mäta medelvärdet för kontinuerligt pulsande. Men vill komma i provdrift nu i fält!

2023-07-29
Installerat protype II i mitt off-grid solcellssystem i husvagnen för riktig fälttest.
Fungerar väldigt bra och ger en riktigt fin driftsöversikt över AGM-blykol batterierna. Vistades där i två dygn och kunde verifiera att de två olika Time-To-Go prognoserna (från 1hr / 24hr statistik) är riktigt bra och fungerar som tänkt med 12V kylskåpskompressorns intermittenta drift med ca 25% av tiden aktivt igång! Fick fint stabila drifttidsprognoser, både för 24hr dygnsdriftens längre tid och aktuell korttids laddningsprognos baserat på senaste 1hr strömstatistik.
De kompletterar varandra väldigt fint!
Även batterimonitorns 100% SoC synkning till helt fulladdat batteri fungerar med väldigt bra repeterbar precision, så riktigt imponerande! Även vid snabbt växlande soligt / molnigt väder!
Visar nu även i PV Battery Dashboard om PV Throttle är ON/OFF (om aktiv strömbegränsad reglering i solladdregulatorn), via grön färgmarkering (ON) av cirkeldiagrammets centrum där:

PV Throttle ON/OFF indikator
PV Dashboard indikerar om PV Throttle är ON/OFF

2023-08-01
Vid passiv standby-drift i mitt lilla experiment off-grid solcellssystem här hemma med gammalt 44Ah blykolstartbatteri (än så länge) så blir dygnsladdningen för helt fulladdat blybatteri ca +0,140Ah/24h, ca +6mA i medelström. Är baserat på senaste uppmätt 24h medelström.
Är imponerande lite strömförbrukning, speciellt med tanke på att en Battery Reconditioner (9kHz, >50A) hela tiden ligger och pulsar ström in i blybatteriet och laddar upp sig med ström från blybatteriet. Kan finnas ett mindre mätfel för strömmen när PWM-regulatorn strömpulsar, vilket jag ska mäta upp och analysera mer noga senare och så ifall justera filtret för.

2023-08-03
Stämt av att tidmätningen via esp_timer_get_time() 64bit tid internt i ESP32 inte bidrar med en signifikant onoggrannhet till Ah-summeringen från de samplade strömvärdena pga av avvikande CPU-klockfrekvens. Och fick som svar att Industristandard för klockkristallerna är ±20ppm, men idag är kristaller så bra att det är sannolikt inom ±10ppm. Så det är betydligt högre precision än jag får i strömmätningen, så bidrar inte till någon onoggrannhet i Ah-summeringen!
Fick även följdfrågan: "Frågan är väl också hur klockan propagerar internt i processorn? (Både mellan olika delar av hårdvaran men också exekveringstiden för olika instruktioner.)"
Som jag svarade på: Jo det är också en intressant frågeställning.
Men via esp_timer_get_time() får jag tid med µs upplösning, och tar tidsstämplingen via interrupt när INA226-sensorn signalerar att nya mätvärden finns att hämta.
Så tidsstämplingen och mätvärdena får en bra noggrannhet mot varandra.
Sedan skickas de vidare till en Deferred interrupt processing funktion som getts hög prioritet i FreeRTOS, så den exekveringen blir som en direkt förlängning på ISR-funktionen som interruptet triggar. Där hämtar jag strömmätvärdena från en buffert de är lagrade i hos INA226-sensorn, så de påverkas inte av att det tar någon lite tid.
Med µs upplösning har jag goda marginaler för tillräckligt hög tidsprecision samt allt övrigt är kodat så jag inte förstör den precisionen.
Som jag förstått det så tickar inte tiden på från esp_timer_get_time() inne i ISR-funktionen, så jag får verkligen tidsstämplingen för exakt när interruptet triggades.
Har även via 200MHz digitalt minnes-oscilloskop checkat av att interruptet med ISR sker tillräckligt snabbt.
Så jag tror jag har tillräcklig koll på den biten.
Men helt klart en viktig frågeställning också i detta sammanhanget!

2023-08-06
Var och tittade till installationen i off-grid solcellssystemet samt uppdaterade hårdvaran lite enligt det senaste här hemma. Ska ge lite mer exakt mätning av strömpulsandet från PWM-regulatorn vid spänningsreglerad laddning mot blybatteribanken.
De dryga två dygnen jag bodde där nyss när jag installerade ESP32-batterimonitorn där gav lite intressanta första mätvärden och driftsstatistik nu när batteribanken hunnit bli fulladdad igen:
- Senaste lägsta SoC: 75,7% (motsvara ca -51,5Ah)
- Senaste cyklade urladdning: -81,1Ah
- Batteriverkningsgrad Ah: 94,0%
- Batteriverkningsgrad Wh: 88,2%
- Low Tail current: ca 0,14% / 0,0014C
Under de dryga aktiva två dygnen boende blev batteribanken inte fulladdad, men en hel del laddades tillbaka i det växlande solskenet dagtid. Så därför senast lägsta SoC bara motsvarar -51,5Ah urladdat medans "Senaste cyklad urladdning" blev -81,1Ah då den räknar all cyklad urladdning tills fulladdat igen. Är en intressant siffra tycker jag!
Den mätta Batteriverkningsgraden känns bra för några dygns aktiv drift ihop med några dygn till tills fulladdat i det mulna vädret, men de mätningarna kommer troligen påverkas lite av den justering jag gjorde i hårdvaran idag. Samt tror det skiljer lite vid första aktiva drift såhär efter en längre passiv standby-drift mot vid en lite längre aktiv drift med flera fulladdningar under tiden.
Men för blybatteri är de verkningsgraderna riktigt bra vid denna battericyklingen, så märks den är signifikant bättre hos AGM-blykol batterier!

ESP32-batterimonitor driftsstatistik
ESP32-batterimonitor driftsstatistik

2023-08-10
Har förbättrat mätningarna av PWM-solladdregulatorns 30Hz strömpulsade laddning så ESP32 via INA226 nu samplar spänningen över strömshunten i 3,5kHz just när det är PWM-strömpulsning. Det är max vad INA226 kan prestera! Använder då Conversion time 140µs och Averaging 1024 st mätningar. Så 1024st mätningar medelvärdesbildas i INA226 innan interrupt sätts till ESP32 så den hämtar den datan ur bufferten.
Innebär ca 117 samplingar per 30Hz pulsperiod samt medelvärdet för ca 35st 30Hz pulscykler, ihop med en RC-filter tidskonstant på 0,31ms dvs i storlekordning för 1% Duty-cycle.
Så skulle helst velat upp i 2-5ms RC-tidskonstant!
Samplar då kontinuerligt i ca 3,5kHz och mätt att ESP32 hinner med att hantera detta i helt jämn takt med INA226 med nya data var 292:a ms, även när driftsdata förmedlas via ESP32 webbservern via WiFi till webbsida på datorn.
Gör detta bara då ESP32 detekterar att PWM-solladdregulatorn strömpulsar, annars samplas med ca 450Hz dvs blir 7,8ggr oftare såhär.
Jag tycker det märks skillnad, dels så varierade strömvärdet signifikant mer förut (vilket jag trodde var PWM-regulatorn som var lite orolig i regleringen), dels har jag idag haft ett par gånger när solinstrålning minskat långsamt från fullt solsken så PWM-regulatorn växlat mjukt från strömpulsande till jämn DC-ström ut och det har inte gett något synbart hopp i det mätta strömvärdet vid växlingen.
Så känns som det blev bättre såhär med lite mer noggrann mätning av den strömpulsade laddningen. Känns som ett skoj steg framåt!
Impulsen kommer ifrån när jag frågat mer kunniga inom RC-filter / datafiltrering och sampling om råd på Internet. Jag är lite utanför min kunskapszon här!
Ska senare i höst försöka utvärdera det mer nog i mätning via mitt digitala oscilloskop.

2023-08-18
Håller på att i KiCad Spice simulera lite olika filterkonfiguration för strömsignalerna från ström­shunten. För optimering av funktion samt öka kunskapen och insikten kring detta.
Grönt är INA226´s sampling av mätdata ca 3,5kHz, Lila = 1% duty-cycle 30Hz PWM-strömpuls (solladdregulator), Blå = en filterkonfiguration & Röd = en annan filterkonfiguration.
Den röda kurvan sprider ut strömpulsen mjukt över längre tid så den hinner samplas fler gånger för bättre mätprecision. Att den svänger en del gör inget så länge summan (med tecken) av areorna mellan kurvan och 0V X-axeln motsvarar korrekt mätt Ah-summering dvs arean för PWM-strömpulsen, vilket det ser ut att göra. Får ju även medelvärdet för 1024 sådana samplingar som motsvarar ca 35st 30Hz cykler, så svängningen blir helt bortfiltrerad på så sätt.
Skulle vilja ha längre tidskonstant för filtret, men INA226 strömmätingångar får max ha 20-22Ω total filterresistans samt lägsta LSB mätspänning är 2.5µV som gör det svårt ihop!
Men ur detta får jag till lite ytterligare förbättrad mätprecision för strömmen vid aktiv PWM.

KiCad simulering filter
ESP32-batterimonitor KiCad simulering filter

2023-09-02
Simulerat mer med KiCad Spice och utvärderat 3st olika samplingfrekvenser mot det analoga strömsignalfiltret. Ser att den högre ca 3,5kHz samplingen är bra vid PWM-strömpulsladdning samt att en 2ggr högre samplingfrekvens än jag haft hittills samverkar bättre med filtret för mer exakt strömmätning, så ändrat till det för aktiv batteridrift. Behåller den tidigare långsammare samplingen för energisparläge vid nattdrift. Så simuleringarna har därmed hjälpt mig att både optimera programkoden i batterimonitorn och det analoga strömsignalfiltret för ökad mätprecision för strömmen! Så nu analyserar programkoden den momentana batteridriften och växlar mellan tre olika samplingfrekvenser och driftslägen automatiskt. Ser bara så fint ut!
På så sätt utnyttjar jag även INA226-strömsensorns prestanda och möjligheter optimalt.

KiCad simulering filter
ESP32-batterimonitor KiCad simulering filter

Är jäkla intressant med mitt ESP32-baserade "Ultra-precise Battery System Monitor" hobbyprojekt som mäter ström stabilt nere på mA / mAh nivå med bra upplösning!
Så kan väldigt detaljerat följa mitt utrangerade gamla (2016-01-23) startblykolbatteris drift i mitt lilla experiment off-grid solcellssystem här hemma.

Under hela sommaren har lägsta stabil TailCurrent vid fulladdat batteri och aktiv strömbegränsande reglering via PWM-solladdregulatorn sjunkit och är nu nere i ca 110mA dvs 0,25% av de 44Ah i batteriet.
Det bör innebära att PWM-strömpulsladdningen fortsätter att långsamt återbilda gammal sulfatering i blybatteriet, vilket även ström- / spännings-responsen under drift antyder.
Så vid de rätt grunda urladdningar (laddar bara mobilen) så beter sig detta gamla blybatteri som nytt ström- och spännings-mässigt! Laddar väl ur ned till ca 92-93% SoC då och då, mätt mot dess nominella 44Ah C20-kapacitet.
Har inte testat hur det reagerar vid lite djupare urladdning då det är så pass gammalt och inte till för denna typ av drift.
Jag får just nu 100% uppmätt batt­eri­verk­nings­grad vid små urladdningar som jag misstänker beror på små mätfel orsakade av långa signalkablar mellan strömshunt och INA226-sensor i den temporär ex­peri­ment­upp­kopp­ling­en här hemma. Men skulle även delvis kunna bero på att PWM-strömpulsande desulfatera blybatteriet så man via det når TailCurrent lite tidigare.

Jag har byggt ihop en kommunikation mellan min batterimonitor och PWM-solladdregulator, så batterimonitorn får väldigt exakt info om när regulator aktivt PWM-strömpulsar för att begränsa laddströmmen. Indikeras även med grön LED.
Samt använder en TailCurrent < 220mA / 0,5% vid aktiv PWM-pulsreglering som indikering för fulladdat blybatteri, vilket ger väldigt bra precision i 100% SoC synkning till fulladdat blybatteri!
Har därmed en bra marginal mot hur lågt TailCurrent går ned till i aktiv float-laddning som nu de 110mA.
Är 0,5% TailCurrent så vid aktiv strömreglerad float-laddning som indikerar fulladdat blybatteri med bra precision, vilket man inte kan få bara baserat på batterispänning + TailCurrent.

Sägs att lägsta TailCurrent så ökar hos åldrade blybatterier men är inget jag ser här eller heller sett hos min gamla fritidsblybatteribank ens vid 9 års ålder på den. Är kanske pga nyttan PWM-strömpulsladdningen gör?
Men min batterimonitor utvärderar det adaptivt kontinuerligt och anpassar helt automatisk TailCurrent gränsen uppåt för 100% SoC fulladdat blybatteri om det behövs för funktionen.

Har köpt ett nytt AGM-blykol batteri avsett för djupurladdning och solcellsdrift som även klarar av typ längre UPS-standby drift bra med fin livslängd, så bör bli perfekt här hemma.
Så ska snart flytta över mitt hemmasystem till det och får då även som lite mer riktig reservkraft här hemma på 12V 90Ah.
Samt blir lite mer korrekt blybatteridrift för solcellssystemet att utvärdera mot!
Men ser ju även med startblykolbatteriet så intressanta egenskaper blykol ger.

Kom nu vid 17:40-tiden precis ned i ca 90mA / 0,20% TailCurrent vid 5,5% Duty-Cycle PWM-strömpulsande, lägsta hittills :-)
Varit fint soligt hela eftermiddagen.

2023-10-16
Har ändrat till ett par svenska officiella NTP-tidsservrar för synkning av ESP32-RTC:
const char* ntpServer1 = "ntp.netnod.se";
const char* ntpServer2 = "ntp.se";
const char* ntpServer3 = "europe.pool.ntp.org";
Kör nu med denna kombinationen av netnod.se, ntp.se och ntp.org vilket fungerar bra!
Känns vettigt att ha från några olika väletablerade tidsserverdomäner!
Enligt rekommendation ska netnod.se vara allra bäst att använda sig av i Sverige.
Netnod har ett samhällsuppdrag i Sverige att gratis leverera exakt tid över internet, finansierat av Post- och telestyrelsen (PTS).
Samt har nu verifierat att växlingen från bulk-laddning till PWM-pulsande 14,50V aborptionsladdning ger exakt samma uppmätta ladd­ström­värde i helt stabilt fullt solsken, där laddningen segade sig väldigt långsamt upp mot de 14,50V med konstant laddström.
Då växlas INA226´s sampling från 1024x2x588µs till 4x1024x2x140µs som då ger samma mätvärden direkt efter växlingen precis som tänkt, för att sedan långsamt sjunka då laddströmmen begränsas för att hålla konstant reglerad 14,50V laddspänningen för batteriets temperatur.
När den efter ett tag reglerar med ca 80% duty-cycle PWM-pulsat håller de uppmätta strömvärdena sig väldigt stabilt, vilket indikerar att 30Hz strömpulsandet mäts med bra precision såhär!
När jag tidigare mätte 30Hz strömpulsande med INA226 samplande 512x2x1,1ms så fick jag någon sorts interferens så uppmätt strömvärde varierade mycket, vilket såg ut som om regulatorn svängde rätt mycket i sin reglering men var då mätfel.
Så är bättre mätprecision nu, precis som KiCad Spice simuleringarna här ovan visade på!

ESP32-batterimonitor
ESP32-batterimonitor 24h statistik

Jag hade väldig nytta av denna 24h driftsstatistik när jag var ute och fricampade inne längs småvägar i Östgötsk skogsnatur under 7 dygn i början av September. Kom då aldrig under 14 dygns kvarvarande driftstid för 24h Time-To-Go prognosen, och låg flera av dagarna på 3-4 veckors kvarvarande driftstid i det hyfsat soliga vädret med bl.a. 12V kom­pressor­kyl­skåp i drift.
Samt kunde fint se mätvärden på senaste 24 timmarnas förändring i Ah / Wh laddnivå i batteribanken (24hr ΔCHARGE) så jag såg tendensen för laddnivåns utveckling, dvs hur många Ah / Wh man gått plus eller minus senaste 24h.
Laddnivån i batteribanken pendlade mellan ca 70% och 93% SoC där mina AGM-blykol batterier hela tiden tog emot full laddström från solpanelerna under hela den turen, dvs en PSoC-drift under de 7 dygnen som AGM-blykol tål så bra (PSoC: Partial State of Charge).
Min Ultra-precise Battery System Monitor ger riktigt bra nytta under sådan off-grid solcellsdrift!

ESP32-batterimonitor
ESP32-batterimonitor driftsdata under off-grid fricamping


2023-10-18
Har kodat om, gjort code refactoring, av koden för SSE (Server-Sent Events) ihop med biblioteket ESPAsyncWebServer-esphome ver.3.1.0. Hade gjort en "smart" kodning där jag slog ihop 2-4st datavärden separerade med "|" till en sträng jag skickade via SSE AsyncEventSource::send() till webbsidan där JavaScript avkodade det.
Men visade sig att avgPacketsWaiting() då visade på mycket köande av data som gjorde överföringen extremt långsam samt att kodbiblioteket fick kodkrascher då och då av detta.
Så nu gjort om så att jag bara skickar ett enda datavärde via varje SSE AsyncEventSource::send() samt bara om det är ett nytt förändrat värde.
Så långt provat ett par dagar har det fungerat stabilt och snabbt i dataöverföringen till webbsidorna, kanske ihop med nya förbättrade version 3.1.0 av ESPAsyncWebServer. Men krävs typ ett par veckors drift innan det går att avgöra mer säkert om detta löst de lite sällsynta kodkrascherna vid visade webbsidor.
Ska ändå prova med WebSockets för nästa webbsida med inställningar för ESP32-batterimonitorn!
Är fortfarande en hel del som pekar på att WebSockets är stabilare i detta kodbiblioteket!
De nya svenska officiella NTP-tidsservrarna jag nu synkar ESP32-RTC mot fungerar också distinktare och snabbare, så bör ge mindre konkurrens om ESP32-WiFi ihop med SSE vilket även det kanske minskar risken för kodkrasch?

2023-10-19
Lagt in SSEpulse-indikering på alla webbsidorna så ESP32 vet när någon webbsida visas aktivt i webbläsare. ESP32 kan på så sätt hålla webbservern aktiv så länge någon av webbsidorna visas aktivt.
Även skapat en ny Configuration-webbsida för inställningar av ESP32-batterimonitorn, tom än så länge. Ska bli data via WebSockets.

2023-10-20
Håller nu på att lär mig WebSockets kommunikation mellan ESP32-webbservern och dess webbsidor visade i webbläsare. Har kört med SSE (Server-Sent Events) hittills.
Blir en tvåvägskommunikation som även bör kunna hantera större mängd data.
Ska nu först göra en Configuration-webbsida där jag i mitt ESP32-batterimonitor projekt kan göra inställningar för batteribankens kapacitet, strömshuntens data, etc.
Här en första test bara att få igång WebSockets och se att jag lyckas få det att fungera utifrån givet exempel.
När jag har webbsidan upp både i mobilen och på datorn och jag klickar på tryckknappen i mobilen så växlar "State: ON/OFF" direkt via WebSocket-kommunikation Webbsida-ESP32-Webbsida samt uppdateras samtidigt på datorn :-)
Så en bra smidig realtidskommunikation mellan samtliga aktiva webbsidor på olika enheter!
Gick förvånansvärt smärtfritt, snabbt och smidigt att komma såhär långt. Känns riktigt skoj och lovande!
Är utifrån denna artikeln: ESP32 WebSocket Server Arduino – Control GPIOs and Relays
Har här både SSE-pulse indikering (den lilla grå pricken som blinkar) samt WebSockets parallellt i drift på samma webbsida, så de olika teknikerna går att köra parallellt samtidigt.

ESP32-batterimonitor - WebSocket
ESP32-batterimonitor - WebSocket kommunikation test


2023-10-22
Kommit lite längre nu med WebSocket och Configuration-webbsidan.
När jag nu är inne på tredje dagen med kodande / lärande av WebSocket så känns det riktigt intressant och ger flera fina möjligheter till kommunikation server-webbsida-server och därmed möjlighet till väldigt fin funktion.
Samt hyfsat lätt att greppa, koda och få i funktion tycker jag!
Visar här två skärmdumpar från den webbsidan med WebSocket jag kodar nu i ESP32.
"State: ON" är en del av förlagan i artikeln jag utgår ifrån och har jag bara kvar där temporärt medan jag lär mig och utvecklar detta, så kan jag testa av toggling av den ON/OFF via knapptryckning på ena enheten och se att den infon uppdateras samtidigt på alla enheters skärmar som har webbsidan aktiv visad vilket är lite coolt. Ska utnyttja den WebSocket-funktionen till lite annat sedan.
Jag färg-kodar "Save Data" tryckknappen så den visar grönt när all data är sparad och rött så fort något värde för konfigureringen är ändrat och ej sparat, så det syns tydligt.
Växlar tillbaka till grönt först då datan verkligen har sparats i ESP32-flashminnet och returnerar då ett OK från ESP32 via WebSocket till webbsidan som först då växlar till grön bakgrund.

ESP32-batterimonitor - WebSocket
ESP32-batterimonitor - WebSocket kommunikation
ESP32-batterimonitor - WebSocket
ESP32-batterimonitor - WebSocket kommunikation

2023-10-23
Lite mer färdig layout på Configuration-webbsidan:
Detta är de få inställningar som min ESP32 Ultra-precise Battery System Monitor behöver!

ESP32-batterimonitor - WebSocket
ESP32-batterimonitor - WebSocket kommunikation

2023-10-24
AGM-blykol (lead-carbon) uppmätt 97,8%(Ah) / 92,4%(Wh) batteriverkningsgrad:
Hämtat driftsdata från ESP32-batterimonitorn i mitt off-grid solcellssystem från sju dygns fricampande i husvagnen 5-11 September 2023.
Under turen blev batteribanken aldrig helt fulladdad så fick sju dygns PSoC-cyklande mellan ca 95% och 70% SoC laddnivå, vilket är jättebra för utvärdering av batteriverkningsgraden med hög precision! Och detta då i verklig cyklisk solcellsdrift med 12V kompressorkylskåp m.m.!
Mina 2x106Ah Victron lead-carbon AGM-blykol i 12V parallelldrift jobbade då med en batteriverkningsgrad på hela 97,8%(Ah) / 92,4%(Wh), vilket är jättebra för blybatterier! Speciell vid så pass grund cykling som max 29% DoD (71% SoC)!
Lägst laddnivå var 71% SoC / -61,5Ah samt totalt cyklad urladdning var -213,1Ah under veckan.
Batterimonitorn summerar totalt urladdade Ah så när batterierna cyklas fram och tillbaka under flera dygn i PSoC-drift innan de tillslut blir fulladdade igen.
Nu är mina AGM-blykol strömpulsladdade via en PWM-regulator, vilket ger bättre batteriverkningsgrad och bättre laddmottagning högre upp i SoC mot fulladdat. För enkla öppna fritidsblybatterier gör det signifikant skillnad med jag vet inte hur mycket blykol påverkas av det.
Var en hyfsat solig vecka med många stunder med helt klart solsken samt en del soldis och lite lätt molnigt kortare stunder i vacker skogsbygd.
AGM-blykol batterierna tog emot full laddström som kom från mina 250Wp + 40Wp solpaneler utan att PWM-solladdregulatorn behövde strypa strömmen någon enda gång under veckan!
Det innebär att mina AGM-blykol ger samma effektivitet som LiFePO4 hade gjort i min drift, men i mitt tycke med en enklare mer bekymmersfri drift! Så riktig skoj att få mätt det av min ESP32-batterimonitor!
Den uppmätta Batteriverkningsgraden används i batterimonitorn för att kunna få riktigt bra precision på mätt laddstatus!
Efter nästan två månaders skarp drift nu fanns inget synligt minnesläckage för kodexekveringen i ESP32, trots att det ofta hävdas att det blir så med C++! Samt ESP32 har inte rebootat utan haft 100% stabil drift. Känns bra! Ska jag bara få det kring WiFi, webbservern och webbsidor helt 100% stabilt också, vilket ger kodkrasch någon sällsynt gång typ 1ggr/14dygn vid frekvent visande av driftsdata via webbsidorna. Men nått lång även där nu - verkar vara något med WiFi eller Serial.print() nu som bråkar. Ska testa Serial.end() och se om det gör skillnad!
Idag blev även den s.k. "coup-de-fouet" effektens initiala spänningsdipp vid urladdning väldigt tydlig då batterispänningen snabbt sjönk ned till 12,15V initialt, för att sedan hämta sig igen efter lite mer urladdning. En djup "coup-de-fouet" effekt innebär dels att blybatterierna är riktigt 100% SoC fulladdade, samt dels att blybatterierna är i riktigt bra kondition!
Så en bra signal från min AGM-blykolbatteribank, kanske något jag även borde logga i min ESP32-batterimonitor? Kan användas som ett värde på SoH (State of Health) för blybatterier: Battery state of health estimation through coup de fouet, så kunde kanske ge en bild av batteribankens hälsa över tid?

Victron lead-carbon efficiency
ESP32-batterimonitor - Victron lead-carbon AGM-blykol batteriverkningsgrad

2023-11-07
Installerade ytterligare en solpanel till mitt lilla experimentella off-grid solcellssystem i lägenheten, denna på 45Wp. Så har nu 40Wp + 45Wp innanför fönsterrutor (som dämpar ca 50% av solenergin med sina energiglas) i SydVäst-läge. Ger nu ca 2,5ggr mer ström, så tydligen fungerar den nya solpanelen lite bättre innanför fönsterglasen.
Blir lite bättre med ström för bra utvärdering av min ESP32-batterimonitor samt för AGM-blykol batteriets drift. Bör även fungera något bättre under vintermånaderna nu! Den nya solpanelen sitter även lite bättre placerad så den får vintersol lite tidigare utan trädskugga.
Blev tydligt bättre med laddström nu så kändes skoj, vilket även syns på batterimonitorns webbsida "Latest 24hr running statistics" efter ett drygt dygns drift 2023-11-07:

Latest 24hr running statistics
ESP32-batterimonitor - Latest 24hr running statistics 2023-11-07

2023-11-13
Yes, nu tror jag att jag löst att min ESP32-batterimonitor med webbserver glest kraschat när jag växlar visad webbsida i webbläsaren, vilket gäckat mig länge nu!
När man klickar på webbsidans meny för att visa en annan webbsida så kan man råka klicka dubbelt på en sådan länk och då skickas två nästan simultana request till ESP32-webbservern, vilket den då blir överbelastad av och man får en kodkrasch. Är nog störst risk i mobilen.
Samma skulle kunna hända om man visar ESP32-webbsidorna på flera olika enheter samtidigt typ mobil och laptop och användarna där råkar klicka på länk till ny webbsida i menyn i stort simultant.
Så nu har jag både i webbsidornas html-kod spärrat detta samt även om man skulle råka trycka två olika meny-länkar nästan direkt simultant.
Samt jag har även nu lagt in i ESP32 C++ koden för webbserverns funktion så att simultana request för webbsidor där fördröjs 1500ms sedan senaste request innan de skickas till webbläsaren, om de nu kommer tätare än så. Annars skickas webbsidan direkt som vanligt.
Men tar ju några veckors drift innan jag kan känna mig hyfsat säker på att detta var lösningen på det problemet, då jag på senare tid bara fått sådan kodkrasch ca 1ggr/14dagar.
De exempel med webbserver i ESP32 jag hittat visar bara för en enda basic webbsida, så sådant här måste man lista ut själv och lära sig vilket inte är helt enkelt.
Men en bit till på väg mot helt stabil kodfunktion även med webbserver igång och webbsidor visade i webbläsare.
Övrig egen kod har fungerat helt stabil i verklig drift nu i mitt off-grid solcellssystem sedan i somras. Även helt utan något minnesläckage!

2023-11-14
Har idag kört en stresstest med 3st enheter uppkopplade samtidigt flera timmar mot ESP32-webbservern samt bläddrat mycket mellan webbsidorna på servern i ESP32-batterimonitorn, och allt fungerade stabilt och med bra respons.
Har inte varit helt stabilt förut, så en bra indikering på att stabiliteten blivit signifikant bättre. Känns lovande!

2023-11-20
Har idag tagit "mod" till mig och kopplat den högeffektiva MP1584EN DC-DC 3A step-down omvandlare direkt till +5V på ESP32-kortet, justerad till 5,0V utspänning. Det sänkte strömförbrukningen i light-sleep för min ESP32-batterimonitor till 6mA, vilket ger knappt 8mA genomsnittligt förbrukning i night-mode energispardrift med stor del av tiden i light-sleep mellan strömavläsningarna och beräkningarna 1ggr/2,2s!

2023-11-24
Andra dagen med lite sol som märktes för blykol-batteriets laddstatus här hemma i mitt lilla experiment off-grid solcellssystem :-)
Annars har det nästan dagligen laddats ur lite sedan många veckor tillbaks så det varit nere på 68% SoC som lägst nu enligt min ESP32-batterimonitor.
Motsvarar nog närmre 2 månaders urladdning med strömmen från PWM-solladdregulatorn, min ESP32-batterimonitor samt 2st Battery Reconditioner elektronikboxar. Jag har i en annan Dashboard-webbsida än de jag visar här med en tidräkning sedan senast fulladdning, men nu håller jag på att utveckla min programkod / firmware så batterimonitorn startas om lite då och då när jag laddar in ny kod, så kan därför inte se hur länge sedan det var.
Är inte så många timmar/dag som solen når mina solpaneler direkt nu, samt stor del av den tiden lyser den låga solen genom en stor lövträdkrona. Så max ström ↑+0.928A känns bra (av max ca +2A på sommaren), samt +1.309Ah/24hr ΔCHARGE hyfsat ändå idag.
Jag gillar min Dashboard-webbsida "Latest 24hr running statistics" där jag får bra data och aggregerad statistik över senaste 24h driften! Så ser väldigt tydligt hur laddningen utvecklat sig, hur mycket Ah/Wh som laddats ur/i batteriet senaste 24h (24hr ΔCHARGE) samt hur lång återstående laddtid det är med den senaste 24h solpanelströmmen (TIME TO GO) som nu visar ↑08d20h. Eller annars återstående driftstid, typ ↓35d15h.
Ger bara så mycket mer info och bättre överblick över batteri­driften än bara precis Ah- och SoC-laddstatus samt Time-To-Go för den momentana ur­ladd­nings­ström­men som nu kvällstid!
Där kan jag se att senaste 24h var lägsta batterispänning ↓12.241V, vilket motsvarar ca 70% SoC enligt SoC-Volt-tabellen för blykol-batteri under svag urladdning, vilket väldigt bra motsvarar lägsta uppmätta SoC på ↓70% samma 24h period.
Så verkar som att långtids­stabili­teten i batteri­monitorns ladd­status­mät­ning har bra precision :-)
Har nu 7st Dashboard-webbsidor i ESP32 mikrokontrollerns webbserver. Fortsätter att utveckla detta, nu senast med tvåvägs-kommunikation via WebSocket mellan ESP32 och webbsida för inställningar. Samt optimerar och säkrar koden lite ytterligare.
Så ett kul hobbyprojekt att utveckla vidare nu under vintern :-)

Latest 24hr running statistics
ESP32-batterimonitor - Latest 24hr running statistics 2023-11-24
Configuration
ESP32-batterimonitor - Configuration & Menu

2023-12-01
Kodat så det nu används 2st I2C-seriebussar, en separat för Olimex LCD-modulen som har lite svårt för samverkan med andra enheter på samma I2C och en för INA226-strömsensorn. Blev riktigt bra och får därmed en betydligt mer aktiv snabbare kommunikation då jag slipper lägga in pauser mellan de två enheternas I2C-kommunikation. Var snabbt och enkelt gjort!
Vid nattströmspardrift med light-sleep blev nu den lilla vakna stunden när INA226-interruptet väcker upp ESP32 signifikant kortare så kunde ta upp mot 12-15s innan Task_LCDbuttonsHandler´s asynkrona knappavkänning var 250:e ms kom i interferens med det korta aktiva fönstret och kunde väcka upp batterimonitorn från strömsparläget.
Så fick införa FreeRTOS xTaskAbortDelay(TaskLCDbuttonsHandler) som "Forces the task to leave the Blocked state of the xTaskDelayUntil()", så jag därmed kunde få en synkroniserad avkänning av tryckknapparna med när koden exekverar i det korta aktiva fönstret, vilket blev jättebra! Så blir funktionen kodmässigt helt bra, vilket skulle varit där redan tidigare!
Kräver lite speciell hänsyn vid kodningen: Be careful when using xTaskAbortDelay() along vTaskDelayUntil()!
Känns som detta även lite ytterligare ökar stabiltiteten / robustheten i koden så kodkraschrisken ytterligare minimeras samt reboot vid eventuellt kodproblem helt säkert alltid kan genomföras.
Stresstestat ESP32-webbservern med att visat dess webbsidor på 4st olika enheter samtidigt under en längre tid och bläddrat mellan de olika webbsidorna. Fungerade helt stabilt och bra, med bara något lite segare uppdatering av data! Vid tidigare tester har det lett till kodkrasch, så fått till bra stabilitet nu!
Minnesbelastningen blev då:
84.636b som lägsta lediga heap-minne.
73.716b som största allokerbara heap-minnesfält.
>120.000b (44%) ledigt heap-minne.

2023-12-05
Är svårt att få funktionen med xTaskAbortDelay() stabil ihop med Light-Sleep utan har fått glesa kodkrascher nu med den ett par ggr/dygn.
Provar lite olika lösningar men kanske får jag byta till xQueueSend() istället?
Provar just nu med vTaskDelay(2 / portTICK_PERIOD_MS); efter, som delegerar tid till andra FreeRTOS-Tasks.

2023-12-08
Funktionen xTaskDelayUntil(&xLastWakeTime, xFrequency); i Task_LCDbuttonsHandler() i kombination med xTaskAbortDelay(TaskLCDbuttonsHandler) där Light-Sleep strömsparläget hanteras ger tyvärr glesa kodkrascher, så inte stabilt för den typ av drift!
Så har nu bytt till xQueueReceive(LCDbuttonsHandlerTrigQueue, &LCDLoopTrigQueue, xTicksToWait); i Task_LCDbuttonsHandler() med logik som ger repeterbar 250ms loop-time med xTicksToWait, samt ihop med xQueueSend(LCDbuttonsHandlerTrigQueue, &LoopTrigQueue1, pdFALSE); där Light-Sleep strömsparläge hanteras för synkron avläsning av tryckknapparna där. Och det har fungerat helt stabil i dryga dygnet nu samt ger lika stabil 250ms cykeltid för avkänning av tryckknapparna som med xTaskDelayUntil()!
Och tryckknapparna känns av stabilt varje gång i det väldigt korta aktiva fönstret där ESP32 läser av data fråm INA226-strömsensorn samt bearbetar den och visar på LCD-displayen under i övrigt Light-Sleep, så man enkelt kan väcka upp från strömsparläget till aktiv drift.

ESP32 deferred interrupts processing
ESP32 deferred interrupt processing - strömsparläge med Light-Sleep
Wakeup-time Light-Sleep har fint stabil repeterbar tid!

2023-12-13
Med drygt 4 dygns kontinuerlig drift nu helt stabilt igen visar det att kombinationen xQueueReceive(LCDbuttonsHandlerTrigQueue, &LCDLoopTrigQueue, xTicksToWait) och xQueueSend(LCDbuttonsHandlerTrigQueue, &LoopTrigQueue1, pdFALSE) för Task_LCDbuttonsHandler() fungerar OK så att dess normalt asynkrona drift kan triggas synkront från Light-Sleep strömsparfunktionen.
Dock är det lite överarbetat med en Queue-funktion här då det inte finns något behov av att sända någon data, men använder den redan på annan plats i koden så var snabbt att testa med! Egentligen skulle en Binary Semaphore användas för detta, men "Direct To Task Notifications" verkar än bättre.
Så ska testa med "Direct To Task Notifications" för effektivare kod: "Unblocking an RTOS task with a direct notification is 45% faster and uses less RAM than unblocking a task with a binary semaphore."
Görs via ulTaskNotifyTake() / xTaskNotifyGive().
Gav perfekt funktion direkt med "Direct To Task Notifications" samt ren tydlig enkel kod, så bara att testa om driften håller sig stabil under några dygn nu utan kodkrasch!
Och sedan rensa upp koden för att behålla detta, code refactoring.
2023-12-14
Nu 28h kontinuerlig drift med "Direct To Task Notifications" och det fungerar helt stabilt med riktigt bra tänkt funktion!
Läst lite mer om Direct To Task Notifications och den är avsedd just för denna tillämpning jag gör här, se kodexempel.
2023-12-18
"Direct To Task Notifications" fortsätter att fungera helt stabilt! I nattströmsparläge är ESP32 99,8% av tiden i light-sleep och 0,2% av tiden aktiv med att läsa av mätdata från INA226-strömsensorn, bearbeta dessa samt uppdatera LCD-displayen med. Samt via "Direct To Task Notifications" känner då även ESP32 synkront av tryckknapparnas status, och om någon är nedtryckt så går den ur energisparläget och blir aktiv 100% av tiden. Och då arbetar FreeRTOS Task_LCDbuttonsHandler() helt asynkront och känner av tryckknapparnas status 1ggr/250ms för en responsiv känsla oberoende av övrig kodexekvering.
Har tidigare sänkt ESP32-processorns klockning till 80MHz under strömsparläget, men provad nu att köra 240MHz (max) och det gav en gnutta lite lägre strömförbrukning för strömsparläget! Så kör så nu. Då kanske strömsparläget närmar sig 99,9% tid i light-sleep?
Då drar min ESP32-batterimonitor från 12,5V matning bara 6mA i nattströmsparläget, väl under mitt mål på <15mA!
Har nu även provat att istället för CONV_TIME_1100 behålla CONV_TIME_588 & AVERAGE_1024 för INA226 under nattströmsparläget, och nu med den snabbare dataavläsning med 2xI2C så påverkades strömförbrukningen minimalt i strömsparläge och är fortfarande väl <7mA.
Med CONV_TIME_588 får batterimonitorns INA226 lite noggrannare avläsning av dynamiska strömvärden då det samspelar bättre med RLC-filtret!
Så när det nu påverkar strömsparlägets strömförbrukning minimalt behåller jag det. Kan nog då senare även förenkla och rensa programkoden lite via en code refactoring.
2023-12-20
Har gått igenom koden noga för Task_LCDbuttonsHandler() ihop med StateMachine() och optimerat för strömsnålast och bäst responsiv tryckknapp-funktion under strömsparläge med Light-Sleep. Blev riktigt bra och en märkbar förbättring mot tidigare!
Innan dessa senaste code refactorings hade jag inte kodat för synkron avkänning i det lilla tidsfönstret då ESP32 är i aktiv drift under light-sleep i strömsparläget, så var inte helt responsiv då med avkänning av trycknapparna varje sådan kort period med aktiv processor!
Optimeringarna nu gjordes via noggranna mätningar av kodfunktionen i drift, så riktigt fint tekniskt utvärderat! Nu även något lite strömsnålare i natts­tröm­spar­läge med light-sleep, och framförallt mäter dynamiska strömvärden med bättre precision nu i strömsparläget!
2023-12-21
På min ESP32-batterimonitor från off-grid solcellssystem har jag här hemma kopplat om så DC-DC-omvandlar matar 5V direkt till ESP32-kortet utan att gå via dess 5V-regulator, och där har jag inte haft någon kodkrasch på länge men har inte det lika mycket i drift heller.
Så ska göra samma omkoppling på det i solcellssystemet här hemma, då det kanske kan vara en bidragande orsak att ESP32´s driftspänning kanske droppar för mycket ibland med WiFi och webbserver igång.
Med direkt 5.0V från DC-DC-omvandlaren har ESP32 där 3,3V matningsspänning, medan där jag matar via 5V-regulatorn är det 4,5V resp. 3,2V.
I strömsparläge 99,5% tid i light-sleep ned till 95% beroende av hur mycket som skrivs till LCD-displayen, men >99% i snitt.
Dock är denna tidsdata utskriven via Serial.print() som också tar lite exekveringstid:
Active CPU-time in Light-Sleep (us): 6121, Cycle Time (ms): 1207, Time-quota (%): 0.51.
Gjort lite code refactoring typ Task Stack Size optimering, eliminerat ytterligare några fall som kanske kunde ge Division by Zero (fick en sådan kodkrasch nyss, men inte haft på länge vad jag vet) samt optimerat / förtydligat en del beräkningar, etc.

2023-12-29
Espressif32 systemprogramvaran blev uppdaterad till ver. 6.5.0:
- Platformio / Platform-Espressif32 v6.5.0
- Arduino Release v2.0.14, lite fixat i WiFiClient som kan vara bra för mig
- Espressif ESP-IDF Release v5.1.2, a bugfix update
Och nyligen kom också PlatformIO IDE 3.0 for VSCode och har nu PlatformIO 3.4.4.
Är väldigt många mikrokontrollers som stöds nu: Platformio/Espressif32/boards.
Med Espressif32 v6.5.0 minskade SRAM-användningen med ca 30% (!), både lägsta ledigt under exekvering, största allokerbara minnessegment samt totalt ledigt minne under exkevering i mitt projekt! Är väldigt positivt!
Jag har även gjort en helt ny Hard-reset-handler placerad i Setup()-funktionen, så även soft-resets görs till hard-resets. Detta då ESP32 flera gånger hängt sig när den av någon anledning själv bootat om med soft-reset. Jag loggar nu även 8st olika händelser som får ESP32 till att boota om, så jag får bra statistik på vad som är orsaken, om det nu skulle inträffa.
Målet är att ESP32 aldrig själv ska boota om!
Jag har även äntligen börjat hitta mer info om hur jag ska koda WebSocket för en multi-webbsides webbplats i ESP32! Så känns som det börjar lossna lite där också.
Ska gå över helt till WebSocket från att jag nu använder SSE (Server Side Events)!

2023-12-31
Har uppdaterat kod-blockschemat för ESP32-batterimonitor delen i PWM-solladd­regulatorn med den senaste kodutvecklingen. Har bl.a. nu senast ändrat så att Task_DeferredInterruptIN226() nu skickar ett Queue-meddelande till Task_StateMachine() istället för att direkt anropa StateMachine->StateHandler() funktionen. Så nu sker allt via Inter-Task Communication från Task_DeferredInterruptIN226(), så som tänkt!

Förut med direkt funktionsanrop till StateMachine->StateHandler() så vid nattströmsparläge sätts ESP32 i light-sleep inne i den funktionen, vilket medförde att Task_Deferred­Interrupt­IN226() väntade på det och ej exekverade färdigt. Det innebar i sin tur att i Light-Sleep-Mode var då inte Task_Deferred­Interrupt­IN226() i läge att direkt ta emot INA226´s interrupt via dessa ISR utan det skedde en fördröjning där i väntan på att State­Machine->State­Handler() och Task_Deferred­Interrupt­IN226() skulle exekvera färdigt efter att INA226-interruptet väckt upp ESP32 igen från light-sleep!
Nu tar det bara 4-5µs med xQueueSend() till Task_StateMachine() och sedan exekverar Task_DeferredInterruptIN226() färdigt till xQueueReceive() där den väntar beredd på att ta emot nästa xQueueSendToBackFromISR() från INA226-ISR för att läsa av de nya datavärdena från INA226. Det innebär att programkoden nu arbetar mer optimalt och effektivt med bättre precision, samt så asynkront oberoende som är min kodstrategi! Ett bra steg framåt för en riktigt bra kodfunktion!
Trots att detta är rätt avancerad FreeRTOS-funktionalitet krävdes bara 5 kodrader för att uppnå funktionen, vilka fungerade perfekt direkt. En typisk fördel med FreeRTOS kodning!
Nu fungerar det som en charm i hur de olika kodblocken samarbetar med varanda via Task´s.

Har nu även kodat nytt hur programmet hanterar reset (reboot) efter eventuell kodkrasch som ger soft-reset, där programmet nu alltid gör en hard-reset direkt på det i setup() för att säkerställa OK programfunktion igen, efter att först sparat statistik på orsaken samt sparat driftsdata.
Sparar nu 8st olika orsaker till reset (reboot) så man kan följa vad som orsakar det, även om målet är att det aldrig ska inträffa. Samt sparar i flash den viktigaste driftsdatan för själva batterimonitorns funktion, så inget går förlorat där kring batteribankens laddstatus.
Har då lärt mig att man kan inte spara en instans av en class i RTC-minnet via RTC_NOINIT_ATTR utan de datavärdena nollställs när class-definitionen på nytt laddas in. Så har fått gå över till att spara denna data även i separata RTC_NOINIT_ATTR-variabler!
Är noga validerat idag 2023-12-31 och fungerar nu helt perfekt, efter en hel del efterforskning!
Bl.a. lärt mig: "Variable with RTC_NOINIT_ATTR is not initialized at program start to not erase the value stored in the RTC memory." Så gör det i setup() nu för ESP_RST_POWERON.

Samt konstaterar att efter kodkrasch med soft-reset fungerar inte kodens hard-reset OK via att en GPIO drar RST-pin (EN-pin) låg, för det sker troligen för kort stund för OK hard-reset.
"The ESP32 chip enable needs to be low for 150µs at each reset." Guaranteeing a minimum reset pulse with, required to ensure all registers are cleared.
WROOM-32 datasheet: To ensure the power supply to the ESP32 chip during power-up, it is advised to add a RC delay circuit at the EN pin. The recommended setting for the RC delay circuit is usually R = 10kΩ and C = 0.1µF. källa
I ESP32-WROOM Datasheet står det:
"To ensure that the power supply to the ESP32 chip is stable during power-up, it is advised to add an RC delay circuit at the EN pin. The recommended setting for the RC delay circuit is usually R = 10kΩ and C = 1µF. However, specific parameters should be adjusted based on the power-up timing of the module and the power-up and reset sequence timing of the chip."
I Espressif Boot Mode Selection står:
"If this circuitry is implemented (all Espressif boards have it), adding a capacitor between the EN pin and GND (in the 1µF-10µF range) is necessary for the reset circuitry to work reliably. This is shown in the ESP32 Module section of the schematic."
Så en kondensator mellan 0,1µF - 10µF är enligt detta OK för ESP32 EN-pin (reset-pin).
En ESP32-GPIO utgång bör max belastas med -15mA dvs ≥220Ω, för urladdning av 0.1µF.
ESP32 GPIO pins info, restrictions and features - 220Ω x 0.1µF = 22µs, ESP-pullupR≥45kΩ
Så R bör kunna vara åtminstone 1kΩ!
Får prova med ett sådant RC-nät till RST-pin och se om det fixar hard-reset problemet.
Ett sådant RC-nätverk gör även att ESP32 kan boota säkert när stigtiden för matningsspänningen är lite för långsam, då RST-pin hålls låg medan matningsspänningen hinner stabilisera sig.

INA226 samplar nu mätvärden (ström, spänning, effekt) drygt 70.000.000ggr/24h (även i natt-ström­spar­läge Light-Sleep-Mode) dvs ca 1ggr/1,2ms, samt när PWM-regulatorn strömpulsar 30Hz samplar INA226 4ggr så ofta ca 1ggr/0,3ms (3.333Hz) för hög precision i mätningarna då.
Det innebär att ESP32-batterimonitorn mäter även väldigt dynamisk ström med hög precision!
Bidrar till en riktigt långtidsstabil exakt mätning av laddnivån i batteribanken!

2024-01-03
Haft i drift 3,5dygn med senaste kodförbättringarna med den egna koden i drift men utan webbservern aktiv och kan inte se något minnesläckage alls, vilket känns bra för drygt 7000 rader egenskriven C++ kod!
RAM ESP.getMinFreeHeap(): L129.816B
RAM ESP.getMaxAllocHeap: A110.580B
RAM ESP.getFreeHeap: F238.528B (77%)
Har även hela dagen idag återaktiverat WiFi & Webbservern i ESP32 via dess trycknapp en massa gånger från nattströmsparläge (Light-Sleep-Mode) och det fungerar superstabilt nu!

2024-01-05
Äntligen kan jag avkoda de Back-/Stack-Trace jag får vid kodkrasch i ESP32, via tips om en Stack Trace Decoder, vilket underlättar felsökning och kodutveckling framöver nu!
Nu har jag fångat en Back-/Stack-Trace för "Guru Meditation Error: Core 1 panic´ed (IntegerDivideByZero). Exception was unhandled." och avkodat den via ESP Stack Trace Decoder utifrån min firmware.elf fil. Är sannolikt det kvarvarande problem jag har med kodkrasch ibland med webbservern i ESP32 aktiv bläddrandes mellan alla webbsidorna där.
Hade "Guru Meditation Error: Core 0 panic´ed (IntegerDivideByZero)" redan 2023-03-17!
Och det är i ESPAsyncWebServer-esphome/src\AsyncEventSource.cpp:312 den kodkraschen sker, där i min kod rad 6605 anropar min funktion "if (HandlerEventDataSSE(eventsStat24hr, LoopTimeTask)" som i min kod rad 7051 anropar "EventsSSE.avgPacketsWaiting() * EventsSSE.count()" som är i "ESPAsyncWebServer-esphome/src\AsyncEventSource.cpp" där tydligen kodkraschen sker på rad 312 som är i dess funktion "AsyncEventSource::­avgPacketsWaiting()"!

Så är anropet till "EventsSSE.avgPacketsWaiting()" som tydligen resulterar i en IntegerDivideByZero, då det blir det 2:a anropet till "AsyncEventSource.cpp:312"!
Och kodraden AsyncEventSource.cpp:312:
return ((aql) + (nConnectedClients/2))/(nConnectedClients);, där divisionen är!
Så när det är nConnectedClients=0 blir det kodkrasch där!
Är en integer: uint32_t nConnectedClients.
Så är inte min kod som kraschar utan i SSE-koden hos ESPAsyncWebServer-esphome!
Det stärker min tanke på att växla från SSE till WebSocket som en möjlig lösning, vilket jag påbörjat! Men blir SSE stabilt nu får det vara kvar på några webbsidor!
Har läst att WebSocket ska vara stabilare och mer välutvecklat än SSE i ESPAsyncWebServer, men det var långt efter att jag satsade på SSE i mitt kodprojekt ESP32-batterymonitor!

Jag har länge misstänkt ESPAsyncWebServer-esphome kodbiblioteket för dessa kodkrascher och nu äntligen kunnat bekräfta det!
Har provat en liten bugfix där för AsyncEventSource.cpp:312:
return ((aql) + (nConnectedClients/2))/(fmax(nConnectedClients, 1));
som ser till att det inte blir division med zero där, bara som en test om min kod blir stabil då!
(original: return ((aql) + (nConnectedClients/2))/(nConnectedClients);)
Nu har jag idiotbläddrat fram och tillbaka mellan alla min webbsidor i ESP32-webbservern en lång stund, även växlat innan de är färdigladdade, och ingen kodkrasch!
Det har jag inte kunnat förut!
Även nu testat att ha webbservern igång under 4h och regelbundet bläddrat mellan alla webbsidorna helt stabilt!
RAM-minnesbelastningen är då: L126.320B, A110.580B & F159.200B 51% / F236.556B 76%.
Bara så jäkla skönt - då kan jag fokusera på att nu utveckla funktionalitet istället!
Så verkar som den lilla kodfixen i det kodbiblioteket fixade mitt kvarvarande problem!
Då borde jag ju egentligen bidra med den bugfixen till dem efter en längre tids test av den här hemma, men har aldrig gjort något sådant till ett open-source kodbibliotek.
ESPHome skriver om sin webbserver: "Please note that enabling this component will take up a lot of memory and may decrease stability"! Så kanske löst en del av det med min bugfix.
Guru Meditation Error: Core 1 panic´ed (IntegerDivideByZero). Exception was unhandled.

Core 1 register dump: PC : 0x400e07b2 PS : 0x00060430 A0 : 0x800d5990 A1 : 0x3ffe0f80
A2 : 0x00000000 A3 : 0x00000000 A4 : 0x00000000 A5 : 0x3ffb8ec4
A6 : 0x00000005 A7 : 0x3ffe0f9c A8 : 0x00000000 A9 : 0x3ffe0f60
A10 : 0x3ffe0f88 A11 : 0x3ffb8d04 A12 : 0x00000000 A13 : 0x00000000
A14 : 0x00000039 A15 : 0x00000000 SAR : 0x00000011 EXCCAUSE: 0x00000006
EXCVADDR: 0x00000000 LBEG : 0x4008ab5c LEND : 0x4008ab72 LCOUNT : 0xffffffff

Backtrace: 0x400e07af:0x3ffe0f80 0x400d598d:0x3ffe0fb0 0x400d72ce:0x3ffe0fd0
-------
ESP Stack Trace Decoder Output:
0x400e07b2: AsyncEventSource::avgPacketsWaiting() const at D:\bosse\Documents\PlatformIO\Projects\PWMcontroller\.pio/libdeps/wemos_d1_uno32/ESPAsyncWebServer-esphome/src\AsyncEventSource.cpp:312
0x400e07af: AsyncEventSource::avgPacketsWaiting() const at D:\bosse\Documents\PlatformIO\Projects\PWMcontroller\.pio/libdeps/wemos_d1_uno32/ESPAsyncWebServer-esphome/src\AsyncEventSource.cpp:312
0x400d598d: HandlerEventDataSSE(AsyncEventSource const&, unsigned long const&, unsigned int) at D:\bosse\Documents\PlatformIO\Projects\PWMcontroller\src\main.cpp:7051
0x400d72ce: Task_WebServerESP32(void*) at D:\bosse\Documents\PlatformIO\Projects\PWMcontroller\src\main.cpp:6604

Stack-Trace processing
Stack-Trace processing via ESP Stack Trace Decoder

2024-01-09
Jag har nu analyserat den funktionen avgPacketsWaiting() i AsyncEventSource.cpp där detta sker i, i kodbiblioteket ESPAsyncWebServer-esphome. Och de tar egentligen hand om detta fallet precis i början av den funktionen där med check om if(_clients.isEmpty()) return 0;, så detta måste handla om en sällsynt s.k race condition pga preemptive multitasking i FreeRTOS!
Så när ett variabelvärde hinner ändra sig pga FreeRTOS race condition mellan att det checkas precis i början av funktionen till att det används för division i retur-värdet i slutet så blir det sällsynt division med noll.
Då är min kodlösning med fmax() rätt säker då jag där bara använder nConnectedClients-värdet en gång för att undvika division med noll där som ger en Thread-safe lösning:
return ((aql) + (nConnectedClients/2))/(fmax(nConnectedClients, 1));
Från originalet: return ((aql) + (nConnectedClients/2))/nConnectedClients;
Bör finnas en liten risk för även sällsynt race condition med en if-else sats istället, tänker jag!
Om nConnectedClients hinner ändras från att det checkas i if() till att det används i divisorn.
Men bäst vore om man tilldelade värdet till en lokal variabel som sedan används konsekvent genom funktionen! Det blir dels tydligare, dels mer framtidssäkert mot kodningsmisstag om funktionens kod vidareutvecklas. Blir nog även exekveringsmässigt något effektivare. Ville dock inte ändra så mycket i denna koden.
Ett väldigt intressant fall upplever jag, kring svårigheten med att koda för preemptive multitasking med FreeRTOS!
Då har jag lyckats bra i min egen C++ FreeRTOS kodnings 7000 rader, då den kört stabilt i skarp drift fler månader i sträck utan vare sig någon kodkrasch eller något minnesläckage, trots flitig avancerad användning av FreeRTOS´s funktionalitet samt C++ objectorienterad kodning.
Läst på och analyserat lite mer kring denna race-condition i funktionen avgPacketsWaiting() i AsyncEventSource.cpp och nu istället ersatt originalkoden:
return ((aql) + (nConnectedClients/2))/nConnectedClients;
med denna if()-else-satsen då variabeln nConnectedClients är en lokal variable som ej kan ändras av annan kod och därmed är säker mot race-condition:
if (nConnectedClients > 0U)
{
 return ((aql) + (nConnectedClients/2)) / nConnectedClients; // round up
}
else
{
 return 0;
}

2024-01-06
Har nu (äntligen) byggt ett nytt batteriboxsystem runt mitt nya AGM-blykol batteri 12V UPLUS 90Ah Lead-Carbon och installerat PWM-regulator, strömshunt samt el-/USB-uttag och min ESP32-batterimonitor där, allt kopplat till solceller för ström. Även monterat en 12V/230V 100W ren sinus växelriktare, strömsnål och tyst fläktlös.
Gjort ett betydligt bättre och snyggare bygge nu, då det förra var lite provisoriskt som test och snabbt få något att kunna utveckla mot.
Det gamla tog jag i drift 2019-05-05 med mitt gamla Blykol-startbatteri Tudor High Tech Carbon Boost 2.0 från bilen Tudor High Tech TA456 45Ah Flooded, nu det 2:a där i drift köpt 2016-01-23 överflyttat till batteriboxen 2021-03-25 efter drygt 5 års drift i bilen, och fortfarande välfungerande nu 8 år gammalt!

Har varit bra att testköra min ESP32-batterimonitor mot ett så gammalt blybatteri och sett att allt fungerar bra då också, med 0,5% Tail-current för 100% SoC fulladdat m.m.!
UPLUS 90Ah Lead-Carbon är ett AGM-blykol batteri avsett för djupurladdning och solcellsdrift med exceptionellt bra cyklingslivslängd, som även klarar av typ längre UPS-standby drift bra så bör bli perfekt här hemma.
Blir då lite mer korrekt blybatteridrift för solcellssystemet att utvärdera mot, samt får då även som lite mer riktig reservkraft här hemma på 12V 90Ah ca 1kWh!

Idag var det soligt så PWM-regulator kom upp till strömpulsad reglerad laddning >1h idag mot det fulladdade UPUS-blykol. Det innebär att det blev aktiverat och helt 100% SoC fulladdat, en bra utgångspunkt nu att följa dess drift. Ska var flera soliga dagar på rad nu.
Med 0,5% Tail-current (<450mA för 90Ah) som indikering för 100% SoC fulladdat under spänningsreglerad laddning, så kom den redan idag ned i 300mA i 13,8V float-laddning, dvs med 1,5ggr marginal för den utvärderingen. Blir nog än lägre framöver då batteriet aktiverats lite mer av strömpulsad laddning. Skoj att jag nu löst buggen i webbservern som gäckat mig länge, när jag nu börjar följa detta batteriets drift via min Ultra-precise ESP32-batterimonitor!

Min ESP32-batterimonitor har nu varit i drift här hemma sedan 3 Mars 2023, så 3/4 år. Min C++ kod har hela tiden arbetat stabilt utan minnesläckage, men jag har haft problem med stabiliteten hos kodbiblioteket ESPAsyncWebServer-esphome för webbservern i ESP32. Men där har jag nu gjort en buggfix. Givetvis har programkoden förbättrats och förfinats samt fått lite mer funktionalitet under vägen, men har ändå hela tiden loggat laddnivån i blybatteriet fint. Men precisionen har förbättrats något under resan, så nu är den riktigt bra!

batteriboxsystem
Batteriboxsystem 12V 90Ah AGM-blykol drivet av solceller

2024-01-08
Följer den fina data & info jag får över batterisystemets drift i mitt lilla experiment solcellssystem här hemma i lägenheten i dagens solväder för mitt nya fina AGM-blykol batteri 12V UPLUS 90Ah Lead-Carbon.
Nu precis synkade min ESP32-baserade "Ultra-precise Battery System Monitor" sin 100% SoC fulladdat mot fulladdat batteri, och precis sekunden innan det skedda visade den -0,29Ah i laddnivå för blybatteriet!
Och då har jag ännu inte haft en battericykel den hunnit utvärdera batteriverkningsgraden för det, så den använder 100% för det, vilket innebär att med utvärderad batteriverkningsgrad hade den kommit ytterligare närmre 0,0Ah i laddnivå vid synkningen!
Men -0,29Ah för ett 90Ah batteri utgör ändå en högprecisions synkning av 100% SoC, så känner mig nöjd med det.
Så är väldigt tillfreds med den princip jag har för att synka 100% SoC, ihop med de få lätta inställningarna som krävs!
Synkade då vid 99,7% SoC, vilket ju är superbra precision!
Är en del av att min ESP32-batterimonitor ger så bra precision i sin mätning och beräkning av batteribankens laddnivå, ihop med att den använder verklig uppmätt batteriverkningsgrad för varje laddcykel samt en Ultra-precise strömsensor.
Och har aktiverat ESP32-webbservern samt bläddrat bland webbsidorna över driftsdatan för batteridriften rätt många gånger nu senaste dygnet där, inte minst idag, och ingen kodkrasch!!!

Latest 24h running statistics
Latest 24h running statistics

2024-01-09
Soligt väder idag också, och ESP32-batterimonitorn synkade 100% SoC till fulladdat batteri vid -0,166Ah laddnivå, i och för sig bara från -1Ah laddnivå. Men skoj 100% SoC synkningen sker med sådan precision även vid så minimala battericyklingar.

Latest 24h running statistics
Latest 24h running statistics

2024-01-13
Lagt in i programkoden så att den nu loggar dels "Battery Cell Balancing time" (hr/day), dels loggar total driftstid för ESP32-batteriomonitorn. "Battery Cell Balancing time" gäller blybatterier och den tid de befinner sig i aktiv spänningsreglerad drift i antingen absorptions- eller float-laddfaserna. Det är främst då blybatteriets självbalansering av cellerna är aktiv.
Nu har ESP32-batterimonitorn till mitt lilla off-grid experiment solcellssystem varit i drift i drygt 6 dygn sedan bugfixen i kodbiblioteket ESPAsyncWebServer-esphome, där jag flera gånger varje dag bläddrat runt bland dess webbsidor med driftsdata. Och helt fullt stabilt nu utan minsta lilla kodkrasch, samt utan något mätbart minnesläckage eller fragmentering av RAM-minnet!
Är första gången jag kunnat checka minnesläckage / fragmentering över en längre tid med ESPAsyncWebServer-webbservern i drift bläddrande runt bland webbsidorna, då det tidigare lett till kodkrasch! Så ett ytterligare stort steg framåt nu!
Blir skoj nu att kunna fokusera på att utveckla kod / funktion istället för buggletande!
Men det har lett till en bättre kod som även belastar RAM-minnet mindre, så varit bra ändå.
Samt jag har ökat min kunskap och insikt om FreeRTOS-kodning märkbart!

System Operational Data
System Operational Data

2024-01-15
Kodat en till LCD-meny med en displayvy för "Battery Cell Balancing time" plus total driftstid för ESP32-batterimonitorn. Har nu 23st LCD-displayvyer man kan bläddra runt bland, som visar den mesta av de driftsdata man kan se via webbsidorna, där man kan göra konfigurering av ESP32-batterimonitorn samt man kan nollställa loggad mätdata via 2x16 teckendisplayen.

2024-01-16
Med det nya mätvärdet CellBalancing (hr/day) för blybatterier som mäts sedan idrifttagning i min ESP32-batterimonitor har jag nu fått 3 dygns mätning, med en helsolig dag idag:
CellBalancing är den tid som solladdregulatorn aktivt reglerar batterispänningen och stryper strömmen från solpanelerna. Det är främst då som blybatteriernas självbalansering av battericellerna pågår. För omvårdande blybatteridrift bör man ha tillräckligt med sådan tid, men vad tillräcklig är vet jag inte. Har inte hittat något att läsa om det på Internet.
Men tycker det är motiverat att logga ändå.
Senare ska jag även ha 28dagars loggning av driftsstatistik, så då kommer man kunna se den och de andra siffrorna valbart för 1-4 veckor.
Som idag var första dagen med solsken sedan jag började logga detta och det blev då 16min CellBalancering.
Och jo jag har ett litet mätfel i strömmätningen på ca 3mA som beror på någon läckström eller liknande i min hårdvara, så när mitt AGM-blykol batteri här hemma i lilla experiment off-grid solcellssystem nu bara precis cyklas med den ström som PWM-regulatorn, ESP32-batterimonitorn och mina två Battery Reconditioner drar samt den svaga ström solpanelerna ger nu vintertid så påverkar den så jag falskt får mätt 100% batteriverkningsgrad. Men är väldigt grunda battericyklingar då, samt tyder ju på väldigt hög batteriverkningsgrad.
Själva strömsensorn i sig mäter dock helt korrekt är checkat. Vid 0A ström genom strömshunten visar den 0,0000A, så mäter då 0A med fyra decimaler!
Ska snart ta itu med det i hårdvaran och se hur jag kan åtgärda det!
Men redan märker jag att solen börjar ge mer ström nu jämfört med vid midvinter 21 December, så förändrar sig snabbt nu :-)
Dagens max laddström hamnade på +0,787A (av max ca +2A här sommartid) och batteriet blev fulladdat idag med en fin precisions-synkning till 100% SoC fulladdat batteri igen.

Latest 24h running statistics
Latest 24h running statistics
System Operational Data
System Operational Data

2024-01-19
Kodat en säkerhetsfunktion att om INA226 skulle hänga sig och sluta skicka interrupt för ny data att hämta så görs en automatisk soft-reset av INA226 nu.
Är ett led i att uppnå 24/7/365 stabil drift för batterimonitorn!
I experimentuppkopplingen här hemma har jag ca 1m långa kablar mellan INA226 och strömsensorn och det gör att den Battery Reconditioner som sköter om blybatteriet med 9kHz extremt korta kraftfulla strömpulser in i batteriet motsvarande ca 1MHz och lite långsammar 9kHz 3A strömpulser från batteriet för uppladdning mäts fel i sin strömförbrukning! De korta snabba strömpulserna dämpas och når inte helt fram till INA226, så mäter inte riktigt dessa strömpulser som matas tillbaka in i batteriet. Kom på att partvinna dessa mätkablar nog inte var så smart då, så nu särat på dem och ser ut att mäte mer rätt nu, kanske helt rätt. Är svårt att mäta snabbt pulsad ström helt korrekt!
I skarp drift ska dessa kablar vara max 2dm långa, troligen ca 1dm och då EJ partvinnade.
Får se när batteriet blir helt fulladdat nästa gång med 100% SoC synkning. Men redan idag med denna ändring i drift halva tiden sedan senaste 100% SoC synkning kom jag upp på +0,001Ah som max. Bör bli lite mer imorgon, så en rättvis batteriverkningsgrad kan räknas även för dessa låga strömmar.
Idag blev det lite längre PWM-strömpulsad laddning i solskenet och kom då ned i en tail-current på 265mA jämfört med 450mA som är tail-current för 100% SoC synkronisering (0,5% av 90Ah). Så en marginal mot det på 1,7ggr som känns betryggande! Men styrs även adaptivt.

2024-01-20
Beskrev på Facebook ESP32-batterimonitorns kodfunktion (se även kod-blockschema):
Jag har ingen traditionell programloop i min kod, utan loop() från Espressif Arduino-framework raderar jag direkt utan att använda.
Jag kör istället med 5-6st FreeRTOS Task som fungerar ungefär som självständiga program som kan exekvera oberoende av varandra multitaskande via FreeRTOS preemptive multitasking, så i princip samtidigt parallellt.
Så finns ingen programloop där man linjärt i koden kan följa vad programmet gör.

Jag har en Task som fungerar lite liknande en sådan programloop, en "Deferred interrupt processing" Task som triggas av en interrupt från min smarta INA226-strömsensor via en ISR-funktion() ca 1ggr/s när nya aggregerade mätdata finns att hämta, som är den Task där det mesta utgår ifrån. Den sätter sätter pulsen för programmets exekvering och utgör därmed lite av kärnan i programkoden.
Sedan har jag en "Finite-State Machine (FSM)" Task som styr och övervakar i vilket programläge "state" som min batterimonitor ska arbeta i, som styr vilken funktionalitet som är aktiv för stunden och som reagerar både på input från användaren och från annan kodexekvering samt signaler och då även övervakar WiFi när aktiv.

Och i den Task som fungerar lite liknande en programloop anropar jag inga funktioner() som den då måste invänta dess exekvering innan den kan gå vidare i sin egen exekvering, utan allt sker via s.k. FreeRTOS intertask communications "meddelanden" där det snabbt skickas ett meddelande till en annan Task om vad som ska göras och sedan direkt exekverar vidare.
På så sätt kan denna Task snabbt exekvera färdigt sin loop och invänta ny deferred interrupt från INA226 utan att behöva vänta in exekvering av annan kodfunktion!
Medan de Task den skickat meddelande till exekverar parallellt multitaskande med den.

Jag får på så sätt ett program som exekverar väldigt effektivt, med avancerad funktion som är svår att uppnå utan FreeTROS-Task och på ett sätt en tydlig kod.
Men jag tror kodens programfunktion är jobbig att sätta sig in i för någon annan just för att mycket pågår samtidigt nästan simultant! Så man får ha ett sorts 3D-tänk kring kodexekveringen!

Som exempel har jag en Task som läser av de fyra tryckknapparna på mitt LCD-display shield exakt 1ggr/250ms ±0,5ms självständigt helt asynkront med övrig kodexekvering, som ger en väldigt fin responsive känsla i avkänning av nedtryckt tryckknapp. Den skickar då direkt meddelande till Task LCD-display-handler asynkront för snabb reaktion på LCD-teckendisplayen på nedtryckt knapp, utan att behöva vänta in någon annan kods exekvering.
Samt den Task som läser av mätdatan från INA226-strömsensorn skickar genast de nya datavärdena via ett queue-meddelande till Task LCD-display-handler asynkront för snabb uppdatering på LCD-teckendisplayen.
Kommer båda dessa samtidigt så köas de bara upp i den Task som sköter LCD-displayen och exekveras direkt efter varandra.

Ger bara så fin, smidig och bra funktion, så FreeRTOS med sin multitasking är helt underbart för lite mer avancerad programkodfunktion!
Och gör det lätt att koda avancerad kodfunktion!
"This approach enables parallel execution of tasks, reducing the overall execution time and increasing the system´s responsiveness."
"ISR programming enables the system to respond rapidly to critical events by prioritizing interrupt requests. In time-critical applications, such as data acquisition systems or control systems, interrupts can be employed to capture time-sensitive data accurately without compromising the system´s performance." Dvs det jag gör med interrup för avläsning av INA226´s aggregerade datavärden från dess självständiga kontinuerligt upprepade 1024st mätningar.
Jag ska dock via code-refactoring göra Finite-state Machine funktionen tydligare med mer entydig funktion, då jag nu lärt mig mer samt funderat igenom funktionaliteten bättre.

2024-01-23
Råkade göra ett kodningsfel som triggade WDT (Watchdog Timer) och fick då verifierat att loggningen av de 8st olika felorsakerna fungerar som tänkt i setup():
Total Power-ON resets: 46
WDT soft-resets in total: 479
INT_WDT resets in total: 0
TASK_WDT resets in total: 5
Brownout resets in total: 1
RST_SW resets in total: 6
Other resets in total: 0
Panic Hard-Resets total: 12
Är värdefullt för uppföljning av 24/7/365-driften i skarp drift, att kunna se vilka orsakerna är till reset / reboot samt om / hur ofta det förekommer, där målsättningen är noll gånger.
Men är även värdefullt vid utvecklingen av programkoden såhär!
Kom tack vare det på att detektering av ESP_RST_BROWNOUT inte går att spara som statistik i flash-minnet via preferences, då flash-minnet kan bli korrupt vid skrivning när matningsspänningen är för låg! Fångat 2st BrownOut så nu som gjort programkoden i flash korrupt så den måste laddas upp igen till ESP32! Blev då indikerat som rst:0x10 (RTCWDT_RTC_RESET) efter reset, med direkt reset igen i en kontinuerlig loop.
"The RTC watchdog is used in the startup code to keep track of execution time and it also helps to prevent a lock-up caused by an unstable power source. It is enabled by default (see CONFIG_BOOTLOADER_WDT_ENABLE). If the execution time is exceeded, the RTC watchdog will restart the system.
The RTC watchdog covers the execution time from the first stage bootloader (ROM bootloader) to application startup. It is initially set in the ROM bootloader, then configured in the bootloader with the CONFIG_BOOTLOADER_WDT_TIME_MS option (9000 ms by default).

Är många kod-detaljer att upptäcka på vägen, som inte går att läsa sig till på ett lätt sätt!
Nu varit i drift 18 dygn med buggfixen och lite förbättrad kod samt visat ESP32-webbsidorna med driftsdata flera ggr/dag helt stabilt utan någon kodkrasch! Är lite av ett genombrott!
Mäter även strömmen för 9kHz strömpulserna från Battery Reconditioner med bättre precision nu, trots svårmätt då de extremt korta kraftiga strömpulserna motsvarar ca 1MHz så både induktans och kapacitans i ledningarna och strömshunten inverkar negativt.

2024-01-24
Nu har jag kodat så min Configuration-webbsida hämtar data till de olika input-fälten från ESP32 via WebSocket samt uppdaterar batterispänningen kontinuerligt där. Har tagit bort all SSE (Server Sent Events) för den webbsidan.
Nästa steg blir att skicka tillbaka ändrade data till ESP32 och spara i flash-minnet via preferences. Läst på mycket om WebSocket nu och finns ingen inbyggd funktion för event-driven kodning för varje datavärde men använder onMessage-event där man själv kan skapa en event-liknande struktur via messagedata och switch()-sats. Där är ju SSE lite smidigt med sin helt event-driven funktion, men WebSocket har annan kraftfull funktion.
Efter lite funderande så kan nog WebSocket via sin onMessage-event kombinerat med switch()-sats bli tydligare, mer överskådligt, kompaktare samt få bättre kodstruktur.
Jag tar det lugnt såhär, läser på och funderar så jag får till en bra kodstruktur som är lätt och smidig att bygga vidare på, som nu kring WebSocket! Är nödvändigt med 7000+ rader kod!
Men tills vidare behåller jag SSE för de webbsidor som bara uppdateras med enkla datavärden då det fungerar stabilt nu, men framtiden får utvisa vad WebSocket går för.
På ett sätt är det smidigt att skicka all data via JSON och event-liknande switch()-sats, som med WebSocket! Får se hur det blir med signifikant mer data via JSON för andra webbsidor.
Dessa sex datavärden skickas i alla fall snabbt via JSON / WebSocket.

Configuration
Configuration - Data fetched via WebSocket from ESP32 and updated in inputs

2024-01-26
WebSocket-koden för att spara data i ESP32 flash-minnet från Configuration-webbsida är nu klar! Fått till en väldigt bra struktur och tydlighet i koden, med fint strukturerad funktion.
Samt en kod det är lätt och smidigt att återanvända och bygga vidare på!
Med WebSocket kan jag hantera datavärden väldigt fint strukturerat, med avancerad funktion!
Jag tjänar helt klart på att ta tid på mig och smälta den info jag läst, som om WebSocket nu!
Så fort man editerat någon konfigurerings-data så ändras Save-Data knappen till rött för tydlig visuell indikation att den ändrade datan inte är sparade. Och när man trycker på knappen för att spara så ändras den inte till grönt förrän webbsidan fått tillbaka kvittens på att ESP32 övervakat och checkat att datan verkligen blev sparad i flash-minnet!
Så man kan inte bli lurad om det skulle bli problem med data­kommu­nika­tionen mellan webbsidan och ESP32 med dess webbserver! Ger full datasäkerhet.
Om man har Configuration-webbsidan aktiv i webbläsare på flera enheter så uppdateras den nya datan direkt på alla enheter i stort momentant när den sparas via Save-Data knappen. Och om datan även håller på att editeras på en av de andra enheter så skiftas då Save-Data knappen från rött till grönt på den, så man blir uppmärksammad på att det kommit nya data.
Även funktionen att återupprätta en förlorad WebSocket-anslutning fungerar bra som tänkt. Med webbsidan aktiv i webbläsaren slog jag av strömmen till ESP32 och efter en stund försökte webbsidan kontinuerligt upprepat återupprätta anslutningen 1ggr/2s. När jag sedan slog på strömmen till ESP32 och den startat webbservern så återupprättades WebSocket-anslutningen automatiskt igen! Är också en trevlig funktion med väldigt lite kod för.
Från webbläsarens Konsol:
Trying to open a WebSocket connection...
Firefox kan inte upprätta en anslutning till servern på ws://192.168.112.211/wsConfiguration.
WebSocket Connection closed
Trying to open a WebSocket connection...
GET ws://192.168.112.211/wsConfiguration [HTTP/1.1 500 Internal Server Error 109ms]
Firefox kan inte upprätta en anslutning till servern på ws://192.168.112.211/wsConfiguration.
WebSocket Connection closed
Trying to open a WebSocket connection...
WebSocket Connection opened
myObj0: 212
myObj1: 100
myObj2: 50
myObj3: 90
myObj4: true
myObj5: 12.499

Configuration
Configuration - Edited value(s) to be saved in ESP32 flash
Save-Data button shifts to green at confirmed stored values in ESP32

2024-02-02
Är intressant och lärorikt det här att utveckla en egen ESP32-batterimonitor!
Att mäta ström som varierar snabbt är inte så enkelt och jag har lagt ned mycket arbete på att få bra precision även för det i min batterimonitors mätningar. Och har fått det bra.
Igår var det fint solväder så solpanelerna i mitt lilla experiment off-grid solcellssystem här hemma producerade förhållandevis bra.
Kom upp till så pass fulladdat att PWM-regulatorn började strypa strömmen och då strömpulsade.
Min PWM-regulator visade då +0,4A från solpanelerna i sin display medan min batterimonitor mätte +1,026A in till blykol-batteriet.
Så PWM-regulatorn mätte ca 60% för lite ström när den själv strömpulsade!
Jag har även sett att min NASA-BM1 batterimonitor i husvagnen mäter strömmen lite fel under sådan strömpulsning.
Så ger ju min ESP32-batterimonitor bättre precision i mätning av batteribankens laddnivå och laddström!
Och jo, jag har på olika sätt validerat att det är min som mäter mest rätt.
Och detta har även betydelse utan PWM-strömpulsande då strömmen varierar en del dynamiskt då också.
T.ex. mäter min ESP32-batterimonitor hela det korta startströmförloppet när kylskåpskompressorn startar med hög precision, samt strömmen lär variera en del med växelriktare i drift, etc.
Min batterimonitor gör 1024mätningar/1,2s normalt (1ggr/1,2ms) samt vid PWM-strömpulsandet 4ggr fler dvs 4096mätningar/1,2s (1ggr/0,3ms) , vilket gör att den kan följa även snabba strömförändringar fint.
Jag har dessutom ett speciellt filter för strömsignalen från strömshunten in till strömsensorn som bidrar till den fina mätprecisionen, vilket jag utvecklat via kraftfull simulering i datorprogram.
Man kan ju undra med vilken precision andra batterimonitorer på marknaden mäter dynamiskt varierande ström?
Den grön lysdioden nere till vänster indikerar att solladdregulatorn begränsar strömmen och batteribanken får max ström den kan ta emot, vilket även visas tydligt i driftsdatan på webbsida:

Mätning av PWM-strömpulsad ström
Mätning av PWM-strömpulsad ström

2024-02-04
Nu har jag fått min "Battery 24hr operational graph" diagram över batteridriften i funktion i min ESP32-batterimonitor :-)
Är inte färdigt ännu, då jag bl.a. visar medelvärdet för varje hel timme nu för datavärdena men ska minska ned till för varje 15:e minut eller kanske varje 10:e minut beroende på hur jag upplever det. Varje hel timme räckte gott till annan driftsstatistik jag beräknar ur dem, men blir lite glest för diagrammet.
Men även de medelvärdena uppdateras hela tiden 1ggr/s så är ju ett levande diagram så ändå.
Och de bygger på ca 3 miljoner mätvärden/hr för varje data för driften så är ju mycket och detaljerad data bakom.
Skal-indelningen till höger för ström/effekt justeras automatiskt för datavärdena under de senaste visade 24hr, och då på ett ingenjörsmässigt sätt så det blir lätt att läsa av kurvorna.

X-axeln visar dygnets tid (hr) i kronologisk ordning och jag har då en vertikal svart linje som markerar aktuell tid i diagrammet. Så till vänster är dagens mätvärden och till höger om den är gårdagens värden. På så sätt kan man väldigt tydligt jämföra driften idag med gårdagens utfall, vilket jag tycker ger tydligt bra info över driften. Blir tydligt här med dagens regnväder mot solsken igår! Jag har inte sett det någon annan stans så är en helt egen idé (men finns säkert).

Att jag kör med medelvärden så för datakurvorna är för att få rena tydliga kurvor som tydligt visar batteridriften, samt är ju så batteribanken påverkas av strömmen.
Jag brukar kalla det för att jag förädlar rådata till information!
Är populärt annars att visa precis alla datavärden helt ofiltrerat för data 1ggr/min eller t.o.m. 1ggr/s vilket i mitt tycke ger en rörig otydlig svårtolkad info över driften.
Har funderingar på att senare komplettera med max/min-skuggning till ett par av diagramkurvorna för att visa hur mycket datavärdena varierat, men prioriterar inte det nu.
Har dock redan nu max/min-datavärden sparade för visning på annan webbsida över driften.
Är bara så häftigt att få till visualisering av off-grid batteridriften så som jag önskar, som ger en bara så bra översikt över min solcellsdrift:

Battery 24hr operational graph
Battery 24hr operational graph - skärmdump mobilen
Diagram ofiltrerad rådata
Referens: Diagram över drift, med ofiltrerad rådata som är populärt

2024-02-04
Nu har jag ändra från medelvärde per hr till per 10min och det tog knapp 20min kodfixande att göra det och fungerade direkt - är bara så bra med riktigt välstrukturerad tydligt C++ kodande.
Är en sorts löpande 10min medelvärde som visas, så datakurvorna är hela tiden levande och responsiva uppdaterade 1ggr/1,2s! Och varje sådant 10min medelvärde består av ca 512.000 mätningar för var datakurva, så är bra dataunderlag!
Så provkör detta nu. Skickar då ca 600st mätvärden för senaste 24hr drift via Websocket från ESP32 webbservern till webbsidan i webbläsaren (580st float-mätdata + lite styrdata)!
Och det segar inte utan går snabbt samt ser bra ut!
Har alltid senaste 24hr driftsdata i ESP32, så direkt man öppnar diagram-webbsidan så visas kompletta datakurvor för senaste 24hr!
Efter att ha brottats med SSE-skickade data länge så är detta imponerande!
Så nu visar jag diagrammet med medelvärden för var 10:e minut under 24hr för de 4 data­kurv­orna! Är rätt imponerande att ESP32 med webbserver kan hantera detta så bra!
Ska lägga in en linje som visar när synkning till 100% SoC fulladdat har skett under visade 24hr, samt en indikering under vilka tider PWM-regulatorn begränsat laddströmmen s.k. PV-Throttle.
Har även fixat en extremt sällsynt FreeRTOS race condition som försöker göra två eller flera anslutningar simultant till WiFi och då får WiFi-anslutningen att hänga sig och meddela att där inte finns något WiFi-kort som då kräver reset, WiFiRaceCondBlock.

2024-02-05
Nu är mitt diagram "Battery 24hr operational graph" i min ESP32-batterimonitor produktionsfärdig för skarp drift.
Är fixat så det nu visar medelvärdet för var 10 minuters period mot tidigare var timmes period, så blir lite mer levande diagram nu.
Känns som en sweet-spot mellan hur mycket RAM-minne det tar i ESP32 för all 24h datan, hur mycket data som ska skickas mellan ESP32 och webbsidan när den klickas upp i webbläsaren (nu med 10-minuters intervall ca 600 datavärden som skickas från ESP32 via Websocket till webbsidan) samt balansen mellan lugna stabila datakurvor med tillräcklig detalj och respons på förändrade värden.

Diagrammet är levande och uppdateras hela tiden ca 1ggr/s med nya data för kurvorna skickade via Websocket från ESP32, efterhand som de olika beräknade medelvärdena förändras av ny indata. Samt ESP32 håller alltid senaste 24hr driftsdata, så diagrammet är komplett med 24hr datakurvor så fort webbsidan öppnas!
Även om man inte ser snabba strömspikar med 10-minuters medelvärden så är data för dem med och påverkar medelvärdena så kommer med i diagramkurvorna ändå med de ca 500.000 mätningar av data som underlag för varje sådant 10 minuters medelvärde!

Är bara några små finputsningar till att göra men i princip färdigt.
Här ett diagram över 24 timmar med först varierande molnslöjor med solsken mellan 11:30 till 13:30, sedan lite kraftigare solsken där laddningen kom upp i aktivt reglerad float-laddning (13,8V) under ca 1h. Därefter började solen gå ned.
Att dagens senaste datavärden möts med gårdagens för samma tid på ömse sidor om tidslinjen gör det lätt att se förändringar under senaste 24hr, som nu SOC-laddnivån som ökat något lite här.
När det blivit en 100% SOC synkning under de 24 timmarna så kommer dess tidpunkt markeras med en streckad vertikal linje i diagrammet.
(Att spänningskurvan (blå) rör sig i tydliga steg beror på att jag av misstag bara fått med en decimal mot tänkta två för spänningsvärdena när de skickas till webbsidan, men är fixat nu.)

Battery 24hr operational graph
Battery 24hr operational graph - skärmdump mobilen

2024-02-07
Det här blir riktigt trevligt i skarp drift i mitt riktiga off-grid solcellssystem!
Här från senaste 24h drift i mitt lilla experiment off-grid solcellssystem, med fixad upplösning för spänningskurvan (blå) så även den nu varier kontinuerligt jämnt:

Battery 24hr operational graph
Battery 24hr operational graph - skärmdump mobilen


2024-02-06
Idag blev batteriet helt fulladdat och ESP32-batterimonitorn synkade 100% SoC mot batteriet. Nu har enda urladdningen varit strömförbrukningen för batterimonitorn, PWM-regulatorn och två Battery Reconditioner ihop, så väldigt små strömmar. Så när batterimonitorn detekterade 100% SoC via tail-current vid aktiv float-laddning (PV Throttle) så var det fortfarande någon Ah kvar att återladda enligt mätningarna. Det beror på svårigheter att mäta strömförbrukningen korrekt från den Battery Reconditioner som strömpulsar i 9kHz med superkorta strömpulser motsvarande 1MHz och som utgör den största strömförbrukaren såhär.
Felet motsvarade ca 5mA mätfel under de 20 dygn som gått sedan senaste fulladdat med totalt -12,7Ah cyklad urladdning och 94,9% SoC som lägst av 90Ah, så ändå rätt obetydligt samt verkar rimligt. Nu för experiment off-grid solcellssystemet här hemma har jag att detta mäts ihop med batteriverkningsgrad även vid väldigt grunda urladdningar mot annars minst 10% DoD urladdning för sådan mätning. Så i husvagnens off-grid solcellssystem ger detta helt försumbar inverkan under drift vid aktivt boende där, samt kommer troligen minska med INA226 placerad närmre ström­shunten med korta ledningar.
Kan även jämföras med Victrons BMV-712 / SmartShunt som har en Current threshold på 0,1A som fabriksinställning, dvs den mäter inte inom ±100mA ström, 20ggr större fel än detta!

2024-02-10
Njuter av det fina diagrammet över driften jag fått till :-)
Fixar några småsaker till i diagram-presentationen så är jag riktigt nöjd sedan!
Känns som dessa 10 minuters medelvärden kurvorna ritas utifrån är riktigt bra för att visa driften tydligt! Och att ändå varje sådan 10 minuters punkt är medelvärdet av ca 500.000 mätningar, så riktigt bra dataunderlag där även minsta strömspik är med i medelvärdet.
Och att senaste pågående medelvärdena uppdateras 1ggr/1,2s med en sorts löpande 10 minuters medelvärde så diagrammet är levande hela tiden att titta på.
Ger en tydligare bild av batteribankens drift än med datakurvor ritade utifrån helt ofiltrerad data!
Korta strömspikar påverkar inte laddnivån i batteribanken, men detta visar det som verkligen påverkar laddnivån samtidigt som datakurvorna blir rena, lugna och tydliga.

Battery 24hr operational graph
Battery 24hr operational graph - skärmdump mobilen

2024-02-11
RISE Research Institutes of Sweden:
"Visualiseringar gör att alla kan förstå behov och utmaningar lättare."
"Tillgången på data har ökar snabbt i industrin – och ännu mer blir det i spåren av IoT, sensorer och utbudet av externa data som allt enklare kan integreras i systemen. Men hur kan datan användas till att förbättra processer, förhindra problem, fatta rätt beslut och använda personal och utrustning effektivare? Det är där visualiseringar blir helt avgörande."
RISE: Sju skäl att visualisera data:
"1. Visualiseringar tar sig in i hjärnan blixtsnabbt:
– Våra hjärnor är gjorda för att snabbt se mönster visuellt. Att tolka rådata i Excel tar mycket längre tid, oavsett om datat kommer i form av siffror eller text. Det är också svårt att få överblick – man kan gå igenom siffror i ett kalkylark i timmar och ändå inte få en bra förståelse för hur de hänger ihop. Det här är något som datavisualisering kan ge en omedelbar bild av, där man direkt förstår inte bara siffrorna utan hur de förhåller sig till annat data. Det är så man får verkliga insikter, säger Kristina Knaving.
"
"4. Visualiseringar är mer inkluderande." Typ hela familjen!
"6. Visualiseringar kan visa trender."
Lite det jag gör i ESP32-batterimonitorn för off-grid driften och inte bara visar rå-data :-)
Med min ESP32-batterimonitors drygt 50.000 mätningar/minut rå-data måste all den datan bearbetas för att bli överskådlig, dvs omvandlas till information och visualiseras!

2024-02-12
Här ser man tydligt nyttan med strömsparläget med 99% av tiden i ESP32 light-sleep!
Under natten fram till 06:30 är det strömsparläge, sedan aktiverar jag ESP32 WiFi + webbserver och tar upp webbsidan med detta diagrammet i mobilens webbläsare mellan 06:30-07:30, och sedan flera gånger under den gråmulna dagen samt igår eftermiddag / kväll:

Battery 24hr operational graph
Battery 24hr operational graph - skärmdump mobilen

2024-02-13
Lät ESP32-batterimonitorn arbeta helt orörd under dagen utan att aktivera WiFi + webbserver och titta på data-diagrammet, för att få fram hur den då visar driftskurvorna ostört.
Ger en väldigt tydligt bild över driften, i kontrast till exemplet nedanför från Victrons VRM portal som ger en helt annan otydlig bild av driften med sin nervösa rådata samt val av skalindelning. Tar med referens även från den andra stora Europeiska tillverkaren Studer Innotec.
Jag har läst mycket om gränssnittsdesign (GUI), Human-Machine Interface (HMI) / Dashboard och datavisualisering av större datamängder, så är den kunskapen jag tillämpar här!

Battery 24hr operational graph
ESP32-batterimonitor: Battery 24hr operational graph - skärmdump mobilen
Victron VRM portal
Referens: Victron VRM portal - Battery Voltage and Current 24hr (raw data)
Studor Innotec portal
Referens: Studor Innotec portal - Power and Battery SoC 24hr (raw data?)

2024-02-15
Har lagt in max/min-skuggning (max/min shading) för batterispänningens och strömmens kurvor i diagrammet, så man ser hur mycket dessa har varierat inom varje 10min intervall.
Nu kör jag fortfarande passiv standby vinterdrift här hemma i mitt lilla off-grid solcellssystem, så är inga strömbelastningar som ger någon synbar max/min-shading för batterispänningen.
Tycker man får det bästa av två världar på så sätt, med en lugn tydlig medelvärdesbaserad kurva med skuggningen som visar variationen inom var 10min-segment.
Intressant att se här hur mycket solcellsströmmen varierade mellan 12:30 och 14:00!
Varje Max/Min värde mäts som medelvärdet av 1024 mätningar under 1,2s så helt irrelevanta korta spikar filtreras bort även där, samt varje datapunkt för Max/Min i diagrammet är för en 10min-period med Max/Min av ca 500 sådana Max/Min värden. Och kurvlinjerna representerar medelvädet för varje 10min-period av ca 500.000 mätvärden. Så är kraftfullt dataunderlag!
Ska bli intressant att senare se hur pass spänningsstyva mina AGM-blykol batterier är i min riktiga off-grid solcellsdrift med sin gamla 12V-kylkompressors intermittenta drift!

Battery 24hr operational graph
Battery 24hr operational graph - skärmdump mobilen

2024-02-16
Yes, nu är all funktionalitet i "Battery 24hr operational graph" diagrammet testad och verifierad!
"PV-Throttle" visar när regulatorn begränsar solcellsströmmen för att inte överladda batterierna, här mellan 12:00 och 15:30, samt "Sync 100% SoC" visar när batterimonitorns senaste synkning av sin 100% SoC skett mot fulladdat batteri under denna 24hr period, här vid ca 18:15.
Nu laddade jag även från labaggregatet för att förbereda blykol-batteriet att kunna hinna göra en för detta off-grid solcellssystemet naturlig sådan här laddcykel i morgondagens solväder. Och det gjorde att 100% SoC sykningen skedde med en av två reservmetoder då batteriet lämnar fulladdat tillstånd. Huvudmetoden för synkning är via Tailcurrent då batteribanken precis blir 100% SoC fulladdad, vilket krävs för att kunna beräkna batteriverkningsgrad med bra precision.
Och då fortgår 100% SoC synkningen tills Tailcurrent-villkoret upphör, vilket är tidpunkten som visas här i diagrammet då som "Sync 100% SoC".
Intressant även att när jag ökade laddspänningen från 13,8V float till 14,2V absorption så ökade laddströmmen väldigt lite, vilket nog är en typisk egenskap för AGM-blykol batterier vid så hög SoC som ca 98% här. Men är då laddning utan strömpulsning från labaggregatet!

Battery 24hr operational graph
Battery 24hr operational graph - skärmdump mobilen

2024-02-17
Nu är det färdiga "Battery 24hr operational graph" diagrammet testat med en 24hr cykel med enbart solcellsström under en solig dag, och det ser riktigt trevligt ut precis som tänkt!
När jag här strax efter kl.21 går in och tittar på dagens batteridrift i off-grid solcellssystemet får jag en tydlig bra bild av den tycker jag! Så blir trevligt med detta framöver nu i mitt off-grid.
Skriver även ut siffervärdena för senaste plottade datapunkterna i diagrammets nedre marginal.
Känns som en bra kombination med diagramkurvor plottade från 10min medelvärden samt max/min-skuggning som visar hur ström och spänning varierat inom de 10min-intervallerna.
Blir tydliga data-kurvlinjer samt max-min-plottning som visar driften riktigt bra med dessa statistiskt bearbetade rådata, istället för hysteriskt varierande kurvlinjer direkt från rådata!
Runt kl.15:00 kan man se en hel del max/min-strömvariation men ser man på den plottade röda linjen för medelvärdena så har den påverkats minimalt ändå, och är det som utgör batteriladdningen. Visar även att solladdregulatorn hanterar dessa korta variationer i solinstrålning från molntussar väldigt bra. Strax efter kl.16 försvinner den låga vintersolen bakom ett höghus.
Blev drygt 3h PV-Throttle kl.13-16:20, dvs att solladdregulatorn begränsade solcellsströmmen för att undvika överladdning av batteriet. Och samtidigt med att PV-Throttlingen upphörde så avslutades synkning av 100% SoC mot fulladdat batteri, som indikeras med vertikal lila punktlinje.
Och då den svarta grövre vertikala linjen som indikerar aktuell tid.
Då är detta diagrammet helt färdigt kod- och funktions-mässigt, förutom en liten justering av den blå max/min-skuggningen för spänningen som får göras lite mörkare för bättre synlighet.
Känner mig riktigt nöjd och det gick att göra precis som den målbild / vision jag haft!
Att jämföra sig med konkurrenter, Benchmarking (konkurrentanalys), är en integrerad del i produktutvecklingsprocessen vid kommersiell utveckling, men även intressant vid sådana här pensionärs-hobbyprojekt, därav att jag jämför mig med de marknadsledande inom off-grid solcellsteknik i Europa Studer Innotec och Victron Energy! Och jag tycker mitt hävdar sig bra!
Nästa steg bli att ansluta en till strömsensor för mätning av solcellsströmmen och koppla ihop dess data med en färdigkodad grafik jag redan har.

Battery 24hr operational graph
Battery 24hr operational graph - skärmdump mobilen
Battery 24hr operational graph
Battery 24hr operational graph - inzoomad skärmdump mobilen
Latest 24hr running statistics
Latest 24hr running statistics - skärmdump mobilen

2024-02-19
I dagens mulna väder blev max/min-skuggningen till diagrammets röda strömkurva extra tydlig och fin! Som ett skolboksexempel. Strömvariationen kommer här främst ifrån de två Battery Reconditioner´s strömpulsande, där man även ser hur de minskar sin frekvens när batterispänningen sjunker som syns på medelströmmens kurva mellan kl.04:00 och 07:30.
De lite glesa djupare strömdipparna är när ESP32 kopplar upp sig mot WiFi och Internet och synkar realtidsklockan mot en tidsserver samt därefter visar diagram-webbsidan på datorn. Då går dels ESP32 ur strömsparläget, dels drar WiFi och webbservern lite ström.

Battery 24hr operational graph
Battery 24hr operational graph - skärmdump mobilen

2024-02-21
Fixat den förhoppningsvis sista syllsynta FreeRTOS race condition där via tryckknapp 1 aktivering av WiFi / Webbserver riskerar att ske medans fortfarande i Light-Sleep strömsparläge, och då hänger sig WiFi och kräver en hård reset för kunna aktiveras igen. Nu testat hela dagen och verkligen försökt provocera fram detta normalt sällsynta genom att trycka på tryckknapp 1 precis när LED blinkar för avläsning av ström från INA226 i strömsparläge. Är då den har hängt sig tidigare väldigt glest, men inget alls idag ännu. Men krävs några veckors testande.
Är det sista jag sett nu som kunnat äventyra en helt stabil 365/24/7-drift.
Sedan får ju en riktigt lång skarp drift i mitt off-grid solcellssystem bekräfta det!

2024-02-28
Nu har jag bytt från SSE (Server-Sent Events) till WebSocket för dataöverföringen till webbsidan "Operational data" (Main Dashboard), som en förberedelse att koppla in en INA260-strömsensor för solcellsströmmen samt en temperaturgivare för batteriet. WebSocket är så mycket effektivare och trevligare att arbeta med än SSE samt i denna webbservern ESP­Async­Web­Server-esphome hanterar WebSocket mycket större datamängder smidigt och stabilt. Sedan ger WebSocket möjlighet till tvåvägskommunikation också.
Nästa steg är att ta nuvarande hårdvaran från BreadBoard till att löda in på experimentkort, för att ge plats för INA260 på mitt BreadBoard. Och därefter koppla in och koda för INA260!

2024-03-04
Njuter under tiden av den fina visualiseringen av min off-grid solcells batteridrift!
Fick en perfekt soldag för att visa all funktionalitet tydligt i mitt dashboard-diagram "Battery 24hr operational graph", lite som man skulle ha gjort laboratoriemässigt för att få fram det.
Här visas 4st datakurvlinjer, spänningens och strömmens max/min-skuggning, PV-Throttle samt "Sync 100% SoC" väldigt tydligt plottade utifrån statistiska 10-minuters medelvärden samt max/min för varje 10min intervall. Rådata bearbetad till information. Både under pågående "Sync 100% SoC" samt efteråt samt både vid laddning och urladdning av blykolbatteriet.
Max/min-skuggning är en väletablerad teknik samt att låta 0,5% (0,005C) Tail-current under pågående aktiv spänningsreglerad batteriladdning (PV-Throttle) indikerar 100% SoC fulladdat blybatteri är också väletablerad teknisk kunskap, här 450mA Tail-current för mitt 90Ah blykol.
Visar hela senaste 24h driftsperioden, med dagens data till vänster om den vertikala svarta tidslinjen, och gårdagens till höger om så blir lätt att jämföra vid aktuell tidslinje.
Ger ihop en tydlig bra bild av off-grid solcellssystemets senaste 24h batteridrift tycker jag.
Som den stora strömvariationen från molntussar mellan kl.12-15, sedan mer stabilt solsken.
I första bilden ser man att Tail-current kommit ned till 320mA, så är robusta 40% marginaler mot gränsen 450mA för 100% SoC indikering! Var liknande för mina 9år gamla blybatterier.
Ger en väldigt exakt, robust och stabil synkning av 100% SoC mot fulladdade batterier!
Att göra det utifrån enbart batterispänning och Tail-current går aldrig att få robust och exakt!
Är bara en tillämpning av väletablerade tekniska kunskaper för visad driftdata i diagrammet!
Om det inte skett en "Sync 100% SoC" inom senaste 24h så har jag tiden till senaste sådan angivet på en annan webbsida, men tycker det ger bra info att även ha med i 24h-diagrammet.
Inledde härmed också årets säsong med all mobil-laddning från mitt lilla off-grid solcellssystem.
Ska senare göra ett motsvarande diagram som visar hela off-grid solcellssystemets 24h drift.
Samt jobbar nu på intressant grafik för tydlig visualisering av pågående aktuell off-grid drift.

Battery 24hr operational graph
Battery 24hr operational graph - skärmdump mobilen
Battery 24hr operational graph
Battery 24hr operational graph - skärmdump mobilen
Latest 24hr running statistics
Latest 24hr running statistics - skärmdump mobilen

Jämför man med diagrammet nedan som är lite av branschstandard inom marknaden för off-grid solcellssystem där datakurvorna växlar frenetiskt plottade från rådata, så ser man hur mycket svårare det är att läsa ut information ur det! Datakurvlinjerna trasslar in sig i varandra och blir svårt att avgöra medelvärdena samt svårt med mer än två kurvor i samma diagram.
Med mina datakurvlinjer plottade från statistiskt bearbetad data kan jag visa fyra sådana i samma diagram och de syns tydligt ändå samt ger bra information som verkligen visar batteridriften tydligt! En ingenjörsmässig skalning i mitt diagram gör det också lätt att läsa av data ur det.
Jag är maskiningenjör men har utvecklat mycket mekatroniska system, så är min yrkeskunskap och erfarenhet från det jag nu utnyttjar i mitt pensionärs hobbyprojekt här med batterimonitor.

Diagram branschstandard
Diagram lite av branschstandard med rå-data

2024-03-14
Fick frågan om strömförbrukningen för min ESP32-batterimonitor, så skrev ihop:
ESP32 inkl. INA226 strömsensorn och nattbelyst LCD-teckendisplay drar ca 6mA från 12,5V i aktiv grunddrift när den samplar aktivt 500.000ggr/10min. Jobbar då i ett strömsparläge. Strömsensorn arbetar självständigt strömsnålt och tar kontinuerligt 1024st samplingar som den medelvärdesbildar, sparar i buffert och sätter interrupt-flag till ESP32 var gång det är klart, så ESP32 hämtar bara den mätdatan 1ggr för var 1024:e sampling. Under tiden kan ESP32 vara i light-sleep när jag har den i strömsparläge, vilket blir ca 99% av tiden i light-sleep då.
Vid lite högre strömmar går den ur strömsparläget och då drar den ca 25mA från 12,5V. Om jag minns rätt är gränsen ±150mA när den går ur strömsparläget.
Med även aktiv WiFi och webbserver och kontinuerlig WebSocket-data skickade till webbsida i webbläsare drar den ca 35mA från 12,5V.
Jag ska senare titta på att variera klockfrekvensen för ESP32 (görs direkt i C++ koden), så jag rampar upp prestanda / strömförbrukning när jag går ur strömsparläget med light-sleep, så det inte blir vid en fast strömgräns på ±150mA som nu. Ska se om jag kan få till då att batterimonitorns strömförbrukning är <1/10-del av aktuell batteriström som max.
Har även under flera dagar haft diagrammet nedan öppet i annan webbläsare med aktiv WebSocket under många timmar nu medan jag arbetat framför datorn i annan webbäsaren, och inte noterat att WiFi kopplat ifrån en enda gång! Men har funktioner för återanslutning både för WiFi och WebSocket, så kan ju skett kortvarigt utan att jag sett det. Så ska lägga in räknare i WiFiReconnect() funktionen så jag kan följa upp om det sker.

Battery 24hr operational graph
Battery 24hr operational graph

2024-03-18
Nu har vårsolen för off-grid solcellssystemet kommit på riktigt här i Östergötland, med ca 5h PV-Throttle idag dvs att solladdregulatorn begränsar strömmen från solpanelerna för att hålla den reglerade 13,8V float-laddspänningen korrekt. Min PWM-regulator startar en ny laddcykel med bulk-, absorption-, float-laddning första när batterispänningen kommit under 12,3V, så fram till dess ligger den kvar i float-laddning som är skonsamt för blybatterierna.
Mina solpaneler här hemma står i SydVäst-läge så kl.10:30 lyser solen parallellt med fönstret, sedan början den långsamt lysa mer och mer in genom fönstret mot solpanelerna fram till lite innan 17-tiden, då den såhär års försvinner bakom ett höghus så solcellsströmmen snabbt minskar då.
PV-Throttel innebär att PWM-regulatorn då strömpulsar laddningen, vilket gör att blybatteriet blir verkligen 100,0% SoC fulladdat! Det syns på att Tail-current kom ned till 200mA jämfört med de 450mA (0,5% / 0,005C av 90Ah) som här utgör gräns för detektering av fulladdat blybatteri i min ESP32-batterimonitor.
Med en MPPT-regulators kontinuerliga float-laddström tar det nästan oändlig tid att nå 100,0% SoC fulladdat för blybatterier!
Så då har jag 450mA / 200mA = 2,25ggr marginal mot att säkert kunna detektera fulladdat blybatteri för 100% SoC synkning i batterimonitorn. Ger en stabil robust funktion för det!
Innebär att den välkända tekniska kunskap som finns om 0,5% Tail-current för 100% SoC detektering under PV-Throttle stämmer väldigt bra med verkligheten :-)
Med 0,5% Tail-current under PV-Throttle för detektering av fulladdat blybatteri fås en väldigt exakt och fint repeterbar funktion för det, vilket ger mycket bra precision åt batterimonitorn.
Räknat på de loggade datavärdena här ger dessa 0,5% Tail-current en detektering av fulladdat blybatteri vid drygt 99% SoC, vilket är extremt bra precision då lite marginal alltid behövs.
Med den långa PV-Throttle tiden här idag bör det då blivit minst 99,9% SoC i blybatteriet för 100% SoC synkningen, eftersom Tail-current planar ut på strax under 200mA.

Battery 24hr operational graph
Battery 24hr operational graph

2024-03-20
Har gjort en större code-refactoring på WiFi-anslutningen, där jag haft både gammal och ny kod som inte blivit så optimalt. Är första Arduino/ESP32 projektet jag kodar med FreeRTOS så har lärt mig mycket under vägen nu och utnyttjar FreeRTOS möjligheter betydligt bättre nu i kodandet. Använder bl.a. Inter-task Communication mer flitigt nu för bra effektiv kodexekvering.
Blev både mycket tydligare kod att läsa och förstå, samt förbättrade även funktionen. Anslutningen till 4G-routerns WiFi går signifikant snabbare nu, så kodfunktionen måste ha blivit märkbart bättre såhär nu! Jag har verkligen utvecklas i att koda med FreeRTOS.
På köpet använder programkoden något lite mindre RAM nu, nog för att jag fört över kod i ett par olika egna funktioner men även att köande sker i en meddelandekö till en Task istället för en i RAM inladdad funktion. Är något jag senare ska göra mer av i hela min programkod.
Speciellt ska jag verifiera om det gör skillnad att lyfta ut koden från Task´s så i egna funktioner!
Jag utnyttjar kodbiblioteket WiFiMulti så kan jag ha alla de WiFi-källor som är aktuella för mig definierade samtidigt med SSID i min kod, förutom övrig bra smidig funktion.
2024-03-25
Gjort lite ytterligare code-refactoring på WiFi-anslutningen på delen med synkning av datum/tid mot NTP Client-Server. Fick lite snabbare och bättre tidssynkning där också.
Samt gjort om koden så den nu inte ansluter mot WiFi och NTP under setup() utan man får aktivera det sjäv manuellt via tryckknapp 1, för smidigare inkoppling av ESP32-batterimonitorn i det elektriska systemet.
Samt fortsätter att njuta av mitt diagram över batteridriften, där man här ser att SoC-laddnivån slutade på samma vid 19:15-tiden, så ur- / upp-laddning tog precis ut varandra under dygnet:

Battery 24hr operational graph
Battery 24hr operational graph

2024-04-07 New
Dels kodat så vid uppkoppling mot WiFi via WiFiMulti() så görs upprepade försök i en loop under lite längre tid tills success, så 4G-routern får tid att starta upp då det är aktuellt. Som förberedelse till att ESP32-batterimonitorn ska kunna slå på strömmen till 4G-routern, skicka data till webbsida på webbhotell samt sedan stänga ned 4G-routern igen.
Dels förbättrat stabiliteten för WebSocket genom att ws.text() / ws.textAll() skickande av data till webbsidorna nu villkoras med ws.availableForWrite() / ws.availableForWriteAll() som internt i AsyncWebSocket.cpp checkar om queueIsFull(). Så inte dess buffert överskrids!
Syntes resultat även vid normal drift då ESP.getMinFreeHeap() gav lite mer fritt lägsta RAM mot innan vid webb­sides­blädd­ran­de på två olika enheter (mobil+dator), så WebSocket funktionen verkar stabilare såhär. Ws.text() / ws.textAll() verkar inte stressa bufferten lika mycket nu!
Är ett väldigt letande i kodbiblioteken för att hitta alla möjligheter där, som detta, då det inte är med i de enklare kodexemplen på Internet!

Hade en incident som gav ESP_RST_PANIC så ESP32 botade om, då WebSocket stressades av att ESP32 hade svårt att nå bra kontak via WiFi och jag upprepade gånger startade om webbsidan så WebSocket stressades att skicka data upprepade gånger fast det då var svårt att få fram den! Men då fungerade det jag kodat / byggt så den SoftReset som ESP_RST_PANIC ger upphov till omvandlades till en HardReset typ PowerOn med sparande av viktig data dessförinnan, så skoj att fått det testat också. Så resulterade bara i ett minimalt avbrott i dataloggningen då, helt utan betydelse för precisionen i mätningen av batteribankens laddnivå!

I WiFiMulti.cpp tog jag även bort den sista else{} paragrafen där det görs en WiFi.scanNetworks(true); som är en asynkron scanning om den första synkrona misslyckas, vars resultat aldrig används så känns som en sorts bug. I vart fall stör den när man själv efter att WiFiMulti.cpp misslyckats med att ansluta till WiFi gör upprepade anrop till WiFiMulti.cpp via WiFiMulti::run() för att få till en WiFi-anslutning!

Även lagt tid på att välja mer optimala färger på datakurvlinjerna samt ljusare bakgrund i "Battery 24hr operational graph" för lättare tydligare avläsning på olika enheters skärmar.
Samt även blivit lite code-refactoring där jag varit inne och rotat i koden, så dess funktion och tydlighet hela tiden förfinas. Så börjar kännas riktigt bra nu!
Utöver denna lite självförvållade incidenten (som härmed bör vara förebyggd) har ESP32-batt­eri­moni­torn nu arbeta 100% 24/7-stabilt i flera veckor, trots mina stresstester av den med ständigt aktiverande av WiFi / ESP32-webbserver och bläddrande bland dess webbsidor!

Ska nu koncentera mig på att skapa riktig tennlödd hårdvara i kapsling för det jag hittills har gjort och sedan inkludera en INA260 för strömmätning av strömmen från solcellerna.
I diagrammet syns att de mörkgrå molnen med små klarblå luckor som snabbt drev fram över himmeln gav stor variation i solcellsström mellan kl.14-16, som följdes av klarblå himmel. Strömmen varierade då 10-15ggr på mindre än en sekund, typ från 1A till 10-15A på <1s! Då krävs att batterimonitorn är konstruerad för att mäta så snabbt varierande dynamisk ström för att mäta laddnivån för batteribanken korrekt, som min ESP32-batterimonitor som samplar mätvärdena drygt 50.000ggr/min ihop med noga utvecklat ingångsfilter för strömsignalen!

Battery 24hr operational graph
Battery 24hr operational graph - nya färger på datakurvlinjer + ljusare bakgrund

2024-04-14 New
ESP32 WiFi med 2,4GHz kan ibland störas ut när det här i lägenheten är 10st WiFi-routers samtidigt som WiFiMulti.run() detekterar via WiFi.scanNetworks(). Just 2,4GHz är lite extra känsligt för det.
Så jag låter min programkod göra upprepade försök under 180s att via WiFiMulti.run() koppla upp mot min 4G-routers WiFi, vilket dock är svårt att simulera och testa att det fungerar bra.
Men igår och idag har det blivit tre gånger som det krävts flera försök och de två gångerna igår fungerade det bra på 4:e försöket men idag blev det åter returvärdet WL_NO_SSID_AVAIL som innebär att WiFi.scanNetworks() redan kör. Har då haft vTaskDelay() 500ms mellan försöken så ökar den nu till 1000ms. Hade tidigare 50ms och då blev det WL_NO_SSID_AVAIL varje gång första anslutningen misslyckades. Krävs tydligen lite "settling time"!
Även de svårigheter / seghet det kan ge för WebSocket kommunikation så fungerar ändå den stabilt och bra och återansluter fint automatiskt när den då tappar kontakten, samt villkorandet med ws.availableForWrite() / ws.availableForWriteAll() gör att det blir inga minnes- eller buffert-problem heller då som ger kodkrasch.

2024-04-15 New
I 180s loopen med WiFiMulti.run() som väntar in WiFi från 4G-routern lagt in följande:
if (ReturnValue == WL_NO_SSID_AVAIL)
{
  vTaskDelay(5000 / portTICK_PERIOD_MS); // Settling time to WiFiMulti.run
}
Där WL_NO_SSID_AVAIL är felkoden WIFI_SCAN_RUNNING from WiFi.scanNetworks() i WiFiMulti.cpp.
Tiden får utvisa om 5000ms Settling-time är tillräckligt här eller om den behöver ökas.
Idag vid 19-tiden blev det en WiFi-anslutning som gick via WL_NO_SSID_AVAIL på 3:e försöket och sedan på 4:e försöket anslöt fint till WiFi, så där fungerade det med 5000ms Settling-time!
Senare på kvällen blev det liknande en gång till, så ser ut som att 5000ms Settling-time är OK här! För övriga felkoder är det 1000ms vTaskDelay(), så totalt då 6000ms.

2024-04-16 New
Idag gick den igenom WL_DISCONNECTED, WL_IDLE_STATUS, WL_NO_SSID_AVAIL innan det på 7:e försöket blev WL_CONNECTED, så känns rätt säkert att 5000ms Settling-time är OK!
Och ytterligare en gång liknande där den kopplade upp på 6:e försöket, så fungerar bra nu!
Samt även någon timme innan med bara 2st WL_DISCONNECTED och på 3:e försöket WL_CONNECTED.
Då verkar den funktionen för robust drift ihop med 4G-modem löst! Ytterligare ett steg mot slutlig funktion och drift.
Har justerat till 1500ms vTaskDelay() för alla returvärden utom WL_NO_SSID_AVAIL som nu har 1500ms + 4500ms, då 1000ms verkade lite snålt för bra funktion.
Varför löpande uppmätt verkligt batteriverkningsgrad är så centralt:
I September under 7 dygns fricampingtur blev det kumulativt PSoC-cyklat -213,1Ah pendlande mellan ca 95% SoC och lägst 71% SoC (-61,5Ah absolut) ur min 212Ah batteribank med uppmätt batteri­verk­nings­grad 97,8%(Ah), mätt av min batterimonitor. Då med ett fel i batter­iverk­nings­grad på 5% av -213,1Ah = -10,7Ah vid i snitt 83% SoC (-36Ah absolut) så fås -10,7Ah / -36Ah = 0,30 dvs 30% mätfel i SoC efter bara 7 dygns PSoC-cykling!
Så redan bara 2,5%-enheters feluppskattad batteri­verk­nings­grad skulle då motsvarande gett 15% mätfel i SoC för dessa 7 dygns PSoC-cykling!
Och 7 dygns PSoC-drift är ändå inte så lång tid, så batteri­verk­nings­graden är central i SoC-beräkningarna! Bör klara minst 14 dygns PSoC-cyklingsdrift med bra precison och upp mot en månad med rimlig precsion är min målsättning.
SoC-beräkningen baseras på skillnaden mellan den kumulativa urladdningen / iladdningen fram till nästa 100% SoC synkning och då avgör batteri­verk­nings­graden hur mycket av den kumulativa iladdningen som blir räknat som laddning i batterikemin och hur mycket som blir borträknat som förlust, och beräknas förlusten fel ger det stor inverkan!
Vid många dygns PSoC-cyklande blir skillnaden mellan kumulativ och absolut urladdning snabbt väldigt stor så även små fel i förlustberäkningen ger stor inverkan på beräknad SoC!
Som flera olika säljföretag skriver så variera batteri­verk­nings­graden mycket för traditionella blybatterier beroende på driften de utsätts för, så där är det helt avgörande att bygga SoC-beräkningarna på löpande uppmätt verklig batteri­verk­nings­grad, men även med LiFePO4 fås lätt >2,5%-enheters fel i en manuellt angiven batteri­verk­nings­grad:
"I flera applikationer (särskilt icke nätanslutna solcells och/eller vindanläggningar) kan [batteri] energiverkningsgrad vara av avgörande betydelse.
Tur och retur verkningsgrad (urladdning från 100% till 0% och tillbaka till 100% laddning) hos det genomsnittliga bly-syra batteriet är 80%.
Motsvarande för ett LFP batteri är 92%.
Laddningsprocessen hos bly-syra batterier blir särskilt ineffektivt när 80% laddningstillståndet har uppnåtts, vilket resulterar i 50% effektivitet eller till och med mindre i solcellssystem där flera dagars reservenergi krävs (batteritid i 70% till 100% laddat tillstånd).
Däremot kommer ett LFP batteri fortfarande att uppnå 90% verkningsgrad under ytliga urladdningsförhållanden.
"
Det sista är även intressant då min ESP32-batterimonitor med hög precision mätt upp 97,8%(Ah) / 92,4%(Wh) batteri­verk­nings­grad för mina AGM-blykol cyklat inom 71%-95% SoC!


Idéer: 2023-07-04 / 2023-07-18

  • Ev. 4 x trafikljus diagram: för 7dygn, 24hr, 60min & momentant SoC statistiskt analyserat som visar hur driften ligger till mot "dåligt-väder-reserven". "Dåligt-väder-reserven" kan i sin tur räknas fram ur mätt dygnsmedelström och angiven C20 batterikapacitet plus max DoD.
    Momentant kan vara intressant för att se vad inkopplad last ger för driftstid, typ vid elektrisk matlagning.
    Med 60min SoC statistik då som sämst typ natt likt den som gäller för 24hr.
  • Uppdatera Finite-state Machine funktionaliteten:
    • Förtydliga / utveckla SetStateEnergyCPU() för mikroprocessorns energy-mode:
      • Light-Sleep Mode 240MHz, även invintringsmode med sin ca 12V/6mA strömförbrukning
        Väcks upp 1ggr/s av INA226 interrupt för avläsning av mätvärden + uppdatera LCD-display. Är normalt 99,5% av tiden i light-sleep då för max strömsnålhet.
        Kanske även styra att LCD-displayen uppdateras mindre frekvent, eller filtrera för lugnare ström, då uppdatering av LCD ger bara ca 95% tid i light-sleep då visad data ändras?
        Bör med sin låga strömförbrukning även kunna fungera som invintringsmode för de flesta off-grid solcellssystem, så behov av att koppla loss från batterierna för att rädda batteribanken från djup urladdning vintertid elimineras! = användarvänligt.
      • ESP32 har 240MHz, 160MHz, 80MHz, 40MHz, 20MHz & 10MHz
        Välj frekvens så batterimonitorns strömförbrukning är <1/10-del av aktuell batteriström?
      • 240MHz för full prestand aktiv utan light-sleep vid: högre strömmar / PWM-controller pulsande / WiFi & Webbserver aktiv.
      • 160MHz för mellanhöga strömmar men ej PWM-controller pulsande / ej WiFi
      • 80MHz för lägre strömmar men ej PWM-controller pulsande / ej WiFi
      • 10MHz?, no-Serial.print, no-WiFi, no-BLE, no-PWM, ej PWM-controller pulsande
        Skulle så ifall vara strömsnålt läge vid låga strömmar utan att gå in i light-sleep.
      • Kanske införa en StateEnergyHandler() för tydligare framtidssäker funktion?
    • Se till / checka så allt som hanterar LCD-displayen är i egen kod / Task, för lättare byte till annan LCD-display!
    • Checka av så allt som hanterar trycknapparna är i egen kod / Task, för lätt anpassning till andra tryckknappar!
  • Diagram över 24hr + 1hr Time-To-Go för fast max visad ±14dygns prognostid, inom 28-dygns statistiken.
  • Göra en temperaturstyrd uppdatering av LCD-teckendisplayen? Uppdatera displayen mer sällan när det är kallt. Då slipper man det "kosmetiska" felet av den långsamma uppdateringen av LCD-kristallerna i kyla!
    Jag funderar även på något liknande när jag är i strömspar-mode då ESP32 är i light-sleep 99,5% av tiden, men när det skrivs nya tecken till displayen blir det "bara" ca 95% i light-sleep då det kräver tid.
    För bäst strömsparande bör jag gå över till mer sällan uppdatering av displayen då också.
    Dessa två funktioner hade ju passat att samordna.
    I nästa version tänker jag gå över till INA228 strömsensor och den har en temperaturgivare i sig, så då har jag även den på köpet!
  • Mät batteribankens interna resistans (IR) när kylkåpskompressorn stängs av, för den momentana förändringen i strömförbrukning! Skapa även en kvot mot SoC-nivån just då.
  • Logga tid i aktiv PWM-reglering senaste 14 dygnen. Styr 4G-router uppkoppling för datalagring på server så minst 2h/14dygn ∑ PWM-tid uppnås för AGM-blykol batteriers välmående.
    Styr 12V ström till 4G-router via enkel analys över utvecklingen under senaste 14 dygnen.
    Loggas per dygn för de 14 dygnen för att kunna analyseras bra.
    Minimum uppkoppling 1ggr/dygn och max kontinuerligt är tanken.
  • Mäta vid vilken SoC PV Throttle = ON, dvs till hur högt SoC tar batteribanken emot full laddström från solcellerna. Både senaste och som medelvärde.
    Kanske ha två styck olika mätvärden, där den ena bara mäter för en viss minsta laddström?
    Bara mäta för cyklingar <90% SoC?
  • Mätningen av µs i ESP32 är beroende av processorns klockning som kan avvika något från angiven frekven. Man skulle kunna kaliberar den mot RTC-realtid som hämtas från Internet och mäta över lite längre tid. På så sätt skulle man kunna få en kaliberingssiffra för den som kompenserar för dess avvikelse och därmed öka precisionen i summeringen av Ah / Wh över längre tid. Precisionen är tillräcklig ändå i förhållande till mätgivarna, så behövs inte!
  • Övervaka RAM-minnet för om minnesläckage detekteras som ger kritiskt lite ledigt minne eller för mycket fragmentering av RAM-minnet, och då göra en kontrollerad hard restart där driftsdata sparar så all driftspåverkan undviks?
  • Titta över min strategi för watchdog timer i ESP32-koden:
    A Designer´s Guide to Watchdog Timers , DigiKey
    What is a watchdog timer (WDT)?, ABLIC Inc.
    Watchdog timer, Wikipedia

Länkar: 2023-06-16

  • Solcellsström vid svagt ljus är ett viktig tillskott!
    Webpage: server time: 80.5 ms, (incl. log: 40.9 ms) ||