NL; MT Venus E V2 (V153 BMS:V215); HW P1 (5.1903); App: V1.6.49; Comm.Mod:202409090159; 1 Fase 40A hoofdzek.; Iskra ME382-D1A52-P1 bj 2012; PV 7650 Wpiek; Inventum Ecolution ventilatiewarmtepomp; EV (Seat Mii 32kWh);
Ik ben met iets soortgelijks bezig in Node-RED.antoinevromen schreef op zaterdag 20 september 2025 @ 09:41:
[...]
Jawel ik draai voornamelijk NOM (dus dat is Modus Auto en staat in de app als zelfconsumptie),
maar er kunnen momenten zijn (bijv. 's winters als de batterij bijna nooit vol raakt waarop het script 1 x per week op het laagste tarief toch een keer tot 100% vol laadt t.b.v. behoud accu en soc-drift) of wanneer je bijv. dynamisch tarief hebt en je geraakt niet helemaal door de nacht met de batterij dat je dan de batterij op het laagste tarief gedurende de nacht zoveel bijlaadt dat je in de ochtend over het duurste tarief-moment heen geraakt.
Of bijv. in de winter als de batterij maar voor een deel is vol geraakt en de dure uren rond 19.00/20.00 moeten nog komen zoveel bijlaadt dat je over die dure uren heen geraakt.
Maar ik ben ook nog aan het denken aan het inbouwen van juist verkopen in de zomer op het duurste uur met zonnestroom die gratis in de middag is opgeslagen. Daarnaast ben ik ook nog aan het denken om bijv. in de zomer de batterij niet al van 7 tot 10 te laten volladen (maar die stroom liever naar het net te leveren) en in plaats daarvan op de negatieve uren of 0 uren in de middag hem vol te laden omdat hij toch altijd wel vol raakt op zo'n dag (ook op basis van de voorspellingen van zonne-Watt/m2 die ik download en interpreteer in het script).
Op basis van gemiddeld verbruik en verwachte opwek voor komende 24 en 48 uur de minimale SOC berekenen en dan bij overschot op dure uren ontladen of bij tekort op goedkope uren bijladen tot aan de minimale SOC.
/f/image/idV5sHgV2a3BZSFd9HocSLeF.png?f=fotoalbum_large)
In dit voorbeeld was op dag 2 het verbruik hoger dan gemiddeld, dus de SOC bleef achter, en omdat ik krappe drempelwaarden had ingesteld werd er van het net opgeladen.
Op dag 3 waren de drempelwaarde ruimer ingesteld en werd er niet opgeladen.
Over een week of twee zal ik wat meer details delen.
2x Venus E (Gen1) V153.215, HW P1, Lilygo+HA
Hallo @Hometek ,Hometek schreef op zaterdag 20 september 2025 @ 22:15:
[...]
Ik ben met iets soortgelijks bezig in Node-RED.
Op basis van gemiddeld verbruik en verwachte opwek voor komende 24 en 48 uur de minimale SOC berekenen en dan bij overschot op dure uren ontladen of bij tekort op goedkope uren bijladen tot aan de minimale SOC.
[Afbeelding]
In dit voorbeeld was op dag 2 het verbruik hoger dan gemiddeld, dus de SOC bleef achter, en omdat ik krappe drempelwaarden had ingesteld werd er van het net opgeladen.
Op dag 3 waren de drempelwaarde ruimer ingesteld en werd er niet opgeladen.
Over een week of twee zal ik wat meer details delen.
Exact. Mooi te lezen dat je ook in diezelfde sturings-richting aan het werken bent. Dat is ook de oplossingsrichting die ik aan het inbouwen ben. Op basis van de zon-voorspelling in Watt/m2 kan ik uitrekenen hoeveel PV-kWh ik nog verwacht op te wekken en dan kijk ik of ik vanaf het huidige uur x t/m maximale prijsuur met de huidige soc en verwachte bijlaadhoeveelheid uit kom rekening houdend met een geschat gemiddeld verbruik per uur. Als het met PV-opwek lukt om die drempel-soc te bereiken dan niet bijladen. Als er niet voldoende PV-opwek is, dan kijken of de huidige Net-prijs (verhoogd met RTE-verlies) opweegt tegen de gemiddelde prijs van de laatste uren vooraf en inclusief het maximale prijsuur waarvoor ik Net-stroom zou moeten bijladen. Ook hier is het nog even spelen met de parameters die bepalen hoeveel PV-kWh daadwerkelijk uit zonne Watt/m2 komt en hoeveel W/uur je verbruikt in de nacht en overdag om in te schatten hoeveel de huidige soc nog zal dalen ten gevolge van dat verbruik.
Ik houd daarbij overigens rekening met 2 max-prijsnivo's per dag ; 1 voor de middag (meestal rond 8 uur 's morgens) en 1 voor na de middag (meestal rond 20.00 's avonds); Zodat ik 2 momenten heb waarop ik de soc kan bijsturen door van het Net te laden met goedkope stroom. Maar zoals ik al schreef zijn er in de zomer wellicht nog andere punten van sturing (zoals bijv. niet laden in de ochtend, maar pas als de prijs minimaal/negatief is als de voorspelling toch voldoende PV-stroom aangeeft); Dan leveren die Net-teruggeleverde kWh's in de ochtend nog iets op en bespaar ik mij (een deel van) de negatieve prijs-uren.
[ Voor 14% gewijzigd door antoinevromen op 21-09-2025 08:56 ]
NL; MT Venus E V2 (V153 BMS:V215); HW P1 (5.1903); App: V1.6.49; Comm.Mod:202409090159; 1 Fase 40A hoofdzek.; Iskra ME382-D1A52-P1 bj 2012; PV 7650 Wpiek; Inventum Ecolution ventilatiewarmtepomp; EV (Seat Mii 32kWh);
@antoinevromenantoinevromen schreef op zondag 21 september 2025 @ 08:52:
[...]
Hallo @Hometek ,
Exact. Mooi te lezen dat je ook in diezelfde sturings-richting aan het werken bent. Dat is ook de oplossingsrichting die ik aan het inbouwen ben. Op basis van de zon-voorspelling in Watt/m2 kan ik uitrekenen hoeveel PV-kWh ik nog verwacht op te wekken en dan kijk ik of ik vanaf het huidige uur x t/m maximale prijsuur met de huidige soc en verwachte bijlaadhoeveelheid uit kom rekening houdend met een geschat gemiddeld verbruik per uur. Als het met PV-opwek lukt om die drempel-soc te bereiken dan niet bijladen. Als er niet voldoende PV-opwek is, dan kijken of de huidige Net-prijs (verhoogd met RTE-verlies) opweegt tegen de gemiddelde prijs van de laatste uren vooraf en inclusief het maximale prijsuur waarvoor ik Net-stroom zou moeten bijladen. Ook hier is het nog even spelen met de parameters die bepalen hoeveel PV-kWh daadwerkelijk uit zonne Watt/m2 komt en hoeveel W/uur je verbruikt in de nacht en overdag om in te schatten hoeveel de huidige soc nog zal dalen ten gevolge van dat verbruik.
Ik houd daarbij overigens rekening met 2 max-prijsnivo's per dag ; 1 voor de middag (meestal rond 8 uur 's morgens) en 1 voor na de middag (meestal rond 20.00 's avonds); Zodat ik 2 momenten heb waarop ik de soc kan bijsturen door van het Net te laden met goedkope stroom. Maar zoals ik al schreef zijn er in de zomer wellicht nog andere punten van sturing (zoals bijv. niet laden in de ochtend, maar pas als de prijs minimaal/negatief is als de voorspelling toch voldoende PV-stroom aangeeft); Dan leveren die Net-teruggeleverde kWh's in de ochtend nog iets op en bespaar ik mij (een deel van) de negatieve prijs-uren.
Hetzelfde basisprincipe, maar verschillende strategieën. Iedereen heeft zo zijn eigen voorkeuren
Mijn strategie is om de baterij tegen het einde van de middag altijd op het minimum SOC niveau te hebben. Opladen bij laagste prijs en ontladen bij hoogste prijs gebeurt alleen als er op dat moment toevallig een tekort dan wel een overschot is. Hierdoor zou het systeem redelijk ongevoelig moeten zijn voor het verschuiven van de goedkope en dure momenten gedurende het jaar. Ik kijk niet naar de prijzen zelf, alleen of het een maximum of minimum is.
Voor het ontladen kijk ik naar de minimum SOC voor vandaag, voor het opladen kijk ik ook naar de minimum SOC voor de volgende dag om te voorkomen dat ik vandaag stroom inkoop terwijl er morgen voldoende zon is.
Deze strategie is natuurlijk alleen zinvol bij een installatie met een relatief grote batterij die meestal niet leeg raakt gedurende de nacht.
Voor de PV opwek gebruik ik Solcast, deze integratie levert direct de verwachte kWh voor een specifieke installatie, en er zit sinds kort een handige auto-correctie functie in (zie deze post)
2x Venus E (Gen1) V153.215, HW P1, Lilygo+HA
Zeker. Ofschoon het misschien niet allemaal qua strategie precies te snappen is en ik de consequenties van jouw keuzes niet helemaal kan inschatten, vind ik het vooral goed dat we ieder voor zich de batterij zo kunnen sturen middels wat eenvoudige scripts als wij dat wensen. En er zelfs functionaliteit bij kunnen maken die er op geen andere wijze in het product zit (ik noem maar eens bijv. 1 x per week tot 100% laden, zodat de batterij in de winter niet steeds leeg staat).
Zo stuurde ik ook eerst op minimum en maximum prijs, maar kwam erachter dat ik ook de RTE (verlies t.g.v. laden/ontladen) in de berekening wilde meenemen omdat ik merkte dat soms een verschil van bijv. x-cent zich door de RTE uiteindelijk vertaalde in het feit dat de minimum-stroomprijs (geladen) toch nog hoger was dan de maximum prijs.
Ik ga nu wat scripts van mij hier posten, zodat eenieder die er interesse in heeft zelf eraan kan sleutelen.
Ik denk dat het nog lastig wordt om een grootste gemene deler te vinden voor wat nu de "juiste" strategie is (als die er al is).
Gr. Antoine
NL; MT Venus E V2 (V153 BMS:V215); HW P1 (5.1903); App: V1.6.49; Comm.Mod:202409090159; 1 Fase 40A hoofdzek.; Iskra ME382-D1A52-P1 bj 2012; PV 7650 Wpiek; Inventum Ecolution ventilatiewarmtepomp; EV (Seat Mii 32kWh);
DEEL1antoinevromen schreef op zaterdag 20 september 2025 @ 09:46:
@GoBieN-Be @HiHaHors ,
Oke ik zal in de loop van de komende week het script en een beetje van handleiding waar het script de tarieven en zonne-wattage vandaan haalt hier posten. Als je handig bent in programmeren, dan kun je het daarna zelf aanpassen naar eigen sturings-wensen.
Misschien ook een idee om eens van gedachten te wisselen wat bijv. algemene use-cases zouden kunnen zijn om in te bouwen, zoals ik hier al heb beschreven in mijn eerdere post als antwoord op GoBienBe
Beste Tweakers (o.a. @GoBieN-Be @HiHaHors),
Zoals eerder geschreven hier alvast wat scripts om de batterij middels local-api te sturen.
Veel hiervan was niet mogelijk geweest zonder de hulp van @bommel , die mij ook een stukje voorbeeldcode heeft gegeven destijds.
Wat weetjes vooraf:
-1 de scripts zijn als windows cmd-bestandjes en windows powershell-scripts gemaakt. Pas ze aan naar hartelust want ik ben de software zelf ook nog aan het uitbreiden, maar heb niet de intentie om daar een soort turn-key-project van te maken.
-2 ik ben nooit ver weg mochten mensen vragen hebben, vraag gerust
-3 de windows cmd-bestandjes laat ik middels windows task-scheduler periodiek (elk kwartier of elk uur) draaien, maar in principe gaat het er maar om dat de cmd-bestandjes gestart worden, dus hoe je dat zelf wilt regelen is up to you.
-4 de cmd-bestandjes starten (al dan niet met meegave van parameters) de powershell-scripts, welke de eigenlijke logica bevatten
-5 bij sommige scriptjes met calls naar externe https-providers is een key t.b.v. de externe api vereist. Ik zal hier beschrijven waar je op eenvoudige/gratis wijze zo'n key voor jezelf kunt krijgen. (mijn eigen key is om die reden niet getoond in de scripts om te voorkomen dat we straks allemaal geen toegang meer krijgen vanwege een te hoog aantal api-calls op die externe site onder 1 account).
-6 het spreekt voor zich dat je local-api op de Marstek Vensus E geactiveerd moet hebben. Dat kan via het officiele kanaal (een feedback bericht in de app, waarbij je verzoekt jouw batterij local-api te enabelen; Het kan ook met behulp van de tool van bommel @bommel (https://rweijnen.github.io/marstek-venus-monitor/latest/) onder system in dat tool tref je activeren local-api op poort 30000 aan (meer hierover is ook te vinden op het moeder-forum (Hame / Marstek / Duravolt 5,12kWh plug en play thuisaccu) )
-7 Ik heb momenteel geen idee hoe ik dit gestructureerd aan jullie moet overbrengen omdat ik niet schijn te vinden hoe ik attachments kan meesturen met een forum-post; Vandaar zal ik de script-code hier in een post stoppen. (zoveel is het nu ook weer niet).
-8 om powershell-scripts te kunnen draaien vanuit een windows cmd-box doe je het volgende:
a) start een windows command processor als admin
b) start nu op de prompt powershell.exe
c) start nu op de prompt Get-ExecutionPolicy -List
dat geeft een lijst van rechten weer waarbij alles undefined zal zijn als default
d) start nu op de prompt set-executionpolicy remotesigned
dit geeft de juiste rechten op localmachine nivo
e) door nogmaals op de prompt Get-ExecutionPolicy -List te starten kun je zien dat die rechten effectief zijn geworden. Vanaf nu kun je op die machine vanuit locale-cmd-bestandjes powershell-scripts draaien
[ Voor 10% gewijzigd door antoinevromen op 21-09-2025 17:34 ]
NL; MT Venus E V2 (V153 BMS:V215); HW P1 (5.1903); App: V1.6.49; Comm.Mod:202409090159; 1 Fase 40A hoofdzek.; Iskra ME382-D1A52-P1 bj 2012; PV 7650 Wpiek; Inventum Ecolution ventilatiewarmtepomp; EV (Seat Mii 32kWh);
=====
====code:
1 2 3 4 5 6 c: cd \netcat-setup echo inputmode kan zijn: AI, Auto, Passive, ManualLaden, ManualOntladen set /p inputmode= powershell.exe -file c:\netcat-setup\avzetMODEaan.ps1 -DeviceIP "192.168.178.234" -Mode %inputmode% pause
powershell-scriptje avzetMODEaan.ps1
=====
==============code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 # example usage: # .\MT-LocalApi-Example -DeviceIP 192.168.20.82 -RemotePort 30000 -LocalPort 30000 -PerCallTimeoutMs 2000 -MaxRetries 3 param( [Parameter(Mandatory=$true)][string]$DeviceIP = "192.168.178.xxx", [Parameter(Mandatory=$true)][string]$Mode = "xx", [int]$RemotePort = 30000, [int]$LocalPort = $RemotePort, [int]$PerCallTimeoutMs = 5000, [int]$MaxRetries = 3, [int]$InterCallDelayMs = 1000 ) Add-Type -AssemblyName System.Net # Create socket, enable reuse, bind to LocalPort (so source port is fixed) $udp = New-Object System.Net.Sockets.UdpClient $udp.Client.SetSocketOption([System.Net.Sockets.SocketOptionLevel]::Socket, [System.Net.Sockets.SocketOptionName]::ReuseAddress, $true) $udp.Client.ExclusiveAddressUse = $false $udp.Client.Bind([System.Net.IPEndPoint]::new([System.Net.IPAddress]::Any, $LocalPort)) $udp.Client.ReceiveTimeout = 1000 ## 250 function Send-And-Wait([string]$Method, [hashtable]$Params) { for($try=1; $try -le $MaxRetries; $try++){ $rpcId = Get-Random -Minimum 1000 -Maximum 65000 # JSON-RPC id (unique per try) $req = @{ id=$rpcId; method=$Method; params=$Params } | ConvertTo-Json -Compress -Depth 6 Write-Host ($req) $bytes = [Text.Encoding]::UTF8.GetBytes($req) [void]$udp.Send($bytes, $bytes.Length, $DeviceIP, $RemotePort) Write-Host ("→ [{0}/{1}] {2} {3}" -f $try,$MaxRetries,$Method,($Params | ConvertTo-Json -Compress)) $deadline = [datetime]::UtcNow.AddMilliseconds($PerCallTimeoutMs * [math]::Pow(1.35, $try-1)) $remote = [System.Net.IPEndPoint]::new([System.Net.IPAddress]::Any,0) while([datetime]::UtcNow -lt $deadline){ try { $resp = $udp.Receive([ref]$remote) $txt = [Text.Encoding]::UTF8.GetString($resp) $obj = $txt | ConvertFrom-Json -ErrorAction SilentlyContinue if($obj -and $obj.id -eq $rpcId){ Write-Host ("av1<= [{0}] {1}`n{2}`n" -f $rpcId,$Method,$txt) Start-Sleep -Milliseconds $InterCallDelayMs return } # ignore late/unrelated frames and keep waiting } catch { # slice timeout; keep looping until overall deadline } } Start-Sleep -Milliseconds (100 + (Get-Random -Minimum 0 -Maximum 80)) } Write-Host ("<= [--] {0} -- timeout after {1} ms x{2}`n" -f $Method,$PerCallTimeoutMs,$MaxRetries) Start-Sleep -Milliseconds $InterCallDelayMs } # Warm-up (often helps) Send-And-Wait "Marstek.GetDevice" @{ ble_mac = "0" } Send-And-Wait "ES.GetMode" @{id=0} if ($Mode -eq "AI") { ##Write-Host ("Mode={0}" -f $Mode) Send-And-Wait "ES.SetMode" @{id=1; config = @{id=1; mode= "AI"; ai_cfg= @{enable=1}}} } if ($Mode -eq "Auto") { ##Write-Host ("Mode={0}" -f $Mode) Send-And-Wait "ES.SetMode" @{id=1; config = @{id=1; mode= "Auto"; auto_cfg= @{enable=1}}} } if ($Mode -eq "Passive") { ##Write-Host ("Mode={0}" -f $Mode) Send-And-Wait "ES.SetMode" @{id=1; config = @{id=1; mode= "Passive"; passive_cfg= @{power=100;cd_time=3}}} } if ($Mode -eq "ManualLaden") { ##Write-Host ("Mode={0}" -f $Mode) ##N.B. laden van de accu moet met een negatief getal bij power Send-And-Wait "ES.SetMode" @{id=1; config = @{id=1; mode= "Manual"; manual_cfg= @{time_num=1;start_time="04:00";end_time="05:00";week_set=127;power=-2500;enable=1}}} } if ($Mode -eq "ManualOntladen") { ##Write-Host ("Mode={0}" -f $Mode) ##N.B. ontladen van de accu moet met een positief getal bij power Send-And-Wait "ES.SetMode" @{id=1; config = @{id=1; mode= "Manual"; manual_cfg= @{time_num=1;start_time="16:00";end_time="19:00";week_set=127;power=210;enable=1}}} } # Optional: drain late packets $remote = [System.Net.IPEndPoint]::new([System.Net.IPAddress]::Any,0) while([datetime]::UtcNow -lt $until){ try { $txt = [Text.Encoding]::UTF8.GetString($udp.Receive([ref]$remote)) Write-Host ("<= [late] {0}:{1}`n{2}`n" -f $remote.Address,$remote.Port,$txt) } catch {} } $udp.Close()
NL; MT Venus E V2 (V153 BMS:V215); HW P1 (5.1903); App: V1.6.49; Comm.Mod:202409090159; 1 Fase 40A hoofdzek.; Iskra ME382-D1A52-P1 bj 2012; PV 7650 Wpiek; Inventum Ecolution ventilatiewarmtepomp; EV (Seat Mii 32kWh);
Het scriptje avzetMODEaan.ps1 bevat code waarin o.a. de huidige soc, de huidige ongrid-power, de huidige modus worden weergegeven. Daarnaast zitten in het scriptje alle voorbeelden om de mode van de batterij te switchen naar 1 van de volgende: AI, Auto, Manual-laden, Manual-ontladen en Passive
Ik heb zelf momenteel hardcoded het cmd-scriptje en het ps1-scriptje in de direcotry c:\netcat-setup staan, maar binnen in het script wordt van .\ uitgegaan, dus je kunt e.e.a. ook naar een andere directory verplaatsen.
[ Voor 26% gewijzigd door antoinevromen op 21-09-2025 17:00 ]
NL; MT Venus E V2 (V153 BMS:V215); HW P1 (5.1903); App: V1.6.49; Comm.Mod:202409090159; 1 Fase 40A hoofdzek.; Iskra ME382-D1A52-P1 bj 2012; PV 7650 Wpiek; Inventum Ecolution ventilatiewarmtepomp; EV (Seat Mii 32kWh);
Onderstaande scriptje haalt op de site jeroen.nl de dynamische tarieven van vandaag op in de vorm van een json-file (dus als je het morgen draait om zeg maar 00:01 uur, dan krijg je uiteraard de tarieven van die dag )
Omdat de inhoud van deze tarieven niet wijzigt sla ik die json-informatie op in een .txt-bestandje (dagtarief.txt), van waaruit ik het later kan inlezen en kan bevragen m.b.t. prijzen en uren waarop die prijzen gelden.
Je ziet dat er in het web-request een key= moet worden meegegeven.
Die key kun je gratis krijgen als je een account aanmaakt bij jeroen.nl . Vervolgens kun je naar de volgende pagina gaan: https://jeroen.nl/account/feeds waar je jouw persoonlijk api-key kunt vinden.
==============
=================code:
1 2 3 c: cd \netcat-setup powershell.exe -file .\avhaalTARIEVEN.ps1
het bestandje avhaalTARIEVEN.ps1
==================
code:
1 2 3 4 5 Add-Type -AssemblyName System.Net $TarievenVandaag = Invoke-WebRequest 'https://jeroen.nl/api/dynamische-energieprijzen/v2/?period=vandaag&type=json&key=op deze plek je eigen api-key van jeroen.nl' $TarievenVandaag = $TarievenVandaag -replace ':"-0,', ':"-0.' $TarievenVandaag = $TarievenVandaag -replace ':"0,', ':"0.' [System.IO.File]::WriteAllText(".\dagtarief.txt", $TarievenVandaag)
NL; MT Venus E V2 (V153 BMS:V215); HW P1 (5.1903); App: V1.6.49; Comm.Mod:202409090159; 1 Fase 40A hoofdzek.; Iskra ME382-D1A52-P1 bj 2012; PV 7650 Wpiek; Inventum Ecolution ventilatiewarmtepomp; EV (Seat Mii 32kWh);
Onderstaande scriptje haalt op de site weerlive.nl (van het KNMI) de voorspelde zonne-wattages weer per uur van de dag op een locatie en slaat dit op in de vorm van een json-file (dus als je het morgen draait om zeg maar 00:01 uur, dan krijg je uiteraard de zonnewaarden van die dag )
Omdat de inhoud van zonnewaarden elk uur wijzigt (en betrouwbaarder wordt) sla ik die json-informatie elk uur op in een .txt-bestandje (zonvandaag.txt), van waaruit ik het later kan inlezen en kan bevragen m.b.t. wattages per uur per m2 op die locatie.
Je ziet dat er in het web-request een key= moet worden meegegeven.
Die api-key kun je gratis krijgen via https://weerlive.nl/delen.php en in het script invullen op de plaats achter key=
=====
Het bestandje avhaalZONNEKRACHT.cmd
=====
=====code:
1 2 3 c: cd \netcat-setup powershell.exe -file .\avhaalZONNEKRACHT.ps1
Het bestandje avhaalZONNEKRACHT.ps1
=====
====code:
1 2 3 Add-Type -AssemblyName System.Net # ,System.Net.Sockets $ZonVandaag = Invoke-WebRequest 'https://weerlive.nl/api/weerlive_api_v2.php?key=jouw-persoolijnk-key&locatie=Voerendaal' [System.IO.File]::WriteAllText(".\zonvandaag.txt", $ZonVandaag)
NL; MT Venus E V2 (V153 BMS:V215); HW P1 (5.1903); App: V1.6.49; Comm.Mod:202409090159; 1 Fase 40A hoofdzek.; Iskra ME382-D1A52-P1 bj 2012; PV 7650 Wpiek; Inventum Ecolution ventilatiewarmtepomp; EV (Seat Mii 32kWh);
Onderstaand het script om periodiek (bijv. elk kwartier) te draaien dat op basis van zonnewattage/m2 , dynamische tarieven voor een dag, de huidige informatie uit je batterij en enkele andere logica bepaalt of
de batterij middels Net-stroom geladen moet worden om zodoende geld te verdienen (bijv. door te handelen, of door ervoor te zorgen dat je de dure uren via de batterij kunt doorkomen met goedkoop geladen net-stroom etc.
=====
Het scriptje avzetMODEdynamisch.cmd
=====
======code:
1 2 3 c: cd \netcat-setup powershell.exe -file .\avzetMODEdynamisch.ps1
Het scriptje avzetMODEdynamisch.ps1
=====
=====code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 # example usage: # .\MT-LocalApi-Example -DeviceIP 192.168.20.82 -RemotePort 30000 -LocalPort 30000 -PerCallTimeoutMs 2000 -MaxRetries 3 param( ##constanten [string]$DeviceIP = "192.168.178.234", [string]$tijdstempel_str = (Get-Date).ToString("yyyy-MM-dd HH:mm:ss"), [string]$bijladen_gedurende_huidig_contract = "N", [int]$RemotePort = 30000, [int]$LocalPort = $RemotePort, [int]$PerCallTimeoutMs = 5000, [int]$MaxRetries = 3, [int]$InterCallDelayMs = 1000, [int]$BijlaadRekenhoeveelheidPerUur_VM_int = 250, [int]$BijlaadRekenhoeveelheidPerUur_NM_int = 500, [int]$capaciteit_batterij_int = 5120, [int]$max_laadcapaciteit_int_int = 2500, [double]$ACDCAComzettnigverlies_double = 0.75, [double]$opslag_energieleverancier_double = 0.0233, [double]$opslag_energiebelasting_double = 0.10154, [double]$btw_perc_double = 0.21, [double]$opslagbedragNetLaden_double = 0.03, [double]$opp_pv_hoogdak_double = (9 + 6) * 1.5 * 1.05 , [double]$opp_pv_laagdak_double = ( 9) * 1.5 * 1.05 , [double]$opp_pv_tuinhuis_double = 4 * 1.7 * 1.05 , ## op 19-sep-2025 in totaal opwek alle panelen 32kWh 45 m2 opp.bij voorspelde 4270 W/m2 = factor 0,166 ## op 20-sep-2025 in totaal opwek alle panelen 14,3kWh 45 m2 opp bij voorspelde 3170 W/m2 = factor 0,10 ## op 21-sep-2025 in totaal opwek alle panelen 10,9kWh 45 m2 opp bij voorspelde 1264 W/m2 = factor 0,19 [double]$ervaringscijfer_kWh_per_zonwaarde = 0.14, ## 32000/(($opp_pv_hoogdak_double + $opp_pv_laagdak_double + $opp_pv_tuinhuis_double)*4270) ##========================================================================= [string]$modenieuw_str = "x", [string]$modenu_str = "x", [string]$modegezet_str = "N", [string]$mode_Go_Passive_str = "N", [int]$bat_soc_int = 999, [int]$ongrid_power_int = 999, [int]$huidigemaand_int = 999, [int]$huidiguur_int = 999, [int]$maxzoekuur_int = -10, [int]$minzoekuur_int = 9999, [int]$minuur_int = 888, [int]$minnegatiefuur_int = 88, [int]$maxuur_int = -10, [int]$zoekuur_int = 9999, [int]$socwaarde_stopladen_int = 9999, [int]$zon_som_waarde_van_nu_tm_einde_dag_int = 9999, [int]$zon_som_waarde_van_nu_tot_nabijste_maxuur_int = 9999, [int]$uren_langer_maxuur_int = 0, [int]$te_verwachten_PV_opbrengst_vanNu_totMaxuur_int = 9999, [int]$benodigde_Energie_vanNu_tot_en_met_Maxuur_int = 9999, [int]$BijlaadHoeveelheidPerUur_int = 9999, [int]$Benodigde_Soc_voor_3_uur_int = 9999, [double]$mintarief_double = 999, [double]$minnegatieftarief_double = 999, [double]$maxtarief_double = -10, [double]$tariefuur_double = 99, [double]$TariefBruto_double = 999, [double]$brutotariefmaxuur_double = 999, [double]$brutotariefhuidiguur_omgerekend_verlies_double = 999, [double]$brutotariefmaxuur_plus_1_double = 999, [double]$brutotariefmaxuur_plus_2_double = 999, [double]$gemiddeld_brutotarief_additionele_bijlaaduren_double = 999, [double]$nettohuidigtarief_double = 999 ) Add-Type -AssemblyName System.Net # ,System.Net.Sockets # Create socket, enable reuse, bind to LocalPort (so source port is fixed) $udp = New-Object System.Net.Sockets.UdpClient $udp.Client.SetSocketOption([System.Net.Sockets.SocketOptionLevel]::Socket, [System.Net.Sockets.SocketOptionName]::ReuseAddress, $true) $udp.Client.ExclusiveAddressUse = $false $udp.Client.Bind([System.Net.IPEndPoint]::new([System.Net.IPAddress]::Any, $LocalPort)) $udp.Client.ReceiveTimeout = 1000 ##=============================================================================================== function Bepaal_ZonWattage_van_tm_Uur ([int]$zon_vanaf_uur_int, [int]$zon_tm_uur_int) { $ZonVandaag = [IO.File]::ReadAllText(".\zonvandaag.txt") $ZonVandaag_obj = $ZonVandaag | ConvertFrom-Json [int]$som_zon_waarden_int = 0 foreach ($Zon_obj in $ZonVandaag_obj) { foreach ($Zon_uur_verw_obj in $Zon_obj[0].uur_verw) { $dag = [datetime](Get-Date $Zon_uur_verw_obj[0].uur -f "yyyy-MM-dd HH:mm:ss") $uur_int = [int]$dag.hour if ($uur_int -ge $zon_vanaf_uur_int -and $uur_int -le $zon_tm_uur_int) { $som_zon_waarden_int = $som_zon_waarden_int + $Zon_uur_verw_obj[0].gr } } } Return [double]$som_zon_waarden_int } ##=============================================================================================== function Bepaal_Tarief_Op_Uur ([int]$vraaguur) { $TarievenVandaag = [IO.File]::ReadAllText(".\dagtarief.txt") $TarievenVandaag_obj = $TarievenVandaag | ConvertFrom-Json foreach ($Tarief_obj in $TarievenVandaag_obj) { $dag = [datetime](Get-Date $Tarief_obj[0].datum_nl -f "yyyy-MM-dd HH:mm:ss") if (($vraaguur -eq $dag.Hour)) { Return [double]$Tarief_obj[0].prijs_excl_belastingen } } Return [double]99999 } ##=============================================================================================== function Bepaal_Gem_BrutoTarief_Van_Tm_Uur ([int]$vraaguur_van, [int]$vraaguur_tm) { $TarievenVandaag = [IO.File]::ReadAllText(".\dagtarief.txt") $TarievenVandaag_obj = $TarievenVandaag | ConvertFrom-Json [double]$som_bedrag_double = 0 [int]$aantal_bedrag_int = 0 $TariefBruto_double = 0 foreach ($Tarief_obj in $TarievenVandaag_obj) { $dag = [datetime](Get-Date $Tarief_obj[0].datum_nl -f "yyyy-MM-dd HH:mm:ss") if (($dag.Hour -ge $vraaguur_van) -and ($dag.Hour -le $vraaguur_tm)) { $TariefBruto_double = [double]($Tarief_obj[0].prijs_excl_belastingen) $TariefBruto_double = [double]($TariefBruto_double + $opslag_energieleverancier_double + $opslag_energiebelasting_double) $TariefBruto_double = [double]($TariefBruto_double * [double](1 + $btw_perc_double)) $som_bedrag_double = [double]($som_bedrag_double + $TariefBruto_double) $aantal_bedrag_int = $aantal_bedrag_int + 1 } } $TariefBruto_double = $som_bedrag_double / $aantal_bedrag_int Return $TariefBruto_double } ##=============================================================================================== function Send-And-Wait([string]$Method, [hashtable]$Params) { [string]$modenu = "dummywaarde-modenu" [string]$bat_soc_str = "dummywaarde-soc" [string]$ongrid_power_str = "dummywaarde-power" for($try=1; $try -le $MaxRetries; $try++){ $rpcId = Get-Random -Minimum 1000 -Maximum 65000 # JSON-RPC id (unique per try) $req = @{ id=$rpcId; method=$Method; params=$Params } | ConvertTo-Json -Compress -Depth 6 $bytes = [Text.Encoding]::UTF8.GetBytes($req) [void]$udp.Send($bytes, $bytes.Length, $DeviceIP, $RemotePort) $deadline = [datetime]::UtcNow.AddMilliseconds($PerCallTimeoutMs * [math]::Pow(1.35, $try-1)) $remote = [System.Net.IPEndPoint]::new([System.Net.IPAddress]::Any,0) while([datetime]::UtcNow -lt $deadline){ try { $resp = $udp.Receive([ref]$remote) $txt = [Text.Encoding]::UTF8.GetString($resp) $obj = $txt | ConvertFrom-Json -ErrorAction SilentlyContinue if($obj -and $obj.id -eq $rpcId){ if ($Method -eq "ES.GetMode") { $modenu = $obj.result.mode $bat_soc_str = $obj.result.bat_soc $ongrid_power_str = $obj.result.ongrid_power } Start-Sleep -Milliseconds $InterCallDelayMs return $Method, $modenu, $bat_soc_str, $ongrid_power_str } # ignore late/unrelated frames and keep waiting } catch { # slice timeout; keep looping until overall deadline } } Start-Sleep -Milliseconds (100 + (Get-Random -Minimum 0 -Maximum 80)) } Write-Host ("<= [--] {0} -- timeout after {1} ms x{2}`n" -f $Method,$PerCallTimeoutMs,$MaxRetries) Write-Output ("<= [--] $Method --timeout after $PerCallTimeoutMs ms x $MaxRetries retries") >> .\avzetMODEdynamischOutput.txt Start-Sleep -Milliseconds $InterCallDelayMs } ##=============================================================================================== ##HOOFDPROGRAMMA ## Globale logica flow: ## -1- warm batterij api op door een dummy call (getdevice) te doen ## -2- bepaal huidige mode, huidige soc en huidige power ## -3- afhankelijk van of het huidige uur voormiddag of namiddag is bepaal in die 12 uur het moment van het vroegste uur met het hoogste tarief in die 12 uur ## beginnend vanaf het nu t/m 11 resp. nu t/m 23 ## -4- afhankelijk van of het huidige uur voormiddag of namiddag is bepaal in die 12 uur het moment van het laatste uur met het laagste tarief in die 12 uur ## beginnend vanaf nu t/m 11 resp. nu t/m 23 tot maximaal het uur waarin het maximum tarief wordt bereikt in dat 12 uurs-bestek ## -5- bepaal het laagste tariefuur van de gehele dag (t.b.v. eventueel latere sturing op negatieve tarieven ## -6- bepaal of het financieel aantrekkelijk is om de batterij-Soc hoger te laden zodat hij 1 of 2 uur langer dan het max-uur nog stroom heeft. ## -7- bepalen te verwachten PV-opbrengst op basis zonne-wattage de komende uren en het benodigde wattage om ## vanaf nu tot en met het max-uur te geraken(eventueel verlengt met 1 of 2 extra uren als dat financieel aantrekkelijk is) ## -6- bepaal tot welke soc waarde minimaal geladen moet worden wanneer er besloten is in dit programma dat de batterij geladen wordt ## namiddags wordt dit 98%, zodat je zo ver mogelijk de nacht in kunt komen; ## voormiddags wordt dit % berekend zodanig dat de batterij op basis van $BijlaadRekenhoeveelheidPerUur Watt leveren tot 2 uur na het voormiddag-maximumtarief nog kan ontladen ## -7- afhankelijk van voormiddag of namiddag inschatten wat de soc-waarde zou moeten zijn om over het dichts-bijzijnde maximum-tarief heen te geraken vanaf uur nu rekening ## rekening houdend met het geschatte uurverbruik tot max-uur (of maxuur + 1 of 2 uur) ## -8- wanneer er op basis van de huidige soc en te verwachten PV-opbrengst geen energietekort te verwachten is tot max-uur dan socwaarde-laden-int laag zetten zodat er niet wordt geladen ## -9- wanneer er energietekort is om over het max-uur heen te geraken nog bepalen of het huidig tarief (rekening houdend met RTE-verlies) financieel aantrekkelijk is om bij te laden ## waarbij het omgerekende huidige tarief wordt vergeleken met het gemiddelde-bruto-tarief van max-uur en de uren vooraf aan maxuur die qua soc aangevuld moeten worden. ##-10- bepaal of er geladen moet worden; ## a) Als op het huidige uur de gewenste soc lager is dan de huidige soc, dan maximaal bijladen gedurende dit kwartier totdat ## de stop-laad-waarde waarop hij weer naar Auto gaat wordt bereikt (tarief moet wel lonen t.o.v. omzetverlies plus een opslagbedrag) ## b) Als soc >= $socwaarde_stopladen_int en modus is niet Auto dan op Auto zetten; anders blijven doorladen en de modus niet veranderen. ## c) 1x per week op zondagnamiddag gedurende de wintermaanden (okt t/m feb) op goedkoopste uur tot 100% laden (als hij niet al 100% is) ## d) in de zomer als veel zon verwacht (misschien zelfs negatieve prijzen) dan tot dat (lage/negatieve) moment ontladen en op dat lage/negatieve uur vol laden ## e) in de zomer als veel zon is geladen met zonnestroom (misschien zelfs negatieve prijzen) dan bij erg hoge prijzen juist verkopen op die max-uren ## (kan alleen bij saldering omdat je na einde salderingsregeling de belastingen niet meer terug krijgt en dan die wel zou moeten betalen later op de dag als je weer stroom nodig hebt) ## f) in de ochtend wanneer het maxuur van die 12 uur nog moet komen kijken of je voldoende soc hebt om 1 uur over dat maxuur te geraken. Als het min-uur nog moet komen en dat ook financieel niet ## rendabel is kun je de batterij een tijd in passive zetten, zodat je in de ochtend toch nog genoeg over hebt voor het maxuur en het daarop volgende uur. ## # Warm-up (often helps) $resultaat = Send-And-Wait "Marstek.GetDevice" @{ ble_mac = "0" } # Ophalen mode, soc en huidige power $resultaat = Send-And-Wait "ES.GetMode" @{id=0} if ($resultaat[0] -eq "ES.GetMode") { $modenu_str = $resultaat[1] $bat_soc_int = [int]$resultaat[2] $ongrid_power_int = [int]$resultaat[3] } $huidigemaand_int = (Get-Date).Month $huidiguur_int = (Get-Date).Hour if ($huidiguur_int -gt 11) { $maxzoekuur_int = 23 $minzoekuur_int = 12 $BijlaadHoeveelheidPerUur_int = $BijlaadRekenhoeveelheidPerUur_NM_int }else{ $maxzoekuur_int = 11 $minzoekuur_int = 0 $BijlaadHoeveelheidPerUur_int = $BijlaadRekenhoeveelheidPerUur_VM_int } $TarievenVandaag = [IO.File]::ReadAllText(".\dagtarief.txt") $TarievenVandaag_obj = $TarievenVandaag | ConvertFrom-Json ## -ErrorAction SilentlyContinue ## bepaal het vroegste max-tarief en bijbehorende max-uur (tussen 0-11 uur resp. 12-23 uur) foreach ($Tarief_obj in $TarievenVandaag_obj) { $dag = [datetime](Get-Date $Tarief_obj[0].datum_nl -f "yyyy-MM-dd HH:mm:ss") if (($dag.Hour -le $maxzoekuur_int) -and ($dag.Hour -ge $minzoekuur_int)) { if ([double]$Tarief_obj[0].prijs_excl_belastingen -gt $maxtarief_double) { $maxtarief_double = [double]$Tarief_obj[0].prijs_excl_belastingen $maxuur_int = $dag.Hour } } } ## bepaal het laatste min-tarief en bijbehorende min-uur (tussen Nu-11 uur resp. Nu-23 uur en max-uur binnen dit nu-to-12 uurs-bestek) $maxzoekuur_int = $maxuur_int foreach ($Tarief_obj in $TarievenVandaag_obj) { $dag = [datetime](Get-Date $Tarief_obj[0].datum_nl -f "yyyy-MM-dd HH:mm:ss") if (($dag.Hour -le $maxzoekuur_int) -and ($dag.Hour -ge $huidiguur_int)) { if ([double]$Tarief_obj[0].prijs_excl_belastingen -le $mintarief_double) { $mintarief_double = [double]$Tarief_obj[0].prijs_excl_belastingen $minuur_int = $dag.Hour } } } ##Als het uur dat ligt vooraf aan het laatste minimum-tarief, dan kan het minimum-uur op dat voorliggende uur worden gezet, waardoor en meer tijd is om de batterij vol te krijgen ##mocht dat nodig zijn (omdat de soc onder de 50 ligt). if ($minuur_int -ne 0 -and $minuur_int -ne 12 ) { $tariefuur_double = Bepaal_Tarief_Op_Uur ($minuur_int - 1) if (($tariefuur_double -eq $mintarief_double) -and ($bat_soc_int -lt 50)) { $minuur_int = $minuur_int - 1 } } #zoek het laatste meest negatieve uur vanaf uur 0 tot einde dag $maxzoekuur_int = 23 $minzoekuur_int = 0 foreach ($Tarief_obj in $TarievenVandaag_obj) { $dag = [datetime](Get-Date $Tarief_obj[0].datum_nl -f "yyyy-MM-dd HH:mm:ss") if (($dag.Hour -le $maxzoekuur_int) -and ($dag.Hour -ge $minzoekuur_int)) { if ([double]$Tarief_obj[0].prijs_excl_belastingen -le $minnegatieftarief_double -and [double]$Tarief_obj[0].prijs_excl_belastingen -lt 0) { $minnegatieftarief_double = [double]$Tarief_obj[0].prijs_excl_belastingen $minnegatiefuur_int = $dag.Hour } } } ##bepaal of het financieel aantrekkelijk is om de batterij-Soc hoger te laden zodat hij 1 of 2 uur langer dan het max-uur nog stroom heeft. $brutotariefmaxuur_double = Bepaal_Gem_BrutoTarief_Van_Tm_Uur $maxuur_int $maxuur_int $brutotariefhuidiguur_omgerekend_verlies_double = Bepaal_Gem_BrutoTarief_Van_Tm_Uur $huidiguur_int $huidiguur_int $brutotariefhuidiguur_omgerekend_verlies_double = ($brutotariefhuidiguur_omgerekend_verlies_double / $ACDCAComzettnigverlies_double) + $opslagbedragNetLaden_double $nettohuidigtarief_double = Bepaal_Tarief_Op_Uur($huidiguur_int) if ($maxuur_int -ne 11 -and $maxuur_int -ne 23) { $brutotariefmaxuur_plus_1_double = Bepaal_Gem_BrutoTarief_Van_Tm_Uur($maxuur_int + 1)($maxuur_int + 1) if ($maxuur_int -ne 10 -and $maxuur_int -ne 22) { $brutotariefmaxuur_plus_2_double = Bepaal_Gem_BrutoTarief_Van_Tm_Uur($maxuur_int + 2) ($maxuur_int + 2) } } if ($brutotariefmaxuur_plus_1_double -gt $brutotariefhuidiguur_omgerekend_verlies_double) { $uren_langer_maxuur_int = 1 if ($brutotariefmaxuur_plus_2_double -gt $brutotariefhuidiguur_omgerekend_verlies_double) { $uren_langer_maxuur_int = 2 } } ##bepalen te verwachten PV-opbrengst op basis zonne-wattage de komende uren en het benodigde wattage om ##vanaf nu tot en met het max-uur te geraken(eventueel verlengt met 1 of 2 extra uren als dat financieel aantrekkelijk is) $zon_som_waarde_van_nu_tm_einde_dag_int = Bepaal_ZonWattage_van_tm_Uur $huidiguur_int 23 $zon_som_waarde_van_nu_tot_nabijste_maxuur_int = Bepaal_ZonWattage_van_tm_Uur $huidiguur_int ($maxuur_int - 1) $te_verwachten_PV_opbrengst_vanNu_totMaxuur_int = [int]($ervaringscijfer_kWh_per_zonwaarde * $zon_som_waarde_van_nu_tot_nabijste_maxuur_int) * ($opp_pv_hoogdak_double + $opp_pv_laagdak_double + $opp_pv_tuinhuis_double) $benodigde_Energie_vanNu_tot_en_met_Maxuur_int = [int]($maxuur_int - $huidiguur_int + $uren_langer_maxuur_int) * $BijlaadHoeveelheidPerUur_int $energietekort_int = [int]($benodigde_Energie_vanNu_tot_en_met_Maxuur_int - $te_verwachten_PV_opbrengst_vanNu_totMaxuur_int - (($bat_soc_int - 11) / 100 * $capaciteit_batterij_int)) ##afhankelijk van voormiddag of namiddag inschatten wat de soc-waarde zou moeten zijn om over het dichts-bijzijnde maximum-tarief heen te geraken vanaf uur nu ##rekening houdend met het geschatte uurverbruik tot max-uur (of maxuur + 1 of 2 uur) $socwaarde_stopladen_int = (11 + ((($maxuur_int + $uren_langer_maxuur_int - $huidiguur_int) * $BijlaadHoeveelheidPerUur_int) / $capaciteit_batterij_int ) * 100) $Benodigde_Soc_voor_3_uur_int = (15 + ((3 * $BijlaadHoeveelheidPerUur_int) / $capaciteit_batterij_int ) * 100) if ($socwaarde_stopladen_int -gt 100) { $socwaarde_stopladen_int = 100 } ##wanneer er op basis van de huidige soc en te verwachten PV-opbrengst geen energietekort te verwachten is tot max-uur dan socwaarde-laden-int laag zetten zodat er niet wordt geladen if ($energietekort_int -lt 0) { ##als het energietekort negatief is (er is nog voldoende pv-opbrengst te verwachten incl. huidige staat bat) dan niet bijladen $socwaarde_stopladen_int = 10 }else{ if ($huidiguur_int -lt $maxuur_int) { ##er is energietekort om over het max-uur heen te geraken; nu nog bepalen of het huidig tarief (rekening houdend met RTE-verlies) financieel aantrekkelijk is om bij te laden $bijlaadSoc_int = $socwaarde_stopladen_int - $bat_soc_int $bijlaadduur_int = [int][math]::ceiling(($bijlaadSoc_int / 100 * $capaciteit_batterij_int) / $max_laadcapaciteit_int_int) $gemiddeld_brutotarief_additionele_bijlaaduren_double = Bepaal_Gem_BrutoTarief_Van_Tm_Uur ($maxuur_int - $bijlaadduur_int) ($maxuur_int) if ($gemiddeld_brutotarief_additionele_bijlaaduren_double -le $brutotariefhuidiguur_omgerekend_verlies_double) { ## financieel niet aantrekkelijk om bij te laden dus socwaarde_stopladen_int laag zetten $socwaarde_stopladen_int = 9 ## het maxuur moet nog komen en er is een energietekort om alle tussenliggende uren tot maxuur te overbruggen en het is financieel niet interessant om bij te laden; ## Is het dan misschien mode passive nog een optie wanneer er voldoende soc is op basis van huidig geschat uurverbruik om het duurste uur en de 2 eromheen liggende uren ## nog met batterijstroom te voorzien? if ($bat_soc_int -le $Benodigde_Soc_voor_3_uur_int) { $mode_Go_Passive_str = "J" } } }else{ ## in de namiddag is het maxuur reeds verstreken; dan kijken of er voldoende soc is om middels mode passive op basis van huidig geschat uurverbruik om ## het duurste uur en de 2 eromheen liggende uren nog met batterijstroom te voorzien? if ($huidiguur_int -ge 12 -and $bat_soc_int -le $Benodigde_Soc_voor_3_uur_int) { $mode_Go_Passive_str = "J" } } } Write-Host ("av9a: minuur {0}h/ mintar Eur.{1}/ maxuur {2}h/ maxtar Eur.{3}/ minnegatiefuur {4}h/ minnegatieftar Eur.{5}/ maand {6} mnd/ uur {7}h/ huidigtarief Eur.{8}/ maxbrutotar Eur.{9}" -f $minuur_int,$mintarief_double,$maxuur_int,$maxtarief_double, $minnegatiefuur_int, $minnegatieftarief_double, $huidigemaand_int, $huidiguur_int, $nettohuidigtarief_double, $brutotariefmaxuur_double) Write-Host ("av9b: mode {0}/ soc {1}%/ soc-stop {2}%/ power {3}W/ kWh-need-tot-maxuur {4}W/ PV-tot-maxuur {5}W/ zonwaarde {6}W/m2/ zonwaarde-tot-max {7}W/m2/ Energietekort {8}W/ huidigtar-omgerekend Eur.{9}" -f $modenu_str,$bat_soc_int,$socwaarde_stopladen_int,$ongrid_power_int,$benodigde_Energie_vanNu_tot_en_met_Maxuur_int , $te_verwachten_PV_opbrengst_vanNu_totMaxuur_int, $zon_som_waarde_van_nu_tm_einde_dag_int, $zon_som_waarde_van_nu_tot_nabijste_maxuur_int, $energietekort_int, $brutotariefhuidiguur_omgerekend_verlies_double) Write-Host ("av9c: uren-langer-max {0}h/ gem-brutotarief-addit-bijlaad Eur.{1}" -f $uren_langer_maxuur_int, $gemiddeld_brutotarief_additionele_bijlaaduren_double) Write-Output ("--> Mode/Soc/Soc-Stop/Pow/Mnd/uur/kWh-need-tot-maxuur/PV-tot-maxuur/huidigtarief`t$modenu_str`t/$bat_soc_int %`t/$socwaarde_stopladen_int %`t/$ongrid_power_int W`t/$huidigemaand_int mnd`t/$huidiguur_int h`t/$benodigde_Energie_vanNu_tot_en_met_Maxuur_int W`t/$te_verwachten_PV_opbrengst_vanNu_totMaxuur_int W`t/Eur. $nettohuidigtarief_double") >> .\avzetMODEdynamischOutput.txt Write-Output ("--> Min/Max/Zon/Zon-tot-maxuur/Energietekort/Minnegatief`t`t`t`t`t`t`t$minuur_int h `t/Eur. $mintarief_double`t/$maxuur_int h`t/Eur. $maxtarief_double`t/$zon_som_waarde_van_nu_tm_einde_dag_int W/m2`t/$zon_som_waarde_van_nu_tot_nabijste_maxuur_int W/m2`t/$energietekort_int W`t/$minnegatiefuur_int h`t/Eur. $minnegatieftarief_double ") >> .\avzetMODEdynamischOutput.txt Write-Output ("--> Uren-langer-Max/gem-brutotarief-addit-bijlaad/huidigtar-omgerekend/maxbrutotar`t$uren_langer_maxuur_int h`t`t/Eur. $gemiddeld_brutotarief_additionele_bijlaaduren_double`t/Eur. $brutotariefhuidiguur_omgerekend_verlies_double`t/Eur. $brutotariefmaxuur_double") >> .\avzetMODEdynamischOutput.txt ## ## Bepalen of er van mode gewisseld moet worden. No-brainer use-cases het eerst geimplementeerd: ## vanaf hier zijn bekend: $modenu_str, $bat_soc_int, $socwaarde_stopladen_int, $ongrid_power_int, $huidigemaand_int, $huidiguur_int, ## $minnegatieftarief_double, $minnegatiefuur_int, $maxtarief_double, $maxuur_int, $minuur_int, $mintarief_double ## $te_verwachten_PV_opbrengst_vanNu_totMaxuur_int, $zon_som_waarde_van_nu_tm_einde_dag_int, $zon_som_waarde_van_nu_tot_nabijste_maxuur_int, ## No-brainer-a: Als het uur van maximaal tarief nog moet komen binnen 12 uur en er is nu een tarief dat bijladen aantrekkelijk maakt en bijladen is nodig om over max-tarief te geraken dan maximaal bijladen dit kwartier tot ## de stop-laad-waarde waarop hij weer naar Auto gaat; Verschil tussen de bruto prijzen op die uren moet de AC/DC/AC-omzetting compenseren plus omzetverliesopslag cent if ($bat_soc_int -lt $socwaarde_stopladen_int) { $modenieuw_str = "Manual laden $max_laadcapaciteit_int" $modegezet_str = "J" Write-Host ("Tijd: {0} Mode van: {1} --> {2}" -f $tijdstempel_str, $modenu_str, $modenieuw_str) Write-Output ("Tijd: $tijdstempel_str Mode van $modenu_str --> $modenieuw_str") >> .\avzetMODEdynamischOutput.txt ##-Append if ($bijladen_gedurende_huidig_contract -eq "J") { $resultaat = Send-And-Wait "ES.SetMode" @{id=1; config = @{id=1; mode= "Manual"; manual_cfg= @{time_num=1;start_time="00:00";end_time="23:59";week_set=127;power=-2500;enable=1}}} } } ## No-brainer-c: 1x per week op zondagnamiddag gedurende de wintermaanden (okt t/m feb) op goedkoopste uur tot 100% laden (als hij niet al 100% is) ## Prijs is hierbij niet meer van toepassing if (((get-date).DayOfWeek -eq "Sunday") -and ($huidigemaand_int -ge 10 -or $huidigemaand_int -le 2) -and ($modenu_str -ne "Manual") -and ($minuur_int -eq $huidiguur_int) -and ($bat_soc_int -lt 100) -and ($huidiguur_int -ge 12)) { $socwaarde_stopladen_int = 100 $modenieuw_str = "Manual laden $max_laadcapaciteit_int (1xper week 100%)" $modegezet_str = "J" Write-Host ("Tijd: {0} Mode van: {1} --> {2}" -f $tijdstempel_str, $modenu_str, $modenieuw_str) Write-Output ("Tijd: $tijdstempel_str Mode van $modenu_str --> $modenieuw_str") >> .\avzetMODEdynamischOutput.txt ##-Append if ($bijladen_gedurende_huidig_contract -eq "J") { $resultaat = Send-And-Wait "ES.SetMode" @{id=1; config = @{id=1; mode= "Manual"; manual_cfg= @{time_num=1;start_time="00:00";end_time="23:59";week_set=127;power=-2500;enable=1}}} } } ## No-Brainer-d: in de zomer als veel zon wordt verwacht (misschien zelfs negatieve prijzen) dan tot dat (lage/negatieve) moment ontladen en op dat lage/negatieve uur vol laden ## nog te implementeren TODO ## No-Brainer-e: in de zomer als veel zon is geladen met zonnestroom (misschien zelfs negatieve prijzen) dan bij erg hoge prijzen juist verkopen op die max-uren. ## nog te implementeren TODO ## No-Brainer-f: indien mode_Go_Passive_str = J dan naar mode passive switchen. if ($mode_Go_Passive_str -eq "J") { $modenieuw_str = "Passive" $modegezet_str = "J" Write-Host ("Tijd: {0} Mode van: {1} --> {2}" -f $tijdstempel_str, $modenu_str, $modenieuw_str) Write-Output ("Tijd: $tijdstempel_str Mode van $modenu_str --> $modenieuw_str") >> .\avzetMODEdynamischOutput.txt if ($bijladen_gedurende_huidig_contract -eq "J") { $resultaat = Send-And-Wait "ES.SetMode" @{id=1; config = @{id=1; mode= "Passive"; passive_cfg= @{power=100;cd_time=3}}} } } ## No-brainer-b: Als soc >= $socwaarde_stopladen_int en modus is niet Auto dan op Auto zetten if (($modenu_str -ne "Auto") -and ($bat_soc_int -ge $socwaarde_stopladen_int)) { $modenieuw_str = "Auto" $modegezet_str = "J" Write-Host ("Tijd: {0} Mode van: {1} --> {2}" -f $tijdstempel_str, $modenu_str, $modenieuw_str) Write-Output ("Tijd: $tijdstempel_str Mode van $modenu_str --> $modenieuw_str") >> .\avzetMODEdynamischOutput.txt ##-Append $resultaat = Send-And-Wait "ES.SetMode" @{id=1; config = @{id=1; mode= "Auto"; auto_cfg= @{enable=1}}} } if ($modegezet_str -eq "N") { $modenieuw_str = $modenu_str Write-Host ("Tijd: {0} Mode niet gezet; blijft {1}" -f $tijdstempel_str, $modenu_str) Write-Output ("Tijd: $tijdstempel_str Mode niet gezet; blijft $modenu_str") >> .\avzetMODEdynamischOutput.txt ##-Append } ##=============================================================================================== # Optional: drain late packets $remote = [System.Net.IPEndPoint]::new([System.Net.IPAddress]::Any,0) $until = [datetime]::UtcNow.AddMilliseconds(5000) while([datetime]::UtcNow -lt $until){ try { $txt = [Text.Encoding]::UTF8.GetString($udp.Receive([ref]$remote)) Write-Host ("<= [late] {0}:{1}`n{2}`n" -f $remote.Address,$remote.Port,$txt) Write-Output ("<= [late] $remote.Address : $remote.Port /$txt") >> .\avzetMODEdynamischOutput.txt } catch {} } $udp.Close()
[ Voor 10% gewijzigd door antoinevromen op 22-09-2025 12:27 ]
NL; MT Venus E V2 (V153 BMS:V215); HW P1 (5.1903); App: V1.6.49; Comm.Mod:202409090159; 1 Fase 40A hoofdzek.; Iskra ME382-D1A52-P1 bj 2012; PV 7650 Wpiek; Inventum Ecolution ventilatiewarmtepomp; EV (Seat Mii 32kWh);
Geweldig @AUijtdehaag ; Ik wist eerst niet waar je het over had, maar na even zoeken snapte ik dat dit ook kon;AUijtdehaag schreef op zondag 21 september 2025 @ 18:08:
@antoinevromen
Misschien een tip:
Zet het tussen code tags en quote tags, om het leesbaar en duimvriendelijker te maken.
NL; MT Venus E V2 (V153 BMS:V215); HW P1 (5.1903); App: V1.6.49; Comm.Mod:202409090159; 1 Fase 40A hoofdzek.; Iskra ME382-D1A52-P1 bj 2012; PV 7650 Wpiek; Inventum Ecolution ventilatiewarmtepomp; EV (Seat Mii 32kWh);
Stukken beter!antoinevromen schreef op zondag 21 september 2025 @ 18:50:
[...]
Geweldig @AUijtdehaag ; Ik wist eerst niet waar je het over had, maar na even zoeken snapte ik dat dit ook kon;
Dank!
.NL | BYD Atto3 | PulsarPlus EV +Balancer | WP7.7K Z | 2 MT Venus 5.12KWh V153/155 - CT003 V117 | 2 Mitsubitshi single airco's | EPC 0.0 | HA DS224+
@AUijtdehaag Wat je bedoelt met quote-tags is me nog steeds niet duidelijk; Ik heb ermee geexperimenteerd, maar dan wordt het tekstgebied alleen maar kleiner. Wat bedoelde je daarmee (meer ter lering)?
NL; MT Venus E V2 (V153 BMS:V215); HW P1 (5.1903); App: V1.6.49; Comm.Mod:202409090159; 1 Fase 40A hoofdzek.; Iskra ME382-D1A52-P1 bj 2012; PV 7650 Wpiek; Inventum Ecolution ventilatiewarmtepomp; EV (Seat Mii 32kWh);
Prima zo, als we vragen hebben kunnen we naar regelnummer verwijzen en knip en plak is ook handiger.antoinevromen schreef op zondag 21 september 2025 @ 18:55:
[...]
@AUijtdehaag Wat je bedoelt met quote-tags is me nog steeds niet duidelijk; Ik heb ermee geexperimenteerd, maar dan wordt het tekstgebied alleen maar kleiner. Wat bedoelde je daarmee (meer ter lering)?
.NL | BYD Atto3 | PulsarPlus EV +Balancer | WP7.7K Z | 2 MT Venus 5.12KWh V153/155 - CT003 V117 | 2 Mitsubitshi single airco's | EPC 0.0 | HA DS224+
Als je buiten de code tags nog quote tags plaatst dan worden de velden inderdaad ingeklapt (en kunnen uitgeklapt worden) en zo verklein je de post.
Scheelt weer scrollen op een mobiel
[ Voor 7% gewijzigd door AUijtdehaag op 21-09-2025 18:59 ]
Oke. Helder; ga ik nog aanpassenAUijtdehaag schreef op zondag 21 september 2025 @ 18:58:
@antoinevromen
Als je buiten de code tags nog quote tags plaatst dan worden de velden inderdaad ingeklapt (en kunnen uitgeklapt worden) en zo verklein je de post.
Scheelt weer scrollen op een mobiel
NL; MT Venus E V2 (V153 BMS:V215); HW P1 (5.1903); App: V1.6.49; Comm.Mod:202409090159; 1 Fase 40A hoofdzek.; Iskra ME382-D1A52-P1 bj 2012; PV 7650 Wpiek; Inventum Ecolution ventilatiewarmtepomp; EV (Seat Mii 32kWh);
Dank je voor de tip. Heeft een code-dinosaurus weer wat bijgeleerd dat mensen op telefoons zoiets bekijkenAUijtdehaag schreef op zondag 21 september 2025 @ 18:58:
@antoinevromen
Als je buiten de code tags nog quote tags plaatst dan worden de velden inderdaad ingeklapt (en kunnen uitgeklapt worden) en zo verklein je de post.
Scheelt weer scrollen op een mobiel
Maar het is wel een heel stuk beter met dat inklappen en die regelnummers.
NL; MT Venus E V2 (V153 BMS:V215); HW P1 (5.1903); App: V1.6.49; Comm.Mod:202409090159; 1 Fase 40A hoofdzek.; Iskra ME382-D1A52-P1 bj 2012; PV 7650 Wpiek; Inventum Ecolution ventilatiewarmtepomp; EV (Seat Mii 32kWh);
Ben zeer geintersseerd hierin. Volg met belangstelling.Hometek schreef op zaterdag 20 september 2025 @ 22:15:
[...]
Ik ben met iets soortgelijks bezig in Node-RED.
[....]
Over een week of twee zal ik wat meer details delen.
MT Venus E V2 (v153.215) / CT003 (v117) / Kaifa MA105 / LilyGo-RS485 / HA in Proxmox op NUC / 2,97kWP Solar / DIY-ESP32-EVSE / Ampera-E EV
Mooi stukje werk @antoinevromen, al snap ik geen snars van PowerShell.antoinevromen schreef op zondag 21 september 2025 @ 18:50:
[...]
Geweldig @AUijtdehaag ; Ik wist eerst niet waar je het over had, maar na even zoeken snapte ik dat dit ook kon;
Misschien een idee een github account te maken (als je die nog niet hebt) en het project / je code daar op te plaatsen, dan is het ook terug te vinden en voor revisies is dat ook heel handig.
MT Venus E V2 (v153.215) / CT003 (v117) / Kaifa MA105 / LilyGo-RS485 / HA in Proxmox op NUC / 2,97kWP Solar / DIY-ESP32-EVSE / Ampera-E EV
@djdj105 Dank je. Tot een week geleden wist ik ook niets van PowerShell, maar ik heb wel een historie van 30+ jaar in de ICT (en programmeren is zoals fietsen, dat verleer je niet).djdj105 schreef op zondag 21 september 2025 @ 19:17:
[...]
Mooi stukje werk @antoinevromen, al snap ik geen snars van PowerShell.
Misschien een idee een github account te maken (als je die nog niet hebt) en het project / je code daar op te plaatsen, dan is het ook terug te vinden en voor revisies is dat ook heel handig.
Ik heb wel een github account, maar ik wil het niet echt als product gaan onderhouden/promoten. Voor mensen die er wel handig in zijn, die kunnen dit als een soort jump-start gebruiken hoe je de batterij aanroept en hoe je een aantal basale basisgegevens zoals prijzen/zon-voorspelling/batterijstatus etc. kunt inzetten bij het sturen van de batterij.
Ik vond dit met name een handig tool omdat je geen extra hardware/software (zoals bijv home-assistant) nodig hebt en alles via de local-api gaat, die Marstek promoot. In het "hoofd-forum" over Marstek Venus E was al sprake ervan dat Marstek de modbus niet meer zou supporten, en mqtt wordt ook steeds lastiger gemaakt door Marstek waardoor integratie met home-assistant straks waarschijnlijk ook niet meer werkt.
Waarschijnlijk omdat je middels mqtt daarmee load op hun eigen servers in China gaat creeeren en over local-mqtt hoor je helemaal niets meer na de local-api.
NL; MT Venus E V2 (V153 BMS:V215); HW P1 (5.1903); App: V1.6.49; Comm.Mod:202409090159; 1 Fase 40A hoofdzek.; Iskra ME382-D1A52-P1 bj 2012; PV 7650 Wpiek; Inventum Ecolution ventilatiewarmtepomp; EV (Seat Mii 32kWh);
@tvh23 Mooi te lezen dat je er wat aan hebt. Zo kan iedereen op basis van deze voorbeelden het zelf tot maatwerk maken omdat bijna alle aspecten van de sturing in de scripts zitten.tvh23 schreef op maandag 22 september 2025 @ 22:26:
Dank @antoinevromen ik heb het hier werkend gekregen, mijn usecase is om te signaleren dat de verbinding tussen te CT en de batterij lang eruit ligt dat Nom niet werkt of dat de EV gestopt is met laden, dus met name verstoringen / afwijkingen signaleren. Ik draai namelijk alleen nom aangezien ik de terugleverkosten van m'n vast contract wil verminderen. Als ik nog wat tijd over heb, zal ik hem omzetten naar Python zodat ik het op een raspberry kan draaien. M'n laptop heb ik namelijk alleen overdag aan (werk thuis) en de api werkt niet vanuit de cloud (gelukkig maar ;-)
Ik heb in het verleden ook met een raspberry PI gewerkt, maar die is kapot. Maar als je e.e.a. in Python werkend hebt schroom niet het hier te posten.
Gr. Antoine Vromen
NL; MT Venus E V2 (V153 BMS:V215); HW P1 (5.1903); App: V1.6.49; Comm.Mod:202409090159; 1 Fase 40A hoofdzek.; Iskra ME382-D1A52-P1 bj 2012; PV 7650 Wpiek; Inventum Ecolution ventilatiewarmtepomp; EV (Seat Mii 32kWh);
4000Wp Oost, 5000Wp west, 2x 5.12 kWh, BMS V151, HWP1 V1.1903, CT003 V114 App V1.6.32, Shelly 3PRoEM, 3fase, electrisch koken en boiler,maat 43 in de schoenen.😅
Wow, bedankt! Ik heb nu de local API aan de praat (via Bluetooth) en heb met behulp van deze Powershell scripts ook aantoonbaar de Marstek kunnen aansturen, in de app heb ik kunnen zien dat van Self Consumption naar AI optimized geschakeld en terug, toen ik die commando's zag. Nu moet ik maar eens een Python script gaan maken zodat Domoticz hiermee overweg kan en ik niet telkens op app van Marstek hoef te kijken. Stapje verder en ik kan de batterij echt gaan aansturen. CT002 uitlezen schijnt ook al te kunnen heb ik begrepen uit de HA integratie.antoinevromen schreef op zondag 21 september 2025 @ 16:47:
[...]
DEEL1
Beste Tweakers (o.a. @GoBieN-Be @HiHaHors),
Zoals eerder geschreven hier alvast wat scripts om de batterij middels local-api te sturen.
12x 400Wp solar + Enphase IQ7+ op ZZW / Marstek Venus E v153.215 / Marstek CT002 v120 / Homewizard P1 v5.1903 / Domoticz op RPi 3B
Hallo @matramurena , Fijn te lezen dat je iets hebt gehad aan mijn scripts. Het kunnen aansturen van de batterij is vereiste nr. 1 natuurlijk, maar ik ben zelf ook nog steeds de scripts aan het vervolmaken om meer logica erin te brengen m.b.t. de daadwerkelijk sturingslogica (dat is nog een heel apart hoofdstuk als je dat goed wilt doen). Vandaar ook dat deze oplossing zo mooi is dat iedereen dat wat hij/zij wil bereiken er zelf in kan programmeren.matramurena schreef op donderdag 25 september 2025 @ 12:47:
[...]
Wow, bedankt! Ik heb nu de local API aan de praat (via Bluetooth) en heb met behulp van deze Powershell scripts ook aantoonbaar de Marstek kunnen aansturen, in de app heb ik kunnen zien dat van Self Consumption naar AI optimized geschakeld en terug, toen ik die commando's zag. Nu moet ik maar eens een Python script gaan maken zodat Domoticz hiermee overweg kan en ik niet telkens op app van Marstek hoef te kijken. Stapje verder en ik kan de batterij echt gaan aansturen. CT002 uitlezen schijnt ook al te kunnen heb ik begrepen uit de HA integratie.
NL; MT Venus E V2 (V153 BMS:V215); HW P1 (5.1903); App: V1.6.49; Comm.Mod:202409090159; 1 Fase 40A hoofdzek.; Iskra ME382-D1A52-P1 bj 2012; PV 7650 Wpiek; Inventum Ecolution ventilatiewarmtepomp; EV (Seat Mii 32kWh);