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 2
    • Sonoff Basic (z firmware Tasmota)
    • Sonoff TH
    • Alarm Integra 64
    • Czujniki SI7021
    • Czujnik HC-SR04 
    • Czujnik BME-280
    • Moduł WiFi NodeMCU V2
    • Moduł Wifi ESP32
    • Wemos D1 mini
    • Raspberry PI5
    • Nettigo Air Monitor 0.3
    • bramka Zigbee
    • Termostaty TUYA HY368 ZigBee
    • gniazdka zigbee
    • żarówki zigbee
    • sterowanie roletą (zigbee)
    • Ebusd

    plus szereg integracji:

    Szczegółowa lista urządzeń i integracji

  • 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

  • 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"    

    Linki

    https://ebusd.eu

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

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

  • 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
  • Szczegółowa lista sprzętu

    UrządzeniaCelKonfiguracja
    Shelly 1, Shelly 1PM, Shelly 2Sterowanie oświetleniemMQTT
    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 wentylatoremHomeAssistant, Ebusd, Serwer NAS (Samba), analiza obrazu z kamer
    Nettigo Air Monitor 0.3Pomiar jakości powietrza
    Wodomierz Multical 21Pomiar 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

    Urządzenia ZigBee

    UrządzenieCel
    Bramka SONOFF Zigbee 3.0 USB Dongle Plus (ZBDongle-P)Bramka ZigBee
    Termostaty TUYA HY368 ZigBeeTermostaty kaloryferów
    Gniazdka zigbee (Forta IGZ-K)Włączenie/wyłączenie + pomiar mocy
    Żarówki zigbeeSterowanie jasnością
    Silnik roletySterowanie roletą
    Agara CubeSterowanie oświetleniem
    Lampki ogrodowe OSRAMSterowanie oświetleniem zewnętrznym

    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
    SR04Pomiar odległościlink
    NodeMCU2Sterowniki
    Wemos D1 miniSterowniki
    ESP32 + CamKamery
  • Integracja z alarmem Satel Integra 64

    Istnieje oczywiście możliwość integracji przez moduł eth, ale ponieważ jest on kosztowny zaprojektowałem proste rozwiązanie wykorzystując wolne wyjścia w domowej centrali Satel Integra. Nie jest to dwukierunkowa integracja, a jedynie przekazywanie informacji od alarmu do HomeAssistant. Dzięki temu można stworzyć fajne automatyzacje na podstawie wykrytego ruchu. Koszt integracji ok 50 PLN

    W tym rozwiązaniu akumulator w centrali alarmowej jest wykorzystywany jako UPS dla RaspberryPI, co oczywiście skraca czas działania alarmu przy długich wyłączeniach prądu.

    Hardware

    • Konwerter poziomów logicznych dwukierunkowy, 4-kanałowy – Pololu – 2 szt.
    • Przetwornica Step-Down – 9-38V – na 5V – USB – 5A
    • NodeMCU (alternatywnie Wemos D1 mini – tańsze rozwiązanie, ja miałem pod ręką akurat wolny chipset NodeMCU)

    Schemat blokowy

    Zastosowałem 25W przetwornicę napięcia, aby z alarmu zasilić od razu RaspberryPI na którym jest uruchomiony HomeAssistant. Dzięki temu w przypadku braku zasilania RPi działa aż do wyczerpania baterii w alarmie.

    Ważne jest użycie i skonfigurowanie odpowiednich wyjść w na płycie Integra – nie wszystkie wyjścia są wyjściami wysokoprądowymi.

    Uwaga na schemacie nie zaznaczono masy.

    Widok płytki od strony elementów

    Software

    Alarm

    Konfiguracja w systemie alarmowym jest wykonana w oprogramowaniu DLOADX.

    Wyjścia typu Out są wysterowane przez 3 sekundy przez wejścia z czujek PIR

    Wyjście OUT Integra64OpisNodeMcu
    4Zasilanie 12V/3A: – Raspberry 5V/2,5A – NodeMCU 5V/300mA –
    5Załączony alarm w strefach: 1, 3D3/GPIO0
    6PIR1D1/GPIO5
    7PIR2D4/GPIO2
    9PIR3D2/GPIO4
    10PIR4D5/GPIO14
    12PIR5D0/GPIO16
    13PIR6D6/GPIO12
    14PIR7D7/GPIO13

    HomeAssistant

    ESPHome

    Należy wcześniej zainstalować addon ESPHome w HomeAssistant

    Konfiguracja NodeMCU w ESPHome. Należy dodatkowo utworzyć plik secrets.yaml

    esphome:
      name: alarm
      platform: ESP8266
      board: nodemcuv2
    
    wifi:
      networks:
      - ssid: !secret ssid
        password: !secret password
    
      # Enable fallback hotspot (captive portal) in case wifi connection fails
      ap:
        ssid: "Alarm Fallback Hotspot"
        password: !secret password_fallback
    
    captive_portal:
    
    # Enable logging
    logger:
      level: INFO
    
    # Enable Home Assistant API
    api:
      port: 6053
    
    ota:
      - platform: esphome
      
    #web_server:
    
    mqtt:
      broker:  !secret mqtt_broker_ip
      username: !secret mqtt_username
      password: !secret mqtt_password
    
    binary_sensor:
      - platform: gpio
        pin: 
          number: GPIO0
        filters:
          - invert:
          - delayed_on: 250ms
          - delayed_off: 250ms
        name: "alarm_1_3"
        
      - platform: gpio
        pin: 
          number: GPIO5
        filters:
          - invert:
          - delayed_on: 250ms
          - delayed_off: 250ms
        name: "ruch_pir1"
        device_class: motion
    
      - platform: gpio
        pin: 
          number: GPIO2
        filters:
          - invert:
          - delayed_on: 250ms
          - delayed_off: 250ms
        name: "ruch_pir2"
        device_class: motion
        
      - platform: gpio
        pin: 
          number: GPIO4
        filters:
          - invert:
          - delayed_on: 250ms
          - delayed_off: 250ms
        name: "ruch_pir3"
        device_class: motion
    
      - platform: gpio
        pin: 
          number: GPIO14
        filters:
          - invert:
          - delayed_on: 250ms
          - delayed_off: 250ms
        name: "ruch_pir4"
        device_class: motion
        
      - platform: gpio
        pin: 
          number: GPIO16
        filters:
          - invert:
          - delayed_on: 250ms
          - delayed_off: 250ms
        name: "ruch_pir5"   
        device_class: motion
        
      - platform: gpio
        pin: 
          number: GPIO12
        filters:
          - invert:
          - delayed_on: 250ms
          - delayed_off: 250ms
        name: "ruch_pir6"
        device_class: motion
        
      - platform: gpio
        pin:  
          number: GPIO13
        filters:
          - invert:
          - delayed_on: 250ms
          - delayed_off: 250ms
        name: "ruch_pir7"
        device_class: motion

    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'

    Przykładowe automatyzacje

    Włączenie/wyłączenie światła

    - id: 'auto_kuchnia_swiatla_on'
      alias: 'Kuchnia - Włącz światło'
      trigger:
        platform: state
        entity_id: binary_sensor.ruch_pir1
        from: 'off'
        to: 'on'
      condition:
        condition: and
        conditions:
        - condition: state
          entity_id: light.kuchnia
          state: 'off'
          for:
            seconds: 5
        - condition: template
          value_template: "{{ states.sun.sun.attributes.elevation  | int < 3 }}"
      action:
        service: light.turn_on
        entity_id: light.kuchnia
    
    - id: 'auto_kuchnia_swiatla_off'
      alias: 'Kuchnia - wyłącz po 3 min'
      trigger:
        platform: state
        entity_id: binary_sensor.ruch_pir1
        to: 'off'
        for: 
          minutes: 3
      condition:
        - condition: state
          entity_id: light.kuchnia
          state: 'on'
      action:
        service: light.turn_off
        entity_id: light.kuchnia

    Wyłączenie urządzeń przy załączeniu strefy w alarmie

    - id: 'auto_alarm_swiatla_off'
      alias: 'Alarm - Wyłącz światła przy załączonym alarmie'
      trigger:
        platform: state
        entity_id: binary_sensor.alarm_1_3
        from: 'off'
        to: 'on'
        for: 
          seconds: 15
      condition:
        - condition: state
          entity_id: group.swiatla_dol
          state: 'on'
      action:
        - service: light.turn_off
          entity_id: group.swiatla_dol
        - service: switch.turn_off
          entity_id: switch.pompa_wody
        - service: light.turn_off
          entity_id: light.lampki_choinkowe
        - service: media_player.turn_off
          entity_id: media_player.amplituner
        - service: media_player.turn_off
          entity_id: media_player.tv

    Linki

    https://esphome.io

    https://www.satel.pl/instrukcje

  • Sterowanie przez podczerwień i pomiar temperatury, wilgotności i ciśnienia

    Jedno z moich pierwszych urządzeń to pilot na podczerwień (odbiornik i nadajnik) oraz pomiar temperatury, wilgotności i ciśnienia (szacunkowy koszt ok 40 PLN, bez zasilacza). Jest też gotowy shield IR do Wemos D1 mini – co jest prostszym rozwiązaniem niż lutowanie całości.

    Wykorzystane komponenty:

    • Wemos D1 mini
    • BME280
    • nadajnik i odbiornik podczerwieni

    Poniżej schemat logiczny:

    Układ połączeń

    Uwaga – należy jak najdalej odsunąć czujnik BME280 od Wemos D1

    Oprogramowanie

    Do układu Wemos D1 mini zostało wgrane oprogramowanie Tasmota Sensor. Wcześniej używałem ESPHome, ale w tym przypadku trudniej obsługiwać sterowanie różnymi pilotami na podczerwień. Tasmota Sensor rozpoznaje kody pilotów różnych dostawców., dzięki czemu skrypty w HomeAssistant są prostsze. Opcjonalnie można by też użyć wersji tasmota-ir, aby obsłużyć więcej różnych dostawców urządzeń IR.

    Konfiguracja

    Tasmota Sensor

    Dodatkowo w Tasmocie jest ustawiona konfiguracja połączenia do serwera MQTT.

    Odczyt kodów IR z pilota najlepiej przeprowadzić z poziomu konsoli Tasmota.

    HomeAssistant

    Czujnik BME280 wykrywany jest automatycznie przez HA.

    Przykładowy skrypt wysyłający kod IR do urządzenia:

     script:
      amplituner_volume_up:
        alias: Głośniej
        sequence:
          - service: mqtt.publish
            data_template:
              payload: "{\"Protocol\":\"NEC\",\"Bits\":32,\"Data\":0x5EA158A7}"
              topic: cmnd/wemos2/IRSend
              retain: true

    Linki

    https://tasmota.github.io/docs

  • Pobranie danych z licznika wody Multical 21

    Poniżej tania integracja (ok. 50PLN) odczytu bieżącego zużycia wody z licznika Multical 21. Aby uruchomić tą integracja trzeba:

    • spore umiejętności przy lutowaniu oraz
    • kontakt z firmą, która obsługuje rozliczenie wody i trochę cierpliwości, aby otrzymać kod deszyfrujący AES dla licznika

    Licznik Multial 21 może wysyłać dane bezprzewodowo przy użyciu protokołu Wireless M-Bus. Multical21 zapewnia następujące dane:

    • licznik całkowity – całkowite zużycie wody w m³
    • licznik docelowy – zużycie wody do 1. dnia bieżącego miesiąca
    • temperatura średnia – w °C
    • temperatura otoczenia – w °C
    • kody informacyjne – BURST, LEAK, DRY, REVERSE, TAMPER, RADIO OFF
    Kod informacyjny
    wyświetlany na
    wyświetlaczu
    Znaczenie
    LEAK W ciągu ostatniej doby nie zanotowano zatrzymania przepływu przez wodomierz przez minimum jedną godzinę.
    Może to świadczyć o nieszczelności kranu lub zbiornika toalety.
    BURST Stałe wysokie zużycie wody w ciągu pół godziny, co oznacza pęknięcie rury.
    TAMPER Próba oszustwa. Wodomierz nie nadaje się do celów rozliczeniowych.
    DRY Brak wody w wodomierzu. Pomiar nie jest prowadzony.
    REVERSE Woda przepływa przez wodomierz w nieprawidłowym kierunku.
    RADIO OFFRADIO OFF wyświetlany ciągle. Nadajnik radiowy jest permanentnie wyłączony.

    Hardware

    • Wemos D1 mini (lub ESP32) – koszt ok 12 PLN
    • moduł radiowy CC1101 868 MHz z anteną (ja zamówiłem tu) – koszt ok 30 PLN
    • 7 przewodów

    Software

    Połączenie

    Trzeba sporo wprawy, aby zlutować połączenia do CC1101 – raster jest mniejszy niż standardowy goldpin.

    CC1101ESP8266
    VCC3V3
    GNDGND
    CSND8
    MOSID7
    MISOD6
    SCKD5
    GDO0D2

    Poniżej jak mi to wyszło:

    Uruchomienie

    Polecam najpierw złożyć, uruchomić bez kodu deszyfrującego – zweryfikować, czy działa komunikacja . A następnie ponowne programowanie Wemos D1 mini już z kluczem AES. W moim przypadku odczyt następuje z ok 10 metrów przez kilka ścian.

    Aby uzyskać klucz deszyfrujący AES należy skontaktować się ze spółką rozliczającą wodę. W moim przypadku wystarczyło pismo ogólne zgłoszone przez platformę EPUAP (w tym wypadku nie musiałem poświadczać swojej tożsamości) i plik z kluczem oraz hasłem dostałem bezpośrednio na emaila. (podziękowania dla pana Piotra ze Spółki Komunalnej Żukowo).

    Przykładowe pismo znajduje się tu.

    Plik ZIP z plikiem KEM zawiera kluczem AES, Aby odczytać klucz AES konieczne jest hasło i należy użyć dodatkowego programu w python.

    Programowanie

    Na PlatformIO zaimportuj projekt esp-multical21.

    Zmiany w kodzie

    Należy zmienić nazwę pliku config_template.h na config.h oraz w pliku wprowadzić zmiany

    Ustawić numer licznika

    //numer seryjny licznika
    #define SERIAL_NUMBER       0x65, 0x00, 0x05, 0x43

    Ustawić sieć WiFi, adres serwera MQTT

    std::vector<CREDENTIAL> const credentials = {
         { "sid_sieci_wifi", "haslo_sieci_wifi", "", "", ""}   // no MQTT
       , { "sid_sieci_wifi", "haslo_sieci_wifi", "adres_IP_serwera_mqtt", "login_serwera_mqtt", "haslo_serwera_mqtt"}  // MQTT with auth
    };

    Ustawić klucz AES (najlepiej po sprawdzeniu, czy odbiera się ramki z licznika

    #define ENCRYPTION_KEY      0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0x10, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17
    

    Weryfikacja logów na porcie COM z prędkością 115200. Podczas wyszukiwania sieci mruga dioda na chipie Wemos D1.

    Dekodowanie pliku KEM

    Aby odczytać klucz AES należy uruchomić program kem-decryptor.py w pythonie ze strony:

    https://gist.github.com/mbursa/caa654a01b9e804ad44d1f00208a2490

    kem-decryptor.py nazwa_pliku_ZIP_lub_KEM hasło

    Na ekranie oraz w pliku etc\wmbusmeters.d\<numer_Licznika> będzie klucz który przepisujemy do pliku config.h, ponownie kompilujemy i wgrywamy oprogramowanie do Wemos D1 mini.

    Konfiguracja HA

    W moim przypadku Wemos przesyła informacje do serwera MQTT uruchomionego jako dodatek w HA.

    Konfiguracja dla sekcji mqtt:

    Plik configuration,xml

    mqtt: !include mqtt.yaml

    Plik mqtt.xml

      - state_topic: "watermeter/0/total"
        name: "watermeter_total"  
        unit_of_measurement: "m³"
        device_class: water
        state_class: total_increasing
        icon: mdi:water
    
      - state_topic: "watermeter/0/target"
        name: "watermeter_target"  
        unit_of_measurement: "m³"
        device_class: water
        state_class: total_increasing
        icon: mdi:water
    
      - state_topic: "watermeter/0/infocode"
        name: "watermeter_infocode"  
        
      - state_topic: "watermeter/0/flowtemp"
        name: "watermeter_flowtemp"  
        unit_of_measurement: '°C'
        device_class: temperature   
    
      - state_topic: "watermeter/0/ambienttemp"
        name: "watermeter_ambienttemp"  
        unit_of_measurement: '°C'
        device_class: temperature   

    A tak to wygląda w HomeAssistant:

    Linki

    Karta katalogowa Multical 21

    https://github.com/chester4444/esp-multical21

    https://github.com/wmbusmeters