
因為客廳離車庫門有一段距離(什麼?),車庫又停了二台車阻擋視線,所以不是每一次娃娃車來的時候都會知道,最後就變得神經兮兮會探頭探腦。為了解決這個問題,車庫門口架一台監視器再配合物件辨識就解決了。
流程是這樣,利用監視器的副(輔)碼流,透過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將娃娃車辨識給關閉。