top of page

System monitorowania energii
i REST API Smart Meter.

IoT | Parametry zasilania elektrycznego | RestAPI | JSON | Agregacja | Baza danych SQL | Grafana | Dashboardy w czasie rzeczywistym

W tym przykładowym rozwiązaniu InDriver zbiera i przetwarza parametry energii elektrycznej z inteligentnego licznika Shelly 3EM. Dzięki zadaniom InDriver dane są skrupulatnie uzupełniane, synchronizowane z zegarem i agregowane w serie 1-minutowe, 15-minutowe, 1-godzinne i 1-dniowe, a następnie zapisywane w bazie danych SQL. Dzięki wykorzystaniu interfejsu API szeregów czasowych (TSAPI) wizualizacja danych w Grafanie staje się płynna, umożliwiając łatwe udostępnianie w internecie za pośrednictwem przeglądarek internetowych.

Schemat przepływu danych

Zadanie 1 — Gromadzenie, przetwarzanie i rejestrowanie danych RESTAPI w tabeli SQL.

Po uruchomieniu zadania InDriver definiowane jest żądanie danych API REST.

OnStartup:

​

InDriver.import("RestApi");

RestApi.defineRequest('shelly','{"url":"https://shelly-56-eu.shelly.cloud/device/status","data":"id={id}&auth_key={key}","timeout":5000, "type":"post","headers":{"ContentTypeHeader":"application/json"}}');

InDriver.installHook(30000);

PĘTLA

InDriver wysyła żądania danych interfejsu API REST w regularnych odstępach czasu, np. co każdy skonfigurowany okres, na przykład co 30 sekund, zsynchronizowane z zegarem — 00:00:00, 00:00:30, 00:01:00 itd.

OnHook:

​

RestApi.sendRequest('shelly');

 

if (RestApi.isSucceeded()) {

let ts= InDriver.hookTs();

const text = RestApi.getData('shelly');

const obj = JSON.parse(text);

​

let energy1 = Math.abs(obj.data.device_status.emeters[0].total_returned);

let energy2 = Math.abs(obj.data.device_status.emeters[1].total_returned);

let energy3 = Math.abs(obj.data.device_status.emeters[2].total_returned);

​

let power1 = Math.abs(obj.data.device_status.emeters[0].power);

let power2 = Math.abs(obj.data.device_status.emeters[1].power);

let power3 = Math.abs(obj.data.device_status.emeters[2].power);

​

let data = {

power1 : power1,

power2 : power2,

power3 : power3,

voltage1 : Math.abs(obj.data.device_status.emeters[0].voltage),

voltage2 : Math.abs(obj.data.device_status.emeters[1].voltage),

voltage3 : Math.abs(obj.data.device_status.emeters[2].voltage),

current1 : Math.abs(obj.data.device_status.emeters[0].current),

current2 : Math.abs(obj.data.device_status.emeters[1].current),

current3 : Math.abs(obj.data.device_status.emeters[2].current),

energy1 : energy1,

energy2 : energy2,

energy3 : energy3,

energy_total: energy1 + energy2 + energy3,

power_total: power1 + power2 + power3

}

​

let shelly = {Shelly:data};

let list = [];

list.push(shelly);

InDriver.debug(JSON.stringify(list));

 

InDriver.sendMessage(ts, 'DeviceData', JSON.stringify(list));

InDriver.sqlExecute("azureserver",

"insert into public.shelly (source, ts, data )

values ( 'Shelly','"+ts.toISOString()+"',$$"+JSON.stringify(list)+"$$);");

}

obj = {"isok":true,"data":{"online":true,"device_status":{"ram_free":32692,"mac":"34945477F146","fs_size":233681,"fs_free":154616,"getinfo":{"fw_info":{"device":"shellyem3-34945477F146","fw":"20221027-110030\/v1.12.1-ga9117d3"}}, "ram_total":49928, "emeters":[{"power":-312.8,"pf":-0.93, "current":1.42, "voltage":238.72, "is_valid":true, „łącznie”: 0, „zwrócono łącznie”: 1699355}, {„moc”: -281,56, {„pf”: -0,8, „bieżące”: 1,46, „napięcie”: 240,94, „prawidłowe”: prawda, „łącznie”: 20,5, „zwrócono łącznie”: 1734052,1}, {„moc”: -10,16, {„pf”: -0,26, „bieżące”: 0,16, „napięcie”: 240,05, "is_valid":true,"total":0,"total_returned":542968.2}],"serial":17383,"has_update":true,"unixtime":1699182633,"cloud":{"enabled":true,"connected":true},"actions_stats":{"skipped":0},"v_data":1,"total_power":-604.52, "uptime":171876,"mqtt":{"connected":false},"_updated":"2023-11-05 13:11:49","cfg_changed_cnt":0,"relays":[{"ison":false,"has_timer":false,"timer_started":0,"timer_duration":0,"timer_remaining":0,"overpower":false,"is_valid":true,"source":"i...ip":"192.168.0.111","rssi":-74},"fs_mounted":true,"update":{"status":"pending", "has_update":true, „nowa_wersja”: „20230913-114244\/v1.14.0-gcb84623”, „stara_wersja”: „20221027-110030\/v1.12.1-ga9117d3”}}}}

Z danych wyodrębniane są kluczowe parametry energetyczne, takie jak moc, napięcie, prąd i energia. Dodatkowo przeprowadzane są szczegółowe obliczenia, w szczególności w celu korekcji kierunku prądu, co jest kluczowym krokiem w przypadku nieprawidłowego podłączenia przekładnika prądowego.

Wynikowe przetworzone dane są przechowywane w obiekcie JSON, jak pokazano poniżej:

dane = {"moc1": 312,8,"moc2": 281,56, "moc3": 10,16, "napięcie1": 238,72, "napięcie2": 240,94, "napięcie3": 240,05, "prąd1": 1,42, "prąd2": 1,46, "prąd3": 0,16, "energia1": 1699355, "energia2": 1734052,1, "energia3": 542968,2,"suma_energii": 3976375,3, "suma_mocy': 604,45}

Oto parametry energii otrzymane w formacie JSON

z inteligentnego licznika za pośrednictwem interfejsu API REST:

Na koniec przetworzone parametry energii są zapisywane w tabeli SQL, przedstawionej poniżej:

select * from public.shelly order by ts desc limit 10

​

Parametry energii w formacie JSON rejestrowane w tabeli SQL

Zadanie 2 – Agregacja danych

W drugim zadaniu wykonywany jest algorytm agregacji danych z biblioteki Time Series API (TsApi), jak pokazano poniżej. TsApi jest dostępne w InDriver.

onStartup:

InDriver.import("TsApi");

InDriver.installHook(60000);

TsApi.defineAggregator("ShellyAggregation","azureserver","shelly","Europe/Warsaw",'["Shelly"]');

​

W tym przykładzie agregacja jest wykonywana z częstotliwością 1 minuty.

onHook:

TsApi.aggregate(" ShellyAggregation ");

Po zastosowaniu algorytmu agregacji generowane są tabele SQL dla określonych interwałów, z domyślnymi opcjami 1 minuty, 15 minut, 1 godziny i 1 dnia. Dla tabeli wejściowej „shelly” generowane są odpowiednie tabele: „shelly_1minute”, „shelly_15minute”, „shelly_1hour” i „shelly_1day”.

wybierz * z public.shelly_1hour zamów według ts desc limit 10

Parametry energii zebrane z inteligentnego licznika są przechowywane w tabeli SQL w formacie JSON

Dodatkowo, każda tabela agregacji zawiera kolumnę „dodatki”, która zawiera wartości statystyczne z poprzedniego interwału. Obejmuje to wartości minimalne (min.), maksymalne (maks.), średnie (śr.) i delta. Kolumna „dodatki” wskazuje również status, rozróżniając wartości pochodzące z danych rzeczywistych („rzeczywiste”) od wartości szacowanych/interpolowanych („szacowane”).

Dzięki stale obliczanym kompletnym tabelom agregacji dla danych wejściowych JSON z dowolnego źródła możesz bez wysiłku tworzyć wizualizacje i dashboardy, wykonywać dodatkowe obliczenia lub generować raporty.

Przykładowy wiersz z tabeli agregowanej „shelly_1hour”:

źródło

ts

dane

dodatki

Shelly

2023-11-06 18:00:00+00

Zagregowane i interpolowane parametry energii (moc, prąd, napięcie, energia) w formacie JSON w tabeli SQL.
Zagregowane dane z liczników energii w formacie JSON

Dzięki opisanemu przepływowi danych zaimplementowanemu w InDriver, tworzenie wizualizacji staje się proste.

Agregacja i obliczenia delty dla każdego interwału generują natychmiastowe wartości zużycia energii. InDriver przekształca obiekty JSON z interfejsu API REST w tabele w czasie rzeczywistym, tworząc dane gotowe do wyświetlenia na pulpicie nawigacyjnym.

select ts, (extras->'statistics'->0->'Shelly'->'energy_total'->>'delta')::double precision as energy_consumption

from public."shelly_1hour" where "source" = 'Shelly' and ts >=  date_trunc('month', now() ) and ts <= now()

Wykres zużycia energii z zapytania SQL
bottom of page