[Flow] Powiadomienia dla przesyłek (polish_shipment_tracking)

//mod-edit posty zostały przeniesone z wątku Karta z śledzeniem paczek (Polish Shipment Tracking)
@stirante Dziękuję za szybką reakcję :slight_smile: Integracja działa bardzo ok.


Przetestowana dziś rano z powiadomieniem

Wrzuć może flow dla innych. Szybko będe mógł wkleić. Przyda się każdemu

Nie widzę problemu, tylko czy mieszanie w tym wątku będzie zasadne ?
Flow jest spersonalizowany pod telegram bot , czyli trzeba w NR doinstalować

Sam proces jest dość prosty, na podstawie atrybutów czujnika z integracji tworzymy wiadomość i ewentualnie dodajemy przypominanie
flows.json (3,7 KB)

Właśnie o to mi chodziło jeśli ktoś będzie chciał sobie takie coś zrobić to będzie miał już przygotowane. Wydaje mi się że to jest odpowiednie miejsce o to chyba w tym chodzi aby dzielić się rozwiązaniami.

Skorzystałem z Flow autora, dziękuję za udostępnienie.
Proszę o informację którą encję należy wpisać w pierwszym (początkowym) nodzie - state node.

Do events state podstawiasz encję sensora utworzonego przez integrację, o której mowa.
Jest jednak mały problem, po odebraniu przesyłki encja pozostaje w systemie tylko jakiś czas , potem zostaje usunięta, więc ten flow przestaje mieć większy sens. Muszę to przemyśleć i sprawdzić czy mogę to jakoś przerobić.

Właśnie te encje tworzą się dopiero w momencie utworzenia przesyłki i jest w niej zawarty nr paczki.
Gdy w danej chwili nie ma żadnych przesyłek utworzonych integracja nie wystawia również encji, które można byłoby wykorzystać w nodzie events state.

Integracja jest w fazie wstępnego rozwoju i już autor z pomocą @Allon dodaje czujnik binarny, który będzie bardzo pomocny. Oczywiście flow będzie do przeróbki i trzeba się uzbroić w cierpliwość

Nie zdążyłem więc zasługa dodania dla autora, ale poprawiłem pare błędów które mogły by przeszkadzać.

Jasna sprawa, muszę przyznać, że w moim przypadku jest bardzo przydatna integracja :+1:

Przyznam że sam miałem robić nawet baze wszystkich integracji do śledzenia przesyłek a w szczególności inpostu, ale widzę że nie muszę

Panowie, podrzućcie proszę Flow umożliwiający wysyłanie wiadomości w momencie gdy przesyłka jest gotowa do odbioru.
Same powiadomienia zrobię za pomocą SMS, bo mam modem GSM zintegrowany z HA i tu sobie poradzę.

Ponieważ nie jestem w stanie wydobyć informacji do NR o paczkach z HA , ani przez get entites, ani events all, podszedłem do tematu trochę inaczej, może to się komuś nie podobać, ale nie jestem specem od NR i naprawdę mimo prób z czujnikiem “Aktywne przesyłki” czyli zmiana stanu na inny niż 0, potem opóźnienie kilka sekund i próby filtrowania z wszystkich encji nic nie wskórałem. Postanowiłem wykorzystać brokera mqtt do publikowania tablicy przesyłek i to robię automatyzacją w HA.
Automatyzacja to cykliczna co 5 min publikacja “sprawdzająca” po domenie ‘polish_shipment_tracking’.
Wszystkie informacje można podejrzeć w mqtt explorer, temat to paczki/aktualizacja.
W samym HA to już wszystko, a kod automatyzacji wstawiam poniżej.
Nie korzystam z czujnika stanu przesyłek, który zawsze jest dostępny w integracji.

alias: Paczki → MQTT (polling)
triggers:
  - minutes: /5
    trigger: time_pattern
actions:
  - variables:
      paczki: |
        {{
          states.sensor
          | selectattr('attributes.integration_domain','eq','polish_shipment_tracking')
          | map(attribute='attributes')
          | list
        }}
  - data:
      topic: paczki/aktualizacja
      payload: "{{ paczki | tojson }}"
    action: mqtt.publish
mode: single

W NR za pomocą noda mqtt-in subskrybuję jeden temat i dzięki temu mam informację o wszystkich przesyłkach lub ich braku.
Dalej flow “rozbija” tablicę na pojedyncze widomości rozróżniając paczki po numerze i aktualnym statusie, wysyła powiadomienie dla każdej paczki osobno tylko wtedy gdy jest gotowa do odbioru.
Dodatkowo jest przypominanie o nieodebranej przesyłce co 8h resetowane po odebraniu.
Tworzenie wiadomości jest typowo pod telegram bot, ostatnia funkcja.
Jak ktoś potrafi zrobić to bez udziału automatyzacji, to sam chętnie skorzystam.


A tu do pobrania i uzupełnienia o dane brokera i bota
telegram.json (3,0 KB)

Nie jestem w to dobry ale dodałem custom eventy. Może to pomoże?

Integracja publikuje zdarzenia na magistrali hass.bus:

  • polish_shipment_tracking_new_shipment - nowa przesyłka

  • polish_shipment_tracking_shipment_status_changed - przesyłka zmieniła stan

Przykładowy payload:


{

"courier": "inpost",

"shipment_id": "1234567890",

"entity_id": "sensor.inpost_paczka_1234567890",

"status_raw": "in_transit",

"status_key": "in_transport"

}

Dla polish_shipment_tracking_shipment_status_changed dodatkowo występują pola:

  • old_status_raw

  • old_status_key

  • new_status_raw

  • new_status_key

1 Like

Witajcie, ja to zrobiłem w ten sposób

Pierwszy nod: “Paczka”

wybieramy encję jako regex: i wpisujemy ^sensor.paczka_.*, system sam wyszukuje wszystkie encje sensor.paczka… i reaguje na zmianę ich statusu.

1 Like

Sprawdzałeś jak to się zachowa gdy jeszcze nie ma encji “sensor.paczka” ?
Czy pojawienie się encji uruchomi trigger ?

Tego nie wiem bo mam w aplikacji inpostu starą i nie aktywną już przesyłkę, która od razu wygenerowała encje. Nie wiem też jak zachowa się flow w wypadku multiskrytki, gdy będzie kilka przesyłek w jednej skrytce. W pojedynczych przesyłkach działa ale sprawdzone mam tylko z InPostu.

Mimo wszystko dzięki za pomysł, analizując teoretycznie samo pojawienie się sensora może jeszcze nie wywołać akcji, ale zmiana stanu z utworzona , na w transporcie, powinno już wyzwolić trigger :slight_smile:
Będę to testował . Dzięki

Nie da się w NR nasłuchiwać na custom eventy? Specjalnie zrobiłem custom event na pojawienie się paczki jako sensora oraz zmianę jego statusu żeby nie trzeba było się męczyć z tym. Szybkie wyszukiwanie mówi że to może pomóc: First Automation | node-red-contrib-home-assistant-websocket

Działa wszystko w 100% mój flow poniżej jakby ktoś chciał skorzystać

[
    {
        "id": "7a244de00b607592",
        "type": "switch",
        "z": "a57403b63afbeda8",
        "name": "Status",
        "property": "payload",
        "propertyType": "msg",
        "rules": [
            {
                "t": "eq",
                "v": "created",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "in_transport",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "handed_out_for_delivery",
                "vt": "str"
            },
            {
                "t": "eq",
                "v": "waiting_for_pickup",
                "vt": "str"
            },
            {
                "t": "neq",
                "v": "waiting_for_pickup",
                "vt": "str"
            }
        ],
        "repair": false,
        "outputs": 5,
        "x": 310,
        "y": 4100,
        "wires": [
            [
                "ad42ce02d91bc9eb"
            ],
            [
                "34d81518c2434068"
            ],
            [
                "9d73f74b5459cc3a"
            ],
            [
                "d5e9daf6a25d95db",
                "f92790e2943119ba"
            ],
            [
                "47efefa6d5cd8e9c"
            ]
        ]
    },
    {
        "id": "d5e9daf6a25d95db",
        "type": "function",
        "z": "a57403b63afbeda8",
        "name": "Wiadomość - waiting_for_pickup",
        "func": "const attr = msg.data?.new_state?.attributes;\nif (!attr) return null;\n\n// --------- LOKALIZACJA ---------\nconst location = attr.location ?? \"W doręczeniu przez kuriera\";\n\n// --------- NADAWCA (dynamiczny) ---------\nlet sender = attr.sender;\n\n// jeśli brak sender, szukamy dowolnego klucza zaczynającego się od \"sender\"\nif (!sender) {\n    const senderKey = Object.keys(attr).find(k =>\n        k.toLowerCase().startsWith(\"sender\")\n    );\n    sender = senderKey ? attr[senderKey] : \"Nieznany nadawca\";\n}\n\n// --------- WIADOMOŚĆ ---------\nconst text = `📦 *Paczka gotowa do odbioru*\n🚚 Kurier: ${attr.courier ?? \"Brak danych\"}\n📨 Nadawca: ${sender}\n🔢 Numer: ${attr.tracking_number ?? \"Brak numeru\"}\n📍 Lokalizacja: ${location}\n🔓 * Kod odbioru:* ${ attr.open_code }`;\n\nflow.set(\"paczka_text_1\", text);\n\nmsg.payload = {\n    type: \"message\",\n    chatId: \"0000000000\",\n    content: text,\n    options: {\n        parse_mode: \"Markdown\"\n    }\n};\n\nreturn msg;",
        "outputs": 1,
        "timeout": "",
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 670,
        "y": 4120,
        "wires": [
            [
                "77a73a98d592374e"
            ]
        ]
    },
    {
        "id": "f92790e2943119ba",
        "type": "trigger",
        "z": "a57403b63afbeda8",
        "name": "Przypomnienie co 12h",
        "op1": "",
        "op2": "remind",
        "op1type": "nul",
        "op2type": "str",
        "duration": "12",
        "extend": true,
        "overrideDelay": false,
        "units": "hr",
        "reset": "",
        "bytopic": "all",
        "topic": "paczka",
        "outputs": 1,
        "x": 640,
        "y": 4160,
        "wires": [
            [
                "9f7211778077fb4e"
            ]
        ]
    },
    {
        "id": "9f7211778077fb4e",
        "type": "function",
        "z": "a57403b63afbeda8",
        "name": "Przypomnienia",
        "func": "const base = flow.get(\"paczka_text\");\nif (!base) return null;\n\nmsg.payload = {\n    type: \"message\",\n    \"chatId\": \"0000000000\", // tu podaj swój chatID\n    content: `⏰ *Przypomnienie*\\n\\n${base}`,\n    options: {\n        parse_mode: \"Markdown\"\n    }\n};\n\nreturn msg;\n",
        "outputs": 1,
        "timeout": "",
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 860,
        "y": 4160,
        "wires": [
            [
                "77a73a98d592374e"
            ]
        ]
    },
    {
        "id": "47efefa6d5cd8e9c",
        "type": "trigger",
        "z": "a57403b63afbeda8",
        "name": "Stop przypomnień",
        "op1": "",
        "op2": "",
        "op1type": "nul",
        "op2type": "nul",
        "duration": "0",
        "extend": false,
        "overrideDelay": false,
        "units": "second",
        "reset": "true",
        "bytopic": "all",
        "topic": "paczka",
        "outputs": 1,
        "x": 630,
        "y": 4200,
        "wires": [
            []
        ]
    },
    {
        "id": "77a73a98d592374e",
        "type": "telegram sender",
        "z": "a57403b63afbeda8",
        "name": "Telegram",
        "bot": "19ff4b39bf671e48",
        "haserroroutput": false,
        "outputs": 1,
        "x": 1100,
        "y": 4060,
        "wires": [
            []
        ]
    },
    {
        "id": "6d27e8b391623a90",
        "type": "server-state-changed",
        "z": "a57403b63afbeda8",
        "name": "Paczka",
        "server": "42e1a8c4.ec01f8",
        "version": 6,
        "outputs": 1,
        "exposeAsEntityConfig": "",
        "entities": {
            "entity": [],
            "substring": [],
            "regex": [
                "^sensor\\.paczka_.*",
                "^sensor\\.inpost_.*",
                "^sensor\\.pocztex_.*"
            ]
        },
        "outputInitially": true,
        "stateType": "str",
        "ifState": "",
        "ifStateType": "str",
        "ifStateOperator": "is",
        "outputOnlyOnStateChange": true,
        "for": "0",
        "forType": "num",
        "forUnits": "minutes",
        "ignorePrevStateNull": false,
        "ignorePrevStateUnknown": false,
        "ignorePrevStateUnavailable": false,
        "ignoreCurrentStateUnknown": false,
        "ignoreCurrentStateUnavailable": false,
        "outputProperties": [
            {
                "property": "payload",
                "propertyType": "msg",
                "value": "string",
                "valueType": "entityState"
            },
            {
                "property": "data",
                "propertyType": "msg",
                "value": "",
                "valueType": "eventData"
            },
            {
                "property": "topic",
                "propertyType": "msg",
                "value": "",
                "valueType": "triggerId"
            }
        ],
        "x": 90,
        "y": 4100,
        "wires": [
            [
                "7a244de00b607592"
            ]
        ]
    },
    {
        "id": "34d81518c2434068",
        "type": "function",
        "z": "a57403b63afbeda8",
        "name": "Wiadomość - in_transport",
        "func": "const attr = msg.data?.new_state?.attributes;\nif (!attr) return null;\n\n// --------- LOKALIZACJA ---------\nconst location = attr.location ?? \"W doręczeniu przez kuriera\";\n\n// --------- NADAWCA (dynamiczny) ---------\nlet sender = attr.sender;\n\n// jeśli brak sender, szukamy dowolnego klucza zaczynającego się od \"sender\"\nif (!sender) {\n    const senderKey = Object.keys(attr).find(k =>\n        k.toLowerCase().startsWith(\"sender\")\n    );\n    sender = senderKey ? attr[senderKey] : \"Nieznany nadawca\";\n}\n\n// --------- WIADOMOŚĆ ---------\nconst text = `📦 *Paczka już jedzie do Ciebie*\n🚚 Kurier: ${attr.courier ?? \"Brak danych\"}\n📨 Nadawca: ${sender}\n🔢 Numer: ${attr.tracking_number ?? \"Brak numeru\"}\n📍 Lokalizacja: ${location}`;\n\nflow.set(\"paczka_text_1\", text);\n\nmsg.payload = {\n    type: \"message\",\n    chatId: \"0000000000\",\n    content: text,\n    options: {\n        parse_mode: \"Markdown\"\n    }\n};\n\nreturn msg;",
        "outputs": 1,
        "timeout": "",
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 650,
        "y": 4040,
        "wires": [
            [
                "77a73a98d592374e"
            ]
        ]
    },
    {
        "id": "9d73f74b5459cc3a",
        "type": "function",
        "z": "a57403b63afbeda8",
        "name": "Wiadomość - handed_out_for_delivery",
        "func": "const attr = msg.data?.new_state?.attributes;\nif (!attr) return null;\n\n// --------- LOKALIZACJA ---------\nconst location = attr.location ?? \"W doręczeniu przez kuriera\";\n\n// --------- NADAWCA (dynamiczny) ---------\nlet sender = attr.sender;\n\n// jeśli brak sender, szukamy dowolnego klucza zaczynającego się od \"sender\"\nif (!sender) {\n    const senderKey = Object.keys(attr).find(k =>\n        k.toLowerCase().startsWith(\"sender\")\n    );\n    sender = senderKey ? attr[senderKey] : \"Nieznany nadawca\";\n}\n\n// --------- WIADOMOŚĆ ---------\nconst text = `📦 *Paczka została wydana do doręczenia*\n🚚 Kurier: ${attr.courier ?? \"Brak danych\"}\n📨 Nadawca: ${sender}\n🔢 Numer: ${attr.tracking_number ?? \"Brak numeru\"}\n📍 Lokalizacja: ${location}`;\n\nflow.set(\"paczka_text_1\", text);\n\nmsg.payload = {\n    type: \"message\",\n    chatId: \"0000000000\",\n    content: text,\n    options: {\n        parse_mode: \"Markdown\"\n    }\n};\n\nreturn msg;",
        "outputs": 1,
        "timeout": "",
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 690,
        "y": 4080,
        "wires": [
            [
                "77a73a98d592374e"
            ]
        ]
    },
    {
        "id": "ad42ce02d91bc9eb",
        "type": "function",
        "z": "a57403b63afbeda8",
        "name": "Wiadomość - created",
        "func": "const attr = msg.data?.new_state?.attributes;\nif (!attr) return null;\n\n// --------- LOKALIZACJA ---------\nconst location = attr.location ?? \"W doręczeniu przez kuriera\";\n\n// --------- NADAWCA (dynamiczny) ---------\nlet sender = attr.sender;\n\n// jeśli brak sender, szukamy dowolnego klucza zaczynającego się od \"sender\"\nif (!sender) {\n    const senderKey = Object.keys(attr).find(k =>\n        k.toLowerCase().startsWith(\"sender\")\n    );\n    sender = senderKey ? attr[senderKey] : \"Nieznany nadawca\";\n}\n\n// --------- WIADOMOŚĆ ---------\nconst text = `📦 *Sprzedawca wygenerował etykietę Twojej przesyłki*\n🚚 Kurier: ${attr.courier ?? \"Brak danych\"}\n📨 Nadawca: ${sender}\n🔢 Numer: ${attr.tracking_number ?? \"Brak numeru\"}\n📍 Lokalizacja: ${location}`;\n\nflow.set(\"paczka_text_1\", text);\n\nmsg.payload = {\n    type: \"message\",\n    chatId: \"0000000000\",\n    content: text,\n    options: {\n        parse_mode: \"Markdown\"\n    }\n};\n\nreturn msg;",
        "outputs": 1,
        "timeout": "",
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 640,
        "y": 4000,
        "wires": [
            [
                "77a73a98d592374e"
            ]
        ]
    },
    {
        "id": "19ff4b39bf671e48",
        "type": "telegram bot",
        "botname": "@botname",
        "usernames": "@usernames",
        "chatids": "",
        "baseapiurl": "",
        "testenvironment": false,
        "updatemode": "polling",
        "pollinterval": 300,
        "usesocks": false,
        "sockshost": "",
        "socksprotocol": "socks5",
        "socksport": 6667,
        "socksusername": "anonymous",
        "sockspassword": "",
        "bothost": "",
        "botpath": "",
        "localbothost": "0.0.0.0",
        "localbotport": 8443,
        "publicbotport": 8443,
        "privatekey": "",
        "certificate": "",
        "useselfsignedcertificate": false,
        "sslterminated": false,
        "verboselogging": false
    },
    {
        "id": "42e1a8c4.ec01f8",
        "type": "server",
        "name": "Home Assistant",
        "version": 6,
        "addon": true,
        "rejectUnauthorizedCerts": true,
        "ha_boolean": [
            "y",
            "yes",
            "true",
            "on",
            "home",
            "open"
        ],
        "connectionDelay": true,
        "cacheJson": true,
        "heartbeat": false,
        "heartbeatInterval": "30",
        "areaSelector": "friendlyName",
        "deviceSelector": "friendlyName",
        "entitySelector": "friendlyName",
        "statusSeparator": "at: ",
        "statusYear": "hidden",
        "statusMonth": "short",
        "statusDay": "numeric",
        "statusHourCycle": "h23",
        "statusTimeFormat": "h:m",
        "enableGlobalContextStore": true
    },
    {
        "id": "0561779cf8b2693d",
        "type": "global-config",
        "env": [],
        "modules": {
            "node-red-contrib-telegrambot": "17.0.5",
            "node-red-contrib-home-assistant-websocket": "0.80.3"
        }
    }
]