Webbsidan är senast uppdaterad:
Batterimonitor
NordicOffGrid Ultra-precise Battery System Monitor
Batterimonitor för driftsövervakning av off-grid solcellssystem
Här 98% av solcellsströmen till batteriladdning
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 ESP32-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-solladdregulator
"Att mäta är att veta" myntades redan på 1800-talet av Werner von Siemens!
Kommer uppdatera här efterhand som jag utvecklar Batterimonitorn.
Innehållet här är huvudsakligen råa minnesanteckningar i dagboksform till mig själv som dokumentation av projektet, men här och där är även mer beskrivande / förklarande texter inlagda.
Hur avläsningen av mätdata går till i elektroniken 2024-08-23
Jag använder en INA260 med 15A intern strömshunt för solcellsströmmen, som med mina 250Wp solcellseffekt aldrig kommer över 15A, samt en INA226 med extern strömshunt på 100A/50mV som mäter batteriströmmen. INA260 ska klara 15A kontinuerligt.
Och skillnaden mellan dem blir förbrukarströmmen.
Båda mäter med 16bit upplösning, så mäter ström på mA-nivå, samt de är extremt långtids- och temperatur-stabila så jag inte trodde det var tekniskt möjligt.
De är även fabrikskalibrerade så med 0A genom strömshuntarna ger de mätvärdet 0,0000A ut! Är från Texas Instruments så man kan lita på dessa uppgifter.
Båda INA-sensorerna kan självständigt sampla ett antal ström / spänning / effekt mätvärden som de sedan medelvärdesbildar och sparar i ett register ESP32 kan hämta dem ifrån då de sätter en interrupt-flag för det, medan de fortsätter med nästa samplingsserie. Finns ett antal olika fasta samplingsintervall och antal sampel som ska göras man kan välja bland.
ESP32 läser av mätdatan från dem via I2C-buss.
Så jag låter dessa INA-sensorer sampla 1024st mätdata självständigt under ca 1,2s som de då medelvärdesbildar.
Interrupt-signalen för nya mätvärden att avläsa triggar då en ISR (Interuppt Service Routine) för respektive sensor i ESP32 som i sin tur triggar vars Deferred interrupt processing Task i FreeRTOS i min C++ kod. Genom att använda Deferred interrupt processing minimeras tiden och koden i ISR så ESP32 blockeras så minimalt det går av interrupten! En jäkla fin teknik.
INA260/226 fungerar därmed nästan lite som coprocessorer till ESP32 och avlastar mycket av strömmätandet.
Samplar därmed ström / spänning / effekt värdena drygt 50.000ggr/min, så följer även väldigt dynamisk ström med hög precision typ kylskåpskompressorns startström.
Utnyttjar även ESP32 light-sleep för strömsnål nattdrift, som den då väcks ur av interrupt-signalen från INA266 ca 1ggr/1,2s, så är aktiv mätning även då.
Är då i nattdrift mer än 95% av tiden i light-sleep som ger en märkbar strömbesparing, vilket inte minst är viktigt vid vinterdrift med de korta dagarna då och den minimala solcellsströmmen i mitt off-grid solcellssystem. Strömsnål nattdrift är nu 98,75 - 96,25% av tiden i light-sleep med ett medelvärde på 97,9%, från senaste mätningarna! Är riktigt bra.
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 batteriverkningsgraden ä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 verkningsgraden 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!
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!
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]
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ömshunten 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
Införskaffat den 4G-router jag ska använda för att överföra driftsdata från off-grid solcellssystemet till min webbplats server. Valet föll på en Teltonika RUT241 4G/LTE(Cat 4), 3G, 2G industriell router med bra rykte om stabil tillförlitlig drift, med bra temperaturdriftsområde på -40°C - +75°C, driftsspänning 9VDC - 30VDC samt chassit är i aluminium för bästa värmeöverfö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 4G/LTE(Cat 4, ≤150Mbps), 3G, 2G
- Teltonika RUT241 Flyer
- Teltonika RUT241 Datasheet
- Teltonika RUT241 Quick start guide
- Teltonika RUT241 Wiki
- Teltonika RUT241 Wiki Power Consumption
- Teltonika RUT241 Wiki Firewall
- Teltonika RUT241 Firmware Downloads
- COMBO MIMO Mobile ROOF SMA Antenna
- COMBO MIMO Mobile ROOF SMA Antenna, Datasheet
- Power cable with 4-way screw terminal
- Power cable with 4-way screw terminal, Datasheet
- Teltonika RUT240 Setup Wizard
- Teltonika: Mobile Signal Strength Recommendations
- RUT241 Remote Monitoring & Administration, JSON-RPC, Modbus TCP, MQTT, etc.
- Dustin: Teltonika RUT241
- Ställt in tidsserver se.pool.ntp.org & europe.pool.ntp.org hos RUT241: europe.pool.ntp.org Samt uppdaterat till senaste firmware.
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
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!
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
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 batteriverkningsgrad och coulombverkningsgrad.
Ä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
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 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.
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å.
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.
- WebResponseImpl.h -
#define TEMPLATE_PLACEHOLDER '%'
- PlatformIO: Setting variables in code using build_flags
- Allow to override default template placeholder value with #define during compilation
- Template confused by data containing percent ('%')
- Send large webpage from PROGMEM containing templates with '%' sign in it (CSS part of page)
- Using template processor corrupts response HTML if it includes %
- CSS styles are removed when served by ESP8266 running an ESPAsyncWebServer
- DuckDuckGo: ESPAsyncWebServer "TEMPLATE_PLACEHOLDER"
- ESP32 Arduino HTTP server: Template processing
- ESP32 web server: template processing when serving HTML from file system
- ESPAsyncWebServer README.md
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!
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.
- 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!
- 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!
- Ä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.
- 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!
- 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!
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.
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(){
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!
if(!_async_queue){
_async_queue = xQueueCreate(512, sizeof(lwip_event_packet_t *)); // 32 default
if(!_async_queue){
return false;
}
}
return true;
}
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
Har nu kodat ett menysystem färdigt till 5st webbsidor i ESP32, så nu är där en hel webbplats. Huvudwebbsidan ä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" />
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
Finns lite att läsa på hos espressif kring snabbheten för Interrupt och kod:
High-Level Interrupts
Interrupt allocation
Maximizing Execution Speed
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)
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.
{
auto InterruptTime = esp_timer_get_time();
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xQueueSendToBackFromISR(DeferredInterruptQueue, &InterruptTime, &xHigherPriorityTaskWoken);
if( xHigherPriorityTaskWoken )
{
portYIELD_FROM_ISR(); // same as taskYIELD_FROM_ISR()
}
}
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.
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!
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
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
Ä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
Har kodat "Senaste 24-timmars löpande statistik" för strömmen, med Akuell-, Medelvärdes-, Maxvärdes- & Minvärdes-ström över senaste 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
Hade haft NordicOffGrid Batterimonitorn i drift i dryga 24h när skärmdumpen från mobilen togs idag. De senaste 24h har medelströmmen då varit -5mA i det väldigt gråmulna vädret, samt Max +73mA och Min -82mA. Max laddström mitt lilla experiment solcellssystem 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ömshunt.
Det löpande strömmedelvärdet för 24h är beräknat på ca 80.000 strömvärden 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
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.
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.
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
OBS!
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
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.
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"?).
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!
Ä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.
[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!
Å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!
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- / Multicore-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!
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!
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"!
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.
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.
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.
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.
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.
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!
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.
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:
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!
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.
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.
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(){
cleanupClients() finns inte för SSE där!
ws.cleanupClients();
}
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!
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 APIFö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!
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
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!
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.
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.
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.
Är intressant att se att medan strömvisningen på laboratorienätaggregatet 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 laboratorienätaggregatets strömvisning med en bra multimeter.
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
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.
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 batteriverkningsgrad 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.
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.
Kan nu även se den mesta driftsdatan via LCD-displayen av det som visas på webbsidorna.
Är sannolikt pga kombinationen blykol-batteri, strömpulsladdning 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 battericyklingar 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 solcellssystem! Var dock skoj att se för en battericykling såhär.
Ä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.
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ömpulsladdat.
Å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.
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
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.
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!
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:
Ä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.
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!
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!
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.
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.
På så sätt utnyttjar jag även INA226-strömsensorns prestanda och möjligheter optimalt.
Ä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 batteriverkningsgrad 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 experimentuppkopplingen 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.
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 laddströmvä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å!
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 kompressorkylskå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!
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?
Även skapat en ny Configuration-webbsida för inställningar av ESP32-batterimonitorn, tom än så länge. Ska bli data via WebSockets.
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.
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.
Detta är de få inställningar som min ESP32 Ultra-precise Battery System Monitor behöver!
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?
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:
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!
Har inte varit helt stabilt förut, så en bra indikering på att stabiliteten blivit signifikant bättre. Känns lovande!
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 batteridriften än bara precis Ah- och SoC-laddstatus samt Time-To-Go för den momentana urladdningsströmmen 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ångtidsstabiliteten i batterimonitorns laddstatusmätning 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 :-)
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.
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.
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.
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.
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.
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.
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 nattströmsparläge med light-sleep, och framförallt mäter dynamiska strömvärden med bättre precision nu i strömsparläget!
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.
- 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-solladdregulatorn 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_DeferredInterruptIN226() väntade på det och ej exekverade färdigt. Det innebar i sin tur att i Light-Sleep-Mode var då inte Task_DeferredInterruptIN226() 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 StateMachine->StateHandler() och Task_DeferredInterruptIN226() 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.
Läs mer om min RTC data store längre ned här.
En soft-reset, t.ex. via esp_restart(), resulterar i: "After successful restart, CPU reset reason will be SW_CPU_RESET. Peripherals (except for Wi-Fi, BT, UART0, SPI1, and legacy timers) are not reset.", vilket innebär att även soft-reset från kodkrasch eller WatchDog-Timer inte återställer allt i mikroprocessorn och inte motsvarar en PowerON hard-reset! Som exempelvis vid problem med I2C stack.
Jag har sett detta att efter panic´ed soft-reset kodkrasch har processorn ibland hängt sig och inte nått fram till normalt exekverande programkod igen, typ att "some of the data is still corrupted instead of being cleared out", vilket då krävt en manuell hard-reset via RST-knappen. Och då har den fungerat igen!
Så för att få en fullständig säker ren reset / reboot måste en hard-reset göras, vilket är det jag hackar nu. Är bättre än en extern WDT för den situationen! 2024-05-10
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.
Har nu fått det att fungera stabilt via ett RC-nät mot RST/EN-pin! 2024-05-09
INA226 samplar nu mätvärden (ström, spänning, effekt) drygt 70.000.000ggr/24h (även i natt-strömsparlä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.
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
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!
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!!!
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.
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!
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.
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.
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 datakommunikationen 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
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:
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:
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 datakurvorna! Ä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.)
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:
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ömshunten 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.
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:
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!
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!
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!
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.
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.
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 24/7/365-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 ESPAsyncWebServer-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.
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.
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.
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.
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:
2024-04-07
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 webbsidesbläddrande 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-batterimonitorn 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!
2024-04-14
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
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)
Där
{
vTaskDelay(5000 / portTICK_PERIOD_MS); // Settling time to WiFiMulti.run
}
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
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.
Fungerade bra med anslutning vid 3:e försöket när det inträffade idag 2024-04-20!
2024-04-24 Har nu sett fin stabil funktion flera gånger vid upprepade anslutningförsök med färre WL_NO_SSID_AVAIL
, så blev bra med 1500ms + 4500ms Settling-time för WiFiMulti.run()!
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 batteriverkningsgrad 97,8%(Ah), mätt av min batterimonitor. Då med ett fel i batteriverkningsgrad 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 batteriverkningsgrad 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å batteriverkningsgraden ä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 batteriverkningsgraden 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 batteriverkningsgraden 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 batteriverkningsgrad, men även med LiFePO4 fås lätt >2,5%-enheters fel i en manuellt angiven batteriverkningsgrad:
"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) batteriverkningsgrad för mina AGM-blykol cyklat inom 71%-95% SoC!
2024-04-17
Hade turen att titta på datan över ESP32 RAM-minnesutnyttjandet då WebSocket-dataöverföringen till "Battery 24hr operational graph"-webbsidan stördes ut en längre stund av de 9 andra 2,4GHz WiFi-routers från grannarna, och då användes 10-12kB av det fria RAM-minnet innan ws.availableForWrite() / ws.availableForWriteAll() slog till bromsarna. Och när WebSocket-kommunikationen kom igång igen så återlämnades det RAM-minnet.
Trevligt att få chans att se hur bra, robust och verkningsfullt det fungerar att villkora WebSocket-kommunikationen med ws.availableForWrite() / ws.availableForWriteAll()!
Så gissningsvis kan man räkna med att WebSocket-dataöverföringen använder max 15kB av RAM då när ws.availableForWrite() / ws.availableForWriteAll() bli falska, vilket känns rimligt.
2024-04-24
Robust driftsäkerhet via funktionalitet i programkoden:
Jag kodar en del funktionalitet i ESP32 C++ koden som bara är till för att ge en ökad robusthet i exekveringen / driften. Både aktiv och passiv sådan, där vissa delar i driften övervakas och andra kritiska händelser undviks. Som vissa kritiska passager i koden kan man skydda mot risk för s.k. race-condition, samt sådant som RAM-minne, minnesfragmentering och strömsensorns funktion via I2C m.m. kan övervakas och göras aktiva åtgärder mot om det blir kritiskt där.
Har verifierat att det bidrar till en mer robust stabil 24/7/365-drift av ESP32 kodexekveringen!
Har nu gjort signifikanta framsteg där i hanteringen av WiFi-anslutningen samt WebSocket datakommunikationen. Så dels fungerar de stabilt nu med att kunna hantera rätt grova störningar de övriga ofta 9st 2,4GHz WiFi-nätverken från grannarna här i lägenheten kan orsaka glest.
Dels när ESP32 ska ansluta till WiFi-nätverket kan den nu upprepat stabilt försöka det under rätt lång tid tills lyckad uppkoppling. Samt WebSocket datakommunikationen mellan ESP32-webbservern och webbsidan i webbläsaren kan webbsidan själv automatiskt återansluta om den förloras, vilket är bra om jag är i utkanten av täckningsområdet för WiFi eller den störs ut av andra WiFi-nätverk eller kanske åskoväder.
Är en viktig funktion då ESP32-batterimonitorn vintertid ska kunna stänga ned 4G-routern för extremt strömsnål drift och bara starta den glest för dataöverföring till webbservern. Görs då adaptivt efter hur solcellerna i vintermörkret klarar laddningen av batterierna.
Espressifs ESP32 har 8kB+8kB RAM-minne i realtidsklockan (RTC) där den ena 8kB SRAM (RTC Slow Memory) bibehåller sitt innehåll vid soft-reset från watchdog, reset från panic-funktion i koden eller en kontrollerad reboot från min programkod samt även under deep-sleep, vilket ger intressanta möjligheter. Det minnet raderas bara vid tryck på reset button (hard-reset).
Används via attribute macrot RTC_NOINIT_ATTR för variablerna.
För en batterimonitor är det essentiellt att kunna bibehålla all data som berör batteribankens laddstatus (SoC) även om det skulle inträffa en ESP32 panic-reset av en yttre störning. Så man efter t.ex. 1 veckas PSoC-drift inte riskerar att förlora batteribankens laddstatus!
Så min ESP32-batterimonitor utnyttjar RTC Slow Memory för sådan SoC-data, vilket jag verifierat fungerar perfekt vid soft-reset från watchdog eller reset från panic-funktion i koden!
Jag sparar även dessa data som berör SoC i flash-minnet lite glest, men då flash har begränsad livslängd så kan det inte göras för ofta. Men blir ytterligare en backup för den viktiga datan!
Såg nu senare (2024-05-07) att intressant nog använder ESP Insights också RTC data store: "ESP-Insight currently uses RTC memory to store the messages until it is sent to the cloud. Unlike, normal RAM, RTC store makes data available across soft resets. Thus, it brodens the usefulness of the data across reboot." Beskrivs även här. Läs mer om min RTC data store här ovan.
ESP Insights API och ett kodexempel på To get started with Insights.
Målsättningen är att klara stabil 24/7/365-drift utan att någonsin behöva boota om, men sannolikheten att aldrig behöva boota om är nog inte så stor. Men ska i vartfall uppnå en riktigt lång tid mellan reboot, som då helst enbart ska göras kontrollerat när något krititisk som kräver reboot detekteras via min övervakning av ESP32-driften.
Sker en okontrollerad reboot så garanteras ändå datan kring SoC via RTC Slow Memory!
Detta tar dock kring året i skarp drift att verifiera, men verifierat i 14-dagars stresstestad drift nu.
Samt delar av det är verifierat under det dryga årets skarp drift här hemma under utvecklingen.
Har parallellt med detta nu även verifierat och analyserat hårdvarans kopplingsschema kring INA226 extra noga innan jag löder ihop en mer permanent sådan. Och den är OK!
2024-04-25
Valet jag gjorde för min ESP32-batterimonitor att visa driftsinfo och inställningar på webbsidor via WiFi och webbserver i ESP32 känns helt rätt, än mer nu kanske när jag fått se det i drift.
En modern webbläsare i mobilen / datorn är en avancerad resurs med fint kraftfullt stöd för både grafik-, text/font-, layout- och data-hantering samt JavaScript, och ger via WebSocket en bra möjlighet till fin tvåvägs data- och informations-utbyte direkt mellan webbsida och ESP32.
Ytterligare fördelar är att den resursen belastar inte ESP32 internt samt hanterar touch-skärm.
Har idag kodat så jag via en tryckknapp på webbsidan kan nollställa viss mätdata i ESP32, vilken visas på webbsidan. Har då även inline-kodat en SVG-icon för trycknappen för trevlig grafisk utformning på webbsidan.
Nollställningen gör jag via WebSocket-kommunikation och var inte många kodrader som behövdes för att få till det, inkl. modal dialogruta för kvittens av att datan verkligen ska nollställas.
Sedan direkt efter nollställning skickas den nollade datan ut via WebSocket till alla webbläsare som just då visar den webbsidan, så infon direkt blir uppdaterad där.
Är bara så jäkla smidigt :-)
Gör allt kodande i PlatformIO på VSCode, där jag då kan koda både C++ koden för ESP32 och webbsides-koden för webbsidorna, vilken också lagras i ESP32.
Smidigt att kunna koda allt i samma IDE med så bra stöd som den ger i allt kodandet!
PlatformIO hanterar även de kodbibliotek jag använder till ESP32.
Samt idag har jag haft WiFi i ESP32 igång uppkopplad mot routern och skickande WebSocket data stabilt till webbsida under ca 5h, och då har det registrerats 1st automatisk återanslutning via min WiFiReconnect()!
Så känns bra tycker jag, både stabiliteten och att min WiFiReconnect() faktiskt aktiveras när det behövs.
2024-04-28
Har fått reaktioner på att man i ett privat hobbyprojekt inte skulle kunna få fram en batterimonitor bättre än de utvecklade av stora företag i Europa som Studer Innotec, Victron Energy m.fl. Men i ett pensionärshobbyprojekt har man tid på ett helt annat sätt!
Som lilla startupen Omotion i Lund med trehjuliga elfordonet Omotion 2 utvecklar också helt själva bland annat system för övervakning, felsökning, diagnosticering samt kontroll av batteri- och laddstatus med mera som går via en app, enligt artikel i NyTeknik. Och som startup har man inte lika mycket tid som en pensionerad ingenjör. Men de gör så ändå!
Så jag tycker inte det är så märkligt att jag kan det med all min yrkeserfarenhet av avancerad teknikutveckling samt allmänna tekniska nyfikenhet och driv!
Har nu kodat så det även visas en vertikal linje för dygnets första 0,5% Tail-current "Sync 100% SoC" i min "Battery 24hr operational graph", så jag smidigt kan se / utvärdera dess funktion.
Är blybatteriet som själv talar om att det är fulladdat så vid 0,5% Tail-current (0,45A för mitt 90Ah AGM-blykol), vilket det finns gedigen teknisk information kring från högskola och gurus.
Och ser man här bryter strömkurvans minskning av och blir flackare strax innan vilket sannolikt indikerar att blybatteriet är fulladdat då. Så vetenskap / teori och praktik verkar hänga ihop!
Och strömkurvan planar successivt ut på ca 0,25A som då ger 0,45 / 0,25 = 1,8ggr marginal för robust 0,5% Tail-current funktion. Sedan övervakar min programkod detta och kan adaptivt vid behov öka de 0,5% för Tail-current, om det skulle behövas för typ riktigt åldrade blybatterier.
Ska bli intressant att se mer av vid battericykling med lite djupare urladdningar senare!
Har även en del andra parametrar kodade som mäter och analyserar för att noga verifiera funktionen och precisionen hos min ESP32-batterimonitor, med de visar jag inte.
Är väldigt intressant att blybatteriet själv talar om info såhär om dess drift istället för att försöka ha några grovt gissade kriterier och fasta värden i programkoden för det!
Blybatterier kan även själva tala om på liknande sätt när absorptions-laddningen ska avbrytas och växla till float-laddning, vilket blir mycket exaktare och skonsammar för blybatteriladdningen än någon fast kodad algoritm för det i en solladdregulator!
Både olika battericykling, temperatur, åldrande samt varierande laddströmmar från solceller påverkar detta som då batteriet har med sig när det ger info om att avbryta absorptions-laddningen, på ett helt annat sätt än en fast kodad algoritm kan.
Går naturligtvis att göra för LiFePO4-batterier också, även om en aktiv cellbalanserare kanske kan stör det lite jämfört med den mer naturliga funktionen med självbalansering av cellerna i blybatterikemin.
Jag har idéer kring hur blybatterierna ska kunna ge ytterligare info kring sin drift för än mer optimal skonsam styrning av batteridriften / laddningen, som jag hoppas få chans at testa.
Hur många andra batterimonitorer visar i diagram när Sync 100% SoC sker, så man själv kan se hur precisionen är med det?
2024-04-30
Löste ett lite kodproblem igår med att synkningen av RTC till NTP-tidsserver gjorde att aktuellt index för mina 24h data-arrayer backade ett steg om RTC justerades tillbaka något i tid, vilket hänt rätt sällsynt med synliga små krusningar på datalinjerna tidigare.
Får fram aktuellt 10min-index via:
ArrInd24hrNow = TimeInfo.tm_hour * 6 + (TimeInfo.tm_min / 10);
Så om typ kl.15:10:00 backar till 15:09:59 så backade arrayindex ett steg.
Och med min nya tidslinje för dygnets första Sync 100% SoC så hoppade den igår plötsligt fram ett stort kliv på eftermiddagen samtidigt som det blev små krusningar på datakurvorna. Och ny sådan tidslinje får bara detekteras efter att nytt dygn börjat, som min kod baserar på att senaste dataindex blir mindre än föregående. Och när RTC-tiden justerades bak något igår blev det uppfyllt mitt på dagen! Och då blir det även små fel i beräkningen för datakurvlinjerna.
Har sett sådana små oförklarliga krusningar på datalinjerna glest tidigare också men då inte förstått orsakan, men nu blev det så tydligt.
Så har lagt in en logik där nu att dataindex får bara backa om det görs ett tidshopp i dataindexet på >12h, vilket bör bli idiotsäkert.
Kan bli så dels när ESP32 kört död räkning en tid mellan anrop till SNTP, samt ibland blir även synkningen mot tidsservern fördröjd någon sekund, så man får synkning mot en aning gammal tid. Ständiga små förbättringar i programkoden.
Och nu idag fungerade det perfekt. Och med tredje dagen nu så fortsätter man här att se att strömkurvans minskning bryter av och blir flackare strax innan eller vid första 100% SoC synkningen för dagen, vilket sannolikt indikerar att blybatteriet är fulladdat då.
Så ska bli jätteintressant att följa detta vid lite mer aktiv battericykling framöver, som ger lite djupare urladdningar! Lägsta uppmätta Tail-current under PV-Throttle är nu 183mA.
2024-05-01
Dagens första "Sync 100% SoC" skedde vid 99,3% SoC, vilket är riktigt bra precision!
Samt AGM-blykolbatteriet laddades med full solcellsström fram till ca 97,5% SoC då PV-Throttel startade, men är rätt låg laddström här i mitt experiment off-grid solcellssystem (<2,4A / 90Ah).
Och detta ifrån 92% SoC urladdad nivå som lägst denna battericykeln.
Riktig bra värden fast jag ännu har ca 1m mätkablar mellan strömsensorn och strömshunt, vilket ger lite felmätning av 9kHz strömpulsandet från Battery Reconditioner med något lite för mycket mätt urladdning. Så när jag lött ihop den delen med strömsensorn monterad i en apparatlåda intill strömshunten kommer dessa värden bli ytterligare något bättre!
Laddade både mobilen och lite verktygsbatterier igår kväll, med som mest 64W momentant.
2024-05-03
Idag skedde "Sync 100% SoC" vid 99,1% SoC, mätt av ESP32. Under denna battericykel var lägsta SoC då 95,2% samt cyklad urladdning -4,3Ah / 90Ah, också mätt av ESP32.
Men har då en felmätning av 9kHz strömpulsandet från Battery Reconditioner på grovt -0,8Ah/dygn. Utan den felmätningen hade det skett vid lite högre SoC väldigt nära 100% SoC!
Den felmätningen av de 9kHz strömpulserna kommer minska då jag får strömsensorn INA226 monterad i apparatlåda nära strömshunten, mot de ca 1m långa kablarna mellan dem just nu. Men även såhär är -0,8Ah/dygn fel i stort försumbart i mitt riktiga off-grid solcellssystem!
Även här ser man hur strömkurvans minskning bryter av och blir flackare ungefär vid första "Sync 100% SoC" för dygnet (inringat), vilket sannolikt indikerar att blybatteriet är fulladdat då. Så vetenskap / teori och praktik verkar hänga ihop bra kring 0,5% Tail-current!
Men får bättre data senare från lite djupare battericykling i mitt riktiga off-grid solcellssystem!
Detta är från mitt lilla experiment off-grid solcellssystem i lägenheten.
Är som rena konstverket efter att under så lång tid ha slitit med att få till detta i ESP32 :-)
Så jag tillåter mig att njuta av de fina kurvlinjer över battericykeln jag får i mitt diagram nu :-)
Och samtidigt får jag nya kunskaper och insikter om hur AGM-blykol batterikemin fungerar!
2024-05-06
Visar nu analysdata över själva ESP32-batterimonitorns funktion på webbsida. Mäter, analyserar och beräknar statistik över lite olika nyckelparameterar / nyckeldata under drift som visar med vilken precision min ESP32-batterimonitor arbetar, för att objektivt få fram data på det.
Är ett ingenjörsmässigt sätt att utveckla detta på, med inbyggd analys av egen funktion!
Hittills visar det på väldigt bra precision, i vissa delar på exceptionellt bra precision.
Så verkar kunna leva upp till namnet: Ultra-precise Battery System Monitor!
Samt har ändrat på precisionen i datavisningen av SoC så det är med en decimal överallt nu.
Har även justerat så jag börjar med att ta med 100% av uppmätt batteriverkningsgrad i beräkningarna nu från början, så får verklig drift visa hur det blir. Med den höga precisionen indikerad nu bör det bli bra!
2024-05-07
Första PV-Throttle för dagen idag skedde vid 96% SoC efter återladdning från 92% SoC i float-laddning med max 1,4A. Hade det varit med absorption-laddning hade det varit vid högre SoC, samt har ännu den där lilla felmätningen av 9kHz strömpulsandet från Battery Reconditioner.
Mest bara checkat att mätning med datavisning på webbsidan fungerar OK.
Blir intressant att se vad det blir i mitt riktiga off-grid solcellssystem vid mer aktiv battericykling!
2024-05-08
Fick ny version av ESPAsyncWebServer-esphome:
PS D:\...\Documents\PlatformIO\Projects\PWMcontroller> pio pkg update
Resolving wemos_d1_uno32 dependencies...
Library Manager: Updating ESPAsyncWebServer-esphome @ 3.1.0
Library Manager: Removing ESPAsyncWebServer-esphome @ 3.1.0
Library Manager: ESPAsyncWebServer-esphome@3.1.0 has been removed!
Library Manager: Installing ottowinter/ESPAsyncWebServer-esphome @ 3.2.0
Downloading [####################################] 100%
Unpacking [####################################] 100%
Library Manager: ESPAsyncWebServer-esphome@3.2.0 has been installed!
Library Manager: Resolving dependencies...
Library Manager: Installing esphome/ESPAsyncTCP-esphome
Downloading [####################################] 100%
Unpacking [####################################] 100%
Library Manager: ESPAsyncTCP-esphome@2.0.0 has been installed! (för ESP8266)
Library Manager: Installing Hash
Library Manager: Installing ESP8266WiFi
What´s Changed: Add mutex for queue processing.
Infogade min bugfix i AsyncEventSource.cpp in function avgPacketsWaiting() samt ändrade till TEMPLATE_PLACEHOLDER '$'
för preprocessorn.
På webbsidorna med SSE (Server-Sent Events) uppdateras all SSE-data signifikant snabbare nu och all data i ett svep utan att kön blir aktiverad, så en positiv förbättring.
Även ESP32-RTC synkar nu mer exakt mot NTP-tidsserver så webbläsare och ESP32 visar samma sekund var gång.
När jag superstressade websidan "System Operational Data" som har väldigt mycket SSE-data fick jag en panic´ed-reset, men är inte så jag använder webbsidorna normalt. Så räknar inte det om det inte händer fler gånger vid normal användning. ESP32 gjorde i alla fall en soft-reset + hard-reset (PowerON), så fungerar som tänkt och var igång igen med loggning efter bara några sekunder. Och då med all essentiell loggdata för batterimonitorn sparad och återställd!
Så är "bara" 24h loggdatan för presentation av batteridriften som går förlorad, men ska senare titta på om även den ryms att sparas i RTC Slow Memory (8kB RAM), vilket jag tror.
Så ifall hade man inte märkt något alls av en sådan här reset, då även WebSocket webbsidorna återansluter automatiskt efter sådan reboot.
En 24h datatidsserie tar 1824bytes och alla 6 då 10944bytes, så blir för mycket. Men 4st som visas i diagrammet blir 7296bytes, vilket kanske har chans att rymmas i RTC Slow Memory.
Men ska nog titta på en kombination av glest lagrad data via Preferences samt bara datan sedan dess i RTC Slow Memory, och så ifall kommer jag kunna spara all data inkl. 7dygns drifttidsdata senare. Ska göra lite inledande tester med det!
2024-05-09
Kan då även robust stabilt få till en ESP_RST_POWERON hard-reset via en kontrollerad esp_restart() soft-reset när programkoden t.ex. detekterar för lite ledigt RAM-minne eller för fragmenterat RAM-minne etc.
Här finns alla esp_reset_reason_t Reset reasons definierade för ESP32.
Får även titta lite mer på Error Handling och alla dess Error Codes References.
2024-05-11
Kodat så att efter varje PowerON och soft-reset synkas RTC mot NTP-server automatiskt, med försök under 180s tills lyckad tidssynkronisering. Testade utan tillgänglig WiFi och då hann den med 46st sökande efter WiFi via WiFiMulti.run() under de 180s, tyst stabilt i bakgrunden medan ESP32 visade avlästa datavärden från INA226 på LCD-teckendisplayen. Riktigt bra :-)
Om inte
RTC_NTP_Synchronized == true
efter 180s så görs nya försök var 30:e minut tills lyckad tidssynkronisering, då det krävs innan loggning av data med tidsstämpling startar. Om uppkopplingen till mobilnätet är svag eller inte fungerar t.ex., för robust helt autonom drift.Har nu ökat de 180s till 300s samt verifierat att programkoden som gör nya försök var 30:e minut tills
RTC_NTP_Synchronized == true
uppnås fungerar som tänkt! Var 30:e minut spar ström.Med 300s bör det bli bra marginaler att boota upp 4G-routern samt koppla upp till Internet via mobilnätet, men får också verfieras senare.
Är ytterligare ett steg mot robust stabil autonom 24/7/365-drift!
Senaste dygnet har jag haft min 100W 230V växelriktare påslagen som strömförbrukare så att batterispänningen större delen av tiden legat under den nivån som aktiverar mitt 9kHz strömpulsande från Battery Reconditioner. Så då stämmer mätningarna bättre.
AGM-blykol batteriet blev då urladdat till 94,5% SoC samt PV-Throttling startade vid 97.4% SoC och "Sync 100% SoC" skedde vid 99,7% SoC! Så indikerar laddning med full ström från solcellerna högt upp i SoC samt riktigt bra precision i "Sync 100% SoC"!
Men är dels med lågt urladdningsdjup samt dels med låg laddström, så därför jag kallar det för indikation. Får säkrare bättre värden senare från mitt riktiga off-grid solcellssystem med lite djupare urladdningar och större strömmar. Är ESP32 som loggar dessa mätvärden för utvärdering (samt en del annat också med analys / statistik).
2024-05-13
Kodat så RTC´s epoch-time sparas under en soft-reset så RTC-tiden återställs när ESP32 bootat om efter störning. Är helt nödvändigt för att dataloggningen ska kunna fortsätta med sin RTC-tidsstämpling då uppkoppling mot mobilnätet inte fungerar. Är bara 2-3s som går förlorat under reboot, vilket är helt försumbart för mina 10 minuters data jag tidsstämplar.
Var komplicerat att få till både med tidsfunktioner men än mer att integrera med övrig programfunktion! Men nu hanteras det på ett tydligt robust sätt som även samverkar fint med synkningen mot NTP-tidsserver när mobilnätet är tillgängligt. Espressif System Time, ESP32 – SNTP
Har inte hittat någon kodfunktion som flaggar när RTC har synkat tiden med NTP-tidsservern, så har utvecklat stabila robusta egna funktioner som analyserar och detekterar det, så WiFi-uppkopplingen bibehålls tills tidssynkningen är genomförd oavsett tiden det tar upp till maxtid.
Såg att jag med nya versionen av ESPAsyncWebServer-esphome hade för lite stack-size för Task_WebServerESP32() så ökade på den också. Hade någon kodkrasch i början när jag stresstestade nya versionen, så kan varit denna stack-size som tog slut då.
Körde även igår en dygnsdrift som minimerade felmätningen av mitt 9kHz strömpulsande från Battery Reconditioner.
AGM-blykol batteriet blev då urladdat till 94,2% SoC samt PV-Throttling startade vid 97.6% SoC och "Sync 100% SoC" skedde vid 99,8% SoC! Så indikerar åter laddning med full ström från solcellerna högt upp i SoC samt riktigt bra precision i "Sync 100% SoC" med bra stabil repeterbarhet! Så det här ser bättre ut än vad jag trodde var möjligt! Mätt och analyserat av ESP32.
Day | Lowest SoC | First PV-Throttle SoC | First "Sync 100% SoC" |
2024-05-11 | 94,5% | 97.4% | 99,7% |
2024-05-12 | 94,2% | 97.6% | 99,8% |
2024-05-16
Börjat läsa på om C++11 & C++14 i boken Effective Modern C++ (O´Reilly) då koden default kompileras till C++11 i PlatformIO till ESP32 via Espressif Arduino framework (Compilation C++: 201103). Tanken är att successivt ändra så mycket som möjligt till C++11 i min kod, då det ger bättre, tydligare och säkrare kod!
Dock: By default, ESP-IDF compiles C++ code with C++23 language standard with GNU extensions (-std=gnu++23), så Espressif Arduino framework ligger lite efter där.
C++ features supported: All C++ features implemented by GCC, except for some Limitations, där GCC är lite som MicroC++ typ som MicroPython vs Python (som jag uppfattat det).
Jag provade i platformio.ini med:
build_unflags = -std=gnu++11
och då blev det "Compilation C++: 201703", så även GNU C++17 fungerar, vilket är bra då boken har underrubriken: "42 Specific Ways to Improve Your Use of C++11 and C++14"!
build_flags = -std=gnu++17
Kompilerar därmed nu i PlatformIO med GNU C++17 till ESP32, vilket fungerar bra.
Så siktar då på C++11 / C++14 för min programkod, men även sett visst bra i C++17.
Med C++11 kom även ett bra utökat Standard Template Library (STL) med många färdiga användbara algoritmer, datastrukturer, klasser och funktioner, som ett generellt kodbibliotek.
"Before you assume that you need to write a custom algorithm for your program, first review the C++ Standard Library algorithms. The Standard Library contains an ever-growing assortment of algorithms for many common operations such as searching, sorting, filtering, and randomizing. The math library is extensive." Microsoft
GeeksForGeeks: C++ 11 vs C++ 14 vs C++ 17, Efterlängtat: C++17 new feature : If Else and Switch Statements with initializers if(auto var1 = foo(); var1 > 2)
. Wikipedia C++11, Wikipedia C++14, Modern C++ features: C++20/17/14/11, The evolution of statements with initializers in C++ - part 1, The evolution of statements with initializers in C++ - part 2
Microsoft skriver i artikeln "Welcome back to C++ - Modern C++":
"One of the major classes of bugs in C-style programming is the memory leak. Leaks are often caused by a failure to call delete
for memory that was allocated with new
. Modern C++ emphasizes the principle of resource acquisition is initialization (RAII). The idea is simple. Resources (heap memory, file handles, sockets, and so on) should be owned by an object. That object creates, or receives, the newly allocated resource in its constructor, and deletes it in its destructor. The principle of RAII guarantees that all resources get properly returned to the operating system when the owning object goes out of scope." Vilket då bl.a. de nya smarta pointers hanterar.
Så det klassiska problemet med minnesläckage i C är i C++11 eliminerat med detta!
Såg även att heap minneshanteringen i MicroPython är benägen att skapa problem med heap-fragmentering, där minneshanteringen i C++ är mer robust avseende heap-fragmentering, men beror även mycket på hur man kodar. Så med C++11 / C++14 kodning kan man då sannolikt få minst lika stabilt exekverande kod för 24/7/365-drift som med MicroPython.
Och C++ på ESP32 ger väldigt snabb interrupt-hantering i koden, vilket är en avgörande realtidsfunktion för den höga mätprecision jag får i avläsningen från strömsensorn.
C++ är mycket snabbare än MicroPython, ofta 25-255ggr eller än snabbare!
C++ är även "strictly typed" / "statically typed" vilket jag älskar!
Så valet mellan C++ / MicroPython är nog mest fråga om tycke och smak, samt realtidskrav.
Språk med garbage collection (som MicroPython) är dock olämpliga för realtidssystem.
Bjarne Stroustrup: "C++11 feels like a new language: The pieces just fit together better than they used to and I find a higher-level style of programming more natural than before and as efficient as ever." C++11 - the new ISO C++ standard
Så C eller C++11+ är som två helt olika programmeringsspråk att koda i!
Har nu som första steg bytt alla const till constexp där tillämpligt, och det fungerar bra.
Samt ändrat int64_t ESP_Time_us;
till std::atomic<int64_t> ESP_Time_us;
i class StateMachine
så den hanteras atomic överallt för thread-safety så race-conditions undviks i multitasking / concurrency (concurrency API). Det gick också bra efter några små bra kodförändringar som kompilatorn pekade ut att det krävdes. Så blev även en form av kvalitetscheck av programkoden där.
Ska se över fler variabler att ändras till std::atomic för säkrare multitasking via FreeRTOS.
Kan kanske även ta bort några FreeRTOS-Mutex på så sätt, vilket blir bättre säkrare kod!
Detta är nog även en grund till att kunna utnyttja båda ESP32´s kärnor för min programkod.
Får även titta på std::string
framöver, samt kanske std::vector
/ std::mutex
. C++11: std::string
"C-style strings are another major source of bugs. By using std::string and std::wstring, you can eliminate virtually all the errors associated with C-style strings. You also gain the benefit of member functions for searching, appending, prepending, and so on. Both are highly optimized for speed. When passing a string to a function that requires only read-only access, in C++17 you can use std::string_view for even greater performance benefit." Microsoft
- How To Use Basic Methods Of Strings In C++?.
2024-05-17
Har fortsatt med att ge fler variabler std::atomic
så alla gemensamma variabler med övriga kodfunktioner hos både Task_LCDbuttonsHandler() och GetNTPtimeInternetTimeserverToRTC() och några fler blir atomic för undvikande av race-condition. Totalt 23st std::atomic
nu!
Gjorde att jag nu kunde flytta Task_LCDbuttonsHandler() till core0 utan att något race-condition, konstiga värden eller kodkrasch uppstod som det gjorde vid tidigare försök.
Var den saknade pusselbiten för att smidigt fixa det istället för med mer omständig mutex.
Så std::atomic
hos C++11 / C++14 är ett riktigt lyft för multitasking / threads / concurrency! Samt kodas bara där variabeln typas / definieras, så ingen risk man glömmer någon stans i koden som med mutex, och ger dessutom effektivare kodexekvering och renare tydligare kod.
Kompilatorn ger då även en sorts check att man tänkt rätt kring concurrency med de variablerna, med felmeddelande när något man kodat inte är förenligt med std::atomic
.
GeeksForGeeks: C++ 11 – <atomic> Header, introduces a powerful mechanism for managing concurrent access to shared data in multithreaded applications.
2024-05-18
Kom nya versioner av platform-espressif32 och Espressif Arduino framework i PlatformIO:
Espressif32 6.7.0 som supportar ESP-IDF v5.1.2 samt Arduino ESP32 v2.0.16.
Espressif32 6.7.0 har fått en förbättrad esp32_exception_decoder, så blir intressant om/när jag får en ny kodkrasch att få se tydligare felmeddelande.
Min kod kompilerade och fungerade fint med detta, och en kod-bug som gav en kompileringsvarning jag bug-anmält var nu fixad. Så slipper jag se det gult skrikande varningsmeddelandet!
2024-05-19
Att köra Task_LCDbuttonsHandler() i core0 fungerar nu helt stabilt via std::atomic
för variabler delade med övriga Task´s! Fick tidigare glest panic´ed-kodkrasch vid soft-reset reboot från GetNTPtimeInternetTimeserverToRTC() då den exekverade parallellt med övrig kodexekvering och det ibland uppstod en race-condition för variabler den delade med andra Task´s, men ser också ut att vara helt löst nu via std::atomic
. Så det nya concurrency API i C++11 / C++14 är ett riktigt lyft för smidigt kodande av multitasking / threads / concurrency via FreeRTOS!
Nu även kodat så all Trip-data sparas och återställs vid soft-reset.
2024-05-20
Fick idag ofrivilligt testat att RTC uppdaterar sig mot NTP-tidsserver med försök var 30:e minut tills OK, då Internet var nere 1h timme här hemma när jag startade ESP32. Och när Internet kom tillbaka då så synkade RTC med NTP när första 30-minuters intervallet inträffade.
Och ingen 24h statistisk RTC-tidsstämplad driftsdata skapades innan dess RTC blivit synkad.
Men övrig funktion var i full drift, bara 24h statistiken som inte fanns eller visades.
Så där har jag uppnått avsedd full funktion i min kod, riktigt trevligt!
Nu får jag vid kodkrasch ut precis samma omfattande info via esp32_exception_decoder i serie-terminalen i PlatformIO som jag får ut via ESP Stack Trace Decoder på webben :-)
Så senaste uppdateringen till Espressif32 6.7.0 blev riktigt bra!
Kodat så jag nu får statistik över Heap-minnet (RAM), så jag får info att utgå ifrån för att senare lägga in en kontrollerad soft-reset om det blir kritiskt lågt eller fragmenterat.
2024-05-21
Kodat att det sparas lite statistik för High-SoC battericykling samt vid "Heap-memory critical low" görs nu en kontrollerad soft-reset, både vid för lågt lägsta Heap-memory sedan PowerON samt vid för mycket Heap-fragmentering.
Baserar "if heap critical state requiring a controlled soft-reset" på första uppmätta statistiken över Heap-minnet, så får justera dess villkor när jag fått data för längre tids drift.
Min ESP32-batterimonitor har varit i drift utan uppdatering av programkoden i 7 dygn nu och inte en enda byte i Heap-fragmentering samt även MinFreeHeap stabiliserade sig på en viss nivå så pekar mot frånvaro av minnesläckage. MinFreeHeap kräver en längre driftsperiod för att säkert avgöra frånvaro av Heap-minnesläckage då minnet används dynamiskt hela tiden vid bläddrande mellan webbsidorna.
När man bläddrar mellan de olika webbsidorna från ESP32 så är det slumpen som avgör om skickade SSE / WebSocket data, laddande av webbsideskod samt avläsning av strömsensorns värden med efterföljande statistisk beräkning inträffar exakt samtidigt, så worst-case i Heap-minnesbelastning kan ta ett bra tag innan det registrerats!
7 dygns drift motsvar drygt 500.000 programloopsexekveringar för den Task som är central.
2024-05-22
Har kodat så att om datakommunikationen via I2C till INA226 strömsensorn hänger sig och >5st reset av INA226 misslyckats görs en soft-reset av ESP32, så hela ESP32 startar om automatiskt med allt initierat på nytt igen. Via lite hackad funktion görs då en total reset!
Jag har arbetat som utvecklingsingenjör inom maskinutveckling för processindustrin stor del av yrkeslivet där nedtid / stillastående är extremt dyrt och oacceptabelt, och där är det vanligt med självövervakning så hos maskinsystem. Så tar det tänket med mig här i utvecklingen av mikrokontroller baserade system för autonom 24/7/365-drift nu i mitt pensionärs hobbyprojekt.
2024-05-24
MinFreeHeap: 107000b
Min MaxAllocHeap: 61428b
MaxAllocHeap: 94196b
Verkar ha stabiliserat sig här, med mycket bläddrande bland webbsidorna samt samtidigt både i mobilen och på datorn. Men får se efter längre driftstid senare.
MaxAllocHeap har hållit sig länge på 94196b nu, så den fragmenteras inte. Men kan ju finnas ett / flera kontinuerligt fritt mindre minnesblock som fragmenteras som jag inte ser ännu.
Men å andra sidan så allokeras där 94196b - 61428b = 32768b emellanåt utan fragmentering.
2024-05-26
Preferences har inte plats / kan inte spara mina 6x2080b 24hr loggdata så måste använda LittleFS filsystem istället. Även LittleFS har Dynamic wear leveling för Flash!
Använder i platformio.ini:
board_build.partitions = huge_app.csv
board_build.filesystem = littlefs
Med huge_app.csv fås: SPIFFS 917504b, app0 3145728b, nvs (preferences) 20480b
Och installerat i koden får jag följande data för LittleFS;
[D][main.cpp:2227] setup(): LittleFS mounted OK
[D][main.cpp:2230] setup(): LittleFS.totalBytes: 917504 bytes
[D][main.cpp:2231] setup(): LittleFS.usedBytes: 8192 bytes
huge_app.csv partition table:
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x300000,
spiffs, data, spiffs, 0x310000,0xE0000,
coredump, data, coredump,0x3F0000,0x10000,
Ny version av ESPAsyncWebServer-esphome (v3.2.2) och då kom detta tillbaka då jag glömde lägga in min buggfix för det:
Guru Meditation Error: Core 1 panic'ed (IntegerDivideByZero). Exception was unhandled.
Core 1 register dump:
PC : 0x400eb236 PS : 0x00060a30 A0 : 0x800d5eb0 A1 : 0x3ffb4910
A2 : 0x00000000 A3 : 0x00000000 A4 : 0x00000000 A5 : 0x3ffe0f74
A6 : 0x00000004 A7 : 0x3ffb492c A8 : 0x00000000 A9 : 0x3ffb48f0
A10 : 0x3ffb4918 A11 : 0x3ffdff4c A12 : 0x00000000 A13 : 0x00000000
A14 : 0x372e3537 A15 : 0x00000000 SAR : 0x0000001b EXCCAUSE: 0x00000006
EXCVADDR: 0x00000000 LBEG : 0x4008ac1c LEND : 0x4008ac32 LCOUNT : 0xffffffff
Backtrace: 0x400eb233:0x3ffb4910 0x400d5ead:0x3ffb4940 0x400e2afd:0x3ffb4960
#0 0x400eb233 in AsyncEventSource::avgPacketsWaiting() const at .pio/libdeps/wemos_d1_uno32/ESPAsyncWebServer-esphome/src/AsyncEventSource.cpp:329
#1 0x400d5ead in HandlerEventDataSSE(AsyncEventSource const&, unsigned long const&, unsigned int) at src/main.cpp:5716
#2 0x400e2afd in Task_WebServerESP32(void*) at src/main.cpp:5400 (discriminator 7)
Är fint att jag numera får alla denna Backtrace info direkt i serieterminalen i PlatformIO.
Backtrace info fås via platformio.ino: monitor_filters = time, esp32_exception_decoder
Lagt in den buggfixen nu igen för AsyncEventSource.cpp:329!
2024-05-27
Provar lite med LittleFS, a little fail-safe filesystem designed for microcontrollers.
Testade att via LittleFS skriva en class objects rådata direkt till en datafil, läsa tillbaka den rådatan från datafilen direkt in i class object utan serialization av datan, samt både före och efter läsa av datastorleken för det class object. Som ersättare för Preferences för större dataobjekt:
Size of RingBuff24hrAmp: 2088 bytes
Time to write data: 67939 us
File data written: 2088 bytes
File size stored: 2088 bytes
Time to read data: 15404 us
File data read: 2088 bytes
Size of RingBuff24hrAmp: 2088 bytes
Och det gick bra både rent datamässig i antal bytes samt diagramkurvorna ritas ut precis på samma sätt som innan denna övningen, så blev ingen korrupt data i RingBuff24hrAmp class object! Så ska kunna komplettera Preferences för större dataobjekt som 24hr statistik.
Best way of writing / reading classes-objects to / from txt file, rådata utan serialization:
But, this will only do a byte-for-byte, shallow copy. It will fail if the object contains pointers, references or other objects that contain pointers or references. It will also fail to stream the value of any static data members.
How to store a struct in a file?
LittleFS – the Best File System for Embedded Projects?:
LittleFS is designed to ensure that the file system does not become corrupted and does not wear out from overuse. Organizes its on-disk data structures to be resilient to loss of power.
LittleFS has a very small code size and uses surprisingly little RAM.
LittleFS provides hooks that allow it to be thread safe. The Moddable SDK implements these hooks on devices running FreeRTOS, which includes the ESP32.
Making LittleFS thread-safe - use xSemaphoreTake(fs_mutex,0xffffffff), is already build in
2024-05-28
Igår var det en mängd molntussar som drev förbi på den soliga himlen och gav snabba stora strömvariationer från solcellerna.
Känner mig nöjd med hur jag presenterar det i diagrammet över batteridriften i min ESP32-batterimonitor över off-grid solcellssystemets drift.
Får tydligt fram både hur mycket ström och batterispänning varierar samt visar ändå tydliga stabil kurvor över den aktiva batteriladdningen.
Variationen visas med Max/Min-skuggning till diagramlinjerna för ström/spänning som visar plottade 10min medelvärden. Varje sådan 10min medelvärdes datapunkt är i sin tur medelvärdet för drygt 500.000 datasamplingar, så fångar driften detaljerat.
Sådan Max/Min-skuggning till diagramkurvor är en väl etablerad teknik, så inget jag hittat på.
De flesta batterimonitorer jag sett plottar istället rådatan direkt, som i detta fallet hade gett kurvor som svängt snabbt upp och ned i ett enda virrvarr där de trasslar in sig i varandra och det går inte att läsa ut något vettigt ur dem tycker jag.
Närmar sig att återmontera det andra exemplaret i husvagnen!
2024-05-30
Efter 8d15h-driftstid utan avbrott
Min MaxAllocHeap: 61428b, MaxAllocHeap: 94196b var så redan 2024-05-24, se inlägg då här ovan.
Trots en mängd molnflak som drev förbi på den blå himlen orsakande väldigt dynamiskt varierande solcellsström sker första "Sync 100% SoC" för dygnet robust stabilt! Så den tekniska funktionen jag använder där blev bra och låter sig inte luras av stor strömdynamik i sådant väder, samt fungerar även fint i långvarig float-laddning:
2024-06-01
Mycket kodkrascher + några WDT
SoftReset = egen kontrollerad reboot
Och då blev det ju inte rätt och funktionellt direkt, utan en hel del kodkrascher "panic´ed", WDT-reset, etc.
Men precis varenda gång startar ESP32 om igen via automatisk reboot utan att hänga sig, och det hade jag ju aldrig testat självmant såhär omfattande.
Är en kombination av ESP32´s förmåga och min kod som fixar det.
Men min loggning av reboot orsaker fungerar perfekt!
ESP32 har Hardware Watchdog Timers (WDT) separata för varje kärna, så nog därför den alltid klarar att boota om. ESP32 har även en "RTC Watchdog Timer (RTC_WDT) - used to track the boot time from power-up until the user´s main function" som övervakar hela boot-sekvensen!
Jag gissar att det i stort ger lika bra funktion som en extern WDT, som jag hittills inte kunnat se något behov av. Finns naturligtvis alltid en liten minimal risk att skenande kod råkar stänga av den interna hårdvarubaserade WDT, men tror den risken är mikroskopisk och mest behöver tas hänsyn till i riktigt säkerhetskritiska system som i medicinsk utrustning eller i typ kärnkraftverk.
Men finns då en risk att skenande kod även råkar trigga en GPIO till extern WDT!
Yes nu fungerar allt detta 100% perfekt! Bara så coolt!
Testat stabilt under 3h drift nu, med ett par reboot, och all 24h data och statistik är intakt!
Så nu sparas all 24hr loggdata som jag har lokalt i ESP32, samt alla andra variabler med statistik och data över batteridriften, om ESP32 okontrollerat bootar om av kodkrasch av yttre störning eller problem i programkoden som minnesläckage eller heap-fragmentering eller annat. Samt även vid kontrollerad reset naturligtvis. Är ca 2800st datavärden som sparas.
Och all loggdatan återställs då efter reboot, så blir bara ett par sekunders avbrott.
Senare när jag även har 7 dygns loggdata är kodstrukturen sådan nu att det är lätt att inkludera i detta med väldigt lite ytterligare kod.
Men krävde att jag lärde mig lite nytt inom C++ objektorienterad kodning samt mer djupare detaljer om hur ESP32 fungerar, samt även lärde mig LittleFS.
Har ju haft en hel del kodkrasch-problem med ESPAsyncWebServer-esphome, även om det verkar stabilt nu sedan ett bra tag med min buggfix till det kodbiblioteket.
Så även om en sådan panic´ed soft-reset omstart sker när jag är ute och fricampar kommer jag inte tappa 24h driftstatistik eller data till denna Battery 24hr operational graph här ovan.
Nästan 11h kontinuerlig driftstid
sedan senaste firmware uppdatering
med stresstestad 100% stabil drift.
Fick nästan 11h kontinuerlig ESP32-batterimonitor drift i mitt lilla experiment off-grid solcellssystem med firmware version 2024-05-21 innan jag nu laddad upp denna nya firmware versionens programkod. Med 100% stabil drift trots en hel del stresstestning, så ser riktigt bra ut!
Nu ska jag löda ihop lite hårdvara samt därefter ta en INA260 strömsensor för solcellsströmmen i drift samt fixa den sista C++ koden som krävs för det. Men mycket är redan förberett för det.
Sedan är det äntligen skarp drift igen med camping i husvagnen som gäller.
2024-06-03
Summerade allt RAM-minne jag använder i RTC Slow memory via RTC_NOINIT_ATTR allokering, från sizeof() av de variabler och struct-variables jag använder i min programkod. Blev nu 2495 bytes, så bör vara goda marginaler mot RTC Slow memory´s 8kB.
Då har jag redan med struct-variablerna för solcellsströmmen, så bör inte vara något problem att även få rum för 7dygns driftsdatan till diagram, m.m. framöver!
Lyckades inte hitta någon funktion som ger info om RTC Slow memory minnesanvändning!
Med den nya version av ESPAsyncWebServer-esphome (v3.2.2) så fick jag återigen glesa panic´ed kodkrascher när jag bländrar mellen mina webbsidor från en webbsida med SSE-datakommunikation. Känns rätt hopplöst och får någon gång i framtiden byta ut mina två kvarvarande SSE-webbsidor till WebSocket, då mina WebSocket baserade webbsidor fungerar helt stabilt och med bättre funktion! Men är för stort kodprojekt nu, så ska ha det i skarp drift i husvagnen först. Speciellt den ena SSE-websidan hanterar väldigt mycket olika data att koda för!
Men lyckades i alla fall gör lite optimeringar och kodförbättringar som i stort tog bort problemet, och skulle det nu hända någon gång väldigt glest så bootar ESP32 om automatiskt stabilt nu och återställer all den momentant sparade 24h datan och driftsstatiken så jag har kvar den för visade 24h-statistiken i diagrammen. Så nöjer mig så nu och löder hårdvara istället.
Är löst nu för SSE (se längre ned) med lite anpassning av dynamiken i min kod för SSE-webbsides kommunikationen, så var ingen bugg.
2024-06-04
Efter att kodat att all 24h statistik data sparas / återställs vid SoftReset så fick jag problem med triggad Task WDT under strömspardrift med light-sleep. När jag väl lyckats fånga felmeddelandet "Task watchdog got triggered. The following tasks did not reset the watchdog in time: task_wdt: Task_StateMachi (CPU 1)" så gick det ganska lätt att logiskt ringa in orsaken.
Task_StateMachine() hanterar de asynkrona anropen från DeferredInterruptIN226() och där jag då la anropet till StateMachine::RTCRingBuff24hrSetData efter StateMachine::STATE_HANDLER, och STATE_HANDLER hanterar light-sleep så då låste de två varandra.
Anropet till StateMachine::STATE_HANDLER måste komma sist så övriga hinner exekveras den korta stund ESP32 är vaken för att läsa datavärden från INA226 samt hantera LCD-display och tryckknappsavkänning samt nu då även RTCRingBuff24hrSetData, innan STATE_HANDLER aktiverar light-sleep igen!
Under natten hann det bli 24st triggade Task WDT och all 24h statistik data sparades / återställdes helt korrekt samt ESP32 bootade om helt stabilt, så blev en ofrivillig stresstest på det!
Den funktionaliteten har jag fått riktigt robust och stabil nu för sådana driftsavbrott!
Nu när anropet till StateMachine::STATE_HANDLER är sist igen så ser allt ut att arbeta stabilt.
Även mätt upp att de 6x 1832 bytes 24h class-object data sparade via LittleFS tar ca 550ms - 815ms i exekveringstid att skriva till filsystemet, vilket är helt OK då det görs så extremt sällan.
Däremellan spara jag den ickesparade datan i RTC Slow-memory RAM, vilket både går snabbt samt ej slits av allt skrivande till det. Men finns bara 8kB RAM där, så får kombineras såhär.
Använder 2024-06-18 2500 bytes i RTC-SRAM.
2024-06-05
Ingen triggad Task WDT i natt!
Därmed är denna programkod OK för skarp drift i husvagnen. Så ska bara löda lite hårdvara samt ta i drift en INA260 strömsensor för solcellsströmmen samt lite kodning för det, där mycket redan är förberett i koden. Så närmar sig nu :-)
Jag trodde att en extremt grund obetydlig urladdning som till 98,8% SoC under battericykeln skulle ge en lite mer diffus otydligt detektering av "Sync 100% SoC" fulladdat blybatteri, men blev istället ännu tydligare. Strömkurvans nedgång under PV-Throttle bryter tydligt av precis då 0,5% Tail-current detekteras som indikering för fulladdat blybatteri, vilket sannolikt är pga att det är fulladdat precis då. Har sett detta vid varje "Sync 100% SoC" nu men blev extra tydligt här!
Att laddströmmen minskar snabbare fram till dess och sedan en mer flack minskning efter det.
Gör då även att beräkningen av batteriverkningsgrad sker med hög fin precision!
Så att utgå från väl beprövad vetenskaplig kunskap för detta är helt rätt val!
Ska bli intressant sedan i mitt riktiga off-grid solcellssystem med större strömmar och lite djupare urladdningar att se om det blir lika tydligt där samt stämmer lika bra tidsmässigt.
Är även intressant att se de olika perioderna under dagen med molntussar som driver förbi på den blå himlen och dess inverkan på solcellsström och batterispänning.
Ger en massa fin ny kunskap kring blybatteridrift med denna precisionen i loggning av den.
Och är man nördigt intresserad av blybatteridriften som jag, så är det riktigt skoj!
Är även övertygad om att med en så exakt uppmätt batteriverkningsgrad för varje battericykel så får man en bra indikering för försämrad blybatterihälsa (SoH) om batteriverkningsgraden plötsligt börjar minska. Så ska använda det som en av flera parameterar för SoH senare.
Därmed är ESP32-batterimonitor programkodens funktion väl verifierad för skarp drift nu!
Lite ny info från en stor batteritillverkare: Lead Carbon Battery Technology
2024-06-07
Efter intensiv stresstest av webbsidor
Krävdes lite anpassning av dynamiken i min kod för SSE-webbsides kommunikationen nu när den blivit effektivare och snabbare i ESPAsyncWebServer-esphome (v3.2.0), vilket nu är verifierat att det fixade stabiliteten! Så nu fungerar (äntligen) även SSE bra i ESPAsyncWebServer-esphome (med min bugfix). Därmed är denna ESP32 kodutvecklingen färdig för skarp drift!
Gjorde förändringar i HandlerEventDataSSE() för if(EventsSSE.count() < 1U) samt i hur SSEevents.close() hanteras, hur det annars ger panic´ed kodkrasch glest för SSEevents.send() vid växling av webbsida som en sorts konflikt nu när webbservern hanterar SSE effektivare.
Lite bra läsning: Order of Evaluation in C++17.
2024-06-11
Lade till en rak rödstreckad linje för strömmens medelvärde under senaste 24h i diagrammet. Tycker det är intressant info för batteridriften som diagrammet fokuserar på, även om det blev en aning mer rörigt. Är svårt att uppskatta det medelvärdet själv ur strömkurvan.
Skönt att ha en väl strukturerad programkod, så detta tog inte många kodrader att infoga:
2st kodrader i ESP32 C++ koden, för skickande av denna WebSocket-datan till webbsidan.
12st kodrader i html-filen, för att ta emot WebSocket-datan samt rita önskad diagramlinje.
2024-06-12
Då blev det solcellsström idag som verifierade att dagens första "Sync 100% SoC" blir kvar även vid två fulladdningar av batteriet under 24h med mellanliggande mindre urladdning.
2024-06-16
Skriver ut ESP-info om aktuell ESP32 MCU i mitt projekt när den bootar, och utökade nu med partitionstabellen (kod) och lite annat:
Compilation date: Jun 15 2024
Compilation time: 18:52:09
Compilation file: src/main.cpp
Compilation C++: 201703
ChipCores: 2
ChipModel: ESP32-D0WDQ6
ChipRevision: 1
CpuFreq(MHz): 240
FlashChipSpeed(MHz): 80
FlashChipMode: 2
FlashChipSize(B): 4194304
FlashChipSize(MB): 4.0
SketchSpace(B): 3145728
SketchSize(B): 1191968
FreeSketchSpace(%): 62
HeapSize(B): 312452
FreeHeap(B): 273952
FreeHeap(%): 88
Partition table:
partition addr: 0x010000; size: 0x300000 / 3145728 (bytes); label: app0
partition addr: 0x009000; size: 0x005000 / 20480 (bytes); label: nvs
partition addr: 0x00e000; size: 0x002000 / 8192 (bytes); label: otadata
partition addr: 0x310000; size: 0x0e0000 / 917504 (bytes); label: spiffs
partition addr: 0x3f0000; size: 0x010000 / 65536 (bytes); label: coredump
ESP32 FreeRTOS max Task priority: 24
Use time slicing for equal priority, configUSE_TIME_SLICING: 1
Use preemption, configUSE_PREEMPTION: 1
Tick Rate (Hz), configTICK_RATE_HZ: 1000
Use idle hook, configUSE_IDLE_HOOK: 1
Use tick hook, configUSE_TICK_HOOK: 1
Use runtime stats, configGENERATE_RUN_TIME_STATS: 0
Maximum log verbosity, CONFIG_LOG_MAXIMUM_LEVEL: 1
Default log verbosity, CONFIG_LOG_DEFAULT_LEVEL: 1
SdkVersion: v4.4.7-dirty
ESP IDF version: v4.4.7-dirty
ESP_ARDUINO_VERSION: 2.0.16
sizeof(*RingBuff24hrVolt) (bytes): 1832
6*sizeof(*RingBuff24hrVolt) (bytes): 10992
sizeof(*RTC_24hrUnsavedDataAh) (bytes): 264
6*sizeof(*RTC_24hrUnsavedDataAh) (bytes): 1584
Jag använder i mitt projekt Espressif Arduino-ESP32 huge_app.csv partition table:
# Name, Type, SubType, Offset, Size, Flags
nvs, data, nvs, 0x9000, 0x5000,
otadata, data, ota, 0xe000, 0x2000,
app0, app, ota_0, 0x10000, 0x300000,
spiffs, data, spiffs, 0x310000,0xE0000,
coredump, data, coredump,0x3F0000,0x10000,
vilket stämmer bra med min boot-utskrift.
Fick tips om arduino-esp32/cores/esp32/chip-debug-report.cpp som troligen är en del av nya Espressif Arduino 3.0.x, så ska titta om det är någon mer info där som jag har nytta av att skriva ut vid boot.
Espressif Partition Tables
Espressif Partitions API
2024-06-18
Synkronisering av tid på internet görs ofta med det gamla NTP-protokollet, vilket är lätt att manipulera skriver NyTeknik.
"Trots att NTP är ett äldre protokoll, kan den alltså fortfarande utgöra en mer stabil lösning för tidssynkronisering. För med ett par relativt enkla ändringar i inställningarna kan man ganska säkert skydda sig mot manipulation av tiden. Det kräver dock att man aktivt tar ställning till hur man tar emot tid från NTP-servrar.
– Man kan aktivt säkerställa att få flera NTP-källor samtidigt. Till exempel kör både Apple och Microsoft sina egna NTP-servrar, säger Mikael Vingaard."
Så har jag gjort och kör med Swedish Distributed Time Service Netnod´s NTP-tidserver, som är en säker NTP-leverantör ägd av TU-stiftelsen (Stiftelsen för Telematikens utveckling). De distribuerar svensk nationell tid genom Network Time Protocol (NTP). Sedan har jag även två till helt andra NTP-källor angivna för synkronisering av ESP32 RTC.
Netnod har ett direkt samarbete med PTS som finansierar stora delar av verksamheten.
Sverige först i världen med säker internet-tid, Computer Sweden 2019.
Netnod: What is Network Time Security and why is it important?
2024-06-21
Ett 24h diagram över batteridriften då jag haft en strömförbrukare inkopplad hela dygnet så felmätningen pga långa mätkablar + Battery Reconditioner 9kHz strömpulsandet minimerades.
Gav första PV_Throttle PWM-strömregleringen vid 96,1% SoC samt första "Sync 100% SoC" blev vid höga 99,8% från lägst 94,8% SoC urladdat för battericykeln, mätt av ESP32. Samt vid skärmdumpens tidpunkt ca 22:20 så var det samma SoC på ömse sidor om den vertikala tidslinjen samtidigt som medelströmmen var ≈0A och battericykeln varat ca 1 dygn, vilket innebär extrem hög batteriverkningsgrad och för så grund urladdning! Annars skulle medelströmmen blivit högre för att kompensera för förluster i AGM-blykol batteriet. Snart har jag korta mätkablar mellan INA226 strömsensorn och strömshunten, vilket blir spännande att se effekten av.
Mätt batteriverkningsgrad för denna battericykeln blev: Last Energy(Wh): 97.2%, Last Coulomb(Ah): 100.0%, så det är fortfarande ett litet mätfel från Battery Reconditioner 9kHz strömpulsandet som förhoppningsvis i stort försvinner med korta mätkablar.
Enligt en forskarstudie på Trojan 30XHS battery 100Ah flooded / öppet kvalitetsblybatteri är batteriverkningsgraden vid såhär grund cyklisk drift bara ca 50% vid kontinuerlig laddström (typ MPPT-regulator) med ström motsvarande vad som är aktuellt i off-grid solcellssystem!
Innebär att mitt AGM-blykol batteri har extremt mycket bättre batteriverkningsgrad med strömpulsad laddning vid grund cyklisk drift här! Är intressant med högprecisions-batterimonitor!
AGM-blykol beter sig mer likt LiFePO4 än traditionella blybatterier i sund off-grid solcellsdrift.
2024-06-23
Idag när jag åter en gång aktiverade ESP32-webbservern började min pulse-LED blinka långsammare och checkade via LCD-displayen att program-loopens tid nu var 2758ms mot normala ca 1200ms, samt tittade igenom driftsdatan för mina olika Task´s och kunde se att Task_DeferredInterruptIN226() belastade CPU med 91% mot normalt <1%. Så något hade hänt där i kodexekveringen, vilket är första gången sedan den kom i skarp drift här hemma för dryga året sedan. Och kodexekveringen var fast i det, så efter ett tag fick jag göra en manuell soft-reset via tryckknapparna.
Har nu lagt in en driftsövervakning för även detta som gör en kontrollerad soft-reset om det detekteras under en viss tid. Är fördelen med lite längre utvecklingstid, att även sällsynta händelser hinner uppträda (även om det är frustrerande att inte få det klart snabbare)!
Har läst att Victron SmartSolar MPPT verkar sällsynt drabbas av något liknande som gör att de inte reglerar batteriladdning som de ska men i övrigt är i funktion, som då kräver reset via att göras strömlös. Så är nog något man får räkna med kan inträffa sällsynt vid lite mer komplex kodfunktion i embedded mikrokontrollers. Och då är min funktion med automatisk driftsövervakning och reset / reboot när kritiskt tillstånd detekteras bara så väldigt mycket bättre än att manuellt behöva koppla loss strömmatningen!
Både för min ESP32-batterimonitor och för en solcellsregulator är det då viktigt att automatiskt göra en kontrollerad reset / reboot snarast för att få tillbaka full funktion. Att typ istället bygga in en förebyggande reboot 1ggr/vecka i programkoden löser inte denna sortens problem, då man i värsta fall kan bli utan fullvärdig funktion en hel vecka!
Min ESP32-batterimonitor har nu ett antal sådana här driftsparametrar den självövervakar inkl. RAM-minnet och I2C-bussen och gör en automatisk kontrollerad soft-reset om något kritiskt detekteras, för robust tillförlitlig 24/7/365-drift.
Jag har en pulse-LED nu under kodutvecklingen som visuellt indikerar looptiden samt blinkar med ett för ögat osynligt snabbt mönster som visar kodfunktionen kring deferred interrupt ISR i koden, vilket jag kan studera via oscilloskop för verifiering av kodfunktion.
Jag har lite liknande tänk kring ESP32 soft-reset från WDT (WatchDog Timer) eller panic´ed kodkrasch att för robust drift måste jag då garantera att kritiska mätvärden och statistik sparas och återladdas för fullvärdig fortsatt drift efter reboot, vilket inte en extern WDT löser i sig.
ESP32´s interna WDT är hårdvarubaserad på en separat hårdvarudel på chipet separata för varje kärna samt övervakar även bootsekvensen, så verkar ha en väldigt robust stabil funktion. Finns naturligtvis alltid en liten minimal risk att skenande kod råkar stänga av den interna hårdvarubaserade WDT, men tror den risken är mikroskopisk och mest behöver tas hänsyn till i riktigt säkerhetskritiska system. Jag har valt att kör utan extern WDT men med hard-reset!
Så tills vidare förlitar jag mig helt på intern WDT och fokuserar istället på att soft-reset i sin tur triggar en hard-reset som vid PowerOn så ESP32 inte riskerar att hänga sig efter reboot pga något korrupt som kan bli kvar efter enbart en soft-reset (och då skulle kräva extern WDT), via att jag hackat både hårdvara och mjukvara för att få den funktionen.
Innan jag införde att soft-reset direkt följs av hard-reset hände det ibland att ESP32 hängde sig under bootsekvensen efter en panic´ed kodkrasch och då hade istället en extern WDT behövts. Jag tror detta är en bättre lösning i stort på det, vilket tiden får utvisa.
Så efter en soft-reset sparar jag bara kritisk data lagrad i RTC Slow Memory (8kB RAM) och därefter görs direkt en hard-reset. Tycker jag då får full driftssäkerhet inkl. bevarad kritisk data, även om naturligtvis en extern WDT är en form av den yttersta garanten för att få reboot om ESP32´s interna WDT inte skulle fixa det, men med en rätt grov klumpig funktion i mina ögon sett. Jag tror dock den risken med enbart intern WDT är mikroskopisk nu när soft-reset nästan direkt får trigga en hard-reset varje gång så allt återställs fullständigt i ESP32.
Hittills har det fungerat 100% robust och stabilt såhär via soft- + hard-reset, utan extern WDT!
2024-06-25
Ett 24h diagram över batteridriften igen då jag haft en strömförbrukare inkopplad hela dygnet så felmätningen pga långa mätkablar + Battery Reconditioner 9kHz strömpulsandet minimerades.
Gav första PV_Throttle PWM-strömregleringen vid 96,1% SoC samt första "Sync 100% SoC" blev vid 99,5% från lägst 91,2% SoC urladdat för battericykeln, mätt av ESP32.
Mätt batteriverkningsgrad för denna battericykeln blev: Last Energy(Wh): 96.5%, Last Coulomb(Ah): 100.0%, så det är ändå kvar ett litet mätfel från Battery Reconditioner 9kHz strömpulsandet som förhoppningsvis i stort försvinner med korta mätkablar. Samt denna battericykel varad 3d:22h:33m med totalt -15,6Ah cyklad urladdning, allt mätt av ESP32.
2024-06-28
Fick nya versionen ArduinoJson 7.1 av det kodbiblioteket med lite ny funktionalitet som inte är aktuell för mig nu, samt med lite kodoptimering. För nästa version lovas: "For the next release, I plan to optimize memory consumption. Hopefully, I´ll keep my promise this time." Låter bra!
Borde dock kanske titta lite närmre på denna nya funktion med MessagePack. "MessagePack is an efficient binary serialization format. It lets you exchange data among multiple languages like JSON. But it´s faster and smaller."
Min kod kompilerar fint med denna nya versionen!
2024-06-29
Blev lite hårdvara färdiglödd idag, på klassiska experimentkort.
Två stycken små burkar med strömsensor som till höger där ansluts mot strömshunt och batteribank och till vänster är signalkabeln med I2C, Interrupt-signal samt 3,3V strömförsörjning från ESP32. Inte lika tjusig som egenritade PCB men funkar ändå.
Har hittills haft det uppkopplat på bread-board.
Ett exemplar är inkopplad i drift och fungerade perfekt direkt. Ska snart koppla in den andra också placerad nära intill min strömshunt i mitt lilla experiment off-grid solcellssystem här hemma.
Blir då intressant att se om mätprecisionen ökar med korta mätkablar för 9kHz strömpulsandet från en Battery Reconditioner på AGM-blykol batteriet. Jag tror det. Den ger extrem korta men kraftiga strömstötar som motsvarar ca 1MHz i frekvens, så därför svårt att mäta helt rätt över en strömshunt via lite längre mätkablar som jag haft hittills. Nu blir längden istället i signalkabeln och verkar inte vara något problem där med ca 1m längd för de digitala signalerna.
Så är verkligen på sluttampen nu med min ESP32-batterimonitor.
Mätte strömförbrukning i light-sleep strömsparläget till ca 8,5mA nu med tre deciamaler med digitalmultimetern och stämmer med vad min ESP32-batterimonitor mäter också. Så allt blev OK! Är med senaste programkoden. Då jag införde StateMachine::RTCRingBuff24hrSetData
ökade strömförbrukningen något pga att tiden i light-sleep per loop blev något kortare då.
Och när allt drivs från USB 5V och labbaggregatet visar 0,000A så visar ESP32-batterimonitorn också 0,000A. Är underbart med fabrikskalibrerad "ultra-precise I2C output current sensor".
2024-07-01
Kopplat in en INA260 för solcellsströmmen, kodat och fått kontakt med. Fungerar bra på samma I2C-buss som INA226 för batteriströmmen såhär långt.
Så är bara att koda vidare för fullt integrerad funktion.
2024-07-02
Får fina tydliga medelvärdesfiltrerade diagramkurvor över batteridriften även i väldigt växlande solsken med mycket moln, där kurvor på ofiltrerad rådata bara hade blivit ett enda kaos man inte kunnat läsa ut något vettigt ur. Och samtidig får jag info om hur mycket ström och spänning varierat via skuggning till deras datakurvor ur råmätdatan, så missar inte den informationen!
Kan då även se hur pass bra solladdregulatorn sköter sin reglering.
Är väldigt nöjd med detta.
Yes, nu har jag listat ut hur interrupt-baserad avläsning av data från INA260 fungerar ihop med Adafruits kodbibliotek. Hittade inget kodexempel för just det, så sökt och hittat flera olika kodfragment som gav bra ledtrådar.
Testar av med lite kod direkt i setupESP32() för att lära och få kunskap om hur jag samverkar med det INA260-kodbibliotket.
Så nu är det bara lite grovarbete i att fixa ihop min programkod kring dess användning.
22:00:22.732 > Found INA260 chip
22:00:22.739 > INA260 Voltage(mV): 3311.25
22:00:22.739 > INA260 Current(mA): 2.50
22:00:22.741 > INA260 Power(mW): 10.00
22:00:22.744 > INA260 time read(us): 2147
22:00:22.747 > INA260 Alert pin: 0
22:00:23.922 > INA260 Voltage(mV): 3312.50
22:00:23.922 > INA260 Current(mA): 2.50
22:00:23.925 > INA260 Power(mW): 10.00
22:00:23.928 > INA260 time read(us): 2230
22:00:23.931 > INA260 Alert pin: 1
ΔT: 25.108 - 23.922 = 1.186s innan nya mätdata är färdiga för avläsning via ConvReadyAlert
22:00:25.108 > INA260 Voltage(mV): 3312.50
22:00:25.108 > INA260 Current(mA): 2.50
22:00:25.111 > INA260 Power(mW): 10.00
22:00:25.114 > INA260 time read(us): 2108
22:00:25.117 > INA260 Alert time(ms): 1186
22:00:25.119 > INA260 Alert pin: 1
Med 1024st counts av 0,558ms + 0,558ms fås 1,143s, så stämmer bra med ΔT 1.186s ihop med lite overhead plus att jag här läser av en vanlig GPIO input och inte är en interrupt!
Om all tidsskillnaden utgör overhead fås (186ms - 143ms) / 2048 = 21µs/sampling i overhead.
Därmed har jag listat ut hur interrupt-baserad avläsning av data från INA260 fungerar ihop med Adafruits kodbibliotek samt verifierat att det fungerar.
Använder då:
ina260.setAveragingCount(INA260_COUNT_1024);
ina260.setCurrentConversionTime(INA260_TIME_558_us);
ina260.setVoltageConversionTime(INA260_TIME_558_us);
ina260.setMode(INA260_MODE_CONTINUOUS);
ina260.setAlertType(INA260_ALERT_CONVERSION_READY);
ina260.setAlertPolarity(INA260_ALERT_POLARITY_NORMAL);
ina260.setAlertLatch(INA260_ALERT_LATCH_ENABLED);
samt för reset av Alert: ina260.getAlertLatch(); (länk)
2024-07-03
Tog bara en dryg halvdag att koda allt för att få INA260 strömsensorn till solcellerna i drift med sin ISR deferred interrupt processing samt all loggning och backup inkl. alla datastrukturer kring det. Är bara småjusteringar kring dess samverkan med light-sleep (LS) strömsparläge att fixa och utvärdera. Gjorde mycket copy-&-paste av koden med anpassning tll INA260 funktion, så åter igen blev det tydligt hur bra det är med en tydlig genomtänkt kodstruktur! Skoj!!!
ISR intervall-tiden för INA260 med 1024 avläsningar för medelvärde och 2x588µs samplingtid blir 1186309±2µs, vilket är en oehört liten spridning ihop med att övrig kod exekverar! Deferred interrupt processing + ESP32 är grymt bra med bara ±2µs variation!
Då exekverar samtidigt INA226´s ISR deferred interrupt processing med högre Task-prioritet!
Detta bidrar starkt till att jag kan mäta/logga Ah/Wh med så hög precision!
Printar dess utdata:
2024-07-04
Har nu fixat det sista kring INA260 ISR deferred interrupt processings samverkan med Light-Sleep strömsparläge, och nu fungerar allt effektivt och stabilt. I Light-Sleep körs inte INA260 ISR deferred interrupt processing utan dess mätvärden läses av inne i INA226 ISR deferred interrupt processing, vilket fungera bra då detta bara sker vid väldigt låg ström från solcellerna.
I den printade utdatan ser man att när Light-Sleep (LS) aktiveras ökar ISR intervall-tiden för INA260 från ca 1186301µs till ca 1206570µs som är den för INA226 ISR.
Hade först lite problem med glest triggad WDT, både Task & ISR, samt även lite glesa felmeddelanden från I2C under strömsparläge i light-sleep, men är helt löst nu.
Hittade lite ny funktionalitet för driften i strömsparläget, så koden blev även lite förbättrad såhär.
Så väntar nu ut att båda ISR Deferred Interrupt processing Task´s exekverat färdigt innan jag går in i light-sleep igen. Och samma för DisplayHandler Task.
while(eTaskGetState(TaskDeferredInterruptINA260) != eBlocked || uxQueueMessagesWaiting(INA260PVDeferredInterruptQueue) > 0 || eTaskGetState(TaskDeferredInterruptINA226) != eBlocked)
{
vTaskDelay(2 / portTICK_PERIOD_MS);
}
Lägger en strömgräns för solcellsström på <50mA/100Ah batterikapacitet för att alls få gå in i Light-Sleep strömsparläge.
Med gränsen <50mA/100Ah batterikapacitet fås en strömförsörjning från solcellerna för den egna driften av ESP-batterimonitorn när strömmen överstiger det, från ≥90Ah batterikapacitet. Då även inklusive strömförbrukningen för mina Battery Reconditioner.
Strömförbrukningen ökade inte synbart med INA260 och dess kodfunktioner i drift.
Hade nog misstänkt det då även INA260´s ISR Deferred Interrupt Task nu ska hinna med att exekvera inom den lilla tidsluckan som hålls öppen för det i varje loop innan ESP32 går in i Light-Sleep igen. Tänkte att de proportionerna skulle försämras så strömförbrukningen ökade något.
Får se om jag senare gör ett ultra-strömsparläge där INA226/INA260 samplar betydligt långsammare så det kanske blir upp emot 5-10s/loop, som då kunde styras av att solcellsströmmen är <5mA/100Ah batterikapacitet i Light-Sleep dvs försumbart med ström från solcellerna. Lite typ extra strömsnål "invintringsdrift" / nattdrift. Kunde vara extra viktigt off-grid vintertid.
Införde även Backup-Flags som indikerar pågående databackup till filsystemet och då blockerar light-sleep under den loop-perioden backupen pågår, då det orsakar problem att gå in i light-sleep under pågående skrivning till filsystemet. Checkat nu under ett antal backups i Light-Sleep Mode och fungerar perfekt (körde var 5:e minut)! Samtidigt blockeras även light-sleep när det då byggts upp en liten kö av meddelanden till Task_StateMachine(), som 4st här nedan, så den kön betas av direkt. Sådan backup görs så sällan så inverkan av blockerad light-sleep loop påverkar strömförbrukningen försumbart! Är mycket kring Light-Sleep drift att tänka på!
Under övrig Light-Sleep drift har jag inte sett någon kö till Task_StateMachine().
2024-07-05
Allt arbetar stabilt och bra med även INA260 i drift via gemensamma I2C-bussen och dataavläsning via dess Alert-Interrupt och ISR med Deferred Interupt processing Task. Har varit i drift många timmar nu med detaljerad uppföljnng via PlatformIO´s serial terminal.
Är intressant att efter flera dygns passiv standby-drift med många timmars PV_Throttle float-laddning per dag så blir medelladdströmmen för 24h bara +8mA! Jag gissar att det är lite lågt mätt pga mätfel för 9kHz strömpulsandet från Battery Reconditioner pga långa mätkablar, vilket blir intressant att se skillnaden när jag snart monterar INA226-hårdvaran med korta mätkablar.
Jämfört med självurladdningen som är ca -3%/mån: 0,03 * 90Ah / 30 / 24h = 0,004A dvs 4mA.
Är bl.a. sådan data för batteridriften som är intressant att se, tycker jag! Se diagram nedan:
2024-07-06
Trots haveriet – därför kan Volvo vinna teknikracet - är inte bara mitt projekt som är försenat ;-)
Och även jag vinner nog teknikracet inom detta segment, då funktionaliteten nu är bättre i min ESP32-batterimonitor än jag trodde var möjligt från början!
Idag fått ett intressant cirkeldiagram levande med strömvärdena från solcellerna via nya INA260-strömsensorn. Med rådata bearbetad till fin information. Blev bara så jäkla bra!
ESP32-batterimonitorn drar nu 47mA uppkopplad mot WiFi / Internet och sänder WebSocket data till index.html webbsidan, samt 9mA i light-sleep strömsparläge och 32mA i aktiv drift med webbserver off och tänd LCD-display. Så light-sleep mode sparar drygt 70% ström mot aktiv drift samt 80% mot full webbserver-drift, vilket innebär ordentlig strömspar nytta!
2024-07-07
Lite prestandasiffror kring min egenutvecklade ESP32-batterimonitor:
Genom att koda i modern C++ (C++17) ihop med FreeRTOS kan jag få väldigt bra realtidsprestanda i ESP32 för den interrupt-baserade avläsningen av de två strömsensorernas medelströmvärden. Samtidigt som det stödjer multitasking och att utnyttja båda processorkärnorna Thread-safe med Atomic Operations samt att undvika race-conditions. Modern C++ (från C++11) har även inbyggt skydd mot minnesläckage som automatiskt frigör allokerat minne direkt det slutar användas, till skillnad mot att minnesläckaget i efterhand tas bort via garbage-collection som i MicroPython. Garbage-collection är normalt negativt för realtidsprestanda!
"Garbage collection may take a significant proportion of a program´s total processing time, and affect performance as a result. [...] Garbage collection is rarely used on embedded or real-time systems because of the usual need for very tight control over the use of limited resources."
"This fundamental tenet of garbage collection and the resulting effect on application execution is called the garbage-collection pause or GC pause time. In applications with multiple threads, this can quickly lead to scalability problems."
Programkod i modern C++ med FreeRTOS gör att ström-/effekt-medelvärdena ESP32 hämtar ca 1ggr/s från strömsensorernas 1024st samplingar (ca 50.000samplingar/min) kan hämtas med en tidsonoggrannhet på bara ±2µs, 1.000.000±2µs (uppmätt!)! Därmed sker omvandlingen från A/W till Ah/Wh med oerhört hög tidsprecision. Även realtidsmässig har jag mätt upp tidsonoggrannheten till ca ±10µs, 1.000.000±10µs, dvs felet i den omvandlingen håller sig inom ca 20ppm (0,002%) så helt försumbart!
Har även utvecklat ett avancerat filter för strömsignalerna från strömshunten via simulering i KiCad Spice, så även snabba strömförlopp mellan samplingarna fångas upp.
Strömsensorerna arbetar med 16-bit dubbelriktad (Bi-Directional) upplösning dvs 1/32768 per steg, vilket för 100A strömshunt teoretiskt innebär 3mA upplösning, men dess 1 LSB step size är 2.5µV som för en 100A/50mV strömshunt ger 5mA upplösning. Samt har i övrigt en väldig hög fabrikskalibrerad precision med både extremt bra långtids- och temperatur-stabilitet inom -40°C to +125°C. Så även noggrannheten är väldig bra hos dem.
Med 15A strömsensorn för solcellsströmmen blir då upplösningen teoretiskt 0,5mA, men dess 1-LSB step size är 1.25mA.
Nu finns även motsvarande strömsensor med 20-bit upplösning dvs 1/524288 per steg som för 100A strömshunt ger teoretiskt 0,2mA upplösning, men dess 1 LSB step size på 312.5nV ger för en 100A/50mV strömshunt 0,625mA upplösning! Jag har köpt en sådan och ska senare prova i version två av min ESP-batterimonitor, men den nuvarande räcker nog långt!
Ihop med att jag använder samma exakta metod för att detektera fulladdat blybatteri som inom vetenskaplig forskning, dock lätt anpassad för praktisk off-grid solcellsdrift, så uppnår jag väldigt bra robust precision både i mätningen av batteribankens laddstatus, dess batteriverkningsgrad samt i synkningen av 100% SoC!
Och strömförbrukningen är bara 9mA (12V) vid off-grid passiv standby nattdrift via avancerat utnyttjande av ESP32 Light-Sleep, fortfarande med aktiv strömavläsning ca 1ggr/s från strömsensorerna som i sin tur självständigt samplar data ca 50.000ggr/min från strömshunt.
2024-07-09
Fick ett fint diagram över standby-drift i stabilt solsken som tydligt visar att strömkurvan bryter av kraftigt precis där AGM-blykol batteriet detekteras vara fulladdat och första Sync 100% SoC sker för dagen, se inringat område. Jag tolkar det som att blybatteriet verkligen är fulladdat då med den reaktionen i strömkurvan. Blir intressant att snart kunna se om det blir samma med lite djupare urladdningar och större strömmar i mitt riktiga off-grid solcellssystem i husvagnen.
2024-07-13
Vid lite flyttande av batterimonitorn så kom de långa mätkablarna mellan strömshunten och INA226 en aning mer isär och då minskade tydligt felmätningen av 9kHz strömpulsandet från Battery Reconditioner, så när jag snart har korta mätkablar bör felmätningen bli minimal! Är tydligen den kapacitiva kopplingen som stör.
Såg hos MidNite batterimonitor att de har som ett trafikljus för hur länge sedan blybatterierna blev fulladdade, med:
Grönt: inom senaste 7 dygnen
Gult: mellan 7 - 14 dygn
Rött: mer än 14 dygn sedan
Är en intressant information för att visa en viktig driftsparameter för blybatterier så de mår bra och får lång livslängd. Har själv lite fundering så på en webbsida med tydlig bearbetad info över batteridriften där även folk som inte nördat ned sig i off-grid solcells batteridrift ska kunna få förståelig information, där bl.a. lite liknande info är tänkt. Så en skoj referens!
2024-07-16
ESP32-batterimonitorn låter sig inte luras av kraftigt varierande solcellsström utan gör ändå sin första för dagen "Sync 100% SoC" med hög precision! Ser riktigt bra ut.
2024-07-19
Hade lite givande diskussioner på FB om termer kring batteriladdning.
Varta översätter tail-current för avslutning av absorptions-laddfasen till "slutladdström" i sitt dokument Definitioner av industrispecifika batteritermer, samt anger det som "uppnådda strömmen i slutet av en IU-laddningsprocess (gasbildningsström)".
Innebär att den tail-current som ska avsluta absorptions-laddfasen bör var något över gasbildningsströmmen för AGM- / GEL-blybatterier.
Sedan togs upp att inversen på coulomb-verkningsgrad benäms laddningsfaktor, där min uppmätta 97,8%(Ah) då blir laddningsfaktor 1,022, där 1,15-1,20 ofta anges för traditionella blybatterier men även ned mot 1,08 för optimerade AGM-batterier.
Coulomb-verkningsgrad kan benämnas: Faraday efficiency (also called faradaic efficiency, faradaic yield, coulombic efficiency, or current efficiency.
Och batteriverkningsgrad är då energieffektiviteten (Wh).
Gassing Voltage in Battery Charging
Controlling the corrosion and hydrogen gas liberation inside lead-acid battery
Har kopplat in en DS18B20 för batteritemperatur samt kodat för dess funktion.
Använder kodbiblioteket robtillaart/DS18B20, "Arduino library for the DS18B20 temperature sensor. Restricted to a single sensor per pin. Minimalistic version, async only.", och det verkar verkligen vara minimalistiskt då jag inte ser något ökat utnyttjande av RAM! DS18B20 har mätområde -55°C till +125°C.
Gick snabbt och enkelt med kodning och få det i drift med all funktion direkt.
Läser av DS18B20 med 12bit / 0.0625°C upplösning med ett max fel på ±0.5°C och i snitt inom ±0.2°C, vilket tar 625ms att läsa av var gång om det görs inom en programloop i en sekvens. Men om requestTemperatures() görs i en loop tar det 2,1ms och sedan isConversionComplete() + getTempC() i efterföljande loop tar det 25ms, totalt 27ms för "async only" non-blocking avläsning av temperatur. Motsvarar drygt 2% av en programloop i snitt, så läser jag av var 5:e programloop / 6:e sekund belastar det bara med ca 0,5% i snitt som är i stort försumbart.
Vid WiFi=OFF läser jag bara av var 20:e programloop / 24:e sekund för max strömsnålhet, vilket bara belastar med ca 0,1%.
På så sätt gör DS18B20 sin tidskrävande 12bit konvertering självständigt i bakgrunden!
Ett blybatteri förändrar temperatur så långsamt, så var 24:e sekund blir i realtid ändå!
Limmar fast DS18B20 i en M8 25mm² rörkabelsko för direkt avläsning från en batteripol.
Har även lagt in att om inte isConversionComplete() för getTempC() så aktiverar jag isConnected(5U) som då "resets oneWire and checks if a device can be found" och som därmed försöker återupprätta kontakten med DS18B20-sensorn oavsett dess serienummer. Gör det då även lätt att byta ut till en ny DS18B20.
2024-07-22
Har kopplat upp hela ESP32-batterimonitor enheten inkl. 4G-routern RUT241 som ska vara i husvagnen och testkört komplett i laboratoriemiljö. ESP32´s styrning av strömmatningen till RUT241 fungerar helt som tänkt samt hela sekvensen med att synkronisera RTC med NTP-tidserver på Internet fungerar också perfekt och hanterar väntan på att RUT241 startar och kopplar upp sig så som tänkt. Inga problem med värme heller under många timmars aktiv drift i +27°C. Så ser riktigt lovande ut!
Med RUT241 aktiv drar allt ca 150mA från 12,5V matningen och kortvarigt knappt 350mA som max under anslutning till WiFi / Internet, så är långt under de max 2A för det lilla fina Solid-state relay LCA717 som styr strömmen till RUT241.
Några gånger hade webbläsaren i mobilen svårt att koppla upp till ESP32-webbservern trots att båda var anslutna till RUT241´s WiFi, vilket verkar hänga ihop med det korta avståndet mellan WiFi-antennen och ESP32 på ca 70cm men räckte att rucka lite på antennens läge då.
Fått en fin hållare 3D-printad till min RUT241 4G-router av sonen samt limmar fast DS18B20 tempgivaren för batteritemperatur i en M8 25mm² rörkabelsko för anslutning direkt på batteripol. Skoj att kunna se temperaturen, men ska senare i höst/vinter användas för temperatur-kompenserad blybatteriladdning i den egenutvecklade PWM-regulator jag ska ta fram och integrera i min ESP32-batterimonitor.
2024-07-23
Är fascinerande hur bra, exakt och robust stabilt min detektering av när RTC blivit synkroniserad med NTP-tidserver är! Även när jag nu några dagar kört med uppkoppling via 4G-routern RUT241 som tar sin tid (≈75s i lägenheten) att starta upp och ansluta till Internet med sin strömanslutning styrd av ESP32. Skoj att nu ha verifierat det också.
Därmed är all funktion för skarp drift i husvagnen verifierad laboratoriemässigt. Ska jag bara uppdatera hårdvaran i mitt andra exemplar i lilla experiment solcellssystemet här hemma så jag kan verifiera denna versionen av programkoden i riktig solcellsdrift också, så blir det montage i husvagnen därefter.
2024-07-29
Lött ihop det andra Arduino-shield till ESP32-batterimonitor, så nu har jag två kompletta exemplar färdiga och testad med OK funktion. Blir inte lika smidigt / fint som egna designade PCB, men lika funktionellt.
Efter att jag köpt fina högprestanda AGM-blykol (lead-carbon) batterier våren 2021 kom efter ett tag önskan om en bättre batterimonitor än min NASA BM1, även om jag haft väldigt bra nytta av den sedan 2007. En batterimonitor med bättre långtidsprecision, med automatisk exakt synkronisering till 100% SoC fulladdat (NASA är manuell) samt som visar betydligt mer info om batteridriften.
Men hittade ingen som uppfyllde mina önskemål.
Så jag började koda en mockup-webbsida för hur jag ville ha den grafiska presentationen av batteridriften från en batterimonitor, där jag kunde simulera funktionen via reglage. Där batteridriften visades via rådata som bearbetas till tydlig driftsinformation.
Vilket senare ledde till att jag började utveckla min egna ESP32-batterimonitor!
Och nu äntligen har jag den grafiska visningen aktiv i verklig off-grid solcellsdrift och får se mina tankar där i skarp drift med både solcellsström och batteriström uppdaterat ca 1ggr/s :-)
Visar proportionerna mellan hur mycket av strömmen som kommer från solcellerna respektive batteriet, samt när batterierna laddas hur stor del av solcellsströmmen som går till förbrukning respektive laddning. Samt visar SoC-laddnivå tydligt via en batterisymbol.
Cirkeldiagrammets centrum blir grönt när det är överskott på solcellsström som solladdregulatorn stryper samt blir rött när laddnivån går under 30% SoC så man uppmärksammas på det.
Färgkodningen gör att jag på en liten mobilskärm kan se hur driften är på 3-4m avstånd från den! Sedan har jag andra webbsidor med både mer typ rådata siffror, med driftsstatistik och diagram med rådata bearbetade till information.
Så min ESP32-batterimonitor är nu redo för att återmonteras i husvagnen igen!
Men jag förstår att alla inte tycker detta är ett bra sätt att visa batteridriften på, men är så jag vill ha det. Är bara skoj om vi gör på lite olika personliga sätt, tycker jag.
2024-07-31
Samt ser hur lång tid under dygnet solcellerna ger ett överskott på ström (PV-Throttle), ca 5h igår.
Som igår stod solcellerna för 100% av strömförsörjningen ca 14h det dygnet i mitt lilla experiment off-grid solcellssystem här hemma, samt som max fick AGM-blykol batteriet ca 90% av tillgänglig solcellsström för sin laddning igår.
All data uppdateras live på webbsidorna ca 1ggr/s. Görs via WebSocket / SSE från ESP32 webbservern.
Nu har jag även INA226-strömsenor placerad intill strömshunten med knapp 1dm långa mätkablar mot ca 1m tidigare. Nu är istället den digitala överföringen via I2C ca 1m lång.
Och då verkar den mäta 9kHz strömpulsandet från Battery Reconditioner mer korrekt med sina korta kraftiga strömpulser (50-100A) motsvarande ca 1MHz (ca -75mA medelström när aktiv enligt datablad och nu mätt här), vilket mättes en del fel tidigare. Både nu och tidigare har dess lite längre 3A strömpulser för uppladdning mätts rätt, så därför det summerat blev lite fel förut på lite grovt ca 75-100mA för medelströmmen.
Vid 12,82V batterispänning förbrukades förut -75mA och nu -55mA cirka i kvällsmörker, och -15mA när 12,6V då denna 9kHz Battery Reconditioner är inaktiv under 12,7V.
Blir då: (75-15) / (55-15) = 1,50, så mätte 50% för hög förbrukning för 9kHz strömpulsandet förut! Vilket har påverkat märkbart då det är huvudströmförbrukaren under passiv standby-drift!
Så det känns också skoj! Även om den nog inte mäts 100% rätt nu heller, men väldigt nära.
Vid ca 13,8V float-laddning mäts den dra ca -75mA nu vilket är det som står i dess datablad.
Förut såg den ut att dra minst 150mA vid 13,8V som det mättes då, så en väsentlig skillnad.
Innebär att nu har jag riktigt bra mätprecision även vid låga strömmar trots 9kHz / 1MHz strömpulsandet. Även kraftigt dynamiskt varierande ström mäts därmed väldigt exakt.
Idag satte jag mobilen på laddning vid 9-tiden och då syns att batteriet fick stå för den större delen av den laddströmmen i det mulna vädret. Samt kan se att ca kl.04:30 började solcellerna leverera sin första ström idag.
Jag tycker detta ger en helt annan överskådlig uppfattning om solcellsdriften än bara en massa strömvärden.
Sedan kan jag titta på diagrammet över själva batteridriften och där se dess ström, spänning och laddstatus under dygnet när jag vill ha sådana mer absoluta siffror.
Utöver det har jag webbsidor som visar en mängd olika driftsaspekter i statistik och siffror, där jag då även får en detaljerad objektiv statistik över mina AGM-blykol batteriers drift, som batteriverkningsgrad, hur högt upp i SoC-laddnivå de tar emot full solcellsström (igår till 98,6%), vid vilken SoC-laddnivå batterimonitorn detekterar 100% fulladdade batterier och synkar 100% SoC (igår vid 99,7% SoC), etc.
Så kommer där få vetenskapligt objektiva exakta data som backar upp mina påståenden om hur högpresterande bra mina AGM-blykol batterier fungerar i min batteridrift!
Så ska bli skoj att senare ge mig ut på lite fricampingturer med min batterimonitor i drift i husvagnen :-)
Fick på FB kommentaren: "Du har fått till det grafiska gränssnittet riktigt bra." från en som är riktigt kunnig på gränssnittsdesign, så känns verkligen skoj!
Fler kommentarer: Riktigt snyggt! Bra jobbat! || Wow toppen! Önskar att jag hade tid att pilla på med sånt oxå. Bra jobbat! Toppen design. || Grymt jobbat! Blir det en kommersiell produkt av detta? || Imponerende diy-overvåkning! || Väldigt fint gränssnitt. Lättöverskådligt! || Riktigt snyggt! || Du får helt enkelt bygga fler och sälja :-) Ser fantastiskt ut! || Du inspirerar! || Väldigt snyggt och bra information!
2024-08-02
Fixat ett par matematiska buggar i beräkningarna för Consumption Ah & Wh.
Blev verifierade under dagens drift att det nu är OK.
WebSocket orsakade Panic´ed reset då ESP32 tappade kontakten med WiFi!
Har hänt extremt glest så har varit svårt att fånga en Backtrace-rapport för en sådan händelse och därmed har jag inte haft en aning vad orsakan kunde vara, men lyckades idag.
Fick WiFi STA Disconnected 58ms innan "Guru Meditation Error: Core 1 panic´ed".
Samt "WebSocket client #5 disconnected" 14ms innan "Guru Meditation Error: Core 1 panic´ed".
Backtrace-rapporten angav då rad 5842 som sista exekverade i min kod sedan var det i AsyncWebSocket.cpp:
5840 if (wsOperationalData.availableForWriteAll())
5841 {
5842 wsOperationalData.textAll(String(int(PulseInd)));
5843 }
Så kompletterade den if()-satsen på alla ställen med:
5840 if (wsOperationalData.availableForWriteAll() && WiFi.status() == WL_CONNECTED)
5841 {
5842 wsOperationalData.textAll(String(int(PulseInd)));
5843 }
Samt då även:
if (wsConfiguration.availableForWrite(client->id()) && WiFi.status() == WL_CONNECTED)
{
wsConfiguration.text(client->id(), output);
}
Så hoppas jag på att det är lösningen för detta!Jag hittade ett snarlikt fall på Internet: ERROR: Too many messages queued, samt även Crash in AsyncWebSocket::textAll(String const&).
Nu håller jag tummarna för att inte något mer dyker upp från den senaste utvigningen med INA260 för solcellsströmmen samt DS18B20 för batteritemperaturen, med tillhörande mer bearbetad statistisk mätdata.
2024-08-03
Installerat ett exemplar av min ESP32-batterimonitor i husvagnen nu och den fungerar bra. Inga synliga buggar i programkoden men då jag började med all data nollad så blev några småsaker synliga som behöver några småjusteringar i koden.
Blev bra testat med ström ända upp till 15A samt laddeffekt på 220W som mest.
Men strömshunten i husvagnen verkar ha lite fel i resistansvärdet så mäter en aning för hög ström med dess nominella värden inställda, så får ta fram justerade värden som stämmer bättre med verkligheten. Har ju kontrollmätt här hemma med noggrann strömshunt och då mäter systemet rätt.
Har länge väldigt glest fått panic´ed kodkrasch när jag växlat från webbsidan "Statistic 24hr Data" till annan webbsida och inte förstått hur jag ska åtgärda det eller vad orsaken är, men nu under två dygns campande kom jag plötsligt på den sannolika orsaken till att just den webbsidan ibland orsakar kodkrasch!
Webbsidan får data via SSE från ESP32 webbservern och dess SSE är inte så stabil och kraftfull. Provad från början att slå ihop 3st siffervariablers data till en textsträng och skicka då jag tyckte det kändes rationell och effektivt, men då blev det kodkrasch titt som tätt. Så när jag ändrade till att bara skicka en variabels siffror i taget blev det mycket stabilare. Men denna webbsidan har 3st data-tid uppgifter den skickar och det blir rätt långa textsträngar, jämfört med 4-5 siffror som data, så troligen är problemet där! Samt dessa skickas precis varje loop-cykel dessutom. Så tänker dela upp i datum och tid separat, och datumet behöver bara skickas nytt 1ggr/dygn. Skulle även kunna separera HH:MM från SS så det bara blir sekundsiffrorna som skickas precis varje gång:
Uptime: 00y00m01d 14h18m29s
ESP32: 2024-08-07 22:56:09
Client: 2024-08-07 22:56:09
Även webbsidan "System Data" innehåller en sådan tidsangivelse som uppdateras varje programloop, så bör fixa den också på samma sätt.
Blev lite plottrigt otydligt med 5st diagramkurvor i "PV off-grid Operational status" diagrammet när kylskåpets kompressor hela tiden varier strömmen så kraftigt med sin ON/OFF-drift, vilket jag misstänkte men ville prova.
Så minskar ned till 3st kurvor: SoC, PV-Solar & Batt-Charge, som då ger en tydligt bild av solcells batteridriften.
Samt dubbelcheckar några av beräkningarna igen, som var OK.
Glömde även att koda så RTC synkas minst 1ggr/dygn med NTP tidsserver på Internet, genom att starta upp 4G-routern autonomt! Så får bli en egen Task som hanterar det asynkront från all annan funktion.
2024-08-09
Kodat en
Task_WiFiSyncRTC()
, en asynkron FreeRTOS Task för att aktivera WiFi och synkronisera RTC med NTP-tidsservers tid på Internet. Avbryter inte någon av de andra kodslingorna eller interagerar med dem negativt, oavsett hur lång tid det tar.Med
Task_WiFiSyncRTC()
hanteras nu all anslutning till WiFi / Internet samt aktivering av ESP32 webbservern. Därmed förhindras att det köas upp meddelande i Task_StateMachine() som stör funktionalitet under de normala programlooparna då anslutning till WiFi kan ta en bra stund!Används bl.a. till att synkronisera RTC med NTP tidsserver på Internet vid varje midnatt.
Har nu bara 3st diagramkurvor i "PV off-grid Operational status" diagrammet, vilket blev mycket tydligare.
Kodat så att tidsangivelser med datum+klockslag nu delas upp och skickas separat för minskad SSE-belastning. Även int_64-tider delas nu upp så tid motsvarande YY:MM:DD skickas separat från tid motsvarande HH:MM:SS.
Hade missat att säkra mot "division by zero panic´ed" där % räknas fram i Tripmätaren samt för Amp-Sources, så är fixat nu.
Förreglat PV-Throttle med 5s innan aktiveras då PWM-regulatorn med väldigt korta pulser blockerar sin laddström ut glest, sannolikt för att detektera ifall det är spänning från solcellerna fortfarande.
2024-08-12
Har modifierat lite kring
portENTER_CRITICAL() / portEXIT_CRITICAL()
för 2xISR samt där ESP.getMaxAllocHeap()
används. Samt även ändrat så ESP.getMaxAllocHeap()
bara anropas på ett ställe i koden och den datan lagras i en atomic-variabel för använding på övriga ställen.ESP.getMaxAllocHeap()
anropas bara i Task_LCDbuttonsHandler()
nu och då omgiven av portENTER_CRITICAL() / portEXIT_CRITICAL()
.Tog samtidigt bort
portENTER_CRITICAL_ISR() / portEXIT_CRITICAL_ISR()
i båda ISR.Bör ihop lösa en extremt sällsynt störning i kodexekveringen!
Gav även lite stabilare kodexekvering minnesmässigt.
Men fångade likt förbaskat att det är även en bugg kring Mutex i
ESPAsyncWebServer-esphome
=> AsyncEventSource.cpp
vid SSE-data från webbservern till webbsidan! Så får byta till WebSocket för alla webbsidorna så småningom, men är ett rätt stort jobb. Sker dock väldigt glest nu.Råkade se följande från LiU: "Li-jon: För korta laddcykler är läckströmmar försumbara och Coulombverkningsgraden alltså nära 100%.
Så kan kanske stämma att jag även för mitt 90Ah AGM-blykol vid grunda urladdningar bara ned till strax under 97,5% SoC får mätt 100% Coulombverkningsgrad? Har bara förutsatt att det måste vara ett mätfel, men vad jag kan avgöra verkar ESP32-batterimonitorn nu mäta även 9kHz ströpulsandet från battery reconditioner rimligt korrekt. Men har haft en aningen djupare urladdning och då blev det drygt 97% Coulombverkningsgrad uppmätt. Får testa mer senare.
När mitt experiment AGM-blykol batteri blivit fulladdat (Sync 100% SoC) inom en 24h-period från senaste gången så blir medelsladdströmmen för 24h oftast +10mA - +20mA vid uppnådda 95-97% SoC urladdningsnivå, vilket indikerar väldigt nära 100% batteriverkningsgrad. Att den då vid första "Sync 100% SoC" för dagen mäter 100% coulombverkningsgrad beror på att efter att 0,5% tail-current dektekteras för "Sync 100% SoC" laddas det in några 1/10-dels procent till av SoC-urladdningen som inte kommer med i mätningen, som syns i diagrammet nedan.
Är här i mitt lilla experiment off-grid solcellssystem jag utvärderar batteriverkningsgrad redan när urladdningen bara gått under 97,5% SoC, medan vid drift i mitt riktiga off-grid solcellssystem mäts bara batteriverkningsgrad för urladdning <90% SoC och då blir det helt försumbart!
Går inte att ha lägre än 0,5% tail-current som gräns för detektering av "Sync 100% SoC" för robust tillförlitlig funktion och behövs inte heller vid mer verklig drift i off-grid solcellssystem där den ger en väldigt bra precision i detektering av fulladdat blybatteri. Redan här detekteras fulladdat batteri inom ca 99,7% SoC till 100,1% SoC, en enormt bra precision!
Slutsatsen blir att detta 90Ah AGM-blykol batteri arbetar med extremt bra verkningsgrad vid dessa grunda urladdningar med dessa låga strömmar!
2024-08-21
Lite kodrefaktoring och fixande / optimerande:
Optimerat lite till kring TailCurrentFirstOK
så det fungerar än bättre.
Förändrat hur Ah/Wh beräknas / summeras totalt / trip för både solcellsström (PV) och batteriström, så det blir en tydligare mer ensad beräkning av dem, via BattIs100SoC
. Innebär att de summeras kontinuerligt så länge inte 100% SoC fulladdat batteri detekteras, då bara PV beräknas / summeras minus det till batteriet då. Ger bättre mätvärden för batteridriften där även små urladdningar kommer med samt får mätvärdena att stämma bättre inbördes. Samtidigt som inte en massa ström som matas in i fulladdad batteribank över lång tid tas med, typ i Standby-drift.
Har även gått igenom alla WebSocket.cleanupClients();
så de fungerar OK för de olika WebSocket baserade webbsidorna! Hittade en kodmiss där för wsOperationalData.cleanupClients();
som kan ha orsakat glesa Panic´ed i ESPAsyncWebServer-esphome
kodbiblioteket.
Har gjort förbättringar i webbsidornas Meny-hantering vs SSE / WebSocket så ny webbsida enligt menyval inte aktiveras förrän den initiala belastningen av SSE / WebSocket dataöverföringen är avslutad, genom att räkna antal PulseId´s som är den sista datan som överförs. Tror det då kan undvika Panic´ed pga av mutex-bugg i ESPAsyncWebServer-esphome
. Den har nog bara väldigt glest aktiverats just när jag växlat webbsida snabbt, speciellt då WiFi har fungerat svagt. För när jag nu under två veckor själv manuellt kollat in PulseID så den intitiala dataöverföringen är avslutad har inte den buggen aktiverats vid växling av webbsida!
Har då även lagt in en timer-funktion, så om SSE / WebSocket kommunikationen felar så växlas ändå till ny webbsida 20s efter gjort menyval, så inte detta hänger sig helt då.
Blev en jäkla bra, smidig och effektiv JavaScript-kod för Meny-hanteringen vs SSE / WebSocket för webbsidorna! Som bara märks av när man växlar webbsida lite väl snabbt.
Så är tur jag behärskar både ESP32 C++ / FreRTOS & webbsides Html / JavaScript kodande!
WebSocket Events: Kodat så Events till varje webbsida nu finns i vars sin egen funktion ConfigurationWsEvents(), DataGraphsWsEvents() & OperationalDataWsEvents()
, vilket dels tar bort redundant kod för initiering+drift, dels därmed tar mindre plats i ESP32 flash-minnet samt även belastar RAM-minnet mindre då bara den / de av dessa funktioner som aktivt för stunden används till en webbsida laddas in i RAM. Ska inte ha någon redundant kod!
Gör det även lättare att uppdatera funktionen i framtiden och undviker då att missa att uppdatera samma kod på två ställen, vilket annars är en stor felkälla!
Då är allt färdig för fälttestomgång två i husvagnen igen, då det blev några saker såhär jag behövde fixa och uppdatera och gjorde då även lite motiverad kodrefaktoring för ökad effektivitet.
2024-08-25
Efter de senaste gjorda uppdateringarna gick inte ESP32 in i light-sleep längre, så har gjort en väldigt enkel buggfix för det.
Var bara en kodrad med OnWiFiReconnect
som råkat hamna innanför en IF()-sats istället för precis allra sist i funktionen utanför den.
Passade även på att optimera de olika villkoren för att gå in i light-sleep inkl. den while()-fördröjning jag har för att låta parallellt exekverande kod exekvera färdig innan tillåts gå in i light-sleep, så att display, tryckknappar, webbserver, 2x TaskDeferredInterrupt, synkning av RTC till NTP-tidsserver, etc hinner exekvera färdigt med sina funktioner först.
Fick därmed vid nattdrift lite ytterligare mer tid i light-sleep och därmed lite ytterligare mer strömsnål drift.
Strömsnål nattdrift är nu 98,75 - 96,25% av tiden i light-sleep, med ett medelvärde på 97,9%!
2024-09-03
Justerat lite till kring portENTER_CRITICAL(&Critical_Section_Mux);
så jag bara använder det på två kritiska ställen i koden nu, samt tagit hänsyn till att FreeRTOS API functions must not be called from within a critical section som annars vållar problem. Har även infört en bool INA260Found
flag.
Med den nya Task_WiFiSyncRTC()
(se ovan), en asynkron FreeRTOS Task för att aktivera WiFi och synkronisera RTC med NTP-tidsservers tid på Internet, blev WiFi-uppkopplingen stabilare och kopplar nu alltid upp snabbt. Eller om det är fixandet med portENTER_CRITICAL()
som fick den påverkan. En helt överraskande effekt mot när det hanterades via en annan Task som hanterade många olika uppgifter i den löpande program-loopen eller en portENTER_CRITICAL()
med FreeRTOS API-funktion anropad inom / fler portENTER_CRITICAL()
kodblock som stör FreeRTOS. Så verkar som WiFi och webbserverns kod körs på ett stabilare mer oberoende sätt nu!
Har nu arbetat helt stabilt i 7 dygn, med webbservern aktiverad med visade webbsidor flertalet gånger varje dag samt även under längre tider. Med autonom automatisk uppkoppling till NTP-tidsserver varje natt för synkronisering av RTC.
Idéer: 2023-07-04 / 2024-07-05
- Ultra-strömsparläge:
Får se om jag senare gör ett ultra-strömsparläge där INA226/INA260 samplar betydligt långsammare så det kanske blir upp emot 5-10s/loop, som då kunde styras av att solcellsströmmen är <5mA/100Ah batterikapacitet i Light-Sleep dvs försumbart med ström från solcellerna. Lite typ extra strömsnål "invintringsdrift" / nattdrift. Kunde vara extra viktigt off-grid vintertid.
Men får då mäta hur mycket det sparar mot vad jag förlorar i pulsström mätprecison!
Har nu testat både praktiskt samt mätt exekveringstiden för INA260´s Deferred Interrupt Task, och den är minimala 2,4ms av loop-cykelns 1200ms så är försumbart det kan påverka! - Nya ESP32 kodversioner:
Arduino Release v3.0.1 based on ESP-IDF v5.1.4
Migration from 2.x to 3.0
ESP32: Migrating from version 2.x to 3.0 (Arduino IDE)
Arduino Release v2.0.16 based on ESP-IDF v4.4.7
Platform Espressif32 6.7.0
-----------------
platformio/framework-arduinoespressif32, 3.20017.0 (2.0.17)
espressif/arduino-esp32 , Migration guide from version 2.x to 3.x is available here.
Arduino Release v2.0.17 based on ESP-IDF v4.4.7
Platform Espressif32 6.8.1
ESP32: Migrating from version 2.x to 3.0 (Arduino IDE), Randomnerdtutorials
- 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. (Ger strömsnålast nattdrift i light-sleep, se ovan.)
- 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?
- Light-Sleep Mode 240MHz, även invintringsmode med sin ca 12V/6mA strömförbrukning
- 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!
- Förtydliga / utveckla SetStateEnergyCPU() för mikroprocessorns energy-mode:
- Nu går "bara" 24h loggdatan för presentation av batteridriften förlorad vid reset, men ska senare titta på om även den ryms att sparas i RTC Slow Memory (8kB RAM), vilket jag tror.
Är fixat ihop med LittleFS! - 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?
Typ kanske laddström >1%/0,01C av batterikapaciteten?
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 reset 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
Understanding ESP32´s Multitasking and Watchdog Mechanism: A Deep Dive
What is a watchdog timer (WDT)?, ABLIC Inc.
Watchdog timer, Wikipedia
Länkar: 2023-06-16
- Kalkylator för låg-/högpassfilter, RC, LC & RL, Digikey
- 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).
"Now I use Mongoose that works very well :)"
Mongoose Library - a state-of-the art open source embedded web server:
- Mongoose - Embedded Web Server / Embedded Networking Library
- ArduinoMongoose, ESP32
- Espressif: ArduinoMongoose
- Mongoose Library Embedded Web Server, homepage
- Mongoose Build options for ESP32 & FreeRTOS
- Mongosse Using JSON
- Mongoose Library Websocket server
- Mongoose User Guide - 2-minute integration guide
- Mongoose - ESP32: Device Dashboard
- Mongoose Web Server Library Case Studies
- Mongoose Testimonials
- Websockets using Mongoose Library on ESP32 - Controlling an LED, Youtube
- Use Mongoose as a replacement for AsyncWebServer
- Mongoose/webserver, github snippet
- Mongoose (web server), Wikipedia, officially supported on FreeRTOS
- Mongoose OS Introduces ESP32-based IoT Starter Kits, Espressif
Eventually this code library:
- WebSockets by Markus, WebSocket Server and Client for Arduino ESP32, PlatformIO
- ArduinoWebSockets, GitHub
- ArduinoWebSockets - Comparing changes, GitHub
- Markus, GitHub
- X WebSocket Data Exchange with JSON for ArduinoJson 6, Steph´s µLab +++
- X ESP32 WebSocket Server using Arduino - Control GPIOs and Relays
- X ESP32 WebSocket Server: Display Sensor Readings
- X ESP32 Web Server (WebSocket) with Multiple Sliders (JSON), getValues()
- X How to post JSON data to a HTTP server endpoint [https://] from your ESP32 development board with ArduinoJson
- X bblanchon / ArduinoJson, PlatformIO, arduinojson.org
- Search: html5 post recieve JSON data php
- How to receive JSON POST with PHP?, GeeksforGeeks
- Espressif-arduino-esp32/libraries/HTTPClient/
- Espressif-arduino-esp32/libraries/WiFiClientSecure/
- ESP32: Insert Data into MySQL Database using PHP, on own server [https://]
- ESP32: How to Log Data (9 Different Ways)
- ESP32: Send Email Notification using PHP Script
- 160+ ESP32 Projects, Tutorials and Guides
- BVR-M-R001-1.0 - Motstånd, ytmontering 4W, 1mOhm, 1%, Isabellenhütte, (pdf)
- PBV-R001-F1-1.0 - Effektmotstånd 3W 1mOhm 1 %, Isabellenhütte
- BLOCK SHUNT 100A/50MV - Shunt 100 A, 50 mV class 1.0, Fujita
- PWR220T-20-10R0F - Strömavkänningsmotstånd, Bourns, 10Ω, 20W, TO-220
- Mouser: DC-shunt
- NorthStar NSB Blue+ Battery® lead-carbon Application Manual, 100Ah: Exceptional PSoC cyclic performance, Design life 12+ years, Ultra fast recharge (no charge max current limit), Operating temperature range -40°C to +65°C, Impedance (1Khz) 2.6 mΩ, 34kg, har en coulomb-verkningsgrad på 94% - 99,5% angivet, varierande med temperatur och hur djup urladdningen varit - "The higher the DOD and the higher the temperature is the higher this overcharge need to be to fully charge the battery."
Lägre temperatur = högre coulomb-verkningsgrad. - The overall (charge/discharge) coulomb (current*time efficiency) of prismatic LFP batteries is around 99%. From my logged data over a period of around eighteen months I have 99.4%. The overall power efficiency which is a combination of the coulomb efficiency and the voltage efficiency for my battery is around 95%. This matches the figure I have seen in allot of literature on the subject.
- L.I.M.E Power Cyklingstålighet LiFePO4: "Vi laddar och laddar ur vid ca 0,7C, det vill säga ca 28A mellan 14,8 och 11,0 volt. Mätt i wattimmar laddar vi ur ca 480Wh/cykel och laddar i ca 530Wh/cykel (skillnaden är inre förluster). [Dvs 90% Wh-verkningsgrad.] Det betyder att vi tar nästan hela batteriets kapacitet i anspråk (DOD90%).
Vi har genomfört drygt 500 cykler. Kapaciteten sjönk med 10,8%.
Vi kan konstatera att batteriet mycket väl kan klara 80% av ursprunglig kapacitet efter 1000 cykler. Dessa 500 cykler innebär sannolikt att batterierna även efter 10 års användning i fritidsbåt har en försämring i användbar kapacitet som knappt märks." - Making Your Battery Monitor More Accurate, Marine How To
- Testing the Balmar SG200 Self-Learning Battery Monitor, Marine How To
- Balmar SG200 Battery Monitor
- Balmar Smartgauge Battery Monitoring Unit, Marine How To
- Balmar Smartgauge™ Battery Monitor
- An effect similar to Peukert´s effect during charging, Smartgauge
- A-BMS – Active Battery Management System (lead-acid)
- Simarine PICO, Redefining Smart Battery Monitors
- Simarine Setup & Review, in a RV
- Victron Battery Monitor vs Simarine Pico Monitor, in a RV
- TAO Performance: A complete Energy Management System
- TAO Performance: Keeping your LiFePO4 battery healthy Learn about the optimal conditions and a few simple precautions to keep your LiFePO battery healthy for a long life. Med det TAO rekommenderar så har man i princip samma prestanda från LiFePO4 och bra AGM-blykol batterier med bl.a. max laddström ≤0,3C.
Beskrivs även här: Most LiFePO4 manufacturers specify a maximum charge rate of 0.3C. Låter allvarligare att överskrida max laddström för LiFePO4 än för blybatterier!
För AGM-blykol (lead carbon) ser en max laddström på ≤0,5C ut att vara vanligt! - TAO Performance: What reduces the life of a LiFePO4 battery? Never recharge a LiFePO4 cell when it´s voltage as gone below 2.0 volt. It could create an internal short-circuit and a risk of fire. Allowing a LiFePO4 cell to drop below 2.5V will not only damage the cell but it converts the cell into a timebomb.
- TAO Performance: LiFePO4 Charge Cycle Management TAO BMS has a new feature to manage the LiFePO4 charge cycles and extend battery life.
- TAO Performance: New local and Cloud dashboard
- X2 BMS introduces five new BMS technologies
- LiFePO4 - Blybatteri hybrid
- OpenHybridBMS, ESP8266 based. This project was started because I was not satisfied with the commercial Battery Management Systems available.
- OpenHybridBMS Example status webpage via WiFi
- OpenHybridBMS, GitHub
- Lithium (LiFePO4) management - How to keep Lithium cells safe and healthy
- LiFePO4 - Approaching and exceeding the limits
- Studer Innotec: A year of solar autarky
- Studer Innotec: The next3 latest software release allows now the installation of 2 next3 in parallel, with the same or independent batteries??
- Studer Innotec Facebook
- Studer Innotec website
- OpenStuder gateway is the link from the IT world to a Studer Innotec installation, Open-source
- OpenStuder WebSocket
- Studer: Swiss made advanced energy management via Solar Manager
- Solar Manager FB
- Solar Manager website
- OFF-GRID Expo + Conference
- Victron Open-source
- How to set up Victron BMV Battery Monitor for lead and lithium batteries
- Victron solar production forecast feature, See your estimated future solar yield today.
- Solcast solar data or forecasts, Forecasting data for irradiance and PV power.
- Victron Dynamic ESS Node-RED, uses VRM forecasting and algorithm to optimize when to sell, buy and hold the grid to zero.
- SMHI API för väderprognosdata
- SMHI Meteorologisk prognosmodell PMP3g (2,8 km upplösning) - API
- SMHI Villkor för användning, öppen data
- Förimpedans, "En livsviktig regel är att matningen i en elektrisk starkströmsanläggning frånkopplas inom 0,4s vid kortslutning mellan fas och skyddsjord (höljet) i en apparat. I SS 424 14 05 finns angivet Imax för utlösning av säkring vid olika tider. Med säkring som skydd gäller t.ex. att en 10A diazed kräver en ström på minst 82 A (fabrikat Ifö bryter på 56 A) för att lösa inom 0,4s. En C10A dvärg kräver 100A. En B10A dvärg kräver istället bara 50A för att lösa."
Så 20A => 100A 0,4s tidskonstant för inbyggd 20A eFuse funktion?