Blog o moim SmartDomu

  • Mój „inteligentny” dom

    Przez ostatnich kilka lat coraz bardziej rozbudowałem mój SmartDom w oparciu o HomeAssistanta i ostatnio postanowiłem udokumentować szereg rozwiązań oraz integracji. W 2018 pierwszą instancja działała na Raspberry PI 3 z 2GB RAMu, w tej chwili działa na RPI 5 z 8GB.

    Lista urządzeń, które sterują moim domem:

    • Shelly 1
    • Shelly 1 PM
    • Shelly 1 PM gen 4
    • Shelly 2
    • Shelly 2 PM gen 4
    • Sonoff Basic (z firmware Tasmota)
    • Sonoff TH
    • Alarm Integra 64
    • Czujniki SI7021
    • Czujnik HC-SR04 
    • Czujnik BME-280
    • Czujnik deszczu z czujnikiem oświetlenia (zigbee)
    • Moduł WiFi NodeMCU V2
    • Moduł Wifi ESP32
    • Wemos D1 mini
    • Raspberry PI3 (HyperBian)
    • Raspberry PI5 (Debian) + Raspberry AI Kit + Hailo 8L
    • Nettigo Air Monitor 0.3
    • bramka Zigbee
    • Termostaty TUYA HY368 ZigBee oraz TUYA ID3 GTZ08
    • gniazdka zigbee
    • żarówki zigbee
    • sterowanie roletą (zigbee)
    • Ebusd
    • Listwy LED
    • Kamera USB
    • Tester gleby
    • Tagi NFC

    plus szereg integracji:

    Szczegółowa lista urządzeń i integracji

    Konfiguracja HomeAssistanta

  • Pozycjonowanie obiektów na mapie HA

    Dzięki modułowi map w HA można wyświetlać bieżące pozycje osób, samochodów oraz zwierzaków (psa).

    Lokalizacja na mapie w HA

    HA mapa

    Pozycjonowanie osób

    Weryfikacja pozycji GPS

    Konfiguracja w aplikacji Home Assistant na telefon:

    1. Ustawienia>Aplikacja towarzysząca
    2. ustawić:
      • nazwę urządzenia
      • Działanie w tle
      • Zarządzaj sensorami
        • Jednorazowa dokładna lokalizacja: Włączony
        • Lokalizacja w tle: Włączony
        • Strefa lokalizacji: Włączony
        • (Opcjonalnie) Lokalizacja geokodowana: Włączony
    3. Zezwolić na lokalizację aplikacji
    4. (opcjonalnie) wyłączyć powiadomienia z aplikacji – jeżeli tylko do weryfikacji lokalizacji.

    Weryfikacja obecności w domu

    Dla tych osób, które nie mają włączonej lokalizacji w aplikacji lub nie używają aplikacji wykrycie obecności w domu odbywa się na podstawie integracji PING. Poszczególne telefony mają przypisane na routerze statyczne adresy IP (na podstawie adresów MAC).
    W ustawieniach osoby w HA jest przypisana odpowiednia integracja PING dla telefonu danej osoby.

    Pozycjonowanie samochodów

    Pozycjonowanie samochodów na mapie odbywa się na podstawie lokalizatorów GPS umieszczonych w samochodach. Domyślnie dane z lokalizatora GPS wysyłane są do serwera i widoczne w na mapie HA oraz w aplikacji Traccar.

    Z powodu bezpieczeństwa zależało mi aby wszelkie informacje nie były przechowywane na „obcych” serwerach lokalizacji – stąd konfiguracja własnego serwera do śledzenia samochodów.

    Lokalizacja samochodów w Traccar

    Hardware

    • Lokalizator GPS MKING MK08 wersja OBD2 – koszt ok 110PLN (listopad 2025), link
    • Karta SIM VigrinMobile – koszt ok 5PLN, plus 30PLN/rok

    Software

    • Aplikacja: Traccar
    • Aplikacja na telefon GPS.MIKING (tylko na potrzeby wstępnej konfiguracji i weryfikacji)

    Konfiguracja

    Wymagania: HA wystawione na zewnątrz z poprawnie skonfigurowanym HTTPS i DNS.

    Instalacja aplikacji traccar w HA.

    Przekierowanie portu na routerze dla aplikacji traccar na wewnętrzny IP serwera HA.

    Konfiguracja lokalizatora GPS MKING MK08

    1. Włożenie aktywnej karty SIM do lokalizatora
    2. Instalacja w samochodzie oraz opcjonalne włączenie silnika, poczekanie kilka minut na pierwszy odczyt lokalizacji
    3. Weryfikacja lokalizacji na mapie w aplikacji na telefon: GPS.MIKING
    4. Zmiana hasła lokalizatora w aplikacji GPS.MIKING
    5. Odczyt ustawień lokalizatora – wysłanie SMSa na numer telefonu lokalizatora: CXZT
      W odpowiedzi można zweryfikować: oryginalny adres serwera lokalizacji oraz ID urządzenia
    6. Ustawienie nowego serwera lokalizacji: IP <adres_IP_serwera_Traccar> <port_serwera>
      przykładowo: IP moj_dom.duckdns.org 1234
      odpowiedź SMS: SET IP OK
    7. weryfikacja lokalizacji przez wysłanie SMS: G1234
      odpowiedź SMS: link do lokalizacji na google

    Konfiguracja w Traccar

    1. Konfiguracja protokołu urządzeń
      Należy w addonie Traccar zmodyfikować plik traccar.xml, aby ustawić właściwy protokół komunikacyjny dla lokalizatorów GPS – w moim przypadku protokół to H02

      <!-- Enter you custom configuration below this line -->
      <entry key='h02.port'>5013</entry>

    2. (opcjonalnie) Dodajemy przekierowanie portu skonfigurowanego powyżej na routerze na wewnętrzny IP serwer HA – tylko dla przypadku, gdy HA jest wystawione do internetu i ma zewnętrzny adres IP.
    3. Dodajemy urządzenie w ustawieniach podając ID urządzenia

    Konfiguracja w HA

    Integracja w HA przy użyciu integracji Traccar Server.

    Przykładowe atrybuty

      Dla wygody prezentacji na mapie dla każdego z samochodu dodanie osoby:

      • nazwa
      • zdjęcie
      • nazwa encji z lokalizacją (encja z integracji)

        Pozycjonowanie zwierzaków

        Analogicznie jak pozycjonowanie ludzi czy samochodów na mapie w HA można prezentować lokalizację zwierzaków.

        Hardware

        Tractive – wymagane dedykowane urządzenie oraz opłacanie abonamentu.

        Software

        Intergracja w HA: Tractive – wymagane aktywne konto w aplikacji na telefon Tractive

        Aby ikona na mapie w HA pokazywała zdjęcie należy zrobić kroki analogicznie jak dla samochodu.

        Linki:
        https://www.traccar.org/configuration-file/

        https://tractive.com/pl/pd/gps-dla-psa

      1. Konfiguracja HomeAssistant

        System

        HA działa jako kontener na dockerze. Nie jest to najprostsza konfiguracja, ale jedna z najbardziej elastycznych. Z jednej strony mamy możliwość aktualizacji HA, a z drugiej możliwość uruchomienia dodatkowego oprogramowania – w moim przypadku: Ebusd oraz Samba.

        Dodatki

        AplikcjeCel
        Advanced SSH & Web TerminalTerminal SSH
        DuckDNS + NgnixKonfiguracja SSL plus wystawienie HA do internetu
        ESPHome Device BuilderESPHome – oprogramowanie dla chipów i czujników
        File editorEdycja plików
        FrigatePodgląd kamer, analiza ruchu, serwer NVR
        Home Assistant Google Drive BackupAutomatyczne backupy w chmurze
        Mosquitto brokerSerwer MQTT
        Music Assistant ServerSerwer multimediów
        SQLite WebKlient SQL dla SQLLite
        TasmoAdminZarządzanie urządzeniami Tasmota
        TasmoBackupBackup urządzeń Tasmota
        TraccarŚledzenie samochodów
        Uptime KumaMonitoring urządzeń
        Zigbee2MQTTObsługa urządzeń Zigbee

        HACS

        Niestandardowe integracje

        IntegracjaCel
        HACSModuł do pobierania dodatkowych komponentów i integracji
        AI Automation SuggesterOptymalizacje konfiguracji HA
        AlarmoPanel alarmu
        AntistormPrognoza burz i opadów
        Disk SpaceSensor wielkości dysku
        FrigateIntegracja z frigate
        Media player templateDedykowany player dla niestandardowych urządzeń multimedialnych
        TP-Link RouterObsługa routerów TP-Link
        Uptime KumaIntegracja z Uptime Kuma
        ViomiseIntegracja dla odkurzacza Viomi SE and Xiaomi STY02YM, STYJ02YM
        Waste Collection SchedulePobranie danych
        Xiaomi Cloud Map ExtractorWyświetlanie mapy pracy odkurzacza

        Niestandardowe komponenty

        KomponentyCel
        Advanced Camera CardKomponent kamer z frigate z historią
        Atomic Calendar ReviveKalendarz
        Bar CardPasek Bar
        Battery State CardWyświetlanie stanu baterii
        Button CardKlawisze na GUI
        Disk SpaceIlość przestrzeni dyskowej
        Mini Media PlayerMniejszy komponent dla Media Player
        MushroomDodatkowe elementy graficzne
        Vertical Stack in CardWyświetlanie pionowe na GUI
        Weather CardAnimowana „stara” karta pogody
        Xiaomi Vacuum Map Card Komponent odkurzacza Xiaomi
      2. Monitorowanie otoczenia

        Monitorowanie otoczenia

        Do monitorowania obrazu z kamera do niedawna używałem addona motionEye, jednak ostatnio przesiadłem się na addon Frigate. Oferuje znacznie większe możliwości, takie jak rozpoznawanie określonych obiektów oraz dzięków. W tym rozwiązaniu jest używany akcelerator NPU Hailo8L, odciża procesor RP5 z operacji analizy obrazu. Hailo ma bardzo dobry współczynnik ilości obliczeń do zużywanej mocy. Całość jest zasilana ze standardowego zasilacza RPI5.

        Hardware

        • BLOW IP 5MP WiFi 3,6 mm
        • P-Link Tapo C210
        • Raspberry Pi AI Kit (M.2 HAT+ i akcelerator Hailo-8L) – link
        • (opcjonalnie) TV z GoogleTV
        • (opcjonalnie) Telefon z Androidem wraz ze skonfigurowaną aplikacją HA

        Software

        • Addon: Frigate
        • Integracja HACS: Frigate Home Assistant Integration
        • Komponent HACS: Advanced Camera Card
        • (opcjonalnie) TvOverlay – aplikacja umożliwiająca wyświetlanie powiadomień na Google TV
        • uruchomiony serwer Samba

        Konfiguracja HA

        Używam podłączonego dysku USB do przechowywania nagrań. Dysk jest skonfigurowany jako dysk sieciowy przy użyciu Samby.

        W HA: Ustawienia -> System -> Pamięć masowa

        Instalacja Hailo

        Podłączenie Hailo do RPi5 – link

        Konfiguracja systemu pod Hailo – link

        Niestety paczka hailo-all zawiera firmware i sterownik w wersji 4.20, a wersja Frigate HailoRT 0.15 zwiera oprogramowanie do Hailo w wersji 4.19. Konieczne jest przygotowanie własnej wersji sterownika i frimware do obsługi Hailo. Szczegóły rozwiązania w artykule link.

        Konfiguracja Frigate

        mqtt:
          host: 192.168.1.2
          user: MQTT_USER
          password: MQTT_PASSWORD
        
        ffmpeg:
          hwaccel_args: preset-rpi-64-h264
        
        record:
          enabled: true
          retain:
            days: 3
            mode: motion
          alerts:
            retain:
              days: 10
              mode: motion
          detections:
            retain:
              days: 10
              mode: motion
        timestamp_style:
          position: bl
          format: '%Y.%m.%d %H:%M:%S'
        
        detectors:
          hailo8l:
            type: hailo8l
            device: PCIe
        #    model:
        #      # from https://github.com/hailo-ai/hailo_model_zoo/blob/master/docs/public_models/HAILO8L/HAILO8L_object_detection.rst
        
        model:
          width: 640
          height: 640
          input_tensor: nhwc
          input_pixel_format: bgr
          model_type: yolox
          path: /config/model_cache/h8l_cache/yolov8s.hef
          labelmap:
            0: person
            1: bicycle
            2: car
            3: motorcycle
            4: airplane
            5: bus
            6: train
            7: truck
            8: boat
            9: traffic light
            10: fire hydrant
            11: stop sign
            12: parking meter
            13: bench
            14: bird
            15: cat
            16: dog
            17: horse
            18: sheep
            19: cow
            20: elephant
            21: bear
            22: zebra
            23: giraffe
            24: backpack
            25: umbrella
            26: handbag
            27: tie
            28: suitcase
            29: frisbee
            30: skis
            31: snowboard
            32: sports ball
            33: kite
            34: baseball bat
            35: baseball glove
            36: skateboard
            37: surfboard
            38: tennis racket
            39: bottle
            40: wine glass
            41: cup
            42: fork
            43: knife
            44: spoon
            45: bowl
            46: banana
            47: apple
            48: sandwich
            49: orange
            50: broccoli
            51: carrot
            52: hot dog
            53: pizza
            54: donut
            55: cake
            56: chair
            57: couch
            58: potted plant
            59: bed
            60: dining table
            61: toilet
            62: TV
            63: laptop
            64: mouse
            65: remote
            66: keyboard
            67: cell phone
            68: microwave
            69: oven
            70: toaster
            71: sink
            72: refrigerator
            73: book
            74: clock
            75: vase
            76: scissors
            77: teddy bear
            78: hair drier
            79: toothbrush
        
        #detectors:
        #  hailo8l:
        #    type: hailo8l
        #    device: PCIe
        
        #model:
        #  width: 300
        #  height: 300
        #  input_tensor: nhwc
        #  input_pixel_format: bgr
        #  model_type: ssd
        #  path: /config/model_cache/h8l_cache/ssd_mobilenet_v1.hef
        
        #objects:
        #  track:
        #    - person
        #    - car
        #    - face
        #    - license_plate
        #    - dog
        #    - cat
        #    - package
        #  filters:
        #    person:
        #      threshold: 0.40
        #    car:
        #      threshold: 0.40
        #    face:
        #      threshold: 0.40
        #    license_plate:
        #      threshold: 0.40
        #    dog:
        #      threshold: 0.40
        #    cat:
        #      threshold: 0.40
        #    package:
        #      threshold: 0.40
        
        snapshots:
          enabled: true
          timestamp: true
          bounding_box: true
          retain:
            default: 14
        
        go2rtc:
          streams:
            Wejscie:
              - rtsp://LOGIN:PASS@192.168.4.135/0
            Wejscie_sub:
              - rtsp://LOGIN:PASS@192.168.4.135/1
            Garaz:
              - rtsp://LOGIN:PASS@192.168.4.121:554/stream1
        #      - ffmpeg: Garaz#audio=aac
        #      - ffmpeg: Garaz#audio=opus
        #      - tapo://CLOUD_PASS@192.168.4.135
            Garaz_sub:
              - rtsp://LOGIN:PASS@192.168.4.121:554/stream2
        
        cameras:
          Wejscie: # <------ Name the camera
            enabled: true
            ffmpeg:
              inputs:
                - path: rtsp://127.0.0.1:8554/Wejscie # <--- the name here must match the name of the camera in restream
                  input_args: preset-rtsp-restream
                  roles:
                    - record
                - path: rtsp://127.0.0.1:8554/Wejscie_sub # <--- the name here must match the name of the camera_sub in restream
                  input_args: preset-rtsp-restream
                  roles:
                    - detect
            live:
              stream_name: Wejscie_sub
            onvif:
              host: 192.168.4.137
              port: 8000
              user: USER
              password: PASS
              ignore_time_mismatch: true
            mqtt:
              enabled: true
              timestamp: true
              bounding_box: true
              crop: true
              quality: 90
              required_zones:
                - Chodnik
            motion:
              mask: 0.016,0.034,0.195,0.036,0.194,0.06,0.017,0.059
            zones:
              Chodnik:
                coordinates: 0,0.261,0.203,0.165,0.216,0.281,0.334,0.16,0.454,0.188,0.449,0.364,0.131,1,0,1
                loitering_time: 0
                inertia: 3
              Ulica:
                coordinates: 
                  0.77,0.317,0.776,0.257,0.453,0.183,0.333,0.156,0.221,0.272,0.203,0,0.998,0.003,0.999,0.376
                loitering_time: 0
                inertia: 3
              Parking:
                coordinates: 0.135,1,1,1,1,0.382,0.771,0.32,0.776,0.262,0.458,0.187,0.452,0.367
                loitering_time: 0
            review:
              alerts:
                required_zones:
                  - Chodnik
                  - Parking
          Wejscie2: # <------ Name the camera
            enabled: false
            ffmpeg:
              inputs:
                - path: rtsp://127.0.0.1:8554/Wejscie2 # <----- The stream you want to use for detection
                  roles:
                    - detect
                    - record
            record:
              enabled: true
            detect:
              enabled: true # <---- disable detection until you have a working camera feed
        #      width: 1280
        #      height: 720
        #      fps: 15
            mqtt:
              enabled: true
              timestamp: true
              bounding_box: true
              crop: true
              quality: 90
              required_zones:
                - Chodnik
            motion:
              threshold: 30
              mask: 0,0.058,0.254,0.057,0.255,0.012,0.003,0.01
              contour_area: 20
              improve_contrast: true
        #    onvif:
        #      host: 192.168.4.137
        #      port: 8000
        #      user: admin
        #      ignore_time_mismatch: true
        
            zones:
              Ulica:
                coordinates: 0.531,0.332,0.663,0.381,0.843,0.45,1,0.53,0.999,0.003,0.531,0.004
                loitering_time: 0
                inertia: 3
              Chodnik:
                coordinates: 0.346,1,0.836,0.461,0.64,0.376,0.525,0.337,0.524,0.133,0.003,0.262,0,1
                loitering_time: 0
                inertia: 3
              Parking:
                coordinates: 0.849,0.456,1,0.534,0.998,0.998,0.353,1
                loitering_time: 0
                inertia: 3
            review:
              alerts:
                required_zones:
                  - Ulica
                  - Chodnik
                  - Parking
              detections:
                required_zones:
                  - Ulica
                  - Chodnik
                  - Parking
            objects:
              filters:
                person:
                  mask: 0.34,1,0.835,0.457,0.52,0.342,0,0.578,0.002,0.999
          Garaz: # <------ Name the camera
            enabled: true
            ffmpeg:
              inputs:
                - path: rtsp://127.0.0.1:8554/Garaz # <--- the name here must match the name of the camera in restream
                  input_args: preset-rtsp-restream
                  roles:
                    - record
                - path: rtsp://127.0.0.1:8554/Garaz_sub # <--- the name here must match the name of the camera_sub in restream
                  input_args: preset-rtsp-restream
                  roles:
                    - detect
            live:
              stream_name: Garaz_sub
            onvif:
              host: 192.168.4.121
              port: 2020
              user: USER
              password: PASS
              ignore_time_mismatch: true
            mqtt:
              enabled: true
              timestamp: true
              bounding_box: true
            motion:
              mask: 0,0.047,0.357,0.044,0.357,0,0.002,0.006
        version: 0.15-1

        Ja korzystam z modelu yolov8s, który należy wcześniej wgrać do katalogu homeassistant/model_cache/h8l_cache

        Powiadomienia na telewizorze GoogleTV (opcjonalnie)

        Telewizor z GoogleTV z aplikacją TVOverlay oraz uruchomiony serwer MQTT na instancji HA.

        Konfiguracja TvOverlay

        Uruchamiamy aplikację na TV i ustawiamy:

        • Background Visibility na 0%
        • Clock Visibility na 0%
        • MQTT – IP, login i hasło serwera MQTT
        • More settings -> Battery Optimalization

        Konfigurację można zweryfikować pobierając XMLa z linku http://IP_TV:5001

        Konfiguracja TvOverlay w HA

        Należy dodać w configuration.yaml w sekcji notify poniższy kod (ustawiając IP_TV i port – domyślnie 5001)

        notify:
          - name: TvOverlayNotify
            platform: rest
            method: POST_JSON
            resource: http://[ip]:[port]/notify 
            verify_ssl: false
            title_param_name: title
            data:
              id: "{{ data.id | default(null) }}"
              appTitle: "{{ data.appTitle  | default('Home Assistant') }}"
              appIcon: "{{ data.appIcon | default('mdi:home-assistant') }}"
              color: "{{ data.color | default('#049cdb') }}"
              image: "{{ data.image | default(null) }}"
              smallIcon: "{{ data.smallIcon | default(null) }}"
              largeIcon: "{{ data.largeIcon | default(null) }}"
              corner: "{{ data.corner  | default(null) }}"
              seconds: "{{ data.seconds | default(null) }}"
              
          - name: TvOverlayNotifyFixed
            platform: rest
            method: POST_JSON
            resource: http://[ip]:[port]/notify_fixed
            verify_ssl: false
            title_param_name: title
            data:
              id: "{{ data.id | default(null) }}"
              text: "{{ data.text  | default(null) }}"
              icon: "{{ data.icon | default(null) }}"
              textColor: "{{ data.textColor | default(null) }}"
              iconColor: "{{ data.iconColor | default(null) }}"
              borderColor: "{{ data.borderColor | default(null) }}"
              backgroundColor: "{{ data.backgroundColor | default(null) }}"
              shape: "{{ data.shape | default(null) }}"
              visible: "{{ data.visible | default(true) }}"
              expiration: "{{ data.expiration | default(null) }}"
        
              
        rest_command:
          tvoverlay:
            url: http://[ip]:[port]/set/overlay
            method: POST
            verify_ssl: false
            headers:
              accept: 'application/json'
            content_type:  'application/json; charset=utf-8'
            payload: '{{ payload }}'

        Następnie można przetestować powiadomienie wywołując usługę w HA z menu Narzędzia deweloperskie -> Akcje

        action: notify.tvoverlaynotify
        data:
          message: The garage door has been open for 10 minutes.
          title: Your Garage Door Friend
          data:
            id: notification_sample
            appTitle: AppTitle
            appIcon: mdi:unicorn
            color: "#FFF000"
            smallIcon: mdi:speaker-multiple
            largeIcon: mdi:camera
            corner: bottom_end
            seconds: 20
            image: https://picsum.photos/300

        Wysłanie powiadomienia z Frigate na telefon i TV

        Jeżeli wysyłanie następuje tylko na telefon to można skorzystać z gotowego blueprinta (link).

        Poniżej moja automatyzacja

        - id: '1663062012156'
          alias: Frigate Notifications
          trigger:
            - platform: mqtt
              topic: frigate/events
              id: frigate-event
              payload: NAZWA_KAMERY
              value_template: "{{ value_json['after']['camera'] }}"
              variables:
                after_zones: "{{ trigger.payload_json['after']['entered_zones'] }}"
                before_zones: "{{ trigger.payload_json['before']['entered_zones'] }}"
                camera: "{{ trigger.payload_json['after']['camera'] }}"
                id: "{{ trigger.payload_json['after']['id'] }}"
                label: "{{ trigger.payload_json['after']['label'] }}"
                score: "{{ trigger.payload_json['after']['score'] }}"
                time_clip_start: "{{ trigger.payload_json['after']['start_time'] - 10.0 }}"
          # Conditions must be used to filter out objects / detections that are not of interest
          condition:
            # This condition is used to ensure that I am only notified of objects that are new or only just entered a zone. This is to avoid getting loads of updated notifications for the same dog in my backyard (as an example).
            - condition: or
              conditions:
                - condition: template
                  value_template: "{{ trigger.payload_json['type'] == 'new' }}"
                - condition: template
                  value_template: "{{ before_zones | length == 0 }}"
            - condition: template
              value_template: >-
                    {{ 'Chodnik' in (after_zones + before_zones) }}
        #    - condition: template
        #      value_template: >-
        #        {{
        #         (as_timestamp(now())-as_timestamp(state_attr('automation.frigate_notifications_with_details2',
        #            'last_triggered') | default(0)) | int > 5) }}
            - condition: state
              entity_id: input_boolean.tv_notify_motion
              state: 'on'
        
          action:
            - service: notify.mobile_phone_app
              data:
                message: >-
                   {{ label }}({{ int(score | round(2) * 100) }}%) na {{ after_zones }} wykryty przez {{ camera }}, {{ id }}
                data:
                  image: >-
                        /api/frigate/notifications/{{ id }}/thumbnail.jpg
                  url: >-
                    https://HAOS_EXTERNAL_LINK/api/frigate/notifications/{{ id }}/{{camera}}/clip.mp4
                  actions:
                    - action: URI
                      title: Video
                      uri: >-
                        https://HAOS_EXTERNAL_LINK/api/frigate/notifications/{{id}}/{{camera}}/clip.mp4
                    - action: URI
                      title: Snapshot
                      uri: >-
                        https://HAOS_EXTERNAL_LINK/api/frigate/notifications/{{ id }}/snapshot.jpg
                    - action: URI
                      title: Thumbnail
                      uri: >-
                        https://HAOS_EXTERNAL_LINK/api/frigate/notifications/{{ id }}/thumbnail.jpg
            - service: notify.tvoverlaynotify
              data:
                data:
                  appTitle: Frigate
                  largeIcon: mdi:camera
                  color: "#000800"
                  seconds: 30
                  image: >-
                     https://HAOS_EXTERNAL_LINK/api/frigate/notifications/{{id}}/thumbnail.jpg
                title: >-
                  {{ label }} wykryto na {{ camera }}
                message: >-
                  {{ label }}({{ int(score | round(2) * 100) }}%) na {{ after_zones }} wykryty przez {{ camera }}
          mode: parallel
          max: 10
        #  trace:
        #    stored_traces: 20

        Linki

        https://frigate.video

        https://docs.frigate.video

        https://github.com/gugutab/TvOverlay

        https://github.com/SgtBatten/HA_blueprints

        https://community.home-assistant.io/t/frigate-mobile-app-notifications-2-0/559732/2618

      3. Ambientlight TV za pomocą HyperBian, RPi3 i kamery USB

        Ambientlight TV za pomocą HyperBian, RPi3 i kamery USB

        Fajny projekt, gdzie niewielkim kosztem jest wyświetlane podświetlenie LED za telewizorem na podstawie wyświetlanego obrazu. W moim rozwiązaniu użyta jest kamera umieszczona naprzeciwko TV oraz „stare” Rasberry PI3, które wcześniej sterowało moim domem i po upgrade do RPI5 leżało w szufladzie.

        Została użyta kamera ponieważ na TV wyświetlane są tylko programy z aplikacji streaminowych, nie ma możliwości użycia grabbera sygnału i odczytu obrazu z we/wy HDMI.

        Instalacja jest podzielona na dwie części:

        • RPI3 wraz kamerą USB (kamera umieszczona prawie naprzeciw telewizora),
        • sterowalna listwa LED z ESP32.

        Instalacja

        Schemat blokowy instalacji LED za TV

        Sprzęt

        • Zasilacz 5V/20A (koszt ok 50 PLN) – pewnie można użyć trochę mniejszy,
        • Listwa RGB 2805 (koszt ok 80 PLN) – długość ok 4m (72LED na poziomych listwach i 40 na pionowych),
        • ESP32-DevKitC-32U z anteną (koszt ok 10$),
        • bezpieczniki samochodowe 2x10A,
        • kostka połączeniowa,
        • rezystor 300om (tłumienie zakłóceń na linii DATA),
        • kabel zasilający 2×1.5mm2 – połączenie od zasilacza do kostki.

        Uwagi

        Niestety listwa dolna jest mocniej zasłonięta przez obudowę TV – co powoduje słabsze świecenie diód w dolnej części.

        Konfiguracja

        ESP32

        Zainstalowane oprogramowanie WLED (z przeglądarki Chrome) – link.
        WLED działa przez WIFI, na routerze ustawiony jest stały adres IP. Dodatkowo w WLED ustawiono ilość diód (Length), maksymalną wydajność prądową zasilacza (Maximum PSU Current ) oraz pin z linią danych (Data GPIO).

        RPI3

        Zainstalowane oprogramowanie HyperBian.

        Aby zmniejszyć opóźnienie na linii kamera a listwa LED rejestruje obraz z rozdzielczością 320×240 przy 30FTPs. Relatywnie po kadrowaniu w moim przypadku zostaje ok 100×55 co i tak przewyższa ilość diód LED.

        Integracja z HA

        Standardowa integracja

        Automatyzacje

        Automatyczne włączenie/wyłączenie nagrywania i przetwarzania obrazu przy włączeniu telewizora.

        - id: '1739489846028'
          alias: Turn_off_WLED_salon_on_TV
          description: ''
          triggers:
          - platform: state
            entity_id: media_player.tv
            from: 'on'
            to: 'off'
          conditions: []
          actions:
          - action: light.turn_on
            target:
              entity_id: light.wled210_3
            data:
              brightness_pct: 1    
          - action: switch.turn_off
            metadata: {}
            data: {}
            target:
              entity_id: switch.tv_salon_component_all
          - delay: '00:00:03'
          - action: light.turn_on
            target:
              entity_id: light.wled210_3
            data:
              brightness_pct: 1    
          - action: light.turn_off
            target:
              entity_id: light.wled210_3
          mode: single
        - id: '1739489846029'
          alias: Turn_on_WLED_salon_on_TV
          description: ''
          triggers:
          - platform: state
            entity_id: media_player.tv
            from: 'off'
            to: 'on'
          actions:
          - action: light.turn_on
            target:
              entity_id: light.wled210_3
            data:
              brightness_pct: 1
          - action: switch.turn_on
            target:
              entity_id: switch.tv_salon_component_all
          - action: switch.turn_on
            target:
              entity_id: switch.tv_salon_component_led_device
          - action: light.turn_on
            target:
              entity_id: light.wled210_3
            data:
              brightness_pct: 1    
          mode: single

        Linki

        https://docs.hyperion-project.org

        https://install.wled.me

        https://kno.wled.ge/basics/getting-started

        https://wled-calculator.github.io

        https://www.thegeekpub.com/274631/wled-how-to-setup-and-configure-wled

      4. Monitoring urządzeń w domu

        Duża ilość urządzeń w domowej sieci wifi powoduje zawsze problemy z dostępnością wszystkich urządzeń. Do monitoringu działania urządzeń wykorzystuje dodatek „Uptime Kuma” do HA

        Konfiguracja

        Ustawienia pojedynczego monitora dla urządzenia

        Powiadomienia wysyłam bezpośrednio poprzez HA na komórkę. Większość urządzeń monitoruje na odpowiednim temacie MQTT – przykład powyżej.

        Aby pominąć błędne powiadomienia:

        • dla MQTT – heartbeat: 60 sek oraz ilość prób: 5,
        • dla ping – heartbeat: 300 sek oraz ilość prób: 5,

        Konfiguracja HA

        Za pomocą dodatkowej integracji HACS: „Uptime Kuma HACS integration: standardowej integracji dodane są sensory do HA, dodatkowo wykorzystany Dashboard HACS: button-card.oraz vertical i horizonatal stack.

        Konfiguracja karty:

        type: vertical-stack
        cards:
          - type: horizontal-stack
            cards:
              - type: custom:button-card
                styles:
                  name:
                    - color: gray
                    - font-size: 12px
                entity: sensor.watermeter1_mqtt_status
                icon: mdi:water
                name: mbus
                show_state: false
                color: rgb(255, 0, 0)
                font-size: 6px
                state:
                  - value: up
                    color: rgb(0, 255, 0)
              - type: custom:button-card
                styles:
                  name:
                    - color: gray
                    - font-size: 12px
                entity: sensor.watermeter2_status_2
                icon: mdi:water
                name: cam
                show_state: false
                color: rgb(255, 0, 0)
                state:
                  - value: up
                    color: rgb(0, 255, 0)
              - type: custom:button-card
                styles:
                  name:
                    - color: gray
                    - font-size: 12px
                entity: sensor.kamera_wejscie_status
                icon: mdi:camera
                name: Wejście
                show_state: false
                color: rgb(255, 0, 0)
                state:
                  - value: up
                    color: rgb(0, 255, 0)
              - type: custom:button-card
                styles:
                  name:
                    - color: gray
                    - font-size: 12px
                entity: sensor.kamera_garaz_status
                icon: mdi:camera
                name: Garaz
                show_state: false
                color: rgb(255, 0, 0)
                state:
                  - value: up
                    color: rgb(0, 255, 0)
          - type: horizontal-stack
            cards:
              - type: custom:button-card
                styles:
                  name:
                    - color: gray
                    - font-size: 12px
                entity: sensor.alarm_mqtt_status
                icon: mdi:motion-sensor
                name: Alarm
                show_state: false
                color: rgb(255, 0, 0)
                font-size: 6px
                state:
                  - value: up
                    color: rgb(0, 255, 0)
              - type: custom:button-card
                styles:
                  name:
                    - color: gray
                    - font-size: 12px
                entity: sensor.kotlownia_mqtt_status
                icon: mdi:motion-sensor
                name: Kotłownia
                show_state: false
                color: rgb(255, 0, 0)
                state:
                  - value: up
                    color: rgb(0, 255, 0)
              - type: custom:button-card
                styles:
                  name:
                    - color: gray
                    - font-size: 12px
                entity: sensor.wemos1_mqtt_status
                icon: mdi:remote
                name: Wemos1
                show_state: false
                color: rgb(255, 0, 0)
                state:
                  - value: up
                    color: rgb(0, 255, 0)
              - type: custom:button-card
                styles:
                  name:
                    - color: gray
                    - font-size: 12px
                entity: sensor.wemos2_mqtt_status
                icon: mdi:garage-open
                name: Wemos2
                show_state: false
                color: rgb(255, 0, 0)
                state:
                  - value: up
                    color: rgb(0, 255, 0)
          - type: horizontal-stack
            cards:
              - type: custom:button-card
                styles:
                  name:
                    - color: gray
                    - font-size: 12px
                entity: sensor.pompa_wody_mqtt_status
                icon: mdi:pump
                name: Pompa
                show_state: false
                color: rgb(255, 0, 0)
                font-size: 6px
                state:
                  - value: up
                    color: rgb(0, 255, 0)
              - type: custom:button-card
                styles:
                  name:
                    - color: gray
                    - font-size: 12px
                entity: sensor.ebusd_signal_mqtt_status
                icon: mdi:gas-burner
                name: ebusd
                show_state: false
                color: rgb(255, 0, 0)
                state:
                  - value: up
                    color: rgb(0, 255, 0)
              - type: custom:button-card
                styles:
                  name:
                    - color: gray
                    - font-size: 12px
                entity: sensor.lampa_sypialnia_lewa_mqtt_status
                icon: mdi:lamp
                name: Sypialnia lewa
                show_state: false
                color: rgb(255, 0, 0)
                state:
                  - value: up
                    color: rgb(0, 255, 0)
              - type: custom:button-card
                styles:
                  name:
                    - color: gray
                    - font-size: 12px
                entity: sensor.lampa_sypialnia_prawa_mqtt_status
                icon: mdi:lamp
                name: Sypialnia prawa
                show_state: false
                color: rgb(255, 0, 0)
                state:
                  - value: up
                    color: rgb(0, 255, 0)
          - type: horizontal-stack
            cards:
              - type: custom:button-card
                styles:
                  name:
                    - color: gray
                    - font-size: 12px
                entity: sensor.solaredge_status
                icon: mdi:solar-power-variant
                name: Panele
                show_state: false
                color: rgb(255, 0, 0)
                font-size: 6px
                state:
                  - value: up
                    color: rgb(0, 255, 0)
              - type: custom:button-card
                styles:
                  name:
                    - color: gray
                    - font-size: 12px
                entity: sensor.odkurzacz_status
                icon: mdi:robot-vacuum
                name: ebusd
                show_state: false
                color: rgb(255, 0, 0)
                state:
                  - value: up
                    color: rgb(0, 255, 0)
              - type: custom:button-card
                styles:
                  name:
                    - color: gray
                    - font-size: 12px
                entity: sensor.nam_status
                icon: mdi:air-filter
                name: NAM
                show_state: false
                color: rgb(255, 0, 0)
                state:
                  - value: up
                    color: rgb(0, 255, 0)
              - type: custom:button-card
                styles:
                  name:
                    - color: gray
                    - font-size: 12px
                entity: sensor.drukarka_hp5070_status
                icon: mdi:printer
                name: Drukarka
                show_state: false
                color: rgb(255, 0, 0)
                state:
                  - value: up
                    color: rgb(0, 255, 0)
          - type: horizontal-stack
            cards:
              - type: custom:button-card
                styles:
                  name:
                    - color: gray
                    - font-size: 12px
                entity: sensor.frigate_status_2
                icon: mdi:cctv
                name: Frigate
                show_state: false
                color: rgb(255, 0, 0)
                font-size: 6px
                state:
                  - value: up
                    color: rgb(0, 255, 0)
              - type: custom:button-card
                styles:
                  name:
                    - color: gray
                    - font-size: 12px
                entity: sensor.hyperion_status
                icon: mdi:led-strip-variant
                name: Hyperion
                show_state: false
                color: rgb(255, 0, 0)
                state:
                  - value: up
                    color: rgb(0, 255, 0)
              - type: custom:button-card
                styles:
                  name:
                    - color: gray
                    - font-size: 12px
                entity: sensor.wled_tv_status
                icon: mdi:led-off
                name: WLED TV
                show_state: false
                color: gray
                state:
                  - value: pending
                    color: orange
                  - value: up
                    color: rgb(0,255,0)
                  - value: down
                    color: red
              - type: custom:button-card
                styles:
                  name:
                    - color: gray
                    - font-size: 12px
                entity: sensor.wled_sypialnia_status
                icon: mdi:led-off
                name: WLED Sypialnia
                show_state: false
                color: gray
                state:
                  - value: pending
                    color: orange
                  - value: up
                    color: rgb(0,255,0)
                  - value: down
                    color: red
        
      5. Pobranie danych z analogowego licznika wody

        Prosty projekt odczytujący z analogowego licznika dane i przekazujący informację do HomeAssistant przez MQTT. Projekt wykorzystuje bibliotekę uczenia maszynowego Tensorflow Lite do analizy obrazu.

        Hardware

        • ESP32 + OV2640 2.0MP camera module + antena (koszt ok 10$)
        • karton i trochę srebrnej taśmy

        Software

        AI on the Edge Device

        Konfiguracja

        Link

        https://github.com/jomjol/AI-on-the-edge-device

      6. Sterownie odkurzaczem Viomi Pro 2

        Prosta integracja sterowania odkurzaczem Viomi Pro 2.

        Korzysta z „custom” komponentów (instalowane przez HACS):

        Konfiguracja

        Viomise

        Instalujemy „custom” komponent przez HACS.

        Do konfiguracji będzie potrzebny IP oraz token urządzenia, który można pobrać za pomocą instrukcji.

        Dodajemy integrację z poziomu HA

        Xiaomi Cloud Map Extractor

        W pliku configuration.yaml

        camera:
        - platform: xiaomi_cloud_map_extractor
          host: !secret vacuum_host
          token: !secret vacuum_token
          username: !secret xiaomi_cloud_username
          password: !secret xiaomi_cloud_password
          draw: ['all']
          attributes:
            - calibration_points
        #    - goto
        #    - room_numbers
        #    - rooms
        #    - vacuum_room
        #    - vacuum_room_name
          map_transformation:
            scale: 5
            trim:
              top: 44
              bottom: 35
              left: 48
              right: 25
          sizes:
            charger_radius: 15
            vacuum_radius: 20
            path_width: 5
          colors:
            color_map_outside: [255, 255, 255]

        Home Assistant

        Wygląd karty

        Konfiguracja

        Linki

        https://hacs.xyz

        https://github.com/DominikWrobel/viomise

        https://github.com/PiotrMachowski/Home-Assistant-custom-components-Xiaomi-Cloud-Map-Extractor

        https://github.com/PiotrMachowski/Home-Assistant-custom-components-Xiaomi-Cloud-Map-Extractor

      7. Integracja kotła Valliant z ebusd

        Integracja z kotłem Valliant VC 186 oraz sterownikiem pogodowym VC400 korzysta z protokołu eBUS. Jako adapter eBUS wykorzystywana jest płytka w wersji 2.2 zbudowana na podstawie strony eBus Adapter 3. Od czasu jego zlutowania (2020) pojawiło się kilka nowszych wersji adaptera, ale nie zamierzam zmieniać, bo działa bardzo skutecznie. Komunikacja z HA jest za pomocą serwera MQTT.

        Schemat blokowy

        Wygląd płytki adaptera eBus z UART

        Oprogramowanie

        Korzystam z ebusd uruchomionego na Linuxie (Debian) jako serwis.

        Instalacja

        Instalacja pakietu ebusd wg instrukcji: link.

        Konfiguracja

        Konfiguracja w pliku /etc/default/ebusd

        #tryb standardowy
        #EBUSD_OPTS="--scanconfig -l/var/log/ebusd.log --device=/dev/ttyUSB0 --mqtthost=192.168.0.2 --mqttport=1883 --mqttjson --mqttuser=user_mqtt --mqttpass=pass_mqtt --mqttint=/etc/ebusd/mqtt-hassio.cfg"
        
        #tryb instalatora wi
        EBUSD_OPTS="--scanconfig -l/var/log/ebusd.log --device=/dev/ttyUSB0 --mqtthost=192.168.0.2 --mqttport=1883 --mqttjson --mqttuser=user_mqtt --mqttpass=pass_mqtt --mqttint=/etc/ebusd/mqtt-hassio.cfg --accesslevel=install"

        Oczywiście wartości mqtthost, mqttport, mqttuser, mqttpass należy ustawić na poprawne.

        Aby zmieniać niektóre wartości (krzywa grzewcza, stany liczników gazu) ebusd musi działać w trybie instalatora. Weryfikację, czy dany parametr jest modyfikowalny można sprawdzić w projekcie GIT https://github.com/john30/ebusd-configuration wyszukując odpowieni plik dla instalacji.

        Weryfikacja działania ebusd

        ebusctl info

        dla mojej instalacji komenda zwraca

        version: ebusd 24.1.24.1
        update check: OK
        device: /dev/ttyUSB0, serial
        access: install
        signal: acquired
        symbol rate: 22
        max symbol rate: 1441
        min arbitration micros: 0
        max arbitration micros: 3168
        min symbol latency: 0
        max symbol latency: 15
        scan: finished
        reconnects: 0
        masters: 3
        messages: 432
        conditional: 7
        poll: 110
        update: 16
        address 03: master #11
        address 08: slave #11, scanned "MF=Vaillant;ID=BAI00;SW=0516;HW=7401", loaded "vaillant/bai.308523.inc" ([id_hw=7401]), "vaillant/08.bai.csv"
        address 10: master #2
        address 15: slave #2, scanned "MF=Vaillant;ID=40000;SW=0139;HW=7301", loaded "vaillant/15.400.csv"
        address 31: master #8, ebusd
        address 36: slave #8, ebusd

        Problemy

        Ponieważ rozwiązanie działało już przez kilka lat nastąpiło przepełnienie liczników (ebusd/bai/PrEnergyXXX) odpowiedzialnych za zliczanie zużycia gazu.

        Poniżej komendy do zresetowania odpowiednich liczników:

        #odczyt
        ebusctl read -V -c bai PrEnergyCountHwc1
        
        #zapis
        ebusctl write -c bai PrEnergySumHc1 0
        ebusctl write -c bai PrEnergySumHwc1 0
        ebusctl write -c bai PrEnergyCountHc1 0
        ebusctl write -c bai PrEnergyCountHwc1 0

        Jeżeli przy zapisie są błędy „ERR: element not found” powyższe komendy należy wykonać w trybie instalatora (parametr „–accesslevel=install”).

        Home Assistant

        Karta ogrzewania w HA

        Rozwiązanie bazuje na cyklicznym odczycie danych przez MQTT. Aby oczytać jakąś wartość należy najpierw wysłać wiadomość odpowiedni topic MQTT. Do testowania najlepiej użyć klienta umożliwiającego podłączenie się bezpośrednio do serwera MQTT, np. MQTT Explorer

        Skrypty wymuszające pobieranie danych:

        script:
          ebus_refresh_2m:
            alias: "Pobierz dane ebus"
            sequence:
              - service: mqtt.publish
                data_template:
                  topic: 'ebusd/400/RoomTemp/get'
                  payload: ''   
              - service: mqtt.publish
                data_template:
                  topic: 'ebusd/bai/WaterPressure/get'
                  payload: ''
              - service: mqtt.publish
                data_template:
                  topic: 'ebusd/bai/CirPump/get'
                  payload: ''
              - service: mqtt.publish
                data_template:
                  topic: 'ebusd/400/IsInHoliday/get'
                  payload: ''  
              - service: mqtt.publish
                data_template:
                  topic: 'ebusd/400/IsInParty/get'
                  payload: ''
              - service: mqtt.publish
                data_template:
                  topic: 'ebusd/400/IsInSingleHwcLoadingMode/get'
                  payload: ''           
              - service: mqtt.publish
                data_template:
                  topic: 'ebusd/400/ActualRoomTempDesired/get'
                  payload: ''         
              - service: mqtt.publish
                data_template:
                  topic: 'ebusd/400/HwcTempDesired/get'
                  payload: ''        
              - service: mqtt.publish
                data_template:
                  topic: 'ebusd/bai/PrEnergySumHwc1/get'
                  payload: ''           
              - service: mqtt.publish
                data_template:
                  topic: 'ebusd/bai/PrEnergySumHc1/get'
                  payload: ''           
              - service: mqtt.publish
                data_template:
                  topic: 'ebusd/bai/PrEnergyCountHwc1/get'
                  payload: ''            
              - service: mqtt.publish
                data_template:
                  topic: 'ebusd/bai/PrEnergyCountHc1/get'
                  payload: ''
              - service: mqtt.publish
                data_template:
                  topic: 'ebusd/bai/StorageTemp/get'
                  payload: ''
              - service: mqtt.publish
                data_template:
                  topic: 'ebusd/400/OperatingMode/get'
                  payload: ''
              - service: mqtt.publish
                data_template:
                  topic: 'ebusd/400/OperatingModeHwc/get'
                  payload: ''
          ebus_refresh_30m:
            alias: "Pobierz dane ebus"
            sequence:
              - service: mqtt.publish
                data_template:
                  topic: 'ebusd/bai/HcHours/get'
                  payload: ''
              - service: mqtt.publish
                data_template:
                  topic: 'ebusd/bai/HwcHours/get'
                  payload: ''
              - service: mqtt.publish
                data_template:
                  topic: 'ebusd/bai/FlowSetPotmeter/get'
                  payload: ''
              - service: mqtt.publish
                data_template:
                  topic: 'ebusd/bai/HwcSetPotmeter/get'
                  payload: ''
              - service: mqtt.publish
                data_template:
                  topic: 'ebusd/400/HeatingCurve/get'
                  payload: ''
              - service: mqtt.publish
                data_template:
                  topic: 'ebusd/bai/PrEnergySumHwc2/get'
                  payload: ''           
              - service: mqtt.publish
                data_template:
                  topic: 'ebusd/bai/PrEnergySumHwc3/get'
                  payload: ''           
              - service: mqtt.publish
                data_template:
                  topic: 'ebusd/bai/PrEnergySumHc2/get'
                  payload: ''           
              - service: mqtt.publish
                data_template:
                  topic: 'ebusd/bai/PrEnergySumHc3/get'
                  payload: ''
              - service: mqtt.publish
                data_template:
                  topic: 'ebusd/400/ReducedNightTemp/get'
                  payload: ''

        i odpowiednie automatyzacje, dodatkowo automatyzacja powiadamiająca o zbyt niskim ciśnieniu w instalacji

        automation:
          - alias: "Ebusd - update after start"
            trigger:
              platform: homeassistant
              event: start
            action:
            - delay: 00:01:00
            - service: script.ebus_refresh_2m 
            - service: script.ebus_refresh_30m    
              
          - id: 'update_ebusd_1'
            alias: Ebusd - update 5min
            trigger:
              platform: time_pattern
              minutes: '/2'
            condition:
            - condition: state
              entity_id: sensor.ebusd_running
              state: 'true'
            action:
              - service: script.ebus_refresh_2m
          - id: 'update_ebusd_2'
            alias: Ebusd - update 30min
            trigger:
              platform: time_pattern
              minutes: /30
            condition:
            - condition: state
              entity_id: sensor.ebusd_running
              state: 'true'
            action:
              - service: script.ebus_refresh_30m     
              
          - id: waterpressure_low_notification
            alias: "Ebusd - Waterpressure Low Notification"
            initial_state: 'on'
            
            trigger:
              platform: numeric_state
              entity_id: sensor.cisnienie_wody
              below: 0.75    
            action:
            - service: notify.gmail_notifier
              data:
                message: "Ciśnienie wody za niskie:  {{ states('sensor.cisnienie_wody') }}"
                title: "[HA] Ciśnienie wody"
            - service: persistent_notification.create
              data:
                title: "Ciśnienie wody"
                message: >
                  Ciśnienie wody za niskie:  {{ states('sensor.cisnienie_wody') }}
                notification_id: "waterpressure_error"  

        Poniżej ustawienia mqtt (ustawienie w pliku configuration.yaml oraz mqtt.yaml)

        configuration.yaml

        ...
        mqtt: !include mqtt.yaml
        ...

        mqtt.yaml

        sensor:
        #########
        # EBUSD #
        #########
          - state_topic: "ebusd/global/running"
            name: "ebusd_running"
                
          - state_topic: "ebusd/global/signal"
            name: "ebusd_signal"
            
          - state_topic: "ebusd/global/uptime"
            name: "ebusd_uptime"
            
          - state_topic: "ebusd/global/version"
            name: "ebusd_version"
        
        
          - state_topic: "ebusd/bai/Status01"
            name: "ebus_FlowTemp"
            value_template: "{{ value_json['temp']['value'] }}"
            unit_of_measurement: '°C'
            device_class: temperature
        
          - state_topic: "ebusd/bai/Status01"
            name: "ebus_ReturnTemp"
            value_template: "{{ value_json['temp_1']['value'] | round(1)}}"
            unit_of_measurement: '°C'
            device_class: temperature
        
          - state_topic: "ebusd/bai/Status01"
            name: "Temperatura zewnętrzna"
            value_template: "{{ value_json['temp_2']['value'] | round(1)}}"
            unit_of_measurement: '°C'
            device_class: temperature
        
          - state_topic: "ebusd/bai/Status01"
            name: "Temperatura c.w."
            value_template: "{{ value_json['temp_4']['value'] }}"
            unit_of_measurement: '°C'
            device_class: temperature
            
          - state_topic: "ebusd/bai/Status01"
            name: "Płomień"
            value_template: "{{ value_json['pumpstate']['value'] }}"
        
        ##z automatyzacji
          - state_topic: "ebusd/400/RoomTemp"
            name: "Temperatura Jadalnia"
            value_template: "{{ ((value_json['temp']['value']|float)-1) | round(1)}}"
            unit_of_measurement: '°C'
            device_class: temperature
            
          - state_topic: "ebusd/400/ActualRoomTempDesired"
            name: "Temperatura zadana"
            value_template: "{{ value_json['value']['value'] | round(1)}}"
            unit_of_measurement: '°C'
            device_class: temperature
            
          - state_topic: "ebusd/bai/HcHours"
            name: "Liczba godzin pracy ogrzewania"
            value_template: "{{ value_json['value']['value'] }}"
            unit_of_measurement: 'h'
        
          - state_topic: "ebusd/bai/HwcHours"
            name: "Liczba godzin pracy c.w.u."
            value_template: "{{ value_json['value']['value'] }}"
            unit_of_measurement: 'h'
        
          - state_topic: "ebusd/bai/FlowSetPotmeter"
            name: "Ustawienie ogrzewania"
            value_template: "{{ value_json['value']['value'] | round(1)}}"
            unit_of_measurement: '°C'
            device_class: temperature
        
          - state_topic: "ebusd/bai/HwcSetPotmeter"
            name: "Ustawienie c.w.u"
            value_template: "{{ value_json['value']['value'] | round(1)}}"
            unit_of_measurement: '°C'
            device_class: temperature
            
          - state_topic: "ebusd/bai/WaterPressure"
            name: "Ciśnienie wody"
            value_template: "{{ value_json['press']['value'] }}"
            unit_of_measurement: 'Pa'
            device_class: pressure
            
          - state_topic: "ebusd/bai/CirPump"
            name: "Pompa cyrkulacyjna"
            value_template: "{{ value_json['value']['value'] }}"
            
          - state_topic: "ebusd/400/HeatingCurve"
            name: "Krzywa grzewcza"
            value_template: "{{ value_json['value']['value'] }}"
            
          - state_topic: "ebusd/400/IsInHoliday"
            name: "Tryb wakacyjny"
            value_template: "{{ value_json['value']['value'] }}"
            
          - state_topic: "ebusd/400/IsInParty"
            name: "Tryb impreza"
            value_template: "{{ value_json['value']['value'] }}"
            
          - state_topic: "ebusd/400/IsInSingleHwcLoadingMode"
            name: "Tryb ładowania zasobnika"
            value_template: "{{ value_json['value']['value'] }}"
        
          - state_topic: "ebusd/bai/Status02"
            name: "ebusd_hwcmode"
            value_template: "{{ value_json['hwcmode']['value'] }}"
        
          - state_topic: "ebusd/bai/Status02"
            name: "ebusd_st2_1"
            value_template: "{{ value_json['temp_1']['value'] }}"
        
          - state_topic: "ebusd/bai/Status02"
            name: "ebusd_st2_2"
            value_template: "{{ value_json['temp_2']['value'] }}"
            unit_of_measurement: '°C'
            device_class: temperature    
        
          - state_topic: "ebusd/bai/Status02"
            name: "ebusd_st2_3"
            value_template: "{{ value_json['temp_3']['value'] }}"    
        
          - state_topic: "ebusd/bai/Status02"
            name: "ebusd_st2_4"
            value_template: "{{ value_json['temp_4']['value'] }}"    
            unit_of_measurement: '°C'
            device_class: temperature    
            
          - state_topic: "ebusd/bai/PrEnergySumHwc1"
            name: "ebusd_PrEnergySumHwc1"
            value_template: "{{ value_json['value']['value'] }}"    
            unit_of_measurement: 'W'
            device_class: power
            
          - state_topic: "ebusd/bai/PrEnergySumHwc2"
            name: "ebusd_PrEnergySumHwc2"
            value_template: "{{ value_json['value']['value'] }}"    
            unit_of_measurement: 'W'
            device_class: power
        
          - state_topic: "ebusd/bai/PrEnergySumHwc3"
            name: "ebusd_PrEnergySumHwc3"
            value_template: "{{ value_json['value']['value'] }}"   
            unit_of_measurement: 'W'
            device_class: power
        
          - state_topic: "ebusd/bai/PrEnergySumHc1"
            name: "ebusd_PrEnergySumHc1"
            value_template: "{{ value_json['value']['value'] }}"   
            unit_of_measurement: 'W'
            device_class: power
        
          - state_topic: "ebusd/bai/PrEnergySumHc2"
            name: "ebusd_PrEnergySumHc2"
            value_template: "{{ value_json['value']['value'] }}"   
            unit_of_measurement: 'W'
            device_class: power
        
          - state_topic: "ebusd/bai/PrEnergySumHc3"
            name: "ebusd_PrEnergySumHc3"
            value_template: "{{ value_json['value']['value'] }}"   
            unit_of_measurement: 'W'
            device_class: power
        
          - state_topic: "ebusd/bai/PrEnergyCountHwc1"
            name: "ebusd_PrEnergyCountHwc1"
            value_template: "{{ value_json['value']['value'] }}"    
            unit_of_measurement: 'W'
            device_class: power
        
          - state_topic: "ebusd/400/OperatingModeHwc"
            name: "ebusd_OperatingModeHwc"
            value_template: "{{ value_json.value.value }}"
        
          - state_topic: "ebusd/400/OperatingMode"
            name: "ebusd_OperatingMode"
            value_template: "{{ value_json.value.value }}"

        Konfiguracja dodatkowych obiektów w pliku mqtt.yaml

        climate:
          - name: "Ogrzewanie"
            max_temp: 25
            min_temp: 15
            precision: 0.1
            temp_step: 0.5
            modes:
              - "heat"
              - "off"
            mode_state_template: >-
              {% set values = { 'auto':'auto', 'on':'heat',  'hwc':'cool', 'off':'off'} %}
              {% set state = value_json['pumpstate']['value'] %}
              {{ values[state] if state in values.keys() else 'off' }}
            mode_state_topic: "ebusd/bai/Status01"
            current_temperature_topic: "ebusd/400/RoomTemp"
            current_temperature_template: '{{value_json["temp"].value|float -1.25 }}'
            temperature_state_topic: "ebusd/400/ActualRoomTempDesired"
            temperature_state_template: '{{value_json.value.value}}'
          - name: "Ciepła woda"
            max_temp: 65
            min_temp: 40
            precision: 1
            temp_step: 1
            modes:
              - "heat"
              - "off"
            mode_state_template: >-
              {% set values = { 'hwc':'heat', 'off':'off'} %}
              {% set state = value_json['pumpstate']['value'] %}
              {{ values[state] if state in values.keys() else 'off' }}
              
            mode_state_topic:  "ebusd/bai/Status01"
            temperature_state_topic: "ebusd/400/HwcTempDesired"
            temperature_state_template: '{{value_json.value.value}}'
            temperature_command_topic: "ebusd/400/HwcTempDesired/set"
            current_temperature_topic: "ebusd/bai/StorageTemp"
            current_temperature_template: '{{value_json["temp"].value}}'
        
        number:
          - name: mqtt_tryb_wakacyjny
            icon: mdi:caravan
            min: 0 
            max: 20
            step: 1
            mode: slider
            command_topic: ebusd/400/IsInHoliday/set
            state_topic: "ebusd/400/IsInHoliday"
            value_template: '{{value_json.value.value | int}}'
          - name: mqtt_krzywa_grzewcza
            icon: mdi:chart-bell-curve-cumulative
            min: 0.2
            max: 4
            step: 0.1
            mode: slider
            command_topic: ebusd/400/HeatingCurve/set
            state_topic: ebusd/400/HeatingCurve
            value_template: '{{value_json.value.value | float}}'
        
        switch:
          - name: mqtt_tryb_impreza
            icon: mdi:glass-cocktail
            command_topic: "ebusd/400/IsInParty/set"
            state_topic: "ebusd/400/IsInParty"
            value_template: '{{value_json.value.value }}'
            payload_on: "on"
            payload_off: "off"
          - name: mqtt_tryb_ladowania_zasobnika
            icon: mdi:heat-pump
            command_topic: "ebusd/400/IsInSingleHwcLoadingMode/set"
            state_topic: "ebusd/400/IsInSingleHwcLoadingMode"
            value_template: '{{value_json.value.value }}'
            payload_on: "on"
            payload_off: "off"    

        Zużycie gazu

        Zużycie gazu można wyliczyć na podstawie liczników PrEnergySumHwc1 oraz PrEnergySumHw1. Na podstawie pomiarów należy wyliczyć stosunek zużycia gazu do sumy PrEnergySumHwc1 i PrEnergySumHw1.

        Komponent do wprowadzenia poprzednich wartości odczytanych

        type: entities
        entities:
          - entity: input_number.gas_last_measure
          - entity: input_number.gas_prenergysumhc1
          - entity: input_number.gas_prenergysumhwc1
          - entity: input_number.wspolczynnik_gazu
          - entity: sensor.licznik_gazu
        title: Zużycie gazu
        show_header_toggle: false

        Wyliczenie bieżącej wartości zużycia gazu (plik sensors.yaml)

              licznik_gazu:
                friendly_name: "Licznik gazu"
                unit_of_measurement: "m³"
                device_class: gas
                icon_template:
                    mdi:gas-burner
                value_template: '{{ ((states.input_number.gas_last_measure.state | float) +
                   ((states.sensor.ebusd_prenergysumhc1.state | int +  states.sensor.ebusd_prenergysumhwc1.state | int) -
                   (states.input_number.gas_prenergysumhc1.state | int + states.input_number.gas_prenergysumhwc1.state | int)) /
                   (states.input_number.wspolczynnik_gazu.state | float)
                   ) |round(3) 
                  }}

        Linki

        https://ebusd.eu

        https://adapter.ebusd.eu/v2/index.en.html

        https://github.com/john30/ebusd-configuration/issues/117

      8. Pomiar odległości, temperatury oraz wilgotności

        Kiedyś wymyśliłem, że przydałaby się informacja, czy w garażu jest zaparkowany samochód. Wyszło całkiem proste urządzenie, które poza identyfikacją samochodu, jednocześnie weryfikuje – czy jest otwarta, czy zamknięta brama garażowa oraz mierzy temperaturę i wilgotność w garażu. Koszt ok 40 PLN (bez obudowy i zasilacza na microUSB).

        Czujnik temperatury jest opcjonalny.

        Ważne jest umiejscowienie całego urządzenia – na suficie, czujnik odległości skierowany w dół, nad końcem otwartej bramy garażowej, dzięki temu można wyłapać stany (otwarty garaż, auto/zamknięty garaż, brak auta/zamknięty garaż) dodatkowo czujnik musi być umieszczony nad zaparkowanym autem.

        Wykorzystane komponenty:

        • Czujnik odległości HC-SR04
        • Czujnik SI7021 (ja wykorzystałem wolny czujnik od Sonoff TH10, TH16, itd.)
        • Wemos D1 mini

        Poniżej schemat:

        plus podłączenie SI7021 na D5 (pin 12). Na schemacie nie zaznaczono masy i podłączenie zasilania do Wemos D1 mini.

        Oprogramowanie

        Należy wcześniej zainstalować dodatek ESPHome w HomeAssistant.

        Poniżej konfiguracja Wemos D1 mini w ESPHome. Należy dodatkowo utworzyć plik secrets.yaml w EspHome.

        esphome:
          name: wemos1
          platform: ESP8266
          board: d1_mini
        
        wifi:
          networks:
          - ssid: !secret ssid
            password: !secret password
        
          # Enable fallback hotspot (captive portal) in case wifi connection fails
          ap:
            ssid: "Wemos1 Fallback Hotspot"
            password: !secret password_fallback
        
        captive_portal:
        
        # Enable logging
        logger:
        
        # Enable Home Assistant API
        api:
        
        ota:
          - platform: esphome
          
        web_server:
        
        sensor:
          - platform: dht
            model: SI7021 
            pin: D5
            temperature:
              name: "garaz_temperature"
            humidity:
              name: "garaz_humidity"
            update_interval: 60s
            
          - platform: ultrasonic
            trigger_pin: D7
            echo_pin: D6
            timeout: 3 m
            update_interval: 3s
            name: "garaz_distance"    
            filters:
            - lambda: |-
                 float MAX_DIFFERENCE = .3;  // adjust this!
                 static float last_value_t = NAN;
                 static int count_missed_t = 0;
                 if (count_missed_t == 3) last_value_t = x;
                 if (isnan(last_value_t) || std::abs(x - last_value_t) < MAX_DIFFERENCE) {
                    if (count_missed_t)
                       ESP_LOGI("sensor", "New echo value %.3f", x);
                    count_missed_t = 0;
                    return last_value_t = x;
                 } else {
                    count_missed_t += 1;
                    ESP_LOGW("sensor", "Missed echo value %.3f => %.3f, %d", last_value_t, x, count_missed_t);
                    return last_value_t;
                 }
            - sliding_window_moving_average:
                 window_size: 256
                 send_every: 1  
        mqtt:
          broker:  !secret mqtt_broker_ip
          username: !secret mqtt_username
          password: !secret mqtt_password

        Plik secrets.yaml

        #mqtt
        mqtt_broker_ip: 192.168.1.1
        mqtt_username: uzytkownik_mqtt
        mqtt_password: haslo_mqtt
        
        # Your Wi-Fi SSID and password
        ssid: 'nazwa_wifi'
        password: 'haslo_wifi'
        
        #Wifi Fallback Hotspot
        password_fallback: 'magiczne_haslo'

        Konfiguracja

        Home Assistant

        Czujnik jest wykrywany automatycznie przez Home Assistanta.

        Kod sensora

          - platform: template
            sensors:
              garaz:
                friendly_name: "Garaż"
                value_template: >-           
                    {% if float(states("sensor.garaz_distance"))<float(0.30) -%}
                       Otwarty
                    {% elif (float(states("sensor.garaz_distance"))>float(0.80)) and (float(states("sensor.garaz_distance"))<=float(1.10))  -%}
                       Auto 1
                    {% elif (float(states("sensor.garaz_distance"))>float(1.10)) and (float(states("sensor.garaz_distance"))<=float(1.18))  -%}
                       Auto 2
                    {% elif (float(states("sensor.garaz_distance"))>float(1.18)) and (float(states("sensor.garaz_distance"))<=float(1.30))  -%}
                       Auto 3
                    {% elif (float(states("sensor.garaz_distance"))>float(1.30)) -%}
                       Pusty
                    {% else -%}
                       ???
                    {% endif -%}
                icon_template:
                    mdi:car

        Należy dobrać odpowiednio wysokości, aby poprawnie wykrywać otwarcie garażu oraz poszczególne samochody (muszą się różnić wysokością dachu).

        Automatyzacje

        - id: 'auto_garaz_swiatla_on_gate'
          alias: 'Garaż - włącz światło (brama)'
          trigger:
            platform: state
            entity_id: sensor.garaz
            to: 'Otwarty'
          condition:
            - condition: state
              entity_id: light.garaz
              state: 'off'
              for:
                seconds: 10
          action:
            service: light.turn_on
            entity_id: light.garaz
        
        - id: 'openGarageNotification10m'
          alias: openGarageNotification10m
          description: 'Garaz - powiadomienie o otwarciu przez 10m'
          trigger:
          - platform: state
            entity_id:
            - sensor.garaz
            to: Otwarty
            for:
              hours: 0
              minutes: 10
              seconds: 0
          condition: []
          action:
          - service: script.notify_opengarage_10m
            data: {}
          mode: single

        i przykładowy skrypt z powiadomieniem o otwartym garażu (plik script.yaml)

          notify_opengarage_10m:
            alias: "Powiadomienie - Otwarty garaz przez 10min"
            sequence:
              - service: camera.snapshot
                target:
                  entity_id: camera.esp32camgaraz_esp_cam
                data:
                  filename: ../media/snapshot10m.jpg
              - service: notify.gmail_notifier
                data:
                  title: "[HA] Garaż otwarty"
                  message: "Garaż otwarty"
                  data:
                    images:
                    - ../media/snapshot10m.jpg
      9. Szczegółowa lista sprzętu

        UrządzeniaCelKonfiguracja
        Shelly 1, Shelly 1PM, Shelly 2Sterowanie oświetleniemMQTT
        Shelly 1PM gen4, Shelly 2PM gen4Sterowanie oświetleniemZigbee
        Shelly Door/Window 2Otwarcie/zamknięcie drzwiMQTT
        Sonoff Basic, Sonoff THLampy stojące, choinkaMQTT
        Sonoff BasicPompa wodyMQTT
        Satel Integra 64Wykrywanie ruchu, UPS dla RPIlink
        Raspberry PI5 8GB z wentylatorem,
        Raspberry AI Kit (Hailo-8L)
        HomeAssistant, Ebusd, Serwer NAS (Samba), analiza obrazu z kamer
        Nettigo Air Monitor 0.3Pomiar jakości powietrza
        Wodomierz Multical 21Pomiar zużycia wodylink
        Viomi Pro 2Sterowanie odkurzaniemlink
        Vaillant VC ecoTEC Pro 186/5, Sterownik VC400 plus Ebus 3Sterowanie ogrzewaniemlink
        Google miniSterowanie głosem (ang.)
        AmplitunerSterowanie nagłośnieniemlink
        Falownik SolarEdgeProdukcja prądu
        Drukarka atramentowa HPOdczyt poziomu tuszów
        RPi3 + kamera USBAmbient Light TVlink
        Taśmy LED Podświetlenie TV i sypialni
        Kamera BLOW IP 5MP WiFi 3,6 mmKamera zewnętrzna
        Kamera TP-Link Tapo C210Kamera wewnętrzna
        Zmywarka Bosch Seria 4Sterowanie zmywarką/powiadomienia

        Urządzenia ZigBee

        UrządzenieCel
        Shelly 1PM gen 4, Shelly 2PM gen4Sterowanie oświetleniam
        Bramka SONOFF Zigbee 3.0 USB Dongle Plus (ZBDongle-P)Bramka ZigBee
        Głowice TUYA HY368 ZigBee
        Głowice GTZ08 ZigBee 3.0 TUYA
        Termostaty kaloryferów
        Gniazdka zigbee:
        – BlitzWolf BW-SHP13
        – Forta IGZ-K
        Włączenie/wyłączenie + pomiar mocy
        Żarówki zigbee:
        – OSRAM LIGHTIFY LED Classic A60 clear
        Sterowanie jasnością
        Silnik rolety MOES AM43Sterowanie roletą
        Agara CubeSterowanie oświetleniem
        Lampki ogrodowe OSRAM Smart+Sterowanie oświetleniem zewnętrznym
        Sonoff BASICZBR3Przełącznik
        Czujnik deszczu z czujnikiem oświetlenia Pomiar deszczu i oświetlenia
        Tester gleby (Haozee)Czujnik wilgotności, temperatury, wilgotności gleby

        Czujniki

        Czujnik/ChipCelKonfiguracja
        SI7021Pomiar temperatury i wilgotnościlink
        BME-280Pomiar temperatury, wilgotności i ciśnienialink
        Moduł radiowy CC1101 RF 868MHZ Pomiar zużycia wodylink
        HC-SR04Pomiar odległościlink
        HC-SR501Czujnik PIR (regulowany)
        NodeMCU2Sterowniki
        Wemos D1 miniSterowniki
        Wemos PIR ShieldCzujnik PIR
        ESP32 + CamKamery
        ESP32 + CamOdczyt analogowego licznikalink
        ESP32-S3-Zero-MSterowanie taśmami LED