利用Home Assistant做物件辨識並全屋廣播:娃娃車來了!

娃娃車

因為客廳離車庫門有一段距離(什麼?),車庫又停了二台車阻擋視線,所以不是每一次娃娃車來的時候都會知道,最後就變得神經兮兮會探頭探腦。為了解決這個問題,車庫門口架一台監視器再配合物件辨識就解決了。

流程是這樣,利用監視器的副(輔)碼流,透過rtsp傳送5fps的影像到伺服器上,透過影像辨識軟體辨識到娃娃車後,影像辨識軟體會經由MQTT發佈MQTT事件到MQTT Broker上(Home Assistant也要連上同一個MQTT Broker),這時Home Assistant會收到MQTT Broker廣播的MQTT事件,利用這個事件觸發Home Assistant Automation並做出指定的Action即可。

辨識流程

監視器要找有支援雙碼流的機器會比較好,主碼流給各種NVR使用,以監控和儲存成影片為主,像我用的是群暉的surveillance station。主碼流為了其目的,通常都設定30fps以上且以高解析度為主,拿來做影像辨識會太吃資源且沒有必要,因此我們可以降低副(輔)碼流的fps並拿副(輔)碼流來做影像辨識。

攝影機設定

影像辨識軟體使用的是Frigate,架在Docker上,使用docker-compose佈署,這台伺服器有裝上Google Coral TPU,在辨識上會比純CPU快上很多。

version: "3.9"

services:
  frigate:
    container_name: frigate
    restart: unless-stopped
    image: ghcr.io/blakeblackshear/frigate:stable
    mem_limit: 6g
    privileged: true
    shm_size: '1g'
    ports:
      - "5000:5000"
      - "1935:1935"
      - "8554:8554" # RTSP feeds
      - "8555:8555/tcp" # WebRTC over tcp
      - "8555:8555/udp" # WebRTC over udp
    volumes:
      - /etc/localtime:/etc/localtime:ro
      - ./frigate/config.yml:/config/config.yml
      - /mnt/data/frigate:/media/frigate
      - type: tmpfs
        target: /tmp/cache
        tmpfs:
          size: 1000000000
    devices:
      - /dev/bus/usb:/dev/bus/usb
      - /dev/dri/renderD128

監視器的設定寫在Frigate的config.yml裡

  • mqtt:MQTT對Frigate來說是非必要的,但我們要拿來發佈MQTT事件,所以需要設定。
  • database:除非與預設路徑不同,不然可以不用設定。
  • rtmp:較早的Frigate版本可以re-stream成rtmp,但最新的版本是走go2rtc,因此設為False。
  • ffmpeg:硬體加速,INTEL CPU多用preset-vaapi。
  • birdeye:Frigate有提供birdeye的介面,將符合指定mode的監視器畫面放在一起統一觀看。
  • detectors:我有裝Google Coral TPU,介面是usb,需要宣告,是否有成功使用可以看Frigate的log,看看是否有frigate.detectors.plugins.edgetpu_tfl INFO : TPU found。
  • detect:影像辨識的參數。
  • record:錄影的參數,若沒有7X24的需求,可以設定滿足指定條件才錄影。
  • ui:介面微調的參數。
  • go2rtc:Frigate可以將透過rtsp傳遞過來的串流做re-stream,這些re-stream後的串流可以再給其他程式應用,這樣可以避免太多直連攝影機的連線造成攝影機的負擔。
  • camera:監視器的各種參數。
mqtt:
  host: mqtt_broker_ip
  user: mqtt_broker_user
  password: mqtt_broker_password

database:
  path: /media/frigate/frigate.db

rtmp:
  enabled: False

ffmpeg:
  hwaccel_args: preset-vaapi

birdseye:
  enabled: True
  mode: motion

detectors:
  coral:
    type: edgetpu
    device: usb

detect:
  width: 1280
  height: 720
  fps: 5
  enabled: True
  max_disappeared: 25
  stationary:
    interval: 0
    threshold: 50
    max_frames:
      default: 3000
      objects:
        person: 1000

record:
  enabled: True
  events:
    pre_capture: 5
    post_capture: 5
    objects:
      - person
      - car
      - bus
      - bird
    retain:
      default: 28
      mode: motion

snapshots:
  enabled: True
  clean_copy: True
  timestamp: False
  bounding_box: True
  crop: False
  retain:
    default: 28

ui:
  live_mode: mse
  use_experimental: False
  time_format: browser
  date_style: short
  time_style: short

go2rtc:
  webrtc:
    candidates:
      - stun:8555
  streams:
    dahua_hfw2230sn_entrance_left:
      - rtsp://user:password@camera_ip:554/cam/realmonitor?channel=1&subtype=0
      - "ffmpeg:dahua_hfw2230sn_entrance_left#audio=aac"
    dahua_hfw2230sn_entrance_left_sub:
      - rtsp://user:password@camera_ip:554/cam/realmonitor?channel=1&subtype=1

cameras:
  dahua_hfw2230sn_entrance_left:
    ffmpeg:
      output_args:
        record: preset-record-generic-audio-copy
      inputs:
        - path: rtsp://127.0.0.1:8554/dahua_hfw2230sn_entrance_left_sub
          input_args: preset-rtsp-restream
          roles:
            - detect
        - path: rtsp://127.0.0.1:8554/dahua_hfw2230sn_entrance_left
          input_args: preset-rtsp-restream
          roles:
            - record
    objects:
      track:
        - person
        - car
        - bicycle
        - motocycle
        - bus
    live:
      stream_name: dahua_hfw2230sn_entrance_left
    ui:
      order: 2
      dashboard: True

做到這裡,將Frigate啟動後,若有滿足條件的辨識,就會發出MQTT事件到MQTT Broker上。

最後,Home Assistant可以利用這個MQTT事件啟動自動化(Automation),MQTT事件觸發自動化的當下需滿足娃娃車辨識為開啟、物件標籤為bus、監視器為dahua_hfw2230sn_entrance_right以及分數在0.7以上(Condition),並做出指定的動作(Action),在我這個例子中,是透過Google nestmini做全戶廣播。

- alias: Information:School_Bus_Detect
  trigger:
    - platform: mqtt
      topic: frigate/events
  condition:
    - condition: state
      entity_id: input_boolean.school_bus_detect
      state: "on"
    - "{{ trigger.payload_json['after']['label'] == 'bus' }}"
    - "{{ trigger.payload_json['after']['camera'] == 'dahua_hfw2230sn_entrance_right' }}"
    - "{{ trigger.payload_json['after']['top_score'] > 0.7 }}"
  action:
    - service: tts.google_translate_say
      data:
        entity_id: group.home_broadcast
        message: 娃娃車來了
    - service: input_boolean.turn_off
      entity_id: input_boolean.school_bus_detect

在Condition中有一個條件是input_boolean.school_bus_detect需為on,原因是娃娃車會被分類為bus,但經測試各種貨車也有機會被分成bus,要降低干擾,我把是否要辨識娃娃車寫成一個布林(input_boolean),依時間觸發開關,下面這二段的意思是每天6:50會啟動娃娃車辨識,每天7:10會自動關閉。

- alias: Information:School_Bus_Detect_BooleanOff
  trigger:
    - platform: time
      at: "07:10"
  action:
    - service: input_boolean.turn_off
      entity_id: input_boolean.school_bus_detect

- alias: Information:School_Bus_Detect_BooleanOn
  trigger:
    - platform: time
      at: "06:50"
  action:
    - service: input_boolean.turn_on
      entity_id: input_boolean.school_bus_detect

當然,娃娃車來了之後就不需要辨識了,因此在alias: Information:School_Bus_Detect這個自動化的最後使用了input_boolean.turn_off將娃娃車辨識給關閉。

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *

返回頂端