top of page

System monitorowania energii
i REST API Smart Meter.

IoT | Parametry zasilania elektrycznego | RestAPI | JSON | Agregacja | Baza danych SQL | Grafana | Pulpity nawigacyjne 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 seriach 1-minutowych, 15-minutowych, 1-godzinnych i 1-dniowych, zanim zostaną zapisane w bazie danych SQL. Wykorzystując interfejs API serii czasowych (TSAPI), wizualizacja danych w Grafana 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, "total":0, "total_returned":1699355},{"power":-281.56,"pf":-0.8, "current":1.46, "voltage":240.94, "is_valid":true, "total":20.5, "total_returned":1734052.1},{"power":-10.16,"pf":-0.26, "current":0.16, "voltage":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, "new_version":"20230913-114244\/v1.14.0-gcb84623","old_version":"20221027-110030\/v1.12.1-ga9117d3"}}}}

Kluczowe parametry energii, takie jak moc, napięcie, prąd i energia, są wyodrębniane z danych. Ponadto wykonywane są określone obliczenia, w szczególności w celu skorygowania kierunku prądu, co jest kluczowym krokiem w przypadku nieprawidłowych połączeń transformatorów prądowych.

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

data = {"power1": 312.8,"power2": 281.56, "power3":10.16, "voltage1":238.72, "voltage2":240.94, "voltage3":240.05, "current1":1.42, "current2":1.46, "current3":0.16, "energy1":1699355, "energy2":1734052.1, "energy3":542968.2,"energy_total":3976375.3, "power_total':604.45}

Oto parametry energii otrzymane w formacie JSON

z inteligentnego licznika poprzez REST API:

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

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

Parametry energii w formacie JSON zalogowane do tabeli SQL

Zadanie 2 - Agregacja danych

W drugim zadaniu wykonywany jest algorytm agregacji danych z biblioteki Time Series API (TsApi), jak przedstawiono poniżej. TsApi jest dostępny 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 przedziałów, w tym domyślne opcje 1 minuty, 15 minut, 1 godziny i 1 dnia. Dla tabeli wejściowej „shelly” pojawiają się odpowiadające tabele: „shelly_1minute”, „shelly_15minute”, „shelly_1hour” i „shelly_1day”.

select * from public.shelly_1hour order by 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 rejestruje wartości statystyczne z poprzedniego przedział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 rzeczywistych danych („rzeczywiste”) i szacowane/interpolowane („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 pulpity nawigacyjne, 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 licznika 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 dają natychmiastowe wartości zużycia energii. InDriver przekształca obiekty JSON z REST API w tabele w czasie rzeczywistym, tworząc dane gotowe do wyświetlenia na pulpicie.

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