raspberrypi 官網 raspberrypi 官網

互動 IoT 系統應用 - 上課教材

互動 IoT 系統應用 > 課程內容 > 第 13 章 - 自定義 Magic mirror 版面

第 13 章 - 自定義 Magic mirror 版面

上次更新日期 2022/12/15

魔鏡 (Magic Mirror) 可以開始動作之後,基本上,你可以外加很多喜歡的第三方模組功能,以修改成你自己需要的模樣。 舉例來說,將 USB 的 Webcam 整合到 MM2 裡頭去,可能就是個需要的功能!這個章節,我們就來處理一下這些動作!

學習目標:

  1. 在 MM2 上面安裝需要的模組方式
  2. 了解什麼是 v4l2 (video for Linux version 2, video4Linux2, v4l2)
  3. MJPEG 串流功能

13.1: 第三方模組:使用 MMM-AQI 模組

上一章我們稍微談到 Magic Mirror 之後,你的螢幕目前應該是漂漂亮亮的一片資訊了。不過,螢幕上似乎還有其他空間可以利用! 能不能再填入非預設的顯示模組呢?應該沒問題吧!我們可以來處理空氣品質指標 (Air Quality Index) 的顯示! 讓我們知道空氣品質的狀態喔!

  • 第三方模組的安裝

如果你跟鳥哥一樣懶,那麼預設 Magic Mirror 應該是放置到樹莓派的你慣用帳號的家目錄上面。因此,相關的模組放置, 就會是在 ~/MagicMirror/modules/ 目錄下!該目錄裡面有個名為 default 的子目錄,在 default 底下, 就有我們上一章提到的各個模組,包括 clock, calendar, weather 等等。我們自己安裝的其他模組, 就得要放置到 ~/MagicMirror/modules 底下喔!

Magic Mirror 官方列出的第三方功能模組,可以參考文末的連結,鳥哥從該列表裡面找到的跟 AQI 有關的模組, 使用的是如下的連結:

這個模組的名稱為 MMM-AQI,根據上面的連結,我們可以這樣簡單的進行安裝:

 $ cd ~/MagicMirror/modules/
 $ git clone https://github.com/ryck/MMM-AQI.git
 $ cd MMM-AQI/
 $ npm install

由於等等的模組需要用到你個人的驗證碼 (API Tocken),因此,你得要到底下的網站去填寫你的相關資料, 連結如下:

再出現的視窗中,填寫你的 email 與大名並送出之後,回到你的 email 收信,會收到主旨含有『[WAQI] Air Quality Data Platform Token Registration』的資料,這份 email 很可能會被當成廣告信...無論如何,收到信件,然後按下『Confirm your email address』之後, 就可以得到『Your tocken is .... 』的資料,那個資料就是你的驗證碼了!等等會用到!

  • 設定並重新啟動

接著下來請開始設定這個模組!可以將模組設定寫入到 config.js 的最底下,內容會有點像這樣:

 $ vim ~/MagicMirror/config/config.js
 {
   module: 'MMM-AQI',
   position: 'top_right',
   header: '空氣品質指標(AQI)',
   config: {
     token: "xxxxxxxxxxxxxx",   // 剛剛從 email 收到的 token
     city: "tainan",            // 你需要的城市名稱!我用台南代表~
     iaqi: true,                // 是否需要列出全部的污染物(隨意)
     updateInteval: 30*60*1000, // 多少毫秒 (0.001) 更新一次,這個是 30 分鐘!
     initialLoadDelay: 0,       // 不用Delay
     animationSpeed: 1000,      // 動畫期間
     debug: false,              // 要不要輸出更多除錯訊息
   },
 },
 $ pm2 reload mm2

如果一切順利的話,那你在魔鏡右下方就會看到如下的圖示了!

魔鏡第三方模組支援

鳥哥畢竟是環工出身的,所以對於細部的污染物濃度,還是有點興趣的!只是不喜歡出現太多污染物種, 比較容易造成 AQI 的污染物,就是 PM10, PM2.5 與 O3 而已,因此,鳥哥將這三個物種分別抓出來顯示而已。 這得要修改一下 MMM-AQI.js 的內容喔!其實也不難,差不多在 MMM-AQI.js 裡面的 140 行左右, 增加一小段程式碼即可:

 Object.keys(iaqi).forEach(function (key) {
     // VBird
     mypol = key.toUpperCase();
     if ( mypol == 'O3' || mypol == 'PM10' || mypol == 'PM25' ) {
         iaqiRow = document.createElement("tr");

         iaqiCityCell = document.createElement("td");
         iaqiCityCell.className = "xsmall iaqi key " + aqiClass;
         iaqiCityCell.innerHTML = key.toUpperCase();
         iaqiRow.appendChild(iaqiCityCell);

         iaqiAQICell = document.createElement("td");
         iaqiAQICell.className = "xsmall iaqi value " + aqiClass;
         iaqiAQICell.innerHTML = iaqi[key].v;
         iaqiRow.appendChild(iaqiAQICell);
         dataTable.appendChild(iaqiRow);
     }
 });

以上就是第三方模組安裝的基本流程!

13.2: 使用 Webcam 的串流內容: 了解 v4l2 與相關用法

某些時刻,你可能會用到樹莓派的鏡頭模組~因為需要監視、錄影等等的功能。不過,樹莓派的鏡頭模組雖然比較棒, 但是就是稍嫌貴一些。如果你手邊已經有一般平價的 USB 鏡頭 (Webcam) 的話,那能不能使用這個鏡頭來顯示到 Magic Mirror 上呢? 甚至也能夠處理串流功能呢?這是可以的!只是需要先了解一下什麼是 webcam 傳輸的串流資料格式。

  • Video for Linux version 2, v4l2 串流格式

如果你已經將你的 webcam 安插到樹莓派上面了,那麼可以檢查一下樹莓派是否已經抓到這個 USB 裝置,檢查方式如下:

 $ lsusb
Bus 001 Device 006: ID 046d:082b Logitech, Inc. Webcam C170
Bus 001 Device 005: ID 0461:4d0f Primax Electronics, Ltd HP Optical Mouse
Bus 001 Device 004: ID 046d:c52b Logitech, Inc. Unifying Receiver
....

這樣就抓到了!簡單得很!我的 Webcam 型號是羅技的 C170 這顆舊舊的鏡頭。既然已經抓到了,那麼是否可以列出來, 這個鏡頭的裝置檔名?可以的,只是需要先安裝 v4l (Video for Linux) 軟體!通常這個軟體已經預設安裝了, 如果沒有,那就安裝它!然後檢查一下目前的裝置檔名:

 $ sudo apt-get install v4l-utils

 $ v4l2-ctl --list-devices
bcm2835-codec-decode (platform:bcm2835-codec):
        /dev/video10
....
bcm2835-isp (platform:bcm2835-isp):
        /dev/video13
....
Webcam C170: Webcam C170 (usb-3f980000.usb-1.5):
        /dev/video0
        /dev/video1
        /dev/media3

看起來,我的裝置就是 /dev/video0 了!那如何讀這個裝置呢?可以簡單的透過 ffmpeg 軟體來顯示看看喔:

 $ sudo apt-get install ffmpeg

# 底下這裡,一定要在你的圖形界面上面運作!不然會出問題!
 $ ffplay /dev/video0

如果一切順利,你應該在樹莓派的圖形界面上面可以看到類似底下的資料!你的 Webcam 上面的指示燈應該也會點亮!這時就開始進行串流了!

魔鏡的 USB Webcam 相關

我比較喜歡使用 ffplay,感覺上對 CPU 的 loading 比較小。如果你想要使用 windows 系統上面常見的 vlc player 的話,也可以安裝 vlc player ,然後使用底下的指令來啟動 vlc player 即可!

 $ sudo apt-get install vlc

# 底下這裡,一定要在你的圖形界面上面運作!不然會出問題!
 $ vlc v4l2:///dev/video0

要注意的是,上面的 v4l2 都是小寫,其實大寫內容是『 V4L2 』,並不是四百一十二喔!這裡很容易搞錯!如果一切順利, 畫面會有點像底下這樣:

魔鏡的 USB Webcam 相關

這就是所謂的 Video for Linux version 2 (v4l2) 的協定!抓取的是本機的裝置檔案喔!

  • 鏡頭的最大解析度

我總得知道鏡頭的最大解析度是什麼,以及可支援的解析度為何!不然,等等直接進行串流功能時,很可能會出錯! 這時,你可以使用底下的指令來檢查:

 $ v4l2-ctl --list-formats-ext
ioctl: VIDIOC_ENUM_FMT
        Type: Video Capture

        [0]: 'YUYV' (YUYV 4:2:2)
                Size: Discrete 640x480
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
.....
        [1]: 'MJPG' (Motion-JPEG, compressed)
                Size: Discrete 640x480
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)
                Size: Discrete 352x288
                        Interval: Discrete 0.033s (30.000 fps)
                        Interval: Discrete 0.067s (15.000 fps)

如上所示,看起來我這個舊鏡頭,具有兩種格式,分別是『YUYV』以及『MJPG』兩種格式。而解析度兩者並不同!MJPG 解析度可以到 1024x768, 但是 YUYV 只能到 640x480 呢!此外,支援的每秒幀數只有兩種,分別是 30, 15 fps 而已!如果想要降低系統的負荷, 選擇 15fps 是比較好的!但如果是想要顯示的清楚一點, 30fps 是比較好的。

13.3: 讓樹莓派成為串流伺服器

雖然 /dev/video0 可以透過 v4l2 直接輸出,但是這種格式沒辦法顯示到網頁上!許多軟體都可以協助將這個格式轉成網頁可讀的協定, 不過,對於樹莓派來說,那些軟體都會造成 CPU 挺大的負荷!這樣我們的樹莓派很容易當機啊!那怎辦?

  • 使用 MJPG-Streamer 進行串流

一些樹莓派支援的網站,建議可以使用 MJPG-Streamer 軟體進行串流的建置!不過這個軟體並不是樹莓派原生軟體, 而且因為提供不同的系統使用,所以這個軟體官網僅提供原始碼,我們需要自己進行編譯與安裝才行!還好,整體流程算簡單! 我們可以這樣進行即可:

# 先安裝需要的軟體
 $ apt-cache search  libjpeg
....
libjpeg-tools - Complete implementation of 10918-1 (JPEG)
libjpeg-dev - Development files for the JPEG library [dummy package]
....

 $ sudo apt-get install cmake libjpeg-dev
 $ sudo apt-get install gphoto2 opencv-data

# 下載軟體到正確的目錄並解開
 $ mkdir ~/build
 $ cd ~/build
 $ wget https://github.com/jacksonliam/mjpg-streamer/archive/master.zip
 $ unzip master.zip
 $ cd mjpg-streamer-master/mjpg-streamer-experimental/

# 開始編譯成執行檔之後,安裝起來
 $ make
 $ sudo  make install
 $ which mjpg_streamer
/usr/local/bin/mjpg_streamer

# 列出支援的協定們!我們會用到 input_uvc 輸入,以及使用 http 輸出喔!
 $ ll /usr/local/lib/mjpg-streamer/
-rw-r--r-- 1 root root 19688 12月 15 11:19 input_file.so
-rw-r--r-- 1 root root 20168 12月 15 11:19 input_http.so
-rw-r--r-- 1 root root 56752 12月 15 11:19 input_uvc.so
-rw-r--r-- 1 root root 24320 12月 15 11:19 output_file.so
-rw-r--r-- 1 root root 46040 12月 15 11:19 output_http.so
-rw-r--r-- 1 root root 18864 12月 15 11:20 output_rtsp.so
-rw-r--r-- 1 root root 19432 12月 15 11:20 output_udp.so

# 列出可用的網頁程式範例檔!
 $ ll /usr/local/share/mjpg-streamer/www/
-rw-r--r-- 1 root root  1622  2月 21  2021 javascript_simple.html
-rw-r--r-- 1 root root   201  2月 21  2021 static_simple.html
-rw-r--r-- 1 root root   167  2月 21  2021 stream_simple.html
  • 嘗試啟動串流功能

開始嘗試處理串流,假設我們需要輸出 640x480 的解析度,同時使用 30 fps 的幀數,可以這樣做:

 $ mjpg_streamer -i "input_uvc.so -n -f 30 -r 640x480" \
>    -o "output_http.so -p 8888 \
>    -w /usr/local/share/mjpg-streamer/www"
MJPG Streamer Version.: 2.0
 i: Using V4L2 device.: /dev/video0
 i: Desired Resolution: 640 x 480
 i: Frames Per Second.: 30
 i: Format............: JPEG
 i: TV-Norm...........: DEFAULT
 o: www-folder-path......: /usr/local/share/mjpg-streamer/www/
 o: HTTP TCP port........: 8888
 o: HTTP Listen Address..: (null)
 o: username:password....: disabled
 o: commands.............: enabled

接下來,你只要啟動瀏覽器,並且輸入底下的網址,就可以對你的串流伺服器做控制與觀察了:

  • http://localhost:8888
  • http://localhost:8888/?action=stream

不過,這有個困擾,那就是你的終端機會卡住!所以這個串流伺服器不會一直存在!那怎辦?沒關係,就用 pm2 來處理即可! 先將剛剛的 mjpg_streamer 指令關掉,然後這樣處理一下即可。不過要注意的是,稍後我們整合到 magic mirror 的畫面不想要太大! 因為我的螢幕解析度不夠的關係!所以,我會使用 352x288 的解析度~詳細的解析度請自行使用上面介紹的方式自己查詢後處理!

 $ pm2 start --name camera 'mjpg_streamer -i "input_uvc.so -n -f 30 -r 352x288"\
>     -o "output_http.so -p 8888 -w /usr/local/share/mjpg-streamer/www"'
 $ pm2 save

很快的!你的樹莓派已經變成 webcam 的串流媒體了!

13.4: 將串流內容整合到 Magic Mirror 當中

要將上述的網址整合到 Magic Mirror 當中,最簡單的方法就是透過 iframe 的協助!因為這個串流輸出, 其實使用的是 img 標籤,問題是許多模組,都不懂我們串流輸出的網址列資料,因為網址列最終並不是使用 .jpg 的副檔名, 這真是麻煩!透過查詢第三方模組,最終找到 MMM-iFrame 模組,似乎比較好用一點!

  • 使用 MMM-iFrame 模組
 $ cd ~/MagicMirror/modules/
 $ git clone https://github.com/alberttwong/MMM-iFrame.git
 $ vim ~/MagicMirror/config/config.js
  {
          module: "MMM-iFrame",
          position: "top_left",
          config: {
                  url: ["http://127.0.0.1:8888/?action=stream"],
                  updateInterval: 0.5*60*1000,
                  width: "352",
                  height: "288",
                  frameWidth: "352",
          },
  },

 $ pm2 reload mm2

不過,等等!雖然順利啟動了串流畫面,但是螢幕方向不對啊!沒關係,我們可以透過底下的方法來修改, 讓畫面左右翻轉 180 度即可!使用方式如下:

 $ vim ~/MagicMirror/css/custom.css
.mmm-iframe-wrapper {
   transform: rotateY(180deg);
   border-radius: 30px;
   box-shadow: 0 0 20px white;
}

 $ pm2 reload mm2

一切順利的話,那就可以抓到類似如下的畫面了:

魔鏡的 USB Webcam 相關

13.5: 當週實做

不同的樹莓派版本,它的 CPU 能耐是有差異的。我們上課使用的 raspberry pi 3B 的 CPU 看起來應該是不夠力! 請自行使用『 top -d 2 』觀察一下,如果你的 CPU 經常性的飆高到 40% 以上,那麼看起來 Webcam 的串流可能是太細緻了 (30fps)。 建議修改成 15fps 即可!請使用 pm2 的方法,修改你的串流指令!

  • 使用 pm2 list 列出目前看到的服務列表
  • 使用 pm2 delete 的方式,先刪掉原有的服務
  • 重新設計一個服務
  • 儲存!
  • 參考資料
  1. Magic mirro 官網:
    https://magicmirror.builders/
  2. Magic Mirror 官網列出的第三方模組列表:
    https://github.com/MichMich/MagicMirror/wiki/3rd-party-modules
  3. 樹莓派官方的一些 USB webcam 說明:
    https://raspberrypi-guide.github.io/electronics/using-usb-webcams
    https://www.sigmdel.ca/michel/ha/rpi/streaming_en.html
  4. Magic Mirror Alarm Clock:
    https://www.hackster.io/scozzy/magicmirror-alarm-clock-146233
  5. 移動偵測
    https://github.com/rejas/MMM-MotionDetector

...