Cześć wszystkim! ![]()
Chciałbym podzielić się z Wami rozwiązaniem, nad którym ostatnio pracowałem w ramach optymalizacji autokonsumpcji. Jeśli temat Was zainteresuje, w przyszłości postaram się opisać kolejne kroki i automatyzacje budowane na tych danych.
Problem: Skąd wiedzieć ile mocy idzie w niebo?
Większość z nas opiera automatyzacje na aktualnej produkcji. Jednak gdy magazyn energii jest pełny (SoC = 100%) lub eksport do sieci jest ograniczony (lub wyłączony
) inwerter celowo schodzi z punktu mocy maksymalnej (MPPT).
Wtedy produkcja na wykresie spada, a napięcie na stringach rośnie w stronę napięcia jałowego (Voc). Standardowy sensr pokaże np. 200W poboru własnego mimo że słońce praży i moglibyście właśnie zasilać klimę za darmo. Bez drogieo pyranometru (czujnika nasłonecznienia) trudno ocenić ten potencjał.
Rozwiązanie: Dynamiczny Model Matematyczny (Beta)
Przygotowałem algorytm, który analizuje parametry elektryczne stringów i warunki otoczenia, by oszacować realną dostępną nadwyżkę.
Co bierze pod uwagę kod?
- Fizykę ogniwa i temperaturę: Moc paneli spada wraz z ich nagrzewaniem. Kod stosuje korektę o współczynnik temperaturowy rozróżniając montaż na gruncie (lepszy przewiew) od dachu.
- Korektę Air Mass: Uwzględnia elewację słońca – przy niskim kącie atmosfera silniej tłumi promieniowanie co kod przelicza na realny współczynnik AM.
- Modelowanie krzywej I-V: Wykorzystuje uproszczony model kwadratowy, by na podstawie wzrostu napięcia względem optymalnego Vmp oszacować, ile mocy inwerter aktualnie marnuje.
Wymagania wstępne
Zanim przejdziesz do implementacji upewnij się, że Twój system integruje następujące dane:
- Sensory napięcia (V) i mocy (W) DC osobno dla każdego stringu (pobierane z inwertera).
- Pozycja słońca (np. elewacja słońca z integracji Sunlight Visualizer lub natywnej integracji Sun).
- Dane pogodowe (temperatura zewnętrzna oraz zachmurzenie w %).
- Stan naładowania baterii (SoC) – jeśli posiadaszmagazyn energii.
Źródła danych i sensory
W moim kodzie korzystam z dwóch świetnych integracji do pobierania danych środowiskowych:
- Sunlight Visualizer – do precyzyjnego śledzenia pozycji słońca.
- IMGW-PIB Monitor – skąd pobieram temperaturę oraz zachmurzenie.
Oczywiście nic nie stoi na przeszkodzie abyście użyli własnych sensorów (np. z lokalnej stacji pogodowej Zigbee/WiFi czy integracji Weather) o ile dostarczają one temperatury i nasłonecznienia/zachmurzenia.
Implementacja: Home Assistant (Jinja2)
W tym miejscu należy wkleić kod sensora typu template. Możecie go dodać bezpośrednio w pliku configuration.yaml, a czy przez UI moża dodać, szczerze nie wiem. Jest opcja dodanie przez UI (Pomocnicy → Template → Sensor) choć przy tak złożonej logice configuration.yaml pozostaje czytelniejszy.
Wskazówka: Wartości Vmp i Voc wpisujemy dla pojedynczego modułu – kod sam przemnoży to przez liczbę paneli. To ułatwia sprawę bo te dane najłatwiej spisać prosto z naklejki na plecach panelu lub z karty katalogowej.
template:
- sensor:
- name: "Dostępna Nadwyżka PV (Estymacja)"
unique_id: pv_potential_universal_v1
unit_of_measurement: "W"
device_class: power
state: >
{# --- 1. WEJŚCIA (Podmień na swoje encje lub stację pogodową) --- #}
{% set s_elev = states('sensor.sun_solar_elevation') | float(0) %}
{% set s_temp = states('sensor.weather_imgw_temperature') | float(15) %}
{% set s_clouds = states('sensor.weather_imgw_cloud_coverage') | float(0) %}
{% set s_soc = states('sensor.deye_battery_soc') | float(100) %}
{# --- 2. DANE TWOICH PANELI (Z naklejki pojedynczego panela) --- #}
{% set mppt_strings = [
{
'name': 'Południe Grunt',
'v_now': states('sensor.pv_voltage_1') | float(0),
'p_now': states('sensor.pv_power_1') | float(0),
'vmp_stc': 31.18,
'voc_stc': 37.15,
'ilosc_paneli': 12,
'typ_montazu': 'grunt'
},
{
'name': 'Zachód Dach',
'v_now': states('sensor.pv_voltage_2') | float(0),
'p_now': states('sensor.pv_power_2') | float(0),
'vmp_stc': 30.50,
'voc_stc': 37.05,
'ilosc_paneli': 6,
'typ_montazu': 'dach'
}
] %}
{# --- 3. LOGIKA I BUFORY --- #}
{% set t_coeff = -0.0027 %} {# Współczynnik Pmax/°C #}
{% set sprawnosc_inv = 0.96 %}
{% set buffer = 150 if s_soc < 95 else 50 %}
{% if s_elev < 2 %} 0
{% else %}
{% set am_factor = [0.85, (s_elev / 20)] | min if s_elev < 20 else 1.0 %}
{% set ns = namespace(total_pot=0, current_p=0) %}
{% for s in mppt_strings %}
{# Model temperatury ogniwa: +18K dla gruntu, +28K dla dachu względem otoczenia #}
{% set t_cell = s_temp + (18 if s.typ_montazu == 'grunt' else 28) * (1 - s_clouds/100) %}
{% set vmp_t = s.ilosc_paneli * s.vmp_stc * (1 + t_coeff * (t_cell - 25)) %}
{% set voc_t = s.ilosc_paneli * s.voc_stc * (1 + t_coeff * (t_cell - 25)) %}
{# Estymacja ukrytej mocy na podstawie napięcia DC #}
{% set p_pot = (s.p_now / (1 - ([(s.v_now - vmp_t) / ([1, voc_t - vmp_t]|max), 0.93]|min)**2)) if s.v_now > vmp_t + 2 else s.p_now %}
{% set ns.total_pot = ns.total_pot + p_pot %}
{% set ns.current_p = ns.current_p + s.p_now %}
{% endfor %}
{% set result = (ns.total_pot * sprawnosc_inv * am_factor) - ns.current_p - buffer %}
{{ [0, result] | max | round(0) }}
{% endif %}
Alternatywa: JavaScript (NR / Logic)
Dla osób preferujących logikę w JS lub NodeRed przygotowałem również funkcję, którą możecie wykorzystać w swoich flowach.
function calculatePVSurplus(weather, mpptStrings) {
if (weather.elev < 2) return 0;
const tCoeff = -0.0027;
const invEff = 0.96;
const amFactor = weather.elev < 20 ? Math.min(0.85, weather.elev / 20) : 1.0;
let totalPot = 0;
let currentP = 0;
mpptStrings.forEach(s => {
const tCell = weather.temp + (s.type === 'ground' ? 18 : 28) * (1 - weather.clouds / 100);
const vmpT = s.count * s.vmpStc * (1 + tCoeff * (tCell - 25));
const vocT = s.count * s.vocStc * (1 + tCoeff * (tCell - 25));
let pPot = s.pNow;
if (s.vNow > vmpT + 2) {
const ratio = Math.min((s.vNow - vmpT) / Math.max(1, vocT - vmpT), 0.93);
pPot = s.pNow / (1 - Math.pow(ratio, 2));
}
totalPot += pPot;
currentP += s.pNow;
});
const buffer = weather.soc < 95 ? 150 : 50;
return Math.round(Math.max(0, (totalPot * invEff * amFactor) - currentP - buffer));
}
Kalibracja i precyzja danych
Ważna uwaga: Dokładność tego sensora jest bezpośrednio uzależniona od jakości danych wejściowych. Dane o zachurzeniu z IMGW czy pozycja słońca z Sunlight Visualizer są estymacjami – chmura nad stacją meteo nie zawsze oznacza chmurę nad Twoim dachem. Różnice rzędu 100-200W są całkowicie normalne i wynikają z bezwładności systemów pogodowych.
Jak sprawdzić czy to działa?
- W słoneczny dzień, gdy magazyn jest pełny zanotuj wartość Dostępnej Nadwyżki.
- Włącz duże obciążenie (np. zajnik 2kW).
- Wartość sensora powinna spaść o około 2000W (blisko zera). Jeśli zostaje na dużym plusie lub spada głęboko poniżej zera skoryguj współczynniki sprawności lub bufory w kodzie.
Uwagi praktyczne
- Histereza: Jeśli planujecie używać tego sensora do załączania urządzeń, dodajcie w automatyzacji warunek czasu (np. nadwyżka powyżej 1000W przez przynajmniej 2 minuty). Zapobiegnie to “taktowaniu” przekaźników przy przemykających chmurach.
- Status Beta: Algorytm jest w fazie testów. Wyniki mogą się różnić w zależności od technologii ogniw.
Jeśli projekt się sprawdzi, w przyszłości postaram się pokazać, jak zintegrować te dane oraz postaram się zrobić trochę trudniejszy projekt ![]()
Dajcie znać, jak to u Was wygląda.
![]()