Życzymy Państwu Nowego Roku pełnego innowacji, sukcesów i nieograniczonych możliwości.
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
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
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
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()