2021年1月27日 星期三

生日手環

今天下班回到家水某說要帶菁菁去漢神看手環, 因為她從 15 歲起每年都用自己存的零用錢生日時去買一條手鍊 (聽來好像有點心酸), 現在 18 歲算成年了, 想買個手環給她當生日禮物, 姊姊也是一月壽星, 她滿 20 歲時在台北也沒買個禮物 (姊姊通常都說不用啦), 所以也買了一個給她, 當然還有水某她自己. 想想我好像只有姊姊她們小時候買過生日禮物耶 (慚愧), 上國中之後就都是去聚餐了 (因為買禮物很傷腦筋), 嗯, 為了寵一下家裡的三個女人, 那就老爸我買單吧 (突然覺得自己很霸氣, 呵呵)! 

樹莓派學習筆記 : GPIO 輸出入介面

樹莓派的 GPIO (General Purpose Input Output, 通用輸出入介面) 是樹莓派與外界感測器 (sensor, 例如溫溼度, 亮度, 聲音, 氣壓等) 與致動器 (actuator, 例如馬達, LED, 繼電器等) 溝通的介面, 早期第一代樹莓派 Pi B+ 的 GPIO 為 26 支接腳, 但 Pi 2 之後的樹莓派板子則都是 40 支腳, 前 26 支接腳與 Pi B+ 的完全一樣 (即腳位相容), 因此以前為 Pi 1 B+ 所寫的 GPIO 程式仍可在 Pi 2 以後的樹莓派上順利執行, 參考 :



1. GPIO 硬體接腳配置 : 

GPIO 腳的編號方式有兩種 : 
  • BCM : 與 CPU 的 IO 腳編號相同.
  • BOARD : 腳座在上, 下排最左為腳 1, 上排最左為 2, 上下交替排列至上排最右為腳 40.
通常使用 BCM 編號較方便. 

配合 RPi.GPIO 模組, 部分 GPIO 接腳有特定用途, 如下表所示  : 


 特定功能 說明
 UART 14 (TX), 15 (RX)
 I2C 0 (EEPROM Data), 1 (EEPROM clock), 2 (SDA), 3 (SCL)
 SPI0 7 (CE1), 8 (CE0), 9 (MISO), 10 (MOSI), 11 (SCLK) 
 SPI1 16 (CE2), 17 (CE1), 18 (CE2), 19 (MISO), 20 (MOSI), 21 (SCLK)
 PWM  12, 13, 18, 19 (硬體 PWM), 全部 GPIO 均可軟體設定為 PWM 功能


注意, 基本上 SPI 有 MOSI,MISO, SCLK 與 SS (Slave Select) 這四支腳, SS 腳用來致能 (enable) 特定裝置 (即 Slave 設備) 用的, 但樹莓派不用 SS 這名稱,而是用 CE (chip select).

參考 : 


這些 GPIO 腳可用母-公杜邦線接到麵包板, 若杜邦線不夠長, 也可以先用 40P 母-母排線全部接出來, 再用公-公杜邦線接到麵包板上, 或搭配 T 型轉板 (擴展板).  參考 :



2. RPi.GPIO 模組 : 

樹莓派使用 RPi.GPIO 套件控制 GPIO 接腳, 此套件已內建於樹莓派 Raspbian 作業系統的 Python 中毋須安裝, 直接 import 即可使用 : 

>>> import RPi.GPIO as GPIO   
>>> GPIO.VERSION            #檢視 RPi.GPIO 版本 (也可以在終端機下 pip3 list)
'0.6.3'   
>>> dir(GPIO)      #檢視物件內容
['BCM', 'BOARD', 'BOTH', 'FALLING', 'HARD_PWM', 'HIGH', 'I2C', 'IN', 'LOW', 'OUT', 'PUD_DOWN', 'PUD_OFF', 'PUD_UP', 'PWM', 'RISING', 'RPI_INFO', 'RPI_REVISION', 'SERIAL', 'SPI', 'UNKNOWN', 'VERSION', '__builtins__', '__cached__', '__doc__', '__file__', '__loader__', '__name__', '__package__', '__path__', '__spec__', 'add_event_callback', 'add_event_detect', 'cleanup', 'event_detected', 'getmode', 'gpio_function', 'input', 'output', 'remove_event_detect', 'setmode', 'setup', 'setwarnings', 'wait_for_edge']

目前最新版本為 0.7.0, 可以直接用 pip 附 upgrade 參數升級 RPi.GPIO 版本 : 

sudo pip install --upgrade RPi.GPIO

pi@raspberrypi:~ $ sudo pip install --upgrade RPi.GPIO    
Collecting RPi.GPIO
  Downloading https://www.piwheels.org/simple/rpi-gpio/RPi.GPIO-0.7.0-cp35-cp35m-linux_armv7l.whl (67kB)
Installing collected packages: RPi.GPIO
  Found existing installation: RPi.GPIO 0.6.3
    Not uninstalling rpi.gpio at /usr/lib/python3/dist-packages, outside environment /usr
Successfully installed RPi.GPIO-0.7.0

安裝好後再次進入 Python 環境檢查 :

pi@raspberrypi:~ $ python   
Python 3.5.3 (default, Sep 27 2018, 17:25:39)
[GCC 6.3.0 20170516] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import RPi.GPIO as GPIO   
>>> GPIO.VERSION    
'0.7.0'   

可見確實已升級到最新版本.

參考 : 


但要注意的是, 由於 Linux 是多人多工作業系統, 所以 RPi.GPIO 模組不適合用在實時控制 (real time) 的場合, 對 timing 要求很高的話應該改用 RTOS 作業系統. 


3. 上拉電阻與下拉電阻 : 

GPIO數位輸入腳時應該視功能需要添加一個上拉電阻 (pull-up, 低態動作時) 或下拉電阻 (pull-down, 高態動作時), 如果懸空的話其位準為不確定, 可能造成程式執行結果異常. 此上拉或下拉電阻建議不要

樹莓派的 CPU 本身有內建上拉電阻或下拉電阻, 利用此功能可以不需用外加電阻即可達到避免接腳浮接 (floating) 造成的位準不確定問題. 不過哪支 GPIO 腳具有上拉或下拉電阻是特定的, GPIO 0~8 內建上拉電阻, 而 GPIO 9~27 內建下拉電阻 : 


 內建電阻 GPIO 腳 (BCM 編號)
 上拉電阻 0 ~ 8
 下拉電阻 9 ~ 27


內建上拉與下拉電阻值大約是 50K 歐姆 (接內部的 3.3V 或 GND). 參考 :



4. 類比輸出入 : 

樹莓派 GPIO 全部都是數位輸出入腳, 沒有提供類比輸出入腳, 必須透過外接晶片支援類比輸出與讀取, 例如讀取類比輸入可用 MCP 3004/3008 (ADC),  輸出類比信號可用 MCP 4901/4911/4912 (DAC) 等晶片. 

參考 : 

2021年1月25日 星期一

ETF 0050 & 0056 報酬率試算

今天在整理 Chrome 書籤時發現之前瀏覽過 MoneyDJ 理財網的 ETF 報酬率試算網站, 只要填入標的代號, 投資起訖日期 (至今), 每月扣款金額, 就會算出投資期間的報酬率與資產總額, 可藉此預估未來投資效益與選擇適合之標的, 網址如下 :


以每月扣款 1 萬元為例, 元大 0056 從 2007 年底成立至今 13 年報酬率如下 : 




可見 13 年來總投入金額 157 萬元, 目前資產總額 295 萬元, 約投入金額的近 2 倍. 

而元大 0050.tw 自 2003 年中成立至今 17 年, 每月扣款 10000 元報酬率如下 :




可見 17 年來投入金額 212 萬, 目前資產總額 693 萬, 為投入金額的 3.2 倍, 且以年化報酬率 (即複利) 6.97% 無情輾壓 0056 的 4.92%; 雖然 0050 投資期間比 0056 多 4 年 (投入本金差 55 萬), 但資產總值卻是 0056 的 2.3 倍, 因此理財專家說 0050 較 0056 適合存股是有道理的, 只靠簡單的 buy and hold 傻瓜買進持有投資法就能以 200 萬成本創造出近 700 萬的資產, 這就是成長性+複利的威力. 而這 17 年你可以專心工作, 閒暇時經營你的生活與興趣, 根本不用去看甚麼線圖與技術指標, 也不須研究產業前景等等這些毫無生活情趣的東西. 

如果從 25 歲出社會開始買進持有 0050 到 65 歲退休, 假定年化報酬率固定為 6.97%, 每個月固定扣繳 10000 元, 可用鉅亨網的基金試算網站估算退休時的資產總值大約為 2618 萬元 : 





這 2618 萬元的 0050 股票退休後也不用賣掉, 光靠股息就可以過上舒服的退休生活了. 以歷年至今平均值利率 3.4% 計算, 每年領回股息為 2618 萬*3.4%=89 萬, 相當於月薪 7.4 萬元領到天年, 如果不想留太多遺產, 那就每個月賣一張股票, 以現在股價 130 元計, 2618 萬相當於 200 張股票, 一個月賣一張要近 17 年才賣得完, 那時已經 81 歲了. 每個月賣一張變現 13 萬元, 加上配息月入 7.4 萬, 合計 20.4 萬元似乎有點多 (更別說 40 年後股價不只 130 元), 那就兩個月賣一張, 那要 34 年才賣得完, 屆時已經 65+34=99 歲了, 所以不需要那麼累去研究股票, 只要 "趁早" 定期定額投資 0050 就可以輕鬆退休了, 難怪巴菲特要勸人買 ETF 就好. 

巴菲特說 : "投資如同滾雪球, 重點是要找到夠濕的雪以及夠長的坡", 這夠濕的雪即年化報酬率要夠好夠穩定 (6% 以上), 而夠長的坡就是要及早投資, 如果到了 45 歲才開始準備自己的退休金, 離 65 歲還有 20 年, 則同樣每月扣款投資 0050 退休時總資產只有 522 萬元, 是 25 歲開始投資的人的 1/5 而已 :





如果要達到 2610 萬資產規模, 則 45 歲開始每個月要扣款的金額是 50000 元 : 




所以投資要趁早, 複利的威力主要來自於時間的次方 (指數), 只要週期性地投資指數型資產, 時間的指數魔力就會漸漸發酵. 前陣子看到一篇文章說, 大意是說亞馬遜老闆貝佐夫曾經問巴菲特, 你的投資方法如此簡單有效, 讓你成為世界第二富有的人, 但是為什麼大家不跟你一樣做呢? 巴菲特答說, 因為沒人想要慢慢致富. 現在很多年輕人衝進市場玩起當沖, 為的就是要賺快錢, 但高頻交易就算有收穫, 也被稅費吃掉一大半, 汲汲營營最後肥的是莊家. 

0050 平均股息殖利率參考 GoodInfo : 





2021年1月24日 星期日

2021 年第 4 周記事

今天是 1/24, 忽然又來到月底了, 二哥與菁菁本周開始放寒假, 所以鬧鐘可以調晚一個小時起床了, 相對於學期中趕上學, 生活步調突然放慢覺得好舒坦. 

這周因為要還一本母校的樹莓派借書 ("AIOT與OpenCV實戰應用:Python、樹莓派、物聯網與機器視覺"), 所以就認真看了以前從未涉獵的 GPIO 部份, 同時也拿出久已未摸的板子準備進行實作. 其實以前在 Arduino 上面做的實驗在樹莓派做更簡單, 因為它有 Linux 與 Python 的強大支援 (只是類比部分需外加晶片). 樹莓派應用廣泛, 值得深入研究, 開發農業物聯網應用. 

今天早上去鎮里買菜, 回途看到路邊有一台貨車改裝的野台布袋戲, 哇, 好久沒看到了 (做這行的可能都轉行了), 我停下來看了一下, 發現人偶都沒在動啊, 看來只是固定在上面放錄音帶而已. 我探頭看貨車裡面, 哈, 老闆在那邊滑手機! 下午要準備晚餐時發現沒買到雞胸肉, 所以又跑一趟鎮上的全聯, 經過那邊時發現這回人偶有在動了, 我又探頭看車裡面, 哈, 老闆上工了!




今天下午婷婷帶孩子來玩, 所以就沒去爬山了, 一邊跟孩子玩, 抽空又到菜園去將上週買的六株茄子與早上買的 20 株玉米以及 20 株大陸妹種下去, 離過年不到一個月, 這些都要元宵後才會收成了.  

高科大還書 2 本 (樹莓派 & 生成深度學習)

因有人預約, 下面兩本書昨天先還了 :
  1. AIoT與OpenCV實戰應用 : Python、樹莓派、物聯網與機器視覺
  2. 生成深度學習 : 訓練機器繪畫、作曲、寫作與玩遊戲
第一本我覺得寫得很不錯, 是實戰書籍, 我已看完前兩篇, 下次回借專看第三篇 OpenCV. 第二本我只是借來翻翻而已, 程度還不到, 等基本的深度學習學完再來看. 

2021年1月23日 星期六

樹莓派學習筆記 : 首次開機自動連線 WiFi 基地台的方法 (無頭存取)

今天在讀 "AIOT與OpenCV實戰應用:Python、樹莓派、物聯網與機器視覺" 的樹莓派 Raspbian 作業系統安裝部分時有意外發現, 只要在燒錄完映像檔之後在 SD 卡內加上一個 WiFi 連線設定檔指定基地台的連線帳密, 則樹莓派一開機就可以自動連線到 WiFi, 馬上就可以用筆電進行遠端操控 (即無頭存取, headless access). 

我之前以無頭存取 (headless access) 方式操作樹莓派都還需要將機器接上螢幕與鍵鼠組, 設定好 WiFi 帳密, 開啟 SSH 與 VNC 後才能透過筆電遠端操作樹莓派, 螢幕與鍵鼠組還好準備, 比較麻煩的是轉接頭, 特別是 Zero 需要 Mini HDMI 接頭與一個 USB 分享器 (鍵鼠組與 WiFi dongle 用), 真的有點傷腦筋, 參考 :


而這本書中介紹的方法是, 將映像檔燒錄到 Micro SD 卡後, 取出卡再重新插入電腦讀卡機, 這時在檔案總管中會看到兩個分割, 其中一個為 boot, 用記事本編輯一個名稱為 wpa_applicant.conf 的純文字檔儲存到 boot 分割區的根目錄下, 內容為 :

ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev 
update_config=1
country=TW

network={
    ssid="SSID"
    psk="密碼"
    }

除了這個之外, 還要在 root 之下建立一個名稱為 ssh 的空白檔案, 然後就可以取出 Micro SD 卡放入樹莓派, 這樣開機後就會自動連線指定的 WiFi 基地台了. 如果用手機上網, 可以在手機的 "設定/連接/行動無線基地台與網路共享/行動無線基地台" 中找到樹莓派連線成功後的 IP, 然後用 PuTTY 就可以進行無頭存取. 

此做法也可參考 :


市圖還書 2 本

本周市圖還書 2 本 :
都有人預約得還. jQuery 近期還沒時間做最後整理, 等忙完 Python 再回借. 

2021年1月21日 星期四

樹莓派學習筆記 : 用 wget install 安裝 MQTT 套件 mosquitto

因為用編譯原始碼方式安裝 mosquitto 套件在編譯階段出現錯誤而失敗, 所以只好用 wget install 安裝已編譯好的套件檔 mosquitto 與 mosquitto-clients, 參考 : 


安裝指令如下 :

wget install mosquitto mosquitto-clients  

下面是將安裝過程丟到一個檔案中 : 

pi@raspberrypi:~ $ sudo apt-get install mosquitto mosquitto-clients > mosquitto.txt    
pi@raspberrypi:~ $ cat mosquitto.txt   
正在讀取套件清單...
正在重建相依關係...
正在讀取狀態資料...
下列的額外套件將被安裝:
  libmosquitto1
建議套件:
  apparmor
下列【新】套件將會被安裝:
  libmosquitto1 mosquitto mosquitto-clients
升級 0 個,新安裝 3 個,移除 0 個,有 335 個未被升級。
需要下載 221 kB 的套件檔。
此操作完成之後,會多佔用 500 kB 的磁碟空間。
是否繼續進行 [Y/n]? [Y/n] 下載:1 http://mirror.ossplanet.net/raspbian/raspbian stretch/main armhf libmosquitto1 armhf 1.4.10-3+deb9u4 [47.2 kB]
下載:2 http://mirror.ossplanet.net/raspbian/raspbian stretch/main armhf mosquitto armhf 1.4.10-3+deb9u4 [122 kB]
下載:3 http://mirror.ossplanet.net/raspbian/raspbian stretch/main armhf mosquitto-clients armhf 1.4.10-3+deb9u4 [52.3 kB]
取得 221 kB 用了 2s (75.0 kB/s)
選取了原先未選的套件 libmosquitto1:armhf。
(讀取資料庫 ... 目前共安裝了 148260 個檔案和目錄。)
Preparing to unpack .../libmosquitto1_1.4.10-3+deb9u4_armhf.deb ...
Unpacking libmosquitto1:armhf (1.4.10-3+deb9u4) ...
選取了原先未選的套件 mosquitto。
Preparing to unpack .../mosquitto_1.4.10-3+deb9u4_armhf.deb ...
Unpacking mosquitto (1.4.10-3+deb9u4) ...
選取了原先未選的套件 mosquitto-clients。
Preparing to unpack .../mosquitto-clients_1.4.10-3+deb9u4_armhf.deb ...
Unpacking mosquitto-clients (1.4.10-3+deb9u4) ...
Processing triggers for libc-bin (2.24-11+deb9u4) ...
設定 mosquitto (1.4.10-3+deb9u4) ...
Processing triggers for systemd (232-25+deb9u11) ...
Processing triggers for man-db (2.7.6.1-2) ...
設定 libmosquitto1:armhf (1.4.10-3+deb9u4) ...
設定 mosquitto-clients (1.4.10-3+deb9u4) ...
Processing triggers for libc-bin (2.24-11+deb9u4) ...

可見已經順利完成安裝, 這樣就可以來測試看看用 MQTT 協定來訂閱與發送訊息了 : 

開啟兩個終端機視窗, 一個用來發布訊息 (publisher); 另一個用來訂閱訊息 (subscriber). 首先在訂閱者終端機以下列指令訂閱主題為 abc 所發布的訊息 :

mosquitto_sub -h 發布者網址 -t 主題

pi@raspberrypi:~ $ mosquitto_sub -h localhost -t abc     

訂閱後此終端機視窗會停住, 事實上是進入等待訊息的迴圈. 接著在發布者終端機以下列指令發布訊息 :

mosquitto_pub -h 發布者網址 -t 主題 -m "訊息"

pi@raspberrypi:~ $ mosquitto_pub -h localhost -t abc -m "hello world"

此指令針對 abc 主題發布了 "hello world" 訊息, 這時處於等待訊息迴圈的訂閱者終端機視窗就會顯示所接收到的訊息 :

hello world

發布者連續發布三個訊息 : 

pi@raspberrypi:~ $ mosquitto_pub -h localhost -t abc -m "hello world"  
pi@raspberrypi:~ $ mosquitto_pub -h localhost -t abc -m "hello tony"  
pi@raspberrypi:~ $ mosquitto_pub -h localhost -t abc -m "hello amy"  




訂閱者會連續收到三個訊息 :

hello world
hello tony
hello amy




注意, 訂閱者終端機將一直處於等待接收迴圈直到按下 CTRL+C 才會終止迴圈, 我覺得此迴圈似乎還蠻吃資源的, 訂閱指令一下達後, 桌面操作即變得有點卡卡, CPU 使用從 3% 上升到 20%. 

樹莓派學習筆記 : 編譯 MQTT 套件 mosquitto 原始碼問題

今天繼續讀朱克剛寫的 "AIOT與OpenCV實戰應用:Python、樹莓派、物聯網與機器視覺" 的 MQTT 部分, 書中使用的是 mosquitto 套件, 可用 pip 安裝或從 GitHub 下載原始碼自行編譯, 作者建議自行編譯, 因為可以開啟 websockets 功能以便透過網頁介面進行 MQTT 操作. 

我照作者建議下載原始碼自行編譯, 但編譯過程發生錯誤, 試圖爬文解決未果, 暫且將過程記錄如下, 等待找到解決方案再來重新編譯, mosquitto 套件原始碼下載網址如下 : 


開啟樹莓派的 Chromium 瀏覽器連線上面的 GitHub 網址下載原始碼 zip 壓縮檔 :




下載的壓縮檔 mosquitto-master.zip 預設放在使用者目錄下的 Downloads 資料夾下面, 可使用 unzip 程式解壓縮, 它會建立 mosquitto-master 子目錄來存放這些原始碼 :

pi@raspberrypi:~ $ cd Downloads   
pi@raspberrypi:~/Downloads $ unzip mosquitto-master.zip    
pi@raspberrypi:~/Downloads $ cd mosquitto-master    


1. 編輯 config.mk 檔開啟 websockets 功能 : 

用 nano 編輯 config.mk 檔, 將其中的 WITH_WEBSOCKETS 從原先的 no 改成 yes : 

pi@raspberrypi:~/Downloads/mosquitto-master $ nano config.mk    




這就是自行編譯的好處 : 能在編譯前進行細部功能設定. 


2. 更新套件清單 :

此步驟是必要的, 否則後續下載安裝五套件時可能會因為找不到套件而安裝失敗 : 

sudo apt-get update

pi@raspberrypi:~/Downloads/mosquitto-master $ sudo apt-get update   
下載:1 http://archive.raspberrypi.org/debian stretch InRelease [25.3 kB]  
下載:2 http://archive.raspberrypi.org/debian stretch/main armhf Packages [192 kB]
下載:3 http://raspbian.raspberrypi.org/raspbian stretch InRelease [15.0 kB]
下載:4 http://raspbian.raspberrypi.org/raspbian stretch/main armhf Packages [11.7 MB]
下載:5 http://archive.raspberrypi.org/debian stretch/ui armhf Packages [44.6 kB]
下載:6 http://raspbian.raspberrypi.org/raspbian stretch/non-free armhf Packages [98.9 kB]
取得 12.0 MB 用了 20min 48s (9,640 B/s)                                        
正在讀取套件清單... 完成


3. 安裝五套件 : 

此五套件是支援 MQTT 協定的函式庫 : 

sudo apt-get install libc-ares-dev libwebsockets-dev libssl-dev xsltproc docbook-xsl 

pi@raspberrypi:~/Downloads/mosquitto-master $ sudo apt-get install libc-ares-dev libwebsockets-dev libssl-dev xsltproc docbook-xsl    
正在讀取套件清單... 完成
正在重建相依關係          
正在讀取狀態資料... 完成
下列的額外套件將被安裝:
  docbook-xml libev-dev libev4 libssl-doc libssl1.1 libuv1-dev libwebsockets8
  sgml-data
建議套件:
  docbook docbook-dsssl docbook-defguide dbtoepub docbook-xsl-doc-html
  | docbook-xsl-doc-pdf | docbook-xsl-doc-text | docbook-xsl-doc
  docbook-xsl-saxon fop libsaxon-java libxalan2-java libxslthl-java xalan
  perlsgml w3-recs opensp libxml2-utils
下列【新】套件將會被安裝:
  docbook-xml docbook-xsl libc-ares-dev libev-dev libev4 libssl-dev libssl-doc
  libuv1-dev libwebsockets-dev libwebsockets8 sgml-data xsltproc
下列套件將會被升級:
  libssl1.1
升級 1 個,新安裝 12 個,移除 0 個,有 335 個未被升級。
需要下載 4,105 kB/6,264 kB 的套件檔。
此操作完成之後,會多佔用 30.5 MB 的磁碟空間。
是否繼續進行 [Y/n]? [Y/n] Y
下載:1 http://mirror.ossplanet.net/raspbian/raspbian stretch/main armhf libssl1.1 armhf 1.1.0l-1~deb9u2 [1,119 kB]
下載:2 http://mirror.ossplanet.net/raspbian/raspbian stretch/main armhf libssl-dev armhf 1.1.0l-1~deb9u2 [1,388 kB]
下載:3 http://mirror.ossplanet.net/raspbian/raspbian stretch/main armhf libssl-doc all 1.1.0l-1~deb9u2 [1,478 kB]
下載:4 http://mirror.ossplanet.net/raspbian/raspbian stretch/main armhf xsltproc armhf 1.1.29-2.1+deb9u2 [120 kB]
取得 4,105 kB 用了 14s (284 kB/s)                                              
讀取改變紀錄(changelogs)... 完成
正在預先設定套件 ...
(讀取資料庫 ... 目前共安裝了 143563 個檔案和目錄。)
Preparing to unpack .../00-libssl1.1_1.1.0l-1~deb9u2_armhf.deb ...
Unpacking libssl1.1:armhf (1.1.0l-1~deb9u2) over (1.1.0j-1~deb9u1) ...
選取了原先未選的套件 sgml-data。
Preparing to unpack .../01-sgml-data_2.0.10_all.deb ...
Unpacking sgml-data (2.0.10) ...
選取了原先未選的套件 docbook-xml。
Preparing to unpack .../02-docbook-xml_4.5-8_all.deb ...
Unpacking docbook-xml (4.5-8) ...
選取了原先未選的套件 docbook-xsl。
Preparing to unpack .../03-docbook-xsl_1.79.1+dfsg-2_all.deb ...
Unpacking docbook-xsl (1.79.1+dfsg-2) ...
選取了原先未選的套件 libc-ares-dev:armhf。
Preparing to unpack .../04-libc-ares-dev_1.14.0-1~bpo9+1_armhf.deb ...
Unpacking libc-ares-dev:armhf (1.14.0-1~bpo9+1) ...
選取了原先未選的套件 libev4。
Preparing to unpack .../05-libev4_1%3a4.22-1_armhf.deb ...
Unpacking libev4 (1:4.22-1) ...
選取了原先未選的套件 libssl-dev:armhf。
Preparing to unpack .../06-libssl-dev_1.1.0l-1~deb9u2_armhf.deb ...
Unpacking libssl-dev:armhf (1.1.0l-1~deb9u2) ...
選取了原先未選的套件 libssl-doc。
Preparing to unpack .../07-libssl-doc_1.1.0l-1~deb9u2_all.deb ...
Unpacking libssl-doc (1.1.0l-1~deb9u2) ...
選取了原先未選的套件 libuv1-dev:armhf。
Preparing to unpack .../08-libuv1-dev_1.18.0-3~bpo9+1_armhf.deb ...
Unpacking libuv1-dev:armhf (1.18.0-3~bpo9+1) ...
選取了原先未選的套件 libwebsockets8:armhf。
Preparing to unpack .../09-libwebsockets8_2.0.3-2+b1~rpt1_armhf.deb ...
Unpacking libwebsockets8:armhf (2.0.3-2+b1~rpt1) ...
選取了原先未選的套件 libev-dev。
Preparing to unpack .../10-libev-dev_1%3a4.22-1_armhf.deb ...
Unpacking libev-dev (1:4.22-1) ...
選取了原先未選的套件 libwebsockets-dev:armhf。
Preparing to unpack .../11-libwebsockets-dev_2.0.3-2+b1~rpt1_armhf.deb ...
Unpacking libwebsockets-dev:armhf (2.0.3-2+b1~rpt1) ...
選取了原先未選的套件 xsltproc。
Preparing to unpack .../12-xsltproc_1.1.29-2.1+deb9u2_armhf.deb ...
Unpacking xsltproc (1.1.29-2.1+deb9u2) ...
設定 libev4 (1:4.22-1) ...
設定 docbook-xsl (1.79.1+dfsg-2) ...
設定 xsltproc (1.1.29-2.1+deb9u2) ...
Processing triggers for sgml-base (1.29) ...
Processing triggers for libc-bin (2.24-11+deb9u4) ...
設定 libssl1.1:armhf (1.1.0l-1~deb9u2) ...
設定 sgml-data (2.0.10) ...
Processing triggers for man-db (2.7.6.1-2) ...
設定 libc-ares-dev:armhf (1.14.0-1~bpo9+1) ...
設定 libssl-doc (1.1.0l-1~deb9u2) ...
設定 libuv1-dev:armhf (1.18.0-3~bpo9+1) ...
設定 libev-dev (1:4.22-1) ...
設定 libwebsockets8:armhf (2.0.3-2+b1~rpt1) ...
設定 libssl-dev:armhf (1.1.0l-1~deb9u2) ...
設定 libwebsockets-dev:armhf (2.0.3-2+b1~rpt1) ...
Processing triggers for sgml-base (1.29) ...
設定 docbook-xml (4.5-8) ...
Processing triggers for libc-bin (2.24-11+deb9u4) ...
Processing triggers for sgml-base (1.29) ...


4. 編譯原始碼與安裝套件 :

用 make 指令編譯原始碼 :

make -j4 

pi@raspberrypi:~/Downloads/mosquitto-master $ make -j4    
set -e; for d in lib apps client plugins src; do make -C ${d}; done
set -e; for d in man; do make -C ${d}; done
make[1]: Entering directory '/home/pi/Downloads/mosquitto-master/lib'
make[1]: Entering directory '/home/pi/Downloads/mosquitto-master/man'
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c mosquitto.c -o mosquitto.o
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c actions.c -o actions.o
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c callbacks.c -o callbacks.o
xsltproc --nonet libmosquitto.3.xml
xsltproc --nonet mosquitto-tls.7.xml
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c connect.c -o connect.o
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c handle_auth.c -o handle_auth.o
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c handle_connack.c -o handle_connack.o
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c handle_disconnect.c -o handle_disconnect.o
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c handle_ping.c -o handle_ping.o
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c handle_pubackcomp.c -o handle_pubackcomp.o
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c handle_publish.c -o handle_publish.o
xsltproc --nonet mosquitto.8.xml
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c handle_pubrec.c -o handle_pubrec.o
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c handle_pubrel.c -o handle_pubrel.o
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c handle_suback.c -o handle_suback.o
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c handle_unsuback.c -o handle_unsuback.o
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c helpers.c -o helpers.o
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c logging_mosq.c -o logging_mosq.o
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c loop.c -o loop.o
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c memory_mosq.c -o memory_mosq.o
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c messages_mosq.c -o messages_mosq.o
xsltproc --nonet mosquitto.conf.5.xml
xsltproc --nonet mosquitto_ctrl.1.xml
xsltproc --nonet mosquitto_ctrl_dynsec.1.xml
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c misc_mosq.c -o misc_mosq.o
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c net_mosq_ocsp.c -o net_mosq_ocsp.o
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c net_mosq.c -o net_mosq.o
xsltproc --nonet mosquitto_passwd.1.xml
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c options.c -o options.o
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c packet_datatypes.c -o packet_datatypes.o
xsltproc --nonet mosquitto_pub.1.xml
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c packet_mosq.c -o packet_mosq.o
xsltproc --nonet mosquitto_rr.1.xml
xsltproc --nonet mosquitto_sub.1.xml
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c property_mosq.c -o property_mosq.o
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c read_handle.c -o read_handle.o
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c send_connect.c -o send_connect.o
xsltproc --nonet mqtt.7.xml
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c send_disconnect.c -o send_disconnect.o
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c send_mosq.c -o send_mosq.o
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c send_publish.c -o send_publish.o
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c send_subscribe.c -o send_subscribe.o
make[1]: Leaving directory '/home/pi/Downloads/mosquitto-master/man'
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c send_unsubscribe.c -o send_unsubscribe.o
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c socks_mosq.c -o socks_mosq.o
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c srv_mosq.c -o srv_mosq.o
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c strings_mosq.c -o strings_mosq.o
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c thread_mosq.c -o thread_mosq.o
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c time_mosq.c -o time_mosq.o
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c tls_mosq.c -o tls_mosq.o
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c utf8_mosq.c -o utf8_mosq.o
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c util_mosq.c -o util_mosq.o
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c util_topic.c -o util_topic.o
cc  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps -Wall -ggdb -O2 -Wconversion -fPIC -c will_mosq.c -o will_mosq.o
cc -shared  -Wl,--version-script=linker.version -Wl,-soname,libmosquitto.so.1 mosquitto.o actions.o callbacks.o connect.o handle_auth.o handle_connack.o handle_disconnect.o handle_ping.o handle_pubackcomp.o handle_publish.o handle_pubrec.o handle_pubrel.o handle_suback.o handle_unsuback.o helpers.o logging_mosq.o loop.o memory_mosq.o messages_mosq.o misc_mosq.o net_mosq_ocsp.o net_mosq.o options.o packet_datatypes.o packet_mosq.o property_mosq.o read_handle.o send_connect.o send_disconnect.o send_mosq.o send_publish.o send_subscribe.o send_unsubscribe.o socks_mosq.o srv_mosq.o strings_mosq.o thread_mosq.o time_mosq.o tls_mosq.o utf8_mosq.o util_mosq.o util_topic.o will_mosq.o -o libmosquitto.so.1  -lrt -lssl -lcrypto -lpthread
make -C cpp
make[2]: Entering directory '/home/pi/Downloads/mosquitto-master/lib/cpp'
g++  -I. -I.. -I../include -I../../include -DWITH_TLS -DWITH_TLS_PSK -DWITH_THREADING -DWITH_SOCKS -DWITH_UNIX_SOCKETS -I../deps  -fPIC -c mosquittopp.cpp -o mosquittopp.o
g++ -shared  -Wl,-soname,libmosquittopp.so.1 mosquittopp.o -o libmosquittopp.so.1 ../libmosquitto.so.1 
make[2]: Leaving directory '/home/pi/Downloads/mosquitto-master/lib/cpp'
make[1]: Leaving directory '/home/pi/Downloads/mosquitto-master/lib'
make[1]: Entering directory '/home/pi/Downloads/mosquitto-master/apps'
set -e; for d in db_dump mosquitto_ctrl mosquitto_passwd; do make -C ${d}; done
make[2]: Entering directory '/home/pi/Downloads/mosquitto-master/apps/db_dump'
cc -Wall -ggdb -O2 -Wconversion -I../../include -I../../ -I../../lib -I../../src -I../../deps -DWITH_BROKER -DWITH_PERSISTENCE -c db_dump.c -o db_dump.o
cc -Wall -ggdb -O2 -Wconversion -I../../include -I../../ -I../../lib -I../../src -I../../deps -DWITH_BROKER -DWITH_PERSISTENCE -c print.c -o print.o
cc -Wall -ggdb -O2 -Wconversion -I../../include -I../../ -I../../lib -I../../src -I../../deps -DWITH_BROKER -DWITH_PERSISTENCE -c ../../lib/memory_mosq.c -o memory_mosq.o
cc -Wall -ggdb -O2 -Wconversion -I../../include -I../../ -I../../lib -I../../src -I../../deps -DWITH_BROKER -DWITH_PERSISTENCE -c ../../src/memory_public.c -o memory_public.o
cc -Wall -ggdb -O2 -Wconversion -I../../include -I../../ -I../../lib -I../../src -I../../deps -DWITH_BROKER -DWITH_PERSISTENCE -c ../../lib/packet_datatypes.c -o packet_datatypes.o
cc -Wall -ggdb -O2 -Wconversion -I../../include -I../../ -I../../lib -I../../src -I../../deps -DWITH_BROKER -DWITH_PERSISTENCE -c ../../lib/packet_mosq.c -o packet_mosq.o
db_dump.c: In function ‘dump__cfg_chunk_process’:
db_dump.c:133:98: warning: format ‘%ld’ expects argument of type ‘long int’, but argument 4 has type ‘unsigned int’ [-Wformat=]
 or: Incompatible database configuration (dbid size is %d bytes, expected %ld)",
                                                                            ^
db_dump.c: In function ‘dump__client_msg_chunk_process’:
db_dump.c:210:21: warning: conversion to ‘long unsigned int’ from ‘long int’ may change the sign of the result [-Wsign-conversion]
    cc->message_size += length;
                     ^~
db_dump.c:210:24: warning: conversion to ‘long int’ from ‘long unsigned int’ may change the sign of the result [-Wsign-conversion]
    cc->message_size += length;
                        ^~~~~~
db_dump.c:214:22: warning: conversion to ‘long unsigned int’ from ‘long int’ may change the sign of the result [-Wsign-conversion]
     cc->message_size += msc->length;
                      ^~
db_dump.c:214:25: warning: conversion to ‘long int’ from ‘long unsigned int’ may change the sign of the result [-Wsign-conversion]
     cc->message_size += msc->length;
                         ^~~
db_dump.c: In function ‘main’:
db_dump.c:466:19: warning: conversion to ‘long int’ from ‘uint32_t {aka unsigned int}’ may change the sign of the result [-Wsign-conversion]
      if(fseek(fd, length, SEEK_CUR) < 0){
                   ^~~~~~
cc -Wall -ggdb -O2 -Wconversion -I../../include -I../../ -I../../lib -I../../src -I../../deps -DWITH_BROKER -DWITH_PERSISTENCE -c ../../src/persist_read.c -o persist_read.o
cc -Wall -ggdb -O2 -Wconversion -I../../include -I../../ -I../../lib -I../../src -I../../deps -DWITH_BROKER -DWITH_PERSISTENCE -c ../../src/persist_read_v234.c -o persist_read_v234.o
cc -Wall -ggdb -O2 -Wconversion -I../../include -I../../ -I../../lib -I../../src -I../../deps -DWITH_BROKER -DWITH_PERSISTENCE -c ../../src/persist_read_v5.c -o persist_read_v5.o
../../src/persist_read.c: In function ‘persist__client_chunk_restore’:
../../src/persist_read.c:199:34: warning: conversion to ‘time_t {aka long int}’ from ‘int64_t {aka long long int}’ may alter its value [-Wconversion]
   context->session_expiry_time = chunk.F.session_expiry_time;
                                  ^~~~~
../../src/persist_read.c: In function ‘persist__restore’:
../../src/persist_read.c:527:18: warning: conversion to ‘long int’ from ‘uint32_t {aka unsigned int}’ may change the sign of the result [-Wsign-conversion]
      fseek(fptr, length, SEEK_CUR);
                  ^~~~~~
cc -Wall -ggdb -O2 -Wconversion -I../../include -I../../ -I../../lib -I../../src -I../../deps -DWITH_BROKER -DWITH_PERSISTENCE -c ../../lib/property_mosq.c -o property_mosq.o
cc -Wall -ggdb -O2 -Wconversion -I../../include -I../../ -I../../lib -I../../src -I../../deps -DWITH_BROKER -DWITH_PERSISTENCE -c ../../lib/send_disconnect.c -o send_disconnect.o
cc -Wall -ggdb -O2 -Wconversion -I../../include -I../../ -I../../lib -I../../src -I../../deps -DWITH_BROKER -DWITH_PERSISTENCE -c stubs.c -o stubs.o
cc -Wall -ggdb -O2 -Wconversion -I../../include -I../../ -I../../lib -I../../src -I../../deps -DWITH_BROKER -DWITH_PERSISTENCE -c ../../lib/time_mosq.c -o time_mosq.o
cc -Wall -ggdb -O2 -Wconversion -I../../include -I../../ -I../../lib -I../../src -I../../deps -DWITH_BROKER -DWITH_PERSISTENCE -c ../../src/topic_tok.c -o topic_tok.o
cc -Wall -ggdb -O2 -Wconversion -I../../include -I../../ -I../../lib -I../../src -I../../deps -DWITH_BROKER -DWITH_PERSISTENCE -c ../../lib/utf8_mosq.c -o utf8_mosq.o
cc db_dump.o print.o memory_mosq.o memory_public.o packet_datatypes.o packet_mosq.o persist_read.o persist_read_v234.o persist_read_v5.o property_mosq.o send_disconnect.o stubs.o time_mosq.o topic_tok.o utf8_mosq.o -o mosquitto_db_dump  
make[2]: Leaving directory '/home/pi/Downloads/mosquitto-master/apps/db_dump'
make[2]: Entering directory '/home/pi/Downloads/mosquitto-master/apps/mosquitto_ctrl'
cc -I../mosquitto_passwd  -I. -I../../ -I../../include -I../../src -I../../lib -DWITH_TLS -Wall -ggdb -O2 -Wconversion -DVERSION=\""2.0.5\"" -c mosquitto_ctrl.c -o mosquitto_ctrl.o
cc -I../mosquitto_passwd  -I. -I../../ -I../../include -I../../src -I../../lib -DWITH_TLS -Wall -ggdb -O2 -Wconversion -DVERSION=\""2.0.5\"" -c client.c -o client.o
cc -I../mosquitto_passwd  -I. -I../../ -I../../include -I../../src -I../../lib -DWITH_TLS -Wall -ggdb -O2 -Wconversion -DVERSION=\""2.0.5\"" -c dynsec.c -o dynsec.o
cc -I../mosquitto_passwd  -I. -I../../ -I../../include -I../../src -I../../lib -DWITH_TLS -Wall -ggdb -O2 -Wconversion -DVERSION=\""2.0.5\"" -c dynsec_client.c -o dynsec_client.o
dynsec_client.c:18:25: fatal error: cjson/cJSON.h: 沒有此一檔案或目錄
 #include <cjson/cJSON.h>
                         ^
compilation terminated.
Makefile:57: recipe for target 'dynsec_client.o' failed
make[2]: *** [dynsec_client.o] Error 1
make[2]: *** Waiting for unfinished jobs....
dynsec.c:20:25: fatal error: cjson/cJSON.h: 沒有此一檔案或目錄
 #include <cjson/cJSON.h>
                         ^
compilation terminated.
Makefile:54: recipe for target 'dynsec.o' failed
make[2]: *** [dynsec.o] Error 1
In file included from client.c:31:0:
mosquitto_ctrl.h:21:25: fatal error: cjson/cJSON.h: 沒有此一檔案或目錄
 #include <cjson/cJSON.h>
                         ^
compilation terminated.
Makefile:51: recipe for target 'client.o' failed
make[2]: *** [client.o] Error 1
In file included from mosquitto_ctrl.c:29:0:
mosquitto_ctrl.h:21:25: fatal error: cjson/cJSON.h: 沒有此一檔案或目錄
 #include <cjson/cJSON.h>
                         ^
compilation terminated.
Makefile:48: recipe for target 'mosquitto_ctrl.o' failed
make[2]: *** [mosquitto_ctrl.o] Error 1
make[2]: Leaving directory '/home/pi/Downloads/mosquitto-master/apps/mosquitto_ctrl'
Makefile:9: recipe for target 'all' failed
make[1]: *** [all] Error 2
make[1]: Leaving directory '/home/pi/Downloads/mosquitto-master/apps'
Makefile:66: recipe for target 'mosquitto' failed
make: *** [mosquitto] Error 2
pi@raspberrypi:~/Downloads/mosquitto-master $ 

編譯中出現 "Incompatible database configuration" 與 "fatal error: cjson/cJSON.h: 沒有此一檔案或目錄" 等錯誤訊息, 有空再查原因. 

如果 make -j4 編譯沒有錯誤, 後續還有兩個安裝指令 :

$ sudo make install  (安裝)
$ sudo ldconfig   


5. 建立 mosquitto 目錄 :

$ sudo mkdir /var/lib/mosquitto   


6. 編輯 mosquitto 設定檔 :

$ sudo nano /etc/mosquitto/mosquitto.conf

輸入如下內容 :

port 1883
listener 9001
protocol websockets
pid_file /var/run/mosquitto.pid
persistence true
persistence_location /var/lib/mosquitto/


7. 建立執行 mosquitto 的帳號 : 

一直按 Enter 即可, 密碼可任填 :

$ sudo adduser --shell /usr/sbin/nologin --no-create-home mosquitto 


8. 編輯服務檔 : 

$ sudo nano /etc/systemd/system/mosquitto.service 

輸入內容如下 : 

[Unit]
Description=Mosquitto MQTT Broker Deamon
ConditionPathExists=/etc/mosquitto/mosquitto.conf
After=network.target

[Service]
Type=forking
RemainAfterExit=no
StartLimitInterval=0
PIDFile=/var/run/mosquitto.pid
ExecStart=/bin/sh/ -c "/usr/local/sbin/mosquitto -c /etc/mosquitto/mosquitto.conf -d"
ExecReload=/bin/kill -HUB $MAINPID
Restart=on-failure
RestartSec=2

[Install]
WantedBy=multi-user.target

樹莓派五個重要的系統設定檔

我今天在讀朱克剛寫的 "AIOT與OpenCV實戰應用:Python、樹莓派、物聯網與機器視覺" 時, 在第二章末尾看到樹莓派重要的系統設定檔列表, 我覺得很有參考價值 :


Source : 博客來


參考 :


我實際檢視兩台 Pi 3B 的檔案內容紀錄如下 (作者使用 vi 編輯器, 我改為較好用的 nano) :


1. WiFi 連線設定檔 : 

$ sudo nano /etc/wpa_supplicant/wpa_supplicant.conf

檢視如下 : 

pi@raspberrypi:~ $ cat /etc/wpa_supplicant/wpa_supplicant.conf
ctrl_interface=DIR=/var/run/wpa_supplicant GROUP=netdev
update_config=1
country=TW

network={
ssid="EDIMAX-tony"
psk="123456789abc"
key_mgmt=WPA-PSK
}


2. 開機自動執行的程式 : 

$ sudo nano /etc/rc.local   

pi@raspberrypi:~ $ cat /etc/rc.local
# Print the IP address
_IP=$(hostname -I) || true
if [ "$_IP" ]; then
  printf "My IP address is %s\n" "$_IP"
fi

exit 0


3. 鍵盤設定檔 : 

$ sudo nano /etc/default/keyboard 

重點是 XKBLAYOUT 要設為 us 美式鍵盤 : 

pi@raspberrypi:~ $ cat /etc/default/keyboard
XKBMODEL=pc105
XKBLAYOUT=us
XKBVARIANT=
XKBOPTIONS=
BACKSPACE=guess


4. 系統排程設定檔 (cron table) : 

$ sudo nano /etc/crontab 

目前鄉下家樹莓派設定 :

pi@raspberrypi:~ $ cat /etc/crontab
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.

SHELL=/bin/sh
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin

# m h dom mon dow user command
17 * * * * root    cd / && run-parts --report /etc/cron.hourly
25 6 * * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.daily )
47 6 * * 7 root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.weekly )
52 6 1 * * root test -x /usr/sbin/anacron || ( cd / && run-parts --report /etc/cron.monthly )


5. 系統紀錄檔 : 

$ cd /var/log   
$ ls -al

SD 卡記憶體不足時, 可刪除此目錄底下較舊的紀錄檔. 

pi@raspberrypi:~ $ ls -al /var/log
總計 169012
drwxr-xr-x  9 root  root     4096  1月 21 06:25 .
drwxr-xr-x 12 root  root     4096  4月  5  2019 ..
-rw-r--r--  1 root  root        0 12月 19  2019 alternatives.log
-rw-r--r--  1 root  root     1677 12月 18  2019 alternatives.log.1
-rw-r--r--  1 root  root      273 10月 16  2019 alternatives.log.2.gz
-rw-r--r--  1 root  root      258  4月  9  2019 alternatives.log.3.gz
drwxr-x---  2 root  adm      4096  1月 21 06:25 apache2
drwxr-xr-x  2 root  root     4096 12月 19  2019 apt
-rw-r-----  1 root  adm  10340754  1月 21 06:55 auth.log
-rw-r-----  1 root  adm  26758041  1月 17 06:25 auth.log.1
-rw-r-----  1 root  adm   2148156  1月 11 06:25 auth.log.2.gz
-rw-r-----  1 root  adm   1042196  1月  3 06:25 auth.log.3.gz
-rw-r-----  1 root  adm   1134427 12月 28 06:25 auth.log.4.gz
-rw-r--r--  1 root  root     2766 12月 23 11:53 boot.log
-rw-r--r--  1 root  root        0 11月 13  2018 bootstrap.log
-rw-rw----  1 root  utmp 77451648  1月 21 06:55 btmp
-rw-------  1 root  utmp 49082880  1月  1 06:23 btmp.1
-rw-r-----  1 root  adm     36206  1月 21 06:39 daemon.log
-rw-r-----  1 root  adm     54446  1月 17 06:25 daemon.log.1
-rw-r-----  1 root  adm      5663  1月 11 06:25 daemon.log.2.gz
-rw-r-----  1 root  adm      3774  1月  3 06:25 daemon.log.3.gz
-rw-r-----  1 root  adm      9121 12月 28 06:25 daemon.log.4.gz
drwxr-xr-x  2 root  root     4096  1月  1  2020 dbconfig-common
-rw-r-----  1 root  adm         0 12月 24 06:25 debug
-rw-r-----  1 root  adm      1247 12月 23 11:53 debug.1
-rw-r-----  1 root  adm       434 11月  2 09:50 debug.2.gz
-rw-r-----  1 root  adm       435  8月 16 14:00 debug.3.gz
-rw-r-----  1 root  adm       435  8月  2 14:00 debug.4.gz
-rw-r--r--  1 root  root        0 12月 19  2019 dpkg.log
-rw-r--r--  1 root  root    57781 12月 19  2019 dpkg.log.1
-rw-r--r--  1 root  root     2202 10月 16  2019 dpkg.log.2.gz
-rw-r--r--  1 root  root      160  7月 13  2019 dpkg.log.3.gz
-rw-r--r--  1 root  root     3514  4月  9  2019 dpkg.log.4.gz
-rw-r--r--  1 root  root     2688 12月 18  2019 faillog
-rw-r--r--  1 root  root        0 11月 13  2018 fontconfig.log
-rw-r-----  1 root  adm    789810  1月 21 06:54 kern.log
-rw-r-----  1 root  adm   1185111  1月 17 06:24 kern.log.1
-rw-r-----  1 root  adm    183410  1月 11 06:22 kern.log.2.gz
-rw-r-----  1 root  adm    132016  1月  3 06:25 kern.log.3.gz
-rw-r-----  1 root  adm    190613 12月 28 06:23 kern.log.4.gz
-rw-rw-r--  1 root  utmp   292292 12月 26 22:12 lastlog
drwx--x--x  2 root  root     4096 12月 23 11:53 lightdm
-rw-r-----  1 root  adm    517547  1月 21 06:54 messages
-rw-r-----  1 root  adm    789048  1月 17 06:25 messages.1
-rw-r-----  1 root  adm    129457  1月 11 06:25 messages.2.gz
-rw-r-----  1 root  adm     92798  1月  3 06:25 messages.3.gz
-rw-r-----  1 root  adm    137151 12月 28 06:25 messages.4.gz
drwxr-s---  2 mysql adm      4096  1月 21 06:25 mysql
drwxr-xr-x  2 root  adm      4096 12月 19  2019 nginx
drwxr-x---  2 root  adm      4096  8月 14  2018 samba
-rw-r-----  1 root  adm      5046  1月 21 06:54 syslog
-rw-r-----  1 root  adm    231289  1月 21 06:25 syslog.1
-rw-r-----  1 root  adm     27782  1月 20 06:25 syslog.2.gz
-rw-r-----  1 root  adm     27603  1月 19 06:25 syslog.3.gz
-rw-r-----  1 root  adm     27370  1月 18 06:25 syslog.4.gz
-rw-r-----  1 root  adm     28143  1月 17 06:25 syslog.5.gz
-rw-r-----  1 root  adm     28673  1月 16 06:25 syslog.6.gz
-rw-r-----  1 root  adm     29553  1月 15 06:25 syslog.7.gz
-rw-r-----  1 root  adm     17941  1月 21 06:36 user.log
-rw-r-----  1 root  adm     39414  1月 17 00:54 user.log.1
-rw-r-----  1 root  adm      4011  1月 11 06:14 user.log.2.gz
-rw-r-----  1 root  adm      2489  1月  2 23:10 user.log.3.gz
-rw-r-----  1 root  adm      4751 12月 28 03:36 user.log.4.gz
-rw-rw-r--  1 root  utmp        0  1月  1 06:25 wtmp
-rw-rw-r--  1 root  utmp     3072 12月 27 04:25 wtmp.1
-rw-r--r--  1 root  root    13369 12月 23 11:53 Xorg.0.log
-rw-r--r--  1 root  root    13369 11月  2 09:50 Xorg.0.log.old

找檔案最舊最大的先刪, 但現在 SD 卡已較便宜, 樹莓派最大支援 64GB, 買個 32/64 GB 來用比較沒有 SD 撐爆問題. 


2021年1月20日 星期三

查詢汽機車強制險效期 (下載電子式保險證)

最近機車強制險到期要續保, 名下四台機車 (高雄兩台, 鄉下兩台) 到期日都不一樣, 想說是否政府有設網站讓車主查詢強制險到期日呢? 答案是有的, 網址如下 : 


輸入身分證與車牌號碼就可查詢了 :



 


按查詢結果第二項下載電子式保險證 PDF 檔, 裡面就有到期日了 (開啟 PDF 之密碼為身分證號碼, 英文要大寫).  

關於自然語言處理之 BERT 技術

今天在找 NLP 資料時看到下面這篇文章 :


第一次看到 BERT 以為是通訊原理中的 Bit Error Rate Test 的意思, 但搭上 NLP 顯然不是這意思, 可見 acronym 的岐義現象有多嚴重. BERT (Bidirectional Encoder Representations from Transformers) 恰巧就是解決 NLP 歧義的一個解決方案. 

BERT 是 Google 在 2018 年所提出的一種 NLP 預訓練技術, 屬於雙向深度非監督的詞向量表示法, 會根據上下文對相同的詞彙生成不同之詞向量 (傳統的 word2vec 則與上下文無關), 因此能有效處理歧義問題, 此項技術已於 2019 年底開始被應用在 Google 搜尋引擎中, 參考 : 


Apress 出版的新書 "Hands-on Question Answering Systems with BERT(2021)" 則將 BERT 用在 Q&A 系統中, 值得參考 : 


Source : 天瓏


Apress 出版的另外一本書 "Practical Natural Language Processing with Python (2020)" 的最後一章也介紹了 BERT 技術 : 


Source : 天瓏


不過 BERT 技術需要花費較大的運算力來訓練模型, 如果研究機構能將訓練好的模型開放將可節省許多訓練成本, 參考 :

一文,告訴你NLP中的Transformers究竟是如何運作的
【精度】自然語言處理基礎之attention
百聞不如一碼!手把手教你用Python搭一個Transformer!

NLP 的發展速度飛快, 不加緊跟上不行.

使用 serveo.net 穿透內網存取網頁伺服器 (暫停服務)

前幾天根據趙英傑 "超圖解 Python 程式設計入門" 這本書第十章的介紹, 順利地利用 ngrok 穿透社區網路存取架設於內網的樹莓派本機網站 (即 localhost), 經過幾天的觀察, ngrok 確實都能持續轉發外網的 HTTP/HTTPS 網頁存取, 即使是免費用戶其轉發服務也都很穩定, 參考 :


位於社區網路內或非固定 IP ADSL 網路內的本機網站從 Internet 外網無法存取, 用 ngrok 就可以辦到, 唯一不便之處是每次重新執行 ngrok 後對映至 localhost 的網址都會變. 這就有點麻煩了, 因為遠端使用者不知道網址變了, 會以為網站掛了. 

其實趙英傑書中還介紹了另一個穿透內網瀏覽本機網站的方法, 即透過 serveo.net 的轉發服務, 特點是只要下一個指令就可以, 不用下載任何程式, 只要在樹莓派終端機使用下面的指令就會回應一個網址, 可以從外網瀏覽本機網站 :

ssh -R 80:localhost:80 serveo.net     

其中 -R 表示遠端 (Remote), 第一個 80 為遠端埠號 (不要改), localhost 代表本機 (也可以用 127.0.0.1 或樹莓派從基地台獲得之 IP, 例如 192.168.43.122), 第二個 80 為本機網站的埠號 (依網站伺服器設定可改). 但我實際測試卻得到 "Connection refused" 的回應 : 

pi@raspberrypi:~ $ ssh -R 80:localhost:80 serveo.net    
ssh: connect to host serveo.net port 22: Connection refused




直接連線 serveo.net 無回應, 我找到一個可以測試伺服器是否當機的網站 : 


輸入 serveo.net 測試伺服器狀況, 結果顯示此網站已掛點 :





此解決方案暫時無解, 不知何時才會恢復. 

2021年1月18日 星期一

2021 年第 3 周記事

 似乎才在說是否辦跨年, 今年的第三周過去了, 新年以來追韓劇的熱度降低, 只在周末回鄉下看一集權娜拉主演的暗行御史, 所以最近學的東西較多了, 上週玩了一下我的 Mac mini, 本周則將 LINE 聊天機器人向前推進了一步, Jetson Nano 也準備安裝 GPU CUDA 工具集, 為研究機器學習鋪路. 

姊姊週五回到高雄, 週六請爸坐客運車來高雄, 大家一起去夢時代六樓的新馬辣吃火鍋, 全家一起坐大灰熊的幸福感很久沒有這樣了, 當初買 QRV 可坐七個人就是考量全家出遊都坐得下, 可惜媽已仙遊去了. 這家新馬辣雖是吃到飽, 但不是自取食材, 而是點食材後由服務生送來, 這樣感覺比較不會有一堆人擠在取菜區亂糟糟的感覺. 

昨天早上去晨跑, 本想跑上山, 但才拐一個彎就很喘, 果然跑山不是想像中那麼容易. 下午閒來無事搬張椅子在曬穀場邊嗑瓜子, 小雖貓就坐在矮牆邊看我嗑, 剛好被我拍到它打呵欠的樣子 : 




在鄉下養貓挺好的, 貓很獨立也不用遛貓, 它現在是爸的小跟班, 走到哪就跟到哪.

今天終於將 0056 最後剩下的 8 張全部賣出, 從去年八月進場, 一半參與除息, 另一半參與填息, 到今天 ALL OUT 統計半年總報酬率 7.29%, 雖然比不上那些飆股, 但結果也還不錯, 施昇輝的做法經實驗確實有效可行, 近乎無風險套利, 也沒花多少時間.

2021年1月17日 星期日

數位邏輯實驗零件

二哥學期結束前跟同學借了下學期要上的數位邏輯電路實習課本, 希望我幫他買要用到的零件, 想在寒假時自己跑一遍, 主要是期末專題要做 24 小時制的時鐘, 所需零件清單如下 : 

材料清單 1 : 
  1. 7493*3 
  2. 74163*3
  3. 7447*6
  4. NE555
  5. 七段顯示器 LT502 (共陽極)*6, LT503 (共陰極)
  6. 發光二極體 *1
  7. 電位計 1M*1
  8. 電阻 220*7, 1K*10
  9. 陶瓷電容 0.01u*1, 電解電容 3.3u*1

材料清單 2 : 
  1. 7400, 7401, 7404, 7408, 7432, 74192 (各兩顆)
  2. 全加器 : 7483
  3. 四位元比較器 : 7485
  4. 8 對 1 多工器 : 74151
  5. 3 對 8 解碼器 : 74138
  6. 74147
  7. JK 反器 : 7473
  8. 4 位元 D latch : 7475
  9. 2 位元 D 正反器 : 74LS74
  10. 4 位元移位暫存器 : 74LS153 
  11. 4 位元二進位計數器 : 7493A
  12. 4 位元二進計數器 : 74163
  13. BCD 至 10 進位解碼器 : 7442
  14. BCD 上下數計數器 : 74192
最近要向露天賣家買一批零件, 但若二哥急用那就到禾樺買. 

2020-01-18 補充 :

今天晚上吃過飯後跟二哥去禾樺買零件, 除了 7493, 7483, 74192 等無貨外, 其餘都買到了, 花了大約 600 多, 這如果在露天買應該 400 塊, 實體店面本來就比較貴.

2021年1月16日 星期六

關於 Jetson Nano 的 Ubuntu 當機問題

早上心血來潮將久未使用的 Jetson Nano 開機, 但是在切換 WiFi 基地台時卻發生當機, 滑鼠還會動, 但整個桌面與鍵盤均無反應, 按 CTRL +ALT + DEL 也是一樣, 最後沒辦法只好關電源. 重新啟動後覺得粗暴關機不太妥當, 所以就查了一下 Ubuntu 當機時的解決辦法, 下面這篇建議使用 Alt + SysRq + r/e/i/s/u/b 組合鍵來處理 X Window 當機事件, 參考 : 

這個 SysRq 鍵其實是跟 PrtScr (即一般美式鍵盤的 F12) 做在一起, 是同一個鍵, 但因字太多一般鍵盤通常沒有印出來. 利用 SysRq 鍵可以傳送指令給 Linux 核心, 如果它有回應表示 Linux 系統並沒有整個當掉, 對系統救援很有用. 但使用這個 SysRq 鍵的前提是 Linux 有開啟 SysRq 鍵的所有功能, 啟用狀態紀錄在 /proc/sys/kernel/sysrq 檔案中, 其值若為 1 表示完全啟用 (0 表示完全關閉), 我 cat 這個檔案發現 Jetson Nano 的 Ubuntu 18.04 預設是完全啟用的 (值=1) : 

tony1966@jetson-nano-tony1966:~$ cat /proc/sys/kernel/sysrq    
1

呵呵, 下次再遇到當機 (最好別) 就來試試看 SysRq 鍵的功用吧! 

其他參考文章 :


2021年1月15日 星期五

市圖還書 5 本

本周市圖還書 5 本 :
黃底之書需要回借. 

使用 ngrok 代理伺服器穿透社區網路存取內網的樹莓派本機網站

今天在趙英傑寫的 "超圖解 Python 程式設計入門" 這本書的第十章讀到透過 ngrok 代裡伺服器存取位於內網的本機網站的方法, 我覺得很有意思, 因為家裡使用社區網路, 沒辦法像鄉下家的 ADSL 那樣在路由器上打洞從遠端存取 22 與 80 埠, 所以架設在樹莓派上的網站沒辦法從外網瀏覽, 用這方法應該可行, 今天測試確認 OK, 紀錄如下 :


Source : 博客來


Ngrok 是一個提供 Web 轉發服務的代理伺服器, 使用者須下載 ngrok 程式, 經過驗證後可為內網的網站提供一個外網 URL, 讓外網可以存取內網的 localhost 網站, 但每次啟動 ngrok 程式時轉發的外網 URL 網址會變 . Ngrok 有提供免費方案, 但限制最多同時 40 個連線請求. 

我的樹莓派 Pi 3B 的 80 埠已經被運行中的 Nginx 網頁伺服器占用, 所以開啟樹莓派的 Chromium 瀏覽器連線 localhost (或 127.0.0.1) 會顯示 Nginx 伺服器的歡迎頁面 :




但這只能在內網 (區域網路) 看到, 以下的測試就是希望能在外網也能看到此網頁. 

首先到 Ngrok 網站下載 ngrok 程式 : 


Ngrok 網站會自動偵測作業系統, 它偵測到這是樹莓派, 所以下載頁顯示的是 Linux 版的 ngrok 下載頁面 :




樹莓派網頁下載的檔案預設放在使用者目錄的 Downloads 子目錄下 :

pi@raspberrypi:~ $ cd Downloads   
pi@raspberrypi:~/Downloads $ ls -ls ngrok   
23296 -rwxr-xr-x 1 pi pi 23855086 10月  9  2019 ngrok   

在 Windows 的命令列只要執行 ngrok http 80 即可啟動 80 埠的網站轉發服務, 但在 Linux 必須用 ./ngrok 才行, 否則會找不到 ngrok :

pi@raspberrypi:~/Downloads $ ngrok http 80   
bash: ngrok:命令找不到
pi@raspberrypi:~/Downloads $ ./ngrok http 80

參考 :


這時終端機進入 ngrok 的畫面 : 




可見 ngrok 已產生轉發網址 4c0d8b727244.ngrok.io (預設伺服器在美國), 任何以 HTTP/HTTP 向此 URL 發出的要求都會被轉發到本機的網址 http://localhost:80 (注意 Session Expire 欄位顯示 1 小時 58 分, 表示對於未註冊用戶啟動 ngrok 後只能使用 2 小時而已) : 

ngrok by @inconshreveable                                              (Ctrl+C to quit)
                                                                                       
Session Status                online          
Session Expires           1 hours, 58 minutes                                   
Version                       2.3.35                                                   
Region                        United States (us)                                       
Web Interface                 http://127.0.0.1:4040                                    
Forwarding                    http://4c0d8b727244.ngrok.io -> http://localhost:80      
Forwarding                    https://4c0d8b727244.ngrok.io -> http://localhost:80     
                                                                                       
Connections                   ttl     opn     rt1     rt5     p50     p90              
                              2       0       0.00    0.00    65.52   65.97            
                                                                              

這時在外網用瀏覽器連線此轉發網址 4c0d8b727244.ngrok.io 即可看到內網的網站內容 :




而樹莓派終端機的 ngrok 執行畫面下方也會顯示 HTTP/HTTPS 連線訊息 :




解決 Session Expires 兩小時斷線限制問題的方法是去 ngrok 官網註冊一個免費帳號 : 




按 Get started for free 鈕填寫 email 與密碼 (需 10 碼以上) 按 Sign up 即可 : 




註冊完進入 ngrok 官網的 setup&instalation 頁面, 其中第二項的指令中含有個人的授權碼, 將整個指令複製起來 : 




然後在樹莓派終端機介面先按 CTRL+C 終止目前的轉發服務, 然後把上面所複製的指令貼到終端機即完成授權, 這會產生一個授權檔案 ngrok.yaml  : 

pi@raspberrypi:~/Downloads $ ./ngrok authtoken 1n4EbyjkVWZ1RXPyZVSQ1nKz9Mn_7kbM7zgjAt45W7RGhsx1L
Authtoken saved to configuration file: /home/pi/.ngrok2/ngrok.yml

這時再次輸入 ./ngrok http 80 重新啟動轉發服務 : 

pi@raspberrypi:~/Downloads $ ./ngrok http -region ap 80

此處我們在 http 後用 -region ap 參數指定使用 rgrok 亞太區伺服器 (位於新加坡), 這樣會比上面預設的美國快一些 :




可見已經沒有 Session Expires 這個欄位, 而且伺服器地點也改在亞太區了. 由於重新啟動 ngrok, 所以轉發的網址也改變了, 現在外網必須改用此網址才能存取本機網站 :




Bingo! 但此方法址只是解決了穿透防火牆存取 HTTP/HTTP 埠口問題而已, 如果要完全掌控社區網路內的樹莓派 (即存取桌面), 必須使用樹莓派 Rasbian 作業系統內建的 VNC 才行 (外網使用 VNC Connect), 參考 :


Ngrok 官網提供了許多應用教學, 參考 :



2020-01-16 補充 : 

由於每次執行 ngrok 後產生的外網轉發網址都不同, 這就有一個大問題了, 如果樹莓派不明原因當機重啟, 雖然可以設定樹莓派在系統啟動時自動執行 ngrok, 但是在遠端要怎麼得知轉發網址呢? 我找到下面這篇文章 :


只要開機啟動 ngrok 後執行下列指令 :

curl http://localhost:4040/api/tunnels

此指令會傳回一個 json 格式的回應 :

i@raspberrypi:~ $ curl http://localhost:4040/api/tunnels
{"tunnels":[{"name":"command_line","uri":"/api/tunnels/command_line","public_url":"https://4c0d8b727244.ngrok.io","proto":"https","config":{"addr":"http://localhost:80","inspect":true},"metrics":{"conns": ......}

其中的 public_url 鍵之值即為外網之轉發網址, 只要用 email 傳出去就可以得知最新網址了.