TapHome

Shelly Motion 2

Packet Parser → MQTT
Dodane przez
Ostatnia aktualizacja: 03. 2026
Shelly Motion 2

Shelly Motion 2 (SHMOS-02) to bateryjny (Li-ion 6500 mAh, ładowalny przez USB-C) czujnik ruchu PIR Wi-Fi. TapHome komunikuje się z urządzeniem przez MQTT — zalecany protokół dla bateryjnych urządzeń Shelly, ponieważ czujnik przez większość czasu jest w trybie uśpienia i publikuje dane tylko przy zdarzeniach wybudzenia (wykrycie ruchu lub okresowy timer).

W odróżnieniu od przekaźnikowych urządzeń Gen1 Shelly, które publikują indywidualne topiki stanów, Motion 2 publikuje pełny stan za pośrednictwem jednego payloadu JSON /info przy wybudzeniu. Skrypt nasłuchujący TapHome parsuje ten JSON w celu wyodrębnienia stanu ruchu, natężenia oświetlenia, temperatury, poziomu baterii i atrybutów diagnostycznych.

Szablon obsługuje do 5 czujników Shelly Motion 2 na moduł. Każda instancja czujnika jest rozróżniana zmienną niestandardową sensorN_topic wskazującą na MQTT Client ID urządzenia.

Konfiguracja

Device ID

Każdy Shelly Motion 2 ma unikalne MQTT Device ID w formacie shellymotion2-<MAC>, gdzie <MAC> to pełny 12-znakowy adres MAC w formacie szesnastkowym wielkimi literami (np. shellymotion2-AABBCCDDEEFF).

Device ID można znaleźć:

  • Na etykiecie urządzenia (adres MAC)
  • W interfejsie webowym Shelly: SettingsDevice Info
  • Przez API: GET http://<device-ip>/settings → pole device.hostname
Konfiguracja szablonu

Po zaimportowaniu szablonu w TapHome:

  1. Otwórz moduł Shelly Motion 2 MQTT
  2. Ustaw MQTT Broker IP i Port (domyślnie 1883)
  3. Dla każdej instancji czujnika ustaw zmienną niestandardową sensorN_topic na Device ID odpowiedniego Shelly Motion 2 (np. shellymotion2-AABBCCDDEEFF)

Moduł subskrybuje shellies/#, a skrypty nasłuchujące filtrują wiadomości według skonfigurowanego prefiksu topiku.

Konfiguruj tylko te sloty czujników, których faktycznie używasz. Nieskonfigurowane sloty (z domyślną wartością shellymotion2-deviceid) wyświetlą komunikat błędu wzywający do ustawienia prawidłowego topiku.

Ustawienia czujnika ruchu

Shelly Motion 2 ma kilka konfigurowalnych parametrów wpływających na zachowanie detekcji. Konfiguruje się je bezpośrednio na urządzeniu przez jego interfejs webowy (http://<device-ip>/), nie przez TapHome:

ParametrZakresOpis
Czułość1–256Czułość wykrywania ruchu (niższa = bardziej czuły)
Czas ślepy1–1440 minMinuty ignorowania ruchu po wykryciu
Liczba impulsów1–4Kolejne ruchy wymagane do potwierdzenia
Tryb pracyANY / DARK / TWILIGHT / BRIGHTKiedy detekcja jest aktywna na podstawie oświetlenia otoczenia
Czas uśpienia0–86400 sOkresowy interwał wybudzenia w sekundach

Krótsze czasy uśpienia zwiększają aktualność danych, ale zmniejszają żywotność baterii. Domyślny interwał wybudzenia jest wystarczający dla większości przypadków użycia. Zdarzenia ruchu zawsze wywołują natychmiastowe wybudzenie niezależnie od timera uśpienia.

Możliwości urządzenia

Wykrywanie ruchu

Każda instancja czujnika jest mapowana jako urządzenie Reed Contact z możliwością „security" w TapHome. Stan ruchu jest parsowany z topiku shellies/<id>/info — konkretnie pole $.sensor.motion w payloadzie JSON:

  • trueAlarm (wykryto ruch)
  • falseOK (brak ruchu)

Czujnik budzi się i publikuje swój stan po wykryciu ruchu (zgodnie z ustawieniami czułości, czasu ślepego i liczby impulsów), a także podczas okresowych interwałów wybudzenia.

Atrybuty serwisowe

Każda instancja czujnika udostępnia 14 atrybutów serwisowych na poziomie urządzenia, wszystkie parsowane z payloadu JSON /info:

AtrybutPole źródłoweOpis
Adres IP$.wifi_sta.ipAdres IP Wi-Fi czujnika
Adres MAC$.macSprzętowy adres MAC
Bateria$.bat.voltage, $.bat.valueNapięcie i procent baterii (np. 3,83V (97%))
Sygnał$.wifi_sta.rssiSiła sygnału Wi-Fi w dB
Cloud włączony$.cloud.enabledCzy Shelly Cloud jest włączony
Połączony z cloudem$.cloud.connectedCzy urządzenie jest połączone z Shelly Cloud
Czas urządzenia$.timeBieżący czas na urządzeniu
Natężenie oświetlenia$.lux.valuePoziom oświetlenia otoczenia w luksach
Temperatura$.tmp.value, $.tmp.unitsWewnętrzny odczyt temperatury
Czas pracy$.uptimeCzas od ostatniego restartu
Wersja FW$.fw_info.fwAktualna wersja firmware
Aktualizacja FW$.update.has_updateCzy dostępna jest aktualizacja firmware
Wolna RAM$.ram_total, $.ram_freeDostępna pamięć
Wolne miejsce FS$.fs_size, $.fs_freeDostępna przestrzeń systemu plików

Ostrzeżenie o niskim poziomie baterii jest automatycznie wywoływane, gdy poziom baterii spadnie poniżej 20%.

Dodatkowe możliwości (niezaimplementowane)

Shelly Motion 2 publikuje również wykrywanie wibracji/ingerencji ($.sensor.vibration, konfigurowalna czułość 0–80), kategorię oświetlenia ($.lux.illumination — dark/twilight/bright) oraz stan ładowarki USB ($.charger) przez payload JSON /info. Status online/offline jest dostępny przez topik LWT (shellies/<id>/online). Te możliwości są dostępne w wyjściu MQTT urządzenia, ale nie są mapowane w bieżącym szablonie TapHome. Mogą zostać dodane w przyszłej aktualizacji szablonu.

Rozwiązywanie problemów

Czujnik nie raportuje danych
  1. Sprawdź, czy Shelly Motion 2 jest połączony z Wi-Fi i MQTT jest włączone w ustawieniach urządzenia
  2. Sprawdź, czy zmienna niestandardowa sensorN_topic dokładnie odpowiada Device ID (np. shellymotion2-AABBCCDDEEFF)
  3. Użyj klienta MQTT (np. MQTT Explorer) do subskrypcji shellies/# i sprawdź, czy czujnik publikuje wiadomości przy wybudzeniu
  4. Motion 2 jest zasilany bateryjnie i publikuje dane tylko przy wybudzeniu — wywołaj zdarzenie ruchu, aby wymusić wybudzenie
Stan ruchu nie aktualizuje się
  1. Sprawdź, czy soczewka czujnika PIR nie jest zasłonięta i czujnik jest zamontowany na zalecanej wysokości (1,8–2,5 m)
  2. Jeśli czujnik został niedawno zainstalowany, sprawdź ustawienia czułości i czasu ślepego w interfejsie webowym urządzenia — wysoki czas ślepy oznacza, że czujnik ignoruje ruch przez dłuższy okres po każdym wykryciu
  3. Dostosuj liczbę impulsów, jeśli czujnik wyzwala się zbyt rzadko (niższa = mniej kolejnych ruchów wymaganych)
  4. Sprawdź w TapHome stan urządzenia Reed Contact — 1 = wykryto ruch (alarm), 0 = brak ruchu (OK)
Bateria szybko się rozładowuje
  1. Shelly Motion 2 używa wbudowanego akumulatora Li-ion (6500 mAh) ładowanego przez USB-C, z typowym aktywnym czasem pracy 12–18 miesięcy
  2. Częste wybudzenia z powodu wysokiej aktywności ruchu lub krótkich interwałów uśpienia szybciej rozładowują baterię
  3. Włączenie SSL na MQTT znacząco zmniejsza żywotność baterii — używaj zwykłego MQTT (port 1883) w zaufanej sieci lokalnej
  4. Zapewnij silny sygnał Wi-Fi w lokalizacji czujnika — słaby sygnał oznacza dłuższe czasy połączenia przy każdym wybudzeniu

Urządzenia Gen1 Shelly nie obsługują MQTT przez TLS bez znaczącego wpływu na baterię. Komunikacja między czujnikiem a brokerem MQTT jest zazwyczaj niezaszyfrowana (zwykły MQTT, port 1883). Upewnij się, że broker MQTT znajduje się w zaufanej sieci lokalnej.

Włączenie MQTT na urządzeniach Gen1 Shelly wyłącza łączność Cloud. MQTT i Cloud nie mogą współistnieć na tym samym urządzeniu.

Jak zainstalować w TapHome

Wymagania wstępne

  • Urządzenie Shelly połączone z Wi-Fi (jeśli jeszcze nie, zobacz przewodnik po połączeniu HTTP)
  • Broker MQTT działający w sieci lokalnej (np. Mosquitto, Home Assistant lub wbudowany broker TapHome)
  • TapHome CCU w tej samej sieci co broker

Na urządzeniach Gen1 włączenie MQTT wyłącza Shelly Cloud. Oba nie mogą działać jednocześnie. Na urządzeniach Gen2/Plus to ograniczenie nie obowiązuje.

Krok 1 — Włącz MQTT na urządzeniu Shelly

Urządzenia Gen1 (Shelly 1, 1PM, 2.5, EM, 3EM, Plug S, RGBW2, Dimmer, TRV…)

  1. Otwórz interfejs webowy Shelly: http://<device-ip>/
  2. Przejdź do Internet & SecurityAdvanced — MQTT
  3. Włącz MQTT
  4. Ustaw MQTT Server: <broker-ip>:<port> (np. 192.168.1.10:1883)
  5. Opcjonalnie ustaw MQTT User i MQTT Password, jeśli broker wymaga uwierzytelniania
  6. Kliknij Save — urządzenie zrestartuje się i połączy z brokerem

Urządzenia Gen2 / Plus (Shelly Plus 1, Plus 1PM, Plus 2PM, Plus Plug S, Plus H&T, Pro 3EM…)

  1. Otwórz interfejs webowy Shelly: http://<device-ip>/
  2. Przejdź do SettingsMQTT
  3. Włącz MQTT
  4. Ustaw Server: <broker-ip>:<port> (np. 192.168.1.10:1883)
  5. Client ID jest wstępnie wypełnione identyfikatorem urządzenia (np. shellyplus1pm-AABBCCDDEE) — pozostaw bez zmian, chyba że masz konkretny powód do zmiany
  6. Kliknij Save i zrestartuj urządzenie

Aby sprawdzić, czy MQTT działa, użyj klienta MQTT (np. MQTT Explorer) i zasubskrybuj shellies/# (Gen1) lub <device-id>/# (Gen2). Powinieneś zobaczyć komunikaty o stanie z urządzenia.

Krok 2 — Znajdź Device ID / MQTT Client ID

Niektóre szablony wymagają parametru Device ID lub MQTT Client ID. Jest to unikalny identyfikator używany w topikach MQTT.

  • Gen1: znajduje się na etykiecie jako adres MAC (np. AABBCCDDEE). Device ID = shelly<model>-<mac>, np. shelly1pm-AABBCCDDEE
  • Gen2/Plus: znajduje się w interfejsie webowym Shelly w sekcji SettingsDevice InfoDevice ID lub na etykiecie urządzenia

Krok 3 — Konfiguracja w TapHome

  1. W TapHome dodaj nowy moduł Packet Parser (MQTT)
  2. IP Address: wprowadź adres IP brokera MQTT (np. 192.168.1.10)
  3. Port: 1883 (domyślny; użyj 8883 dla TLS)
  4. Device ID / MQTT Client ID: wprowadź wartość z kroku 2 (jeśli wymagane przez szablon)
  5. Zaimportuj szablon — TapHome automatycznie zasubskrybuje topiki urządzenia

Dostępne urządzenia

Shelly Motion 2 MQTT Moduł
Zmienne niestandardowe
sensor1_topic (string) = shellymotion2-deviceidIdentyfikator MQTT czujnika ruchu 1 — format: 'shellymotion2-DEVICEID' (w interfejsie webowym Shelly → Settings → Device Info)
Open http://shellyIpAddress → Settings → Device info → copy Device ID. Format: shellymotion2-<last6MAC>
sensor2_topic (string) = shellymotion2-deviceidIdentyfikator MQTT czujnika ruchu 2
sensor3_topic (string) = shellymotion2-deviceidIdentyfikator MQTT czujnika ruchu 3
sensor4_topic (string) = shellymotion2-deviceidIdentyfikator MQTT czujnika ruchu 4
sensor5_topic (string) = shellymotion2-deviceidIdentyfikator MQTT czujnika ruchu 5
Czujnik ruchu 1 Kontakt reed Tylko do odczytu

Detekcja ruchu PIR — zgłasza alarm przy wykryciu ruchu, OK bez ruchu; parsuje $.sensor.motion z payloadu JSON /info

boolean
Atrybuty serwisowe
Adres IP
Adres MAC
Bateria
Sygnał
Cloud włączony
Połączony z chmurą
Czas urządzenia
Natężenie oświetlenia
Temperatura
Czas pracy
Wersja FW
Aktualizacja FW
Wolna RAM
Wolne miejsce FS

Czujnik ruchu 1

Nasłuchiwanie
IF (INDEXOF(sensor1_topic, "shellymotion2-deviceid") = 0)
    ADDERROR("Set correct 'sensor1_topic' value in module variables. Topic format is 'shellymotion2-<deviceid>'. The Device ID can be found by opening url 'http://shellyIpAddress', in Settings -> Device info.");
    RETURN(-1);
END

VAR topicPrefix := "shellies/" + sensor1_topic;

IF (INDEXOF(RECEIVEDMSG.TOPIC, topicPrefix + "/info") = 0)
    BOOL status := PARSEJSON(RECEIVEDMSG.PAYLOAD, "$.sensor.motion", 1);
    
    IF ISNULL(status)
        Rc := NaN;
    ELSE
        Rc := status;
    END
    
    VAR battery := PARSEJSON(RECEIVEDMSG.PAYLOAD, "$.bat.value");
    IF battery < 20
        ADDWARNING("Battery low (" + battery + "%)");
    END
END
Atrybuty serwisowe
IP Address
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.wifi_sta.ip"));
END
MAC Address
IF(LENGTH(infoJson) = 0, "-", PARSEJSON(infoJson, "$.mac"));

IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.mac"));
END
Battery
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    VAR voltage := PARSEJSON(infoJson, "$.bat.voltage");
    VAR percentage := PARSEJSON(infoJson, "$.bat.value");

    RETURN(voltage + "V (" + percentage + "%)");
END
Signal
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.wifi_sta.rssi", 1) + "db");
END
Cloud enabled
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.cloud.enabled"));
END
Cloud connected
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.cloud.connected"));
END
Device time
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.time"));
END
Luminance
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.lux.value", 1) + "lux");
END
Temperature
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.tmp.value", 1) + PARSEJSON(infoJson, "$.tmp.units", 1));
END
Uptime
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    VAR upTimeSeconds := PARSEJSON(infoJson, "$.uptime", 1);
    VAR days := FLOOR(upTimeSeconds/86400, 1);
    uptimeSeconds := MOD(upTimeSeconds, 86400);
    var hours := FLOOR(upTimeSeconds/3600, 1);
    uptimeSeconds := MOD(upTimeSeconds, 3600);
    var minutes := FLOOR(upTimeSeconds/60, 1);
    RETURN(days + "day(s) " + hours + "h " + minutes + "m");
END
FW version
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.fw_info.fw"));
END
FW update
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.update.has_update", 1));
END
Free RAM
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    VAR total := PARSEJSON(infoJson, "$.ram_total");
    VAR free := PARSEJSON(infoJson, "$.ram_free");
    RETURN(free + "/" + total + "(B)");
END
Free FS space
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    VAR total := PARSEJSON(infoJson, "$.fs_size");
    VAR free := PARSEJSON(infoJson, "$.fs_free");
    RETURN(free + "/" + total + "(B)");
END
Czujnik ruchu 2 Kontakt reed Tylko do odczytu

Detekcja ruchu PIR — zgłasza alarm przy wykryciu ruchu, OK bez ruchu; parsuje $.sensor.motion z payloadu JSON /info

boolean
Atrybuty serwisowe
Adres IP
Adres MAC
Bateria
Sygnał
Cloud włączony
Połączony z chmurą
Czas urządzenia
Natężenie oświetlenia
Temperatura
Czas pracy
Wersja FW
Aktualizacja FW
Wolna RAM
Wolne miejsce FS

Czujnik ruchu 2

Nasłuchiwanie
IF (INDEXOF(sensor2_topic, "shellymotion2-deviceid") = 0)
    ADDERROR("Set correct 'sensor2_topic' value in module variables. Topic format is 'shellymotion2-<deviceid>'. The Device ID can be found by opening url 'http://shellyIpAddress', in Settings -> Device info.");
    RETURN(-1);
END

VAR topicPrefix := "shellies/" + sensor2_topic;

IF (INDEXOF(RECEIVEDMSG.TOPIC, topicPrefix + "/info") = 0)
    BOOL status := PARSEJSON(RECEIVEDMSG.PAYLOAD, "$.sensor.motion", 1);
    
    IF ISNULL(status)
        Rc := NaN;
    ELSE
        Rc := status;
    END
    
    VAR battery := PARSEJSON(RECEIVEDMSG.PAYLOAD, "$.bat.value");
    IF battery < 20
        ADDWARNING("Battery low (" + battery + "%)");
    END
END
Atrybuty serwisowe
IP Address
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.wifi_sta.ip"));
END
MAC Address
IF(LENGTH(infoJson) = 0, "-", PARSEJSON(infoJson, "$.mac"));

IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.mac"));
END
Battery
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    VAR voltage := PARSEJSON(infoJson, "$.bat.voltage");
    VAR percentage := PARSEJSON(infoJson, "$.bat.value");

    RETURN(voltage + "V (" + percentage + "%)");
END
Signal
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.wifi_sta.rssi", 1) + "db");
END
Cloud enabled
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.cloud.enabled"));
END
Cloud connected
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.cloud.connected"));
END
Device time
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.time"));
END
Luminance
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.lux.value", 1) + "lux");
END
Temperature
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.tmp.value", 1) + PARSEJSON(infoJson, "$.tmp.units", 1));
END
Uptime
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    VAR upTimeSeconds := PARSEJSON(infoJson, "$.uptime", 1);
    VAR days := FLOOR(upTimeSeconds/86400, 1);
    uptimeSeconds := MOD(upTimeSeconds, 86400);
    var hours := FLOOR(upTimeSeconds/3600, 1);
    uptimeSeconds := MOD(upTimeSeconds, 3600);
    var minutes := FLOOR(upTimeSeconds/60, 1);
    RETURN(days + "day(s) " + hours + "h " + minutes + "m");
END
FW version
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.fw_info.fw"));
END
FW update
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.update.has_update", 1));
END
Free RAM
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    VAR total := PARSEJSON(infoJson, "$.ram_total");
    VAR free := PARSEJSON(infoJson, "$.ram_free");
    RETURN(free + "/" + total + "(B)");
END
Free FS space
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    VAR total := PARSEJSON(infoJson, "$.fs_size");
    VAR free := PARSEJSON(infoJson, "$.fs_free");
    RETURN(free + "/" + total + "(B)");
END
Czujnik ruchu 3 Kontakt reed Tylko do odczytu

Detekcja ruchu PIR — zgłasza alarm przy wykryciu ruchu, OK bez ruchu; parsuje $.sensor.motion z payloadu JSON /info

boolean
Atrybuty serwisowe
Adres IP
Adres MAC
Bateria
Sygnał
Cloud włączony
Połączony z chmurą
Czas urządzenia
Natężenie oświetlenia
Temperatura
Czas pracy
Wersja FW
Aktualizacja FW
Wolna RAM
Wolne miejsce FS

Czujnik ruchu 3

Nasłuchiwanie
IF (INDEXOF(sensor3_topic, "shellymotion2-deviceid") = 0)
    ADDERROR("Set correct 'sensor3_topic' value in module variables. Topic format is 'shellymotion2-<deviceid>'. The Device ID can be found by opening url 'http://shellyIpAddress', in Settings -> Device info.");
    RETURN(-1);
END

VAR topicPrefix := "shellies/" + sensor3_topic;

IF (INDEXOF(RECEIVEDMSG.TOPIC, topicPrefix + "/info") = 0)
    BOOL status := PARSEJSON(RECEIVEDMSG.PAYLOAD, "$.sensor.motion", 1);
    
    IF ISNULL(status)
        Rc := NaN;
    ELSE
        Rc := status;
    END
    
    VAR battery := PARSEJSON(RECEIVEDMSG.PAYLOAD, "$.bat.value");
    IF battery < 20
        ADDWARNING("Battery low (" + battery + "%)");
    END
END
Atrybuty serwisowe
IP Address
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.wifi_sta.ip"));
END
MAC Address
IF(LENGTH(infoJson) = 0, "-", PARSEJSON(infoJson, "$.mac"));

IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.mac"));
END
Battery
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    VAR voltage := PARSEJSON(infoJson, "$.bat.voltage");
    VAR percentage := PARSEJSON(infoJson, "$.bat.value");

    RETURN(voltage + "V (" + percentage + "%)");
END
Signal
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.wifi_sta.rssi", 1) + "db");
END
Cloud enabled
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.cloud.enabled"));
END
Cloud connected
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.cloud.connected"));
END
Device time
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.time"));
END
Luminance
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.lux.value", 1) + "lux");
END
Temperature
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.tmp.value", 1) + PARSEJSON(infoJson, "$.tmp.units", 1));
END
Uptime
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    VAR upTimeSeconds := PARSEJSON(infoJson, "$.uptime", 1);
    VAR days := FLOOR(upTimeSeconds/86400, 1);
    uptimeSeconds := MOD(upTimeSeconds, 86400);
    var hours := FLOOR(upTimeSeconds/3600, 1);
    uptimeSeconds := MOD(upTimeSeconds, 3600);
    var minutes := FLOOR(upTimeSeconds/60, 1);
    RETURN(days + "day(s) " + hours + "h " + minutes + "m");
END
FW version
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.fw_info.fw"));
END
FW update
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.update.has_update", 1));
END
Free RAM
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    VAR total := PARSEJSON(infoJson, "$.ram_total");
    VAR free := PARSEJSON(infoJson, "$.ram_free");
    RETURN(free + "/" + total + "(B)");
END
Free FS space
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    VAR total := PARSEJSON(infoJson, "$.fs_size");
    VAR free := PARSEJSON(infoJson, "$.fs_free");
    RETURN(free + "/" + total + "(B)");
END
Czujnik ruchu 4 Kontakt reed Tylko do odczytu

Detekcja ruchu PIR — zgłasza alarm przy wykryciu ruchu, OK bez ruchu; parsuje $.sensor.motion z payloadu JSON /info

boolean
Atrybuty serwisowe
Adres IP
Adres MAC
Bateria
Sygnał
Cloud włączony
Połączony z chmurą
Czas urządzenia
Natężenie oświetlenia
Temperatura
Czas pracy
Wersja FW
Aktualizacja FW
Wolna RAM
Wolne miejsce FS

Czujnik ruchu 4

Nasłuchiwanie
IF (INDEXOF(sensor4_topic, "shellymotion2-deviceid") = 0)
    ADDERROR("Set correct 'sensor4_topic' value in module variables. Topic format is 'shellymotion2-<deviceid>'. The Device ID can be found by opening url 'http://shellyIpAddress', in Settings -> Device info.");
    RETURN(-1);
END

VAR topicPrefix := "shellies/" + sensor4_topic;

IF (INDEXOF(RECEIVEDMSG.TOPIC, topicPrefix + "/info") = 0)
    BOOL status := PARSEJSON(RECEIVEDMSG.PAYLOAD, "$.sensor.motion", 1);
    
    IF ISNULL(status)
        Rc := NaN;
    ELSE
        Rc := status;
    END
    
    VAR battery := PARSEJSON(RECEIVEDMSG.PAYLOAD, "$.bat.value");
    IF battery < 20
        ADDWARNING("Battery low (" + battery + "%)");
    END
END
Atrybuty serwisowe
IP Address
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.wifi_sta.ip"));
END
MAC Address
IF(LENGTH(infoJson) = 0, "-", PARSEJSON(infoJson, "$.mac"));

IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.mac"));
END
Battery
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    VAR voltage := PARSEJSON(infoJson, "$.bat.voltage");
    VAR percentage := PARSEJSON(infoJson, "$.bat.value");

    RETURN(voltage + "V (" + percentage + "%)");
END
Signal
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.wifi_sta.rssi", 1) + "db");
END
Cloud enabled
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.cloud.enabled"));
END
Cloud connected
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.cloud.connected"));
END
Device time
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.time"));
END
Luminance
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.lux.value", 1) + "lux");
END
Temperature
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.tmp.value", 1) + PARSEJSON(infoJson, "$.tmp.units", 1));
END
Uptime
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    VAR upTimeSeconds := PARSEJSON(infoJson, "$.uptime", 1);
    VAR days := FLOOR(upTimeSeconds/86400, 1);
    uptimeSeconds := MOD(upTimeSeconds, 86400);
    var hours := FLOOR(upTimeSeconds/3600, 1);
    uptimeSeconds := MOD(upTimeSeconds, 3600);
    var minutes := FLOOR(upTimeSeconds/60, 1);
    RETURN(days + "day(s) " + hours + "h " + minutes + "m");
END
FW version
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.fw_info.fw"));
END
FW update
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.update.has_update", 1));
END
Free RAM
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    VAR total := PARSEJSON(infoJson, "$.ram_total");
    VAR free := PARSEJSON(infoJson, "$.ram_free");
    RETURN(free + "/" + total + "(B)");
END
Free FS space
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    VAR total := PARSEJSON(infoJson, "$.fs_size");
    VAR free := PARSEJSON(infoJson, "$.fs_free");
    RETURN(free + "/" + total + "(B)");
END
Czujnik ruchu 5 Kontakt reed Tylko do odczytu

Detekcja ruchu PIR — zgłasza alarm przy wykryciu ruchu, OK bez ruchu; parsuje $.sensor.motion z payloadu JSON /info

boolean
Atrybuty serwisowe
Adres IP
Adres MAC
Bateria
Sygnał
Cloud włączony
Połączony z chmurą
Czas urządzenia
Natężenie oświetlenia
Temperatura
Czas pracy
Wersja FW
Aktualizacja FW
Wolna RAM
Wolne miejsce FS

Czujnik ruchu 5

Nasłuchiwanie
IF (INDEXOF(sensor5_topic, "shellymotion2-deviceid") = 0)
    ADDERROR("Set correct 'sensor5_topic' value in module variables. Topic format is 'shellymotion2-<deviceid>'. The Device ID can be found by opening url 'http://shellyIpAddress', in Settings -> Device info.");
    RETURN(-1);
END

VAR topicPrefix := "shellies/" + sensor5_topic;

IF (INDEXOF(RECEIVEDMSG.TOPIC, topicPrefix + "/info") = 0)
    BOOL status := PARSEJSON(RECEIVEDMSG.PAYLOAD, "$.sensor.motion", 1);
    
    IF ISNULL(status)
        Rc := NaN;
    ELSE
        Rc := status;
    END
    
    VAR battery := PARSEJSON(RECEIVEDMSG.PAYLOAD, "$.bat.value");
    IF battery < 20
        ADDWARNING("Battery low (" + battery + "%)");
    END
END
Atrybuty serwisowe
IP Address
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.wifi_sta.ip"));
END
MAC Address
IF(LENGTH(infoJson) = 0, "-", PARSEJSON(infoJson, "$.mac"));

IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.mac"));
END
Battery
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    VAR voltage := PARSEJSON(infoJson, "$.bat.voltage");
    VAR percentage := PARSEJSON(infoJson, "$.bat.value");

    RETURN(voltage + "V (" + percentage + "%)");
END
Signal
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.wifi_sta.rssi", 1) + "db");
END
Cloud enabled
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.cloud.enabled"));
END
Cloud connected
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.cloud.connected"));
END
Device time
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.time"));
END
Luminance
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.lux.value", 1) + "lux");
END
Temperature
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.tmp.value", 1) + PARSEJSON(infoJson, "$.tmp.units", 1));
END
Uptime
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    VAR upTimeSeconds := PARSEJSON(infoJson, "$.uptime", 1);
    VAR days := FLOOR(upTimeSeconds/86400, 1);
    uptimeSeconds := MOD(upTimeSeconds, 86400);
    var hours := FLOOR(upTimeSeconds/3600, 1);
    uptimeSeconds := MOD(upTimeSeconds, 3600);
    var minutes := FLOOR(upTimeSeconds/60, 1);
    RETURN(days + "day(s) " + hours + "h " + minutes + "m");
END
FW version
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.fw_info.fw"));
END
FW update
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    RETURN(PARSEJSON(infoJson, "$.update.has_update", 1));
END
Free RAM
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    VAR total := PARSEJSON(infoJson, "$.ram_total");
    VAR free := PARSEJSON(infoJson, "$.ram_free");
    RETURN(free + "/" + total + "(B)");
END
Free FS space
IF LENGTH(infoJson) = 0
    RETURN("-");
ELSE
    VAR total := PARSEJSON(infoJson, "$.fs_size");
    VAR free := PARSEJSON(infoJson, "$.fs_free");
    RETURN(free + "/" + total + "(B)");
END
Połączenie: Packet Parser → MQTT
Możliwe ulepszenia (4)
  • Vibration / Tamper Detection — Vibration/tamper detection (bool). Available in the /info JSON but not parsed by the listener script. Configurable sensitivity 0-80.
  • Illumination Category — Light category string — dark/twilight/bright. Available in /info but only numeric lux is parsed via service attributes.
  • USB Charger Connected — Whether USB-C charger is plugged in. Available in /info JSON.
  • Connection Status — LWT topic — true on connect, false on disconnect. Could detect offline sensors.

Źródła