LW IT Solutions
« Blog Overview /Smart Home / Integracja falownika Fronius Symo z systemami Smart...
This post in other languages:

Integracja falownika Fronius Symo z systemami Smart Home

Integracja falownika Fronius Symo z systemami Smart Home

Systemy fotowoltaiczne odgrywają kluczową rolę w nowoczesnym zarządzaniu energią. Falownik Fronius Symo oferuje doskonałe możliwości integracji ze środowiskiem Smart Home. Dzięki otwartemu, lokalnemu API pobieranie danych jest niezwykle proste i nie wymaga stałego dostępu do chmury producenta. Takie lokalne podejście gwarantuje wysoką niezawodność i szybki czas reakcji dla automatyzacji.

Autorski skrypt PHP i widżet na smartfonie

Do monitorowania statusu instalacji PV służy dedykowany skrypt PHP uruchomiony na lokalnym serwerze. Skrypt ten odpytuje endpoint API falownika pod adresem [http://192.168.XXX.XXX/solar_api/v1/GetInverterRealtimeData.cgi?Scope=Device&DeviceId=1&DataCollection=CommonInverterData]. Otrzymana odpowiedź w formacie JSON jest dekodowana w celu wyodrębnienia kluczowych parametrów: aktualnie generowanej mocy (PAC) oraz dziennego uzysku energii (DAY_ENERGY).

Odświeżanie danych odbywa się cyklicznie, na przykład co 5 minut, co pozwala na bieżące śledzenie produkcji. W przypadku, gdy falownik przechodzi w stan uśpienia (np. w nocy, gdy produkcja spada do zera, a wartość DAY_ENERGY zwraca błąd lub wartość pustą), zastosowano mechanizm awaryjny. Skrypt odczytuje wówczas ostatnie znane wartości z lokalnego pliku 1.dat, zapobiegając błędom wyświetlania.

Od strony wizualnej skrypt posiada dynamiczne tło, które zmienia kolor w zależności od aktualnie generowanej mocy. Dzięki specjalnej funkcji matematycznej generującej gradient, tło płynnie przechodzi między kolorami (np. od białego, przez pomarańczowy, aż po czerwony) na podstawie wartości PAC. Tak przygotowana strona, wyposażona w mechanizm autoodświeżania, może zostać użyta w aplikacji „Widgetify”, tworząc wygodny i spersonalizowany widżet bezpośrednio na ekranie głównym smartfona.

<?php

// Adjust the IP Address
$x = json_decode(file_get_contents("http://192.168.XXX.XXX/"
."solar_api/v1/GetInverterRealtimeData.cgi?".
"Scope=Device&DeviceId=1&DataCollection=CommonInverterData"), false);

$fallback1 = "";
$fallback2 = "";
if(!isset($x->Body->Data->DAY_ENERGY->Value) || 
$x->Body->Data->DAY_ENERGY->Value === null || 
$x->Body->Data->DAY_ENERGY->Value === false) {
 $y = explode("|", file_get_contents("./1.dat"));
 $fallback1 = $y[0];
 $fallback2 = $y[1];
}
else
{
 file_put_contents("./1.dat", 
 $x->Body->Data->PAC->Value.$x->Body->Data->PAC->Unit.
 "|".$x->Body->Data->DAY_ENERGY->Value.$x->Body->Data->DAY_ENERGY->Unit);
}

if(isset($_GET["x"])) {
 exit($x->Body->Data->PAC->Value.$x->Body->Data->PAC->Unit.
 $fallback1."|".$x->Body->Data->DAY_ENERGY->Value.
 $x->Body->Data->DAY_ENERGY->Unit.$fallback2."|".
 date("H:i:s").($fallback1 != "" ? " F" : ""));
}

function Gradient($HexFrom, $HexTo, $ColorSteps) {
    // credit: Hailwood (stackoverflow)
    $FromRGB['r'] = hexdec(substr($HexFrom, 0, 2));
    $FromRGB['g'] = hexdec(substr($HexFrom, 2, 2));
    $FromRGB['b'] = hexdec(substr($HexFrom, 4, 2));

    $ToRGB['r'] = hexdec(substr($HexTo, 0, 2));
    $ToRGB['g'] = hexdec(substr($HexTo, 2, 2));
    $ToRGB['b'] = hexdec(substr($HexTo, 4, 2));

    $StepRGB['r'] = ($FromRGB['r'] - $ToRGB['r']) / ($ColorSteps - 1);
    $StepRGB['g'] = ($FromRGB['g'] - $ToRGB['g']) / ($ColorSteps - 1);
    $StepRGB['b'] = ($FromRGB['b'] - $ToRGB['b']) / ($ColorSteps - 1);

    $GradientColors = array();

    for($i = 0; $i <= $ColorSteps; $i++) {
        $RGB['r'] = floor($FromRGB['r'] - ($StepRGB['r'] * $i));
        $RGB['g'] = floor($FromRGB['g'] - ($StepRGB['g'] * $i));
        $RGB['b'] = floor($FromRGB['b'] - ($StepRGB['b'] * $i));

        $HexRGB['r'] = sprintf('%02x', ($RGB['r']));
        $HexRGB['g'] = sprintf('%02x', ($RGB['g']));
        $HexRGB['b'] = sprintf('%02x', ($RGB['b']));

        $GradientColors[] = implode(NULL, $HexRGB);
    }
    $GradientColors = array_filter($GradientColors, function($val){
        return (strlen($val) == 6 ? true : false );
    });
    return $GradientColors;
}

function ColorFromGradient($n, $min, $max, $colors) {
    $tablecolors = [];
    $prevcolor = array_shift($colors);
    foreach ($colors as $color) {
        $tablecolors = array_merge($tablecolors, Gradient($prevcolor, $color, 10));
        $prevcolor = $color;
    }
    $max = $max-$min;
    $n-= $min;
    if ($n > $max) $n = $max;
    
    $ncolor = round(count($tablecolors)/$max * $n)-1;
    
    return $tablecolors[$ncolor];
}

?><!DOCTYPE html><html>
<head><script>
function dR() {
setInterval(function(){
  document.getElementById('f3').innerHTML += 'R...';
  var xhr = new XMLHttpRequest();
  xhr.open("GET", "./pvgirdcgi.php?x="+new Date(), true);
  xhr.timeout = 5000;
  xhr.onreadystatechange = function() {
   if(xhr.readyState == 4) {
    document.getElementById('f1').innerHTML = xhr.responseText.split("|")[0];
    document.getElementById('f2').innerHTML = xhr.responseText.split("|")[1];
    document.getElementById('f3').innerHTML = xhr.responseText.split("|")[2];
   }
  }
  xhr.onerror = function() {};
 xhr.send();
}, 8000);
}

	//setTimeout(function(){window.location.reload()},1000*20);
</script>
<style>
<?php 
if(isset($gear) && $gear == true) {
 ?>
 body{text-align:center;margin-top:50px;font-size:32px;}
 <?php
}
?>
span {
 text-shadow:
    0 0 7px #fff,
    0 0 10px #fff,
    0 0 21px #fff,
    0 0 42px #0fa,
    0 0 82px #0fa,
    0 0 92px #0fa,
    0 0 102px #0fa,
    0 0 151px #0fa;
 font-family:Arial,Verdana;
}
</style>
</head><body <?php 
if(isset($gear) && $gear == true)
{
?> onClick="document.querySelector('#pvx').style.display='block';"+
"document.querySelector('.loader').style.display='block';"+
"document.querySelector('#pvall').style.display='none';"+
"window.location.reload();"<?php
}
?>style="background:#<?php echo ColorFromGradient($x->Body->Data->PAC->Value, 
0, 9000, ['FFFFFF', 'FFAA00', 'CC0000']); ?>">

<?php 
if(isset($gear) && $gear == true) {
 ?>
 <style>
.loader {
  border: 16px solid #f3f3f3;
  border-radius: 50%;
  border-top: 16px solid #3498db;
  width: 120px;
  height: 120px;
  -webkit-animation: spin 2s linear infinite; /* Safari */
  animation: spin 2s linear infinite;
}

/* Safari */
@-webkit-keyframes spin {
  0% { -webkit-transform: rotate(0deg); }
  100% { -webkit-transform: rotate(360deg); }
}

@keyframes spin {
  0% { transform: rotate(0deg); }
  100% { transform: rotate(360deg); }
}
</style><div style="display:none;text-align:center;width:100%;
margin-left:-16px;margin-top:100px;" id="pvx">
	<span style="text-align: center;width: 120px;display: inline-block;">
		<span class="loader" style="display:none;"></span>
	</span>
</div>
 <?php
}
?>
<div style="<?php 
if(@$gear != true)
{?>width:80px;<?php } ?>text-align:center;" id="pvall">
	<span style="text-shadow: 1px 1px #ffffff;
	font-family:Arial,Verdana;font-weight:bold;">PV</span><br /><br />
<span style="font-weight:bold;" id="f1"><?php echo $x->Body->Data->PAC->Value.
$x->Body->Data->PAC->Unit.$fallback1; ?></span><br />
<span style="" id="f2"><?php echo $x->Body->Data->DAY_ENERGY->Value.
$x->Body->Data->DAY_ENERGY->Unit.$fallback2; ?></span>
<br /><br />
<span style="" id="f3"><?php echo date("H:i:s").($fallback1 != "" ? " F" : ""); ?></span>
</div>

</body>
</html>
Przebieg odpytywania co pięć minut z lokalnego API Fronius Symo przez skrypt PHP, z rozgałęzieniem przy obecnej wartości DAY_ENERGY i trybem awaryjnym opartym na pliku 1.dat oraz skalą barw tła
API dostarcza, 1.dat pamięta — dlatego wyświetlacz zachowuje nocą swój kształt zamiast pokazywać błąd.

Możliwości w systemie Home Assistant

Ten sam endpoint API Froniusa otwiera ogromne możliwości dla rozbudowanych platform Smart Home, takich jak Home Assistant. Po skonfigurowaniu natywnej integracji Fronius, Home Assistant nieustannie odpytuje dokładnie te same dane.

Daje to następujące możliwości:

  • Panel Energia (Energy Dashboard): Dane o wyprodukowanej energii zasilają wbudowany panel energetyczny, dostarczając długoterminowych statystyk, obliczeń opłacalności oraz poziomu niezależności od sieci energetycznej.
  • Inteligentne automatyzacje: Dane o mocy w czasie rzeczywistym (PAC) mogą służyć jako wyzwalacze (triggers). Na przykład pompa ciepła, klimatyzator lub ładowarka do aut EV mogą włączać się automatycznie, gdy produkcja ze słońca przekroczy zadany próg, co maksymalizuje autokonsumpcję.

Podsumowanie

Falownik Fronius Symo udostępnia czytelne dane w czasie rzeczywistym za pośrednictwem lokalnego API. Zarówno w przypadku zastosowania autorskiego skryptu PHP połączonego z aplikacją Widgetify do szybkiego podglądu na telefonie, jak i przy wykorzystaniu potężnego systemu Home Assistant do zaawansowanych automatyzacji, integracja tego falownika czyni zarządzanie energią słoneczną procesem wysoce efektywnym.

Lukas Wojcik

Lukas Wojcik

Systems architect and technology enthusiast specializing in scalable tracking solutions, GMP Stack (GA4 & GTM), and robust backend architectures. Advocate for clean code and privacy-first design.

Get in Touch

Briefly describe your project or inquiry for a tailored response. This site is protected by reCAPTCHA.

Komentarze: 4

  1. Marcin Herbut

    Mechanizm awaryjny oparty na pliku 1.dat jest sprytny i widać, że powstał z praktyki — nocne wygaszenie falownika wywraca każdy widżet pisany na kolanie.

    Mam jednak wątpliwość co do samej wartości: w nocy widżet pokazuje moc z ostatniego odczytu, czyli z popołudnia. Czy nie uczciwiej byłoby pokazać zero?

    1. Lukas Wojcik Autor

      Zero też byłoby nieprawdą, tylko innego rodzaju: falownik nie zgłasza wtedy zera, on po prostu nie odpowiada. To są dwa różne stany i widżet, który je skleja, myli w obie strony.

      Rozsądny podział przebiega między dwiema wartościami. Dzienny uzysk (DAY_ENERGY) po zachodzie słońca faktycznie się nie zmienia, więc ostatni znany odczyt jest tu poprawną odpowiedzią. Moc chwilowa (PAC) zmienia się co chwilę, więc jej ostatni odczyt po kilku godzinach nie znaczy już nic.

      W skrypcie widać zresztą zalążek rozwiązania: doklejane F przy wartości awaryjnej. Rozdzielenie tych dwóch pól — ostatni uzysk jako wartość, moc jako stan „brak odpowiedzi” z godziną ostatniego odczytu — kosztuje kilka linii i usuwa jedyny przypadek, w którym widżet wprowadza w błąd zamiast informować.

  2. Klaudia Wieczorek

    Ten sam endpoint w skrypcie PHP i w integracji Home Assistant to argument, który przekonał mnie do lokalnego API zamiast chmury producenta.

    Pytanie o częstotliwość: skrypt odpytuje falownik co 5 minut, integracja robi to znacznie częściej, a u nas działałyby równolegle. Czy Symo znosi taki podwójny ruch bez problemu?

    1. Lukas Wojcik Autor

      Samo odpytywanie nie jest problemem — lokalne API Froniusa jest do tego przeznaczone i kilkusekundowy interwał zwykle mu nie szkodzi. Kłopot zaczyna się przy dwóch niezależnych systemach pytających jednocześnie, bo odpowiedzi potrafią się opóźniać, a falownik bywa też jedynym punktem dostępu do licznika Smart Meter.

      Sprawdza się podział na jedno źródło i resztę czytającą z niego. Jeżeli w domu działa Home Assistant, to on jest naturalnym kandydatem: skrypt PHP pobiera wtedy gotową wartość z jego API zamiast dokładać własne zapytanie do falownika.

      Przy okazji znika problem nocny, o którym mowa w artykule. Encje w Home Assistant mają własne oznaczenie niedostępności, więc stan „falownik śpi” nie wymaga już pliku awaryjnego — widżet czyta stan, a nie ostatnią zapamiętaną liczbę.

Napisanie komentarza

Adres e-mail nie jest publikowany. Pola obowiązkowe oznaczono gwiazdką.

ALL ARTICLES & CATEGORIES

CCTV

Śledź tę kategorię przez RSS

Cloud & AI

Śledź tę kategorię przez RSS

Data Privacy

Wszystkie artykuły w tej kategorii (12) Śledź tę kategorię przez RSS

Digital Analytics

Wszystkie artykuły w tej kategorii (47) Śledź tę kategorię przez RSS

Digital Marketing

Wszystkie artykuły w tej kategorii (27) Śledź tę kategorię przez RSS

IT & Networks

Wszystkie artykuły w tej kategorii (16) Śledź tę kategorię przez RSS

Music Production

Śledź tę kategorię przez RSS

Raspberry Pi

Śledź tę kategorię przez RSS

Smart Home

Wszystkie artykuły w tej kategorii (17) Śledź tę kategorię przez RSS

Tworzenie stron internetowych

Śledź tę kategorię przez RSS

Wtyczki i triki WordPress

Śledź tę kategorię przez RSS