產生指定容量的 Raspberry Pi SD 卡影像檔

將 Raspberry Pi 的 SD 記憶卡備份為影像檔很簡單。但那是指同一張 SD 卡備份還原的情形。 在大量部署樹莓派設備時,我們需要一些特別的前置工作,才能產生很多張 SD 記憶卡都能用的影像檔。

win32diskimager 或 etcher 這些 Windows 磁碟備份與寫入工具有個缺點。 它們只能整顆磁碟備份或寫入,不能選擇備份的容量範圍。 然而標示相同容量的 SD 卡,實際容量仍有個別差異。少則十幾 MB ,多則差一、兩百 MB 。 因此,就算你備份的 SD 卡容量比你想寫入的 SD 卡容量只大一些,它也拒絕寫入。 在大量部署樹莓派設備時,非常不利。

我的維護經驗是:

  1. 使用 gparted 縮減 SD 卡使用的分割區容量。 我通常會縮減最後的分割區容量。尾巴留下 100~200MB 的不使用空間。對應 SD 卡容量的誤差量。
  2. 使用 dd 指令建立 SD 卡影像檔。因為 dd 可以指定容量。

Raspberry Pi OverlayFS 檔案系統使用備忘錄

Raspberry Pi 在 IoT 方案中,通常都不接鍵盤與螢幕,也沒有設計電源開關。 所以很多時候, IoT 現場的使用者會把 RPi 設備當成是 Arduino 這類微控制器設備,認為出現狀況時直接關掉設備的電源再打開就好。 就算不是使用者有意為之,在 IoT 現場也很可能遇到電源中斷的意外。

但是 RPi 的工作方式實際上更偏向一般 PC ,故與一般 PC 相似,將直接關掉電源的事視為不正常關機動作。 這種斷電方式可能打斷正將資料寫入檔案系統的工作,造成 SD 記憶卡的檔案系統內容毀損。 因此 RPi 運用在 IoT 方案時,需要設置檔案系統的保護機制。至少要保證它被直接斷電後,檔案系統也不會毀損。

當 RPi 運作 Raspbian 時,可以啟用 OverlayFS 作為檔案系統的保護機制。

Raspberry Pi eth0 有線網路設定的 fallback 組態

Raspberry Pi 使用作業系統 Raspbian GNU/Linux 9.9 (stretch) ,啟用 GUI 桌面。 在此環境下,傳統的網路介面組態 /etc/network/interfaces 無效用。以 /etc/dhcpcd.conf 為準。

dhcpcd.conf 的 eth0 有線網路基本組態就是向 DHCP 服務要求 IP 。如果所處環境沒有 DHCP 服務,那 eth0 就不設定任何 IP 。

如果是在靜態 IP 網路環境中使用 Raspberry Pi ,可以從 Raspbian 桌面上方工作列的 WiFi 圖示,打開「Wireless & Wired Network Settings」設定頁面,設定有線網路 eth0 的靜態 IP 。 若是自行編輯 dhcpcd.conf ,則設定內容如下 (假設靜態 IP 是 192.168.1.99):


interface eth0
inform 192.168.1.99

但 dhcpcd.conf 其實還有一組更有彈性的 fallback 組態,可在自動要求配置 IP 失敗後,才退回靜態 IP 。只是這組態得要動手編輯 dhcpcd.conf 。

Debian 10 安裝筆記

上星期 (2019-07-06) Debian 官方發行了 Debian 10 (buster)。正好我的筆電 Thinkpad X200s 上的 Debian 8 也實在有點舊了。就趁著週末重新安裝作業系統,升級到 Debian 10 。

安裝步驟大致依照我以前的筆記。

本文主要列出和 Debian 舊版不同的地方。這裡沒寫的,就是看以前的安裝筆記。

NodeMCU http recursive 遞回呼叫範例

NodeMCU 的 http 模組可用於存取一般 HTTP 資源,或是呼叫 RESTful API 。 然而, NodeMCU lua 環境的基本程式設計模型是事件驅動模式。 故 http 模組提供的方法也是非同步方法 (async method)。 但它還有一個限制,它一次只能發出一個請求,不允許併發作業。

It is not possible to execute concurrent HTTP requests using this module. NodeMCU Documentation

因此,如果你的控制器需要向 HTTP 伺服器發出多個請求的話,就需要利用一些技巧,例如遞回呼叫,讓你的 HTTP 請求可以一個個地依次發出。 其實就是將非同步方法同步化。

LINQ 與 SQL 的 inner join 語法轉換

我個人用 C# 撰寫資料庫存取程式時,習慣先用 SQL 敘述直接查詢資料庫,確認結果如我預期之後,再把這段 SQL 敘述在程式碼中寫成 LINQ 表達式。 而除錯或維護程式時,則反過來操作,把我覺得結果不如預期的 LINQ 表達式複製出來,改成 SQL 敘述去查資料庫。

這兩件事是我常常在做的,也就有些心得。LINQ 的 inner join 是不錯的範例。很常用,敘述有些長,但格式工整容易對應 SQL 。

NodeMCU timer 鬧鐘計時器範例

Arduino 的程式碼中,呼叫 delay() 方法延時是典型作法。而在網路上也可以找到不少照搬 Arduino 習慣,使用 tmr.delay() 的 NodeMCU lua 程式範例。但請不要抄。 NodeMCU 不建議使用這個方式延時。

This is in general a bad idea, because nothing else gets to run, and the networking stack (and other things) can fall over as a result. The only time tmr.delay() may be appropriate to use is if dealing with a peripheral device which needs a (very) brief delay between commands, or similar.

NodeMCU Documentation

NodeMCU lua 環境的基本程式設計模型是事件驅動模式。但 tmr.delay() 會破壞這個工作模式。程式設計者應該用 tmr 模組的計時器功能取代。

NodeMCU 韌體與軟體更新工具

NodeMCU

NodeMCU,是一個開源的物聯網平台。它使用Lua手稿語言編程。該平台基於 eLua 開源專案, 底層使用ESP8266 sdk 0.9.5版本。

NodeMCU - 維基百科

NodeMCU 使用工具

  • python - 建議 Python3 。執行 esptool 所需。
  • esptool - 韌體更新工具。
  • OpenJDK - 7 或以上版本。建議 OpenJDK 8 。執行 ESPlorer 所需。
  • ESPlorer - IDE 工具。

簡單來說, esptool 用於寫入 NodeMCU 的韌體或任何 ESP8266 的 binary 內容。而 ESPlorer 則是讓 lua 開發者上傳 lua 程式檔。 兩個各自負責不同的內容。

Raspberry Pi 使用 HDMI to VGA 轉接器的設定事項

用電需求

Raspberry Pi 的 HDMI 埠會提供符合 HDMI 規範的最低限度電源(5V/55mA)。但 HDMI to VGA 轉接器的訊號轉換晶片大約需要 50mA ~ 150mA 電流。供電量非常勉強地達標。而畫面解析度愈高,耗電量也愈高。因此 HDMI to VGA 轉接器建議外接供電才會穩定工作。

我碰到的情形是,在未外接電源時,可以正常顯示 NOOBS 的系統安裝畫面。但啟動 Raspbian 時,就會在啟動過程即將進入 GUI 模式前重啟。因為按預設組態, Raspbian 需自動偵測畫面最適解析度。在逐步提高解析度的偵測過程中,耗電量超過 Raspberry Pi 透過 HDMI 送來的電力,導致系統重啟。我必須為 HDMI to VGA 轉接器接上外接電源,才能正常啟動。

因此建議找附帶電源輸入端的品項。如果附帶的電源輸入端是 Micro USB 入電孔,你可以從 Raspberry Pi 的 USB 插座供電給轉接器。

例如:

有人動手改裝不含外部電源輸入的 HDMI to VGA 轉接器:RaspberryPI : HDMI to VGA 加裝 USB 外接電源

.NET Core 筆記 - Anonymous Type List

如何配置一個匿名型別串列。

首先,複習下列定義已知型別串列的語法。


int[] int_list1 = new int[] {1, 3};
var int_list2 = new int[] {1, 3};
var int_list3 = new [] {1, 3};

var list41 = new double[] {1, 3, 5.5};
var list42 = new [] {1, 3, 5.5};
Console.WriteLine(list41.GetType() == list42.GetType());

// error CS0826: 找不到隱含類型陣列的最佳類型
//var list5 = new [] {1, 2, "s"};

第一個例子是明確宣告等號兩邊型別的語法,也是最傳統的語法。

第二個例子引入型別推斷語法,等號右邊明確宣告此處將配置一個整數型別的陣列。所以明眼即可推斷左值之型別必為整數型別陣列。

第三個例子則更進一步,連等號右邊也不明確宣告資料型別。而讓 C# 編譯器先從陣列的資料內容推斷右邊的陣列型別,再依此推斷左邊的型別。這語法要求陣列的所有元素之型別皆可互相隱含轉換,編譯器再從中選出一個不會損失資料精度的型別。例如 new [] {1, 3, 5.5} 將推斷為 double[] 而非 int[] 以保證 5.5 不會變成 5 。若有一個元素的型別不合群,那編譯器就會拋出無法決定最適型別的錯誤。

.NET Core 筆記 - ASP.NET Core 上傳檔案的模型繫結

上傳檔案的設計內容請看 MSDN 文章 File uploads in ASP.NET Core

但模型繫結的型態似乎是文件錯誤。微軟文件寫多檔上傳可用 List<IFormFile> 繫結,但 ASP.NET Core 2 會顯示錯誤訊息 The input was not valid,不能處理。改用 IFormFileCollection 取代 List<IFormFile> 才正確。

如果表單中除了檔案欄位還有其他輸入欄位,則 API 參數清單加上一個 [FromForm] 參數去接其他輸入欄位的內容。這個參數的型態通常可用 Dictionary<string,string>

留言板(disqus)放到首頁使用

我現在把 disqus 放到部落格首頁下方。以網站留言的型式使用。

每篇文章下方也多了一個「留言」鈕,簡單地連結跳回首頁留言板區。

對我的文章有問題的網友,留言時就加個標題、連結或引用文字吧。

.NET Core 筆記 - ASP.NET Core 應用程式托管於IIS服務

基礎知識

首先,請參考微軟的 Host ASP.NET Core on Windows with IIS 。但這篇文章資訊(廢話)很多,不容易找到重點。

ASP.NET Core 內建且默認用 Kestrel HTTP 服務模組。本文以此為準。

由於 ASP.NET Core 應用程式啟動時自帶 Kestrel HTTP 服務模組,本身不需要搭配 IIS 亦可獨立運作。但這種作法偏向微服務形式,而且負載分擔能力不如專業的 Nginx, Apache 或 IIS 。若你需要在一台主機上提供多個不同的 ASP.NET Core 應用程式服務,必須在 Kestrel 之前再加一道 HTTP 服務器,利用反向代理機制 (reverse proxy) ,溝通 Kestrel 與瀏覽器之間的通訊。

IIS 服務主機必須安裝 .NET Core Runtime & Hosting Bundle for Windows 。請到 .NET Core 網站下載

.NET Core 筆記 - async method and sync code

我用 .NET Core 實作一個呼叫 RESTful API 的簡單程式時,碰到一個小麻煩。 .NET Core 的 HttpClient 類提供的方法都是非同步方法 (async method)。 但我是在同步形式的程式碼用到 HttpClient 。我不想回頭去改程式碼加上 async Task 的宣告。所以我得要呼叫非同步方法,但用同步形式程式碼取得結果。

.NET Core 筆記 - ASP.NET Core appsettings.json 與執行環境

一般進行程式開發工作時,至少會分成兩個階段,或說兩個工作會期。開發期/Development/Debug 和 發布期/Production/Release 。並針對這兩個階段,設定不同的執行環境。

例如設定開發期執行環境的資料庫來源是 SQLite ,而發布期執行環境則用客戶指定的資料庫來源 SQL Server 。如此一來,開發人員僅須切換組態檔,就能改變程式的執行環境與參數。方便應付開發、測試、正式部署等工作。

ASP.NET Core 選擇用 DevelopmentProduction 這兩個稱呼區分兩階段。

更新 Github Page 自訂網域名稱的 IP

今天更新部落格一份文件後, github 發了一封 “Page build warning” 的提示信,信中說我的網站域名指向一個過期的 IP 位址。

The custom domain for your GitHub Pages site is pointed at an outdated IP address. You must update your site’s DNS records if you’d like it to be available via your custom domain. For more information, see https://help.github.com/en/articles/using-a-custom-domain-with-github-pages.

Mosquitto 設置安全性 Websocket (wss)

我早先在網頁前端使用 MQTT 處理訊息時,大多是在內網或非加密性網站。所以我用 mosquitte 架設的 MQTT 服務只啟用了一般性的 ws 協定。但近日開發一項基於 PWA 的網站應用 (Web App) 時,看到 mqtt 連線失敗的訊息,才知道處於 https 狀態的網頁, mqtt 也必須走安全性的 wss 連線。

所以我又花了不少時間,將公司內的 mosquitto 服務設置加進 wss 協定。本文也會特別說明 mosquitto 在 Windows 平台上設置 wss 的注意事項。事實上,我大部份時間就是耗在 Windows 平台上頭。

使用 OpenSSL 從 PFX 憑證文件匯出 PEM 憑證與金鑰

本文說明如何使用 OpenSSL 從 PFX 憑證文件匯出 PEM 格式的憑證與金鑰。

透過 SSL 協定建立瀏覽器和網站伺服器之間的安全通道時,必須使用符合 PKCS 標準的憑證文件。而 PKCS 訂立了多種憑證格式,常見的有 X.509 DER, X.509 PEM (Base64), PKCS#12 PFX 三種。這三種格式可以互相轉換。

雖然文件格式可以互相轉換,但大多數應用 SSL 加密通信資料的服務軟體,本身往往只支援其中一種格式。例如微軟 IIS 採用 PFX 格式,而 Apache HTTP Server 與 Nginx 則採用 PEM 格式。一般而言,非開放源碼的服務軟體多採用 PFX 格式;使用 OpenSSL 函數庫的開放源碼的服務軟體選擇 PEM 格式。當你要安裝的服務軟體採用的憑證文件格式與你手上現有的憑證不同時,你可以用 OpenSSL 工具自行轉換。

notifyOSD - non-jquery-ui

notifyOSD 是一個在畫面角落顯示提示訊息的網頁 UI 項目。以固定位置浮動視窗,顯示提示訊息。訊息採堆疊方式管理,新的訊息將疊在已有訊息之上,並在下方顯示已有幾筆提示訊息。

它不使用其他 JavaScript 套件。

Source Repo: non-jquery-ui