Kalendarz google pobieranie danych

Witajcie czy jest jakiś magiczny sposób aby HA a najlepiej node-red pobierał kompletne dane z kalendarza google. Nie tylko pierwsze wydarzenie z dnia ale i następne jak np robi to Atomic Calendar Revive, aby można było z konkretnego wydarzenia zrobić automatyzacje albo żeby w statusie porannym wykazywało wszystkie zaplanowane wydarzenia z dzisiaj, jutro, pojutrze.

ACR jest rozszerzeniem frontendu, więc z zasady nie pobiera niczego z kalendarze google, on korzysta z danych jakie HA już posiada.

Skoro posiada takie dane szczegółowe to dlaczego nie da się ich wyciągnąć ?

Jeśli rozszerzenie frontendu by pobierało samowolnie jakieś dane spoza backendu HA to byłoby złamanie podstawowych zasad konstrukcji HA (jako, że frontend jest renderowany w przeglądarce, a nie na serwerze HA).

Czyli, że nie ma takiej możliwości ?

Możliwości to zapewne są, ale poczekaj na kogoś kto intensywniej używa kalendarzy (swoją drogą jeśli dane potrzebujesz w NR i uważasz, że nie ma ich w HA to lepiej pobieraj z poziomu NR w końcu to 2 całkowicie osobne serwery które nie mają nic wspólnego).

1 polubienie

Jeżeli Atomic Calendar Revive pobierał by te dane z Google bez twojego zezwolenia od razu został by zablokowany. Zapytania dla kalendarza znajdziesz w Narzędzia deweloperskie → Akcje

calendar.get_events

https://www.home-assistant.io/docs/scripts/perform-actions/#use-templates-to-handle-response-data

Zakres pobierania danych start_date_time end_date_time

action: calendar.get_events
target:
  entity_id: calendar.school
data:
  duration:
    hours: 24
response_variable: agenda

Czy to jest normalne, że podając encje wszystkich kalendarzy i zakres danych w którym na 100% coś powinno być to i tak nic nie pokazuje w wyniku odpowiedzi akcji?

Powinno pokazywać, jednak jest pusto.

Tu masz template:

- trigger:
    - platform: homeassistant
      event: start

    - platform: event
      event_type: event_template_reloaded

    - platform: state
      entity_id: calendar.gp2023
  action:
    - service: calendar.get_events
      target:
        entity_id: calendar.gp2023
      data:
        duration:
          days: 2
      response_variable: agenda

    - variables:
        events: "{{ agenda['calendar.gp2023']['events'] }}"
  sensor:
    - name: "Nadchodzące wydarzenia"
      unique_id: nadchodzace_wydarzenia
      icon: mdi:calendar-star
      state: "{{ events | count }}"
      attributes:
        events: >
          {%- if events | count > 0 %}
            {%- for event in events %}
              {%- if (event.start | as_datetime).day == now().day %}
                {{ event.start | as_timestamp | timestamp_custom('Today at %-I:%M %p') }}: {{ event.summary }}
              {%- else %}
                {{ event.start | as_timestamp | timestamp_custom('%A at %-I:%M %p') }}: {{ event.summary }}
              {%- endif %}
              {%- if event.description is defined %} - {{ event.description }}{% endif %}
            {%- endfor %}.
          {%- endif -%}

Action/Akcje:

data:
  start_date_time: "{{ today_at() - timedelta(days=2) }}"
  end_date_time: "{{ now() }}"
action: calendar.get_events
target:
  entity_id: calendar.wmu_2023
response_variable: agenda
data:
  start_date_time: >-
    {{ (now() + timedelta(days=1)).replace(hour=0, minute=0, second=0)   |
    as_timestamp | timestamp_utc }}
  end_date_time: >-
    {{ (now() + timedelta(days=7)).replace(hour=0, minute=0, second=0) |    
    as_timestamp | timestamp_utc }}
action: calendar.get_events
target:
  entity_id: calendar.wmu_2023
response_variable: agenda

timedelta(days=6) }}" ← ilość dni

Znalazłem ten “magiczny” sposób, działa tak jak to sobie założyłem i jak chciałem żeby działał. Dzielę się swoją pracą, może komuś się przyda.

Zaczynamy od instalacji dodatku ALT + SHIFT + PInstallnode-red-contrib-html-pro.

Kod FLOW do importu:

[
    {
        "id": "dcbd23739adda60d",
        "type": "inject",
        "z": "c617c3f41b6c4831",
        "name": "Codziennie o 6:00",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "",
        "crontab": "00 06 * * *",
        "once": true,
        "onceDelay": "0.1",
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 230,
        "y": 5320,
        "wires": [
            [
                "8b664a9fefb8fdfa"
            ]
        ]
    },
    {
        "id": "8b664a9fefb8fdfa",
        "type": "function",
        "z": "c617c3f41b6c4831",
        "name": "Ustaw start i end daty",
        "func": "const now = new Date();\n\n// Ustaw start na dzisiaj, godzina 00:00:00\nconst startDate = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0);\nconst start = startDate.toISOString();\n\n// Ustaw end na 3 dni później, o 23:59:59\nconst endDate = new Date(startDate);\nendDate.setDate(endDate.getDate() + 3);\nendDate.setHours(23, 59, 59);\nconst end = endDate.toISOString();\n\nmsg.start = start;\nmsg.end = end;\nreturn msg;\n",
        "outputs": 1,
        "timeout": "",
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 395,
        "y": 5340,
        "wires": [
            [
                "695f194cdf1b97f0",
                "bd6b2ce4300e5f74",
                "058654d44cde1680"
            ]
        ],
        "l": false
    },
    {
        "id": "695f194cdf1b97f0",
        "type": "http request",
        "z": "c617c3f41b6c4831",
        "name": "Kalendarz Familijny",
        "method": "GET",
        "ret": "obj",
        "paytoqs": "ignore",
        "url": "",
        "tls": "",
        "persist": false,
        "proxy": "",
        "insecureHTTPParser": false,
        "authType": "bearer",
        "senderr": false,
        "headers": [],
        "x": 570,
        "y": 5300,
        "wires": [
            [
                "fdede8368d9a2516"
            ]
        ]
    },
    {
        "id": "bd6b2ce4300e5f74",
        "type": "http request",
        "z": "c617c3f41b6c4831",
        "name": "Kalendarz Sprawdziany",
        "method": "GET",
        "ret": "obj",
        "paytoqs": "ignore",
        "url": "",
        "tls": "",
        "persist": false,
        "proxy": "",
        "insecureHTTPParser": false,
        "authType": "bearer",
        "senderr": false,
        "headers": [],
        "x": 590,
        "y": 5340,
        "wires": [
            [
                "fdede8368d9a2516"
            ]
        ]
    },
    {
        "id": "fdede8368d9a2516",
        "type": "join",
        "z": "c617c3f41b6c4831",
        "name": "Połącz wyniki kalendarzy",
        "mode": "custom",
        "build": "array",
        "property": "payload",
        "propertyType": "msg",
        "key": "topic",
        "joiner": "\\n",
        "joinerType": "str",
        "useparts": true,
        "accumulate": false,
        "timeout": "",
        "count": "3",
        "reduceRight": false,
        "reduceExp": "",
        "reduceInit": "",
        "reduceInitType": "",
        "reduceFixup": "",
        "x": 880,
        "y": 5340,
        "wires": [
            [
                "8e8c3d1213f92cba"
            ]
        ]
    },
    {
        "id": "8e8c3d1213f92cba",
        "type": "function",
        "z": "c617c3f41b6c4831",
        "name": "Przetwarzanie wydarzeń",
        "func": "const allEvents = [];\n\n// msg.payload to tablica z 2 tablicami wydarzeń\nfor (const events of msg.payload) {\n    if (Array.isArray(events)) {\n        allEvents.push(...events);\n    }\n}\n\nconst now = new Date();\nconst today = new Date(now.getFullYear(), now.getMonth(), now.getDate());\nconst oneDayMs = 24 * 60 * 60 * 1000;\n\nconst grouped = {0: [], 1: [], 2: []};\n\nfor (const event of allEvents) {\n    let startDateStr = null;\n\n    if (typeof event.start === 'string') {\n        startDateStr = event.start;\n    } else if (event.start && event.start.dateTime) {\n        startDateStr = event.start.dateTime;\n    } else if (event.start && event.start.date) {\n        startDateStr = event.start.date;\n    }\n\n    if (!startDateStr || !event.summary) continue;\n\n    const startDate = new Date(startDateStr);\n    const diffMs = startDate.getTime() - today.getTime();\n    const dayDiff = Math.floor(diffMs / oneDayMs);\n\n    if (dayDiff >= 0 && dayDiff <= 2) {\n        const time = (event.start && event.start.dateTime)\n            ? startDate.toLocaleTimeString('pl-PL', { hour: '2-digit', minute: '2-digit' })\n            : \"\";\n        const line = time ? `${time} – ${event.summary}` : event.summary;\n        grouped[dayDiff].push(line);\n    }\n}\n\nfunction formatMessages(grouped) {\n    let msgText = \"\";\n    if (grouped[0].length) {\n        msgText += \"Dzisiaj:\\n\" + grouped[0].join('\\n') + \"\\n\\n\";\n    }\n    if (grouped[1].length) {\n        msgText += \"Jutro:\\n\" + grouped[1].join('\\n') + \"\\n\\n\";\n    }\n    if (grouped[2].length) {\n        msgText += \"Pojutrze:\\n\" + grouped[2].join('\\n') + \"\\n\\n\";\n    }\n    if (!msgText) {\n        msgText = \"Brak wydarzeń na najbliższe dni.\";\n    }\n    return msgText;\n}\n\nconst formatted = formatMessages(grouped);\n\nmsg.wiadomosc = {\n    temat: \"Wydarzenia kalendarza\",\n    tresc: formatted,\n    typ: \"technical\"\n};\n\nreturn msg;\n",
        "outputs": 1,
        "timeout": "",
        "noerr": 0,
        "initialize": "",
        "finalize": "",
        "libs": [],
        "x": 1150,
        "y": 5340,
        "wires": [
            [
                "df2d46dc2b60fedd"
            ]
        ]
    },
    {
        "id": "df2d46dc2b60fedd",
        "type": "debug",
        "z": "c617c3f41b6c4831",
        "name": "kal Wszystko",
        "active": false,
        "tosidebar": true,
        "console": false,
        "tostatus": false,
        "complete": "true",
        "targetType": "full",
        "statusVal": "",
        "statusType": "auto",
        "x": 1370,
        "y": 5340,
        "wires": []
    },
    {
        "id": "058654d44cde1680",
        "type": "http request",
        "z": "c617c3f41b6c4831",
        "name": "Kalendarz Prywatny",
        "method": "GET",
        "ret": "obj",
        "paytoqs": "ignore",
        "url": "",
        "tls": "",
        "persist": false,
        "proxy": "",
        "insecureHTTPParser": false,
        "authType": "bearer",
        "senderr": false,
        "headers": [],
        "x": 580,
        "y": 5380,
        "wires": [
            [
                "fdede8368d9a2516"
            ]
        ]
    },
    {
        "id": "6db016f4a9942bdc",
        "type": "inject",
        "z": "c617c3f41b6c4831",
        "name": "Codziennie o 20:00",
        "props": [
            {
                "p": "payload"
            }
        ],
        "repeat": "",
        "crontab": "00 20 * * *",
        "once": true,
        "onceDelay": "0.1",
        "topic": "",
        "payload": "",
        "payloadType": "date",
        "x": 240,
        "y": 5360,
        "wires": [
            [
                "8b664a9fefb8fdfa"
            ]
        ]
    }
]

NOD Kalendarz NAZWA_KALENDARZA:

URL: https://ADRES_HOME_ASSISTANTA/api/calendars/calendar.NAZWA_KALENDARZA?start={{start}}&end={{end}}

jeżeli podajemy adres IP do HA to na końcu musi być port /:8123

NAZWA_KALENDARZA podajemy nazwę z HA, możemy ją sprawdzić w Narzędzia deweloperskieAktualne stany encji w Filtr encji wpisując calendar

TOKEN: musimy go utworzyć w HA ProfilBezpieczeństwoDługotrwałe tokeny dostępu, jeden token powinien się nadać dla kilku kalendarzy.

Dodając lub odejmując kalendarz wpisujemy ilość kalendarzy w NODZIE Połącz wyniki kalendarzySend the message:After a number of message parts.

Powyższy kod pobiera dane kalendarza od godziny 00:00 dnia pierwszego do 23:59 dnia trzeciego, jeżeli chcemy aby podawało tylko wydarzenia aktywne od chwili wywołania to edytujemy NOD Ustaw start i end daty i wklejamy poniższy kod.

const now = new Date();
const start = now.toISOString();
const endDate = new Date(now);
endDate.setDate(endDate.getDate() + 3);
const end = endDate.toISOString();

msg.start = start;
msg.end = end;
return msg;

Wyjściowy komunikat jest skonfigurowany tak aby działał z powiadomieniami utworzonymi przez @artur w poradniku Procesy z życia wzięte - Powiadomienia, typy powiadomień .

1 polubienie