raspberrypi 官網 raspberrypi 官網

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

互動 IoT 系統應用 > 課程內容 > 第 12 章 - Magic mirror 初探

第 12 章 - Magic mirror 初探

上次更新日期 2023/01/04

樹莓派除了可以使用 Linux 作業系統之外,還可以在 Linux 上面安裝個魔鏡軟體, 該軟體如果搭配適當的硬體,還可以讓你的樹莓派立刻變成亮麗的展示播放器!這裡讓我們來處理一下 magic mirror 吧!

學習目標:

  1. 了解什麼是 magic mirror
  2. 在樹莓派上面安裝 magic mirror

12.1: 安裝 magic mirror

走在百貨公司、各大賣場、捷運系統內、火車高鐵站、飛機場航廈等,常常可以看到顯示螢幕,這個螢幕會顯示商品特性、 特價品活動介紹、車次資訊以及航班資訊之外,通常還會有氣象資料、空品資料等等的介紹!這些東西通通集合在一個螢幕上! 有些甚至是投影到玻璃上面,讓顯示資料有浮在牆面上的感覺!這就是所謂的魔鏡!例如底下的連結,甚至已經有推出相關商品了;

  • 安裝 magic mirror

magic mirror 就是實現魔鏡功能的開放原始碼軟體,這個軟體也是透過 nodejs 來實現 server/client 互動功能的! 這真是太棒了!所以,我們就不用重複安裝 nodejs 了!只要直接安裝 Magic mirror 即可。Magic mirror 官網在文末的參考資料中, 而實際程式碼,則統一放在 github 內,因此,基本上,安裝 magic mirror 使用的是 git 指令喔!

# 1. 先下載 Magic mirror 的主程式碼:
 $ git clone https://github.com/MichMich/MagicMirror
 $ ll -d Magic*
drwxr-xr-x 17 rasppi rasppi 4096 12月  2 13:41 MagicMirror

# 2. 進入 MagicMirror 目錄,並觀察檔案
 $ cd MagicMirror
 $ ll
...

# 3. 實際將軟體安裝起來!包括所有需要的模組
 $ npm run install-mm

上面最後一個動作,實際上就已經開始安裝所有需要的軟體!這時候你的樹莓派會從網路上拉下一堆資料, 因為拉這些資料來進行安裝的行為,會花費相當多的時間!而且根據網路速度、你的硬體效能,時間上面會有很大的差異! 根據官網的說法,一般樹莓派 3B 可能會花費 10 分鐘以上的時間,如果比 3B 還慢的系統,更恐怕會長達 30 分鐘以上! 請不要隨意中斷整體過程喔!(鳥哥實際測試,系統花費大約 3~5 分鐘喔!)

  • 啟動 magic mirror

要啟動 magic mirror 之前,請先注意,你的樹莓派系統上面必須要有圖形界面,然後,你的樹莓派也可以直接連接到螢幕, 如果過去你的樹莓派就是以圖形界面桌上型電腦系統的方式存在,那就可以直接啟動 maric mirro 的服務了! 還好,我們的系統就是預設的樹莓派系統,因此,確實有圖形界面!所以,可以這樣直接啟動即可:

# 1. 直接將設定檔複製一份成為預設的設定值:
 $ cp config/config.js.sample config/config.js

# 2. 直接跑 magic mirro 軟體
 $ npm run start
.....
[ctrl]+c

如果一切順利的話,基本上,你樹莓派連接的螢幕,理論上就會出現如下的畫面:

魔鏡示意圖
  • 解決螢幕進入休眠狀況的問題

剛開始你可能不會發現,不過,運作一小段時間 (幾分鐘吧) 之後,就會發現啦,那就是...螢幕會主動進入休眠! 得要滑動滑鼠啦、鍵盤之類的,螢幕才會醒過來...怎麼處理這個問題呢?基本上,可以從 Linux 圖形界面的 Xorg 軟體著手處理。 你可以在啟動 X 視窗的時候,將進入螢幕保護的時間與電源管理關閉,這樣就可以讓螢幕亮晶晶...方法也不難, 修改 /etc/lightdm/lightdm.conf 的設定內容即可:

 $ sudo vim /etc/lightdm/lightdm.conf
.....
[Seat:*]
.....
#xserver-command=X
xserver-command=X -s 0 -dpms
.....

 $ sudo systemctl isolate multi-user
 $ sudo systemctl isolate graphical
 $ ps aux | grep Xorg
root .... tty7    Ssl+ 15:39   0:01 /usr/lib/xorg/Xorg -s 0 -dpms :0 -seat seat0..

這樣,你的螢幕就可以長亮了!

  • 自動關閉螢幕的方式

上面的方式主要是針對重新開機進入系統時強迫系統的預設值~如果你需要定時關閉螢幕,或者是定時啟動螢幕, 那也可以使用 xset 這個指令來處理。處理的方式很簡單,就是 (1)進入休眠模式與 (2)喚醒離開休眠模式而已。

# 進入休眠模式
 $ xset -display :0 s on s 1

# 喚醒螢幕
 $ xset -display :0 s off s activate

你可以自己從遠端連線測試一下這個情況!如果想要定期處理,請自行透過 crontab 來處置囉!除了 xset 之外, 在樹莓派上面,我們也可以透過 vcgencmd 來處理螢幕的電源供應問題。不過與螢幕保護程式不一樣的地方是, 使用 xset 進行的螢幕保護程式,可以透過滑鼠、鍵盤來喚醒。等等使用 vcgencmd 的方式,則一定要使用 vcgencmd 重新喚醒, 否則就一直是關電的情況喔!使用方法如下:

# 關閉螢幕電源
 $ vcgencmd display_power 0
display_power=0

# 打開螢幕電源
 $ vcgencmd display_power 1
display_power=1

# 顯示目前的螢幕電源狀態
 $ vcgencmd display_power
display_power=1

12.2: 簡易修改 magic mirror 的設定

雖然我們的鏡子已經搞定,但是...非常怪啊!竟然是英文與一堆怪異的資料~這是由於設定值預設在美語國家的原因。 我們就得要稍微進行一些簡易的修改,讓系統可以變得正常。詳細的設定可以參考官網的模組說明,我們這裡只做一些簡易的修改!

  • 時區與語言的修改

預設都是英文展示的 Magic mirror 內容,先來修改一下語系資料~直接這樣修改就好了!很簡單:

 $ vim config/config.js
let config = {
    ....
    language: "zh-tw",
    locale: "zh-tw",
    ....

基本上,這樣就可以改成中文了!只是,我們還想要修改一些資料,等等再來重新啟動喔!

  • 時鐘格式更改

預設的時鐘為數位式 (digital),如果想要像一般機械時鐘的指針顯示,也可以使用類比式 (analog) 來展示。 我們可以調整兩者都出現 (both)。由於指針式提供共 12 種模式給我們選擇,而數位式又可以提供日升、日落的時間, 感覺上兩者通通選擇,好像也不錯!

# 1. 先處理時鐘語系時區的修改:
 $ vim config/config.js
   module: "clock",
   position: "top_left",
   config: {
      module: "clock",
      position: "top_left",
      config: {
          timezone: "Asia/Taipei",
          displayType: "both",
          analogSize: "300px",
          analogFace: "face-003",  // 3, 5, 9, 10 我覺得好
          secondsColor: "yellow",
          dateFormat: "dddd, YYYY/MM/DD",
          showSunTimes: true,
          lat: 22.98,       // 輸入經緯度,才能算出日升、日落的時間
          lon: 120.253,
      },
   },
  • 修改日曆成為台灣地區與你專屬資料

假期列表比較麻煩,你當然可以手動處理~不過,有網站資料可以提供你一些最新的資訊,你可以下載之後進行處置。 下載的位置可以從底下來搜尋:

從該網站主選單『CALENDAR』找到左邊『iCal Calender』超連結,按下『Popular Categories』底下的『Holidays』, 就可以使用搜尋的方式,找到關鍵字為『Taiwan』的時間表,如下所示:

魔鏡示意圖 魔鏡示意圖

由於暫時找不到 maric mirror 放置於該軟體內部的資料位置,因此,利用我們自己的 webserver 的功能, 建立好 /var/www/html/download 之後,將找到並下載的檔名『Taiwan_Holidays.ics』放置到該目錄下! 然後修改一下輸出的文字,讓該文字變成中文!這樣才會有正常的行事曆功能:

# 1. 先處理好日曆相關的設定檔放置資料:
 $ cd /var/www/html
 $ sudo mkdir download
 $ sudo chown rasppi:rasppi download
 $ cd download
 $ cp ~/檔案目錄/Taiwan_Holidays.ics .

# 2. 底下的指令請複製貼上即可!轉換相關的中文資料
dos2unix
sed -i "1,2000s/^SUMMARY:Republic Day$/SUMMARY:元旦紀念日/g" Taiwan_Holidays.ics
sed -i "1,2000s/^SUMMARY:Children's Day$/SUMMARY:兒童節/g" Taiwan_Holidays.ics
sed -i "1,2000s/^SUMMARY:Chinese New Year$/SUMMARY:農曆新年/g" Taiwan_Holidays.ics
sed -i "1,2000s/^SUMMARY:Chinese New Year Holiday$/SUMMARY:農曆新年彈性放假/g" Taiwan_Holidays.ics
sed -i "1,2000s/^SUMMARY:Chinese New Year's Eve$/SUMMARY:除夕夜/g" Taiwan_Holidays.ics
sed -i "1,2000s/^SUMMARY:Dragon Boat Festival Holiday$/SUMMARY:端午節彈性放假/g" Taiwan_Holidays.ics
sed -i "1,2000s/^SUMMARY:Dragon Boat Festival$/SUMMARY:端午節/g" Taiwan_Holidays.ics
sed -i "1,2000s/^SUMMARY:Labour Day$/SUMMARY:勞動節/g" Taiwan_Holidays.ics
sed -i "1,2000s/^SUMMARY:Mid-Autumn Festival$/SUMMARY:中秋節/g" Taiwan_Holidays.ics
sed -i "1,2000s/^SUMMARY:National Day$/SUMMARY:國慶日/g" Taiwan_Holidays.ics
sed -i "1,2000s/^SUMMARY:National Day Holiday$/SUMMARY:國慶日彈性放假/g" Taiwan_Holidays.ics
sed -i "1,2000s/^SUMMARY:Qing Ming Festival$/SUMMARY:清明節/g" Taiwan_Holidays.ics
sed -i "1,2000s/^SUMMARY:Peace Memorial Day$/SUMMARY:和平紀念日/g" Taiwan_Holidays.ics
sed -i "1,2000s/^SUMMARY:Peace Memorial Day Holiday$/SUMMARY:和平紀念日彈性放假/g" Taiwan_Holidays.ics

# 3. 開始修改 config/config.js 的內容:
 $ vim config/config.js
   module: "calendar",
   header: "台灣行事曆",
   position: "top_left",
   wrapEvents: true,
   tableClass: "medium",
   config: {
       colored: true,
       calendars: [
           {
              symbol: "glass-cheers", 
              url: "http://localhost/download/Taiwan_Holidays.ics",
           },
           {
              symbol: "calendar-check",
              color: "#fffc00",
              url: "http://localhost/download/ksu-dic.ics",
           },
       ]
   }

上面的 symbol 是每個行事曆開頭的小圖示,眾多小圖示都可以到底下的網站去查看,直接在上頭輸入你想要的格式即可:

至於那個 ksu-dic.ics 則是我們自己指定的行事曆~這個行事曆可以加入我們需要的資料喔!行事曆的格式會有點像底下這樣, 特殊字體是可以重複的部份!

BEGIN:VCALENDAR
VERSION:2.0
PRODID:-//Calendar Labs//Calendar 1.0//EN
CALSCALE:GREGORIAN
METHOD:PUBLISH
X-WR-CALNAME:Taiwan Holidays
X-WR-TIMEZONE:Etc/CST
BEGIN:VEVENT
SUMMARY:崑大 111-1 期末考開始
DTSTART:20230110
DTEND:20230116
LOCATION:Taiwan
DESCRIPTION:參考崑山行事曆
SEQUENCE:0
END:VEVENT
END:VCALENDAR

之後重新啟動你的 Magic Mirror,基本上,就可以看到行事曆變成台灣地區的項目,可以是中文,同時也能夠修改你需要的排程! 相當的方便愉快!

魔鏡示意圖
  • 天氣觀測與預報

預設的天氣模組,可以使用 openweathermap 網站的資料來處理。只是,這個網站目前有多種 API 界面, 我們預計使用免費的 API 界面喔!所以,不要寫錯 API 的資料才行!否則就會出現問題了!一直讀不到... 好吧!那就開始來使用!第一步驟先到 openweathermap 網站進行註冊:

上面的網站點選『API』按鈕,然後往下滑動到『Personal collections』的位置上,就可以看到『Current & Forecast weather』的資料! 此時可以按下訂閱 (subscribe) 的按鈕來處理!如下圖所示:

魔鏡示意圖

由於我們僅須要免費的查閱而已,因此新視窗當中,往下滑動到出現『Free』字樣後,如下圖所示,這才開始取得 API 的金鑰! 如下圖所示。圖中的方塊則是顯示 API 的內容應該如何查詢的流程~有興趣自己寫 code 去分析的話, 應該也能看一下!否則,就直接點選『Get API key』即可。

魔鏡示意圖

如果從來沒有註冊過這個網站的話,那麼就會出現如下的註冊畫面!請填寫好你的帳號密碼與 email 相關資料, 然後按下『create account』,就可以建立好你的帳號了!相關流程如下所示:

魔鏡示意圖 魔鏡示意圖

系統會自動將你登入,此時,前往 API 的畫面取得你的 KEY 即可喔!如下所示:

魔鏡示意圖

重點是左下角 4 號箭頭的一串資料啦!那就是 API 的 key !接下來,我們要展示的是我們所在處,台南地區的天氣! 你可以前往底下的網站找到相關的城市 ID!你可以用程式名稱,不過,鳥哥比較喜歡使用程式所在的代碼! 各縣市資料,可以查 current.city.list.json.gz 這個檔案內容:

鳥哥找到的台南測站號碼為 1668355 喔!然後開始編輯天氣模組吧!

 $ cd ~/MagicMirror
 $ vim config/config.js
  module: "weather",
  position: "top_right",
  config: {
     weatherProvider: "openweathermap",
     apiVersion: "2.5",
     apiBase: "https://api.openweathermap.org/data/",
     weatherEndpoiint: "weather",
     type: "current",
     locationID: "1668355", // 這是台南
     apiKey: "你自己的 API key",
  }
....
  module: "weather",
  position: "top_right",
  header: "Weather Forecast",
  config: {
     weatherProvider: "openweathermap",
     apiVersion: "2.5",
     apiBase: "https://api.openweathermap.org/data/",
     weatherEndpoiint: "forecast",
     type: "forecast",
     locationID: "1668355", // 這是台南
     apiKey: "你自己的 API key",
  }

重新啟動 Magic mirror 之後,天氣狀況與預報就自動產生啦!

魔鏡示意圖
  • 最新新聞消息通知

總有重大新聞的時候,台灣許多新聞電子報都有提供 RSS 訂閱的功能,例如底下:

處理方式就如下所示:

 $ cd ~/MagicMirror
 $ vim config/config.js
   module: "newsfeed",
   position: "bottom_bar",
   config: {
      feeds: [
         {
            title: "東森-即時新聞",
            url: "https://feeds.feedburner.com/ettoday/realtime"
         },
         {
             title: "東森-地方新聞",
             url: "https://feeds.feedburner.com/ettoday/local"
         },
         {
             title: "東森-政治新聞",
             url: "https://feeds.feedburner.com/ettoday/news"
         },
         {
             title: "Mobile - 01",
             url: "https://www.mobile01.com/rss/news.xml"
         },
      ],
      showSourceTitle: true,
      showPublishDate: true,
      broadcastNewsFeeds: true,
      broadcastNewsUpdates: true
   }

重新啟動之後,就會像底下這樣了!相當有趣喔!

魔鏡示意圖

12.3: 讓 magic mirror 開機就啟動

單純使用『npm run start』可以讓 magic mirror 開始運作,只是,運作的 log 與相關訊息都會在原有的終端視窗存在! 你也不能離開該終端視窗~否則就得要按下 [ctrl]+c 來停止這個服務了!該如何讓 magic mirror 程式自己跑呢? 其實,我們可以透過 pm2 這個服務來處理程序的管理,這樣就可以脫離特定終端機的限制了!

  • 使用 pm2 管理 Magic Mirror 服務

如果你的程序是單獨存在的,並不是個可以在背景跑的服務時,那麼你可能就無法脫離終端機的束縛。pm2 則可以用來控制這樣的程序! pm2 可以在背景底下產生一隻管理的服務,然後根據使用者個人服務的設定,來予以管理 (啟動/關閉/重新載入等行為)。 這時,你就可以讓 Magic Mirror 跑在背景裡面,而不用持續保持終端機的連線呢!

# 1. (root 身份) 將 pm2 安裝到樹莓派上:
 $ sudo npm install pm2 -g

# 2. (一般帳號) 到你需要啟動的程序的目錄下,使用 pm2 去啟動服務
 $ cd ~/MagicMirror/
 $ pm2 start --name mm2 "npm run start"
[PM2] Spawning PM2 daemon with pm2_home=/home/rasppi/.pm2
[PM2] PM2 Successfully daemonized
[PM2] Starting /usr/bin/bash in fork_mode (1 instance)
[PM2] Done.
┌─────┬────────┬─────────────┬─────────┬─────────┬──────────┬────────┬
│ id  │ name   │ namespace   │ version │ mode    │ pid      │ uptime │
├─────┼────────┼─────────────┼─────────┼─────────┼──────────┼────────┼
│ 0   │ mm2    │ default     │ N/A     │ fork    │ 13509    │ 0s     │
└─────┴────────┴─────────────┴─────────┴─────────┴──────────┴────────┴

如上所示,此時你的家目錄底下就會產生 .pm2 的隱藏目錄,並且將你個人需要啟動的服務資料 (pm2 稱為 app.js) 都記錄下來! 例如上面的案例中,目前我們的 MagicMirror (通常簡寫為 mm2) 已經在跑,而且在我們的帳號當中,顯示的識別碼 (id) 是 0 號, 而且我們取個名字稱為 mm2 喔!

  • 使用 pm2 觀察剛剛建立的 mm2 軟體

上面的指令可以讓 magic mirror 開始運作!那如何觀察?難道一定要去螢幕前面?事實上,我們可以透過 pm2 的 list 與 monit 來觀察! 例如這樣做:

 $ pm2 list
┌─────┬────────┬─────────────┬─────────┬─────────┬──────────┬────────┬
│ id  │ name   │ namespace   │ version │ mode    │ pid      │ uptime │
├─────┼────────┼─────────────┼─────────┼─────────┼──────────┼────────┼
│ 0   │ mm2    │ default     │ N/A     │ fork    │ 13509    │ 4m     │
└─────┴────────┴─────────────┴─────────┴─────────┴──────────┴────────┴

 $ pm2 monit
魔鏡示意圖

可以做一些簡單的觀察囉!

  • 使用 pm2 管理服務

pm2 還可以進一步管理相關的服務!管理就是 restart/reload/stop 等等!

 $ pm2 reload mm2
 $ pm2 stop mm2
 $ pm2 start mm2

此時的服務是可以被管理的!只是,目前這個 mm2 服務的環境並沒有被儲存!下次重新開機之後, mm2 設定值就消失了! 所以,你應該要將 mm2 這個服務的相關資料儲存下來!即使重新開機之後,你的 pm2 還是會記得你的 mm2 運作腳本唷!

 $ pm2 save
[PM2] Saving current process list...
[PM2] Successfully saved in /home/rasppi/.pm2/dump.pm2

那麼下次重新開機後,如果要重新啟動這個 mm2 的話,就可以透過底下的重生指令來處理:

# 如果重新開機過,可以用底下的指令來重生 mm2 喔!
 $ pm2 resurrect
[PM2] Resurrecting
[PM2] Restoring processes located in /home/rasppi/.pm2/dump.pm2
[PM2] Process /usr/bin/bash restored
....
  • 使用 pm2 帶入 systemd 的服務

如同前面說的,基本上,開機之後,使用剛剛建立 pm2 的用戶,直接執行『 pm2 resurrect 』指令,就可以透過『 pm2 save 』 所以紀錄的資料來重建相關的服。問題是,我們需要一開機就執行這個腳本時,該如何是好?可以透過 pm2 的 startup 取得管理的方式, 例如樹莓派使用的是 systemd,早期的 Linux 也有使用 systemV 的,那就可以透過這個 startup 來取得相關的資料! 如下所示:

 $ pm2 startup
[PM2] Init System found: systemd
[PM2] To setup the Startup Script, copy/paste the following command:
sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd -u rasppi
  --hp /home/rasppi

 $ sudo env PATH=$PATH:/usr/bin /usr/lib/node_modules/pm2/bin/pm2 startup systemd\
>   -u rasppi --hp /home/rasppi

上面 startup 出現什麼,你就執行什麼就對了!該腳本實際上會建立一個名為『/etc/systemd/system/pm2-rasppi.service 的檔案, 並將 pm2 resurrect 寫入到執行腳本當中,同時將該動作 enable 到系統中~這樣開機就會自動執行這隻服務了! 至於管理的方式,還是使用 pm2 來管理即可!當然啦,你也可以使用『 systemctl restart pm2-rasppi 』來管理, 只是,這樣就得要使用 root 的權限來處理!另外,想要完整使用 systemctl 來管理時,可能得要重新開機喔! 基本上,管理還是使用 pm2 比較方便啦!

  • 定時開啟/關閉螢幕

某些時刻你可能會想要定時開關螢幕,例如晚上 10 點過後關閉螢幕,早上 8 點就開啟螢幕~這樣可以處理的方式會變成:

 $ crontab -e
#0 22  *   *   *     xset -display :0 s on s 1 
#0  8  *   *   *     xset -display :0 s off s activate
0  22  *   *   *     vcgencmd display_power 0
0   8  *   *   *     vcgencmd display_power 1

如此即可自動啟動/關閉螢幕!

12.4: 當週實做

將本章的全部動作都完成即可!另外,也可以將各個位置調動一下,設計出你最喜愛的版型即可!

  • 參考資料
  1. Magic mirro 官網:
    https://magicmirror.builders/
  2. 用樹莓派打造一個超薄魔鏡的簡單教程
    https://www.gushiciku.cn/pl/gd2a/zh-tw
    https://onevcat.com/2021/04/magicmirror/
  3. 樹莓派Raspberry Pi關閉休眠、螢幕長亮
    https://blog.twtnn.com/2021/02/raspberry-pi.html
  4. Make your own Smart Mirror with Magic Mirror and a Raspberry Pi
    https://www.marathonus.com/about/blog/make-your-own-smart-mirror-with-magic-mirror-and-a-raspberry-pi/
  5. 我也來做 Magic Mirror 系列:
    https://www.misterngan.com/5705/just-another-magicmirror-2/
  • 更改紀錄
  • 2022/12/08:第一次搞定 Magic Mirror,真的很有趣!只是卡在預設模組的展示方面,花費不少時間去理解!
  • 2023/01/04:因為螢幕保護程式老是無法順利關閉螢幕電源,找到了 vcgencmd 指令來處理,感覺比較好!

...