遊手好閒的石頭成
行於巷弄若於曠野,居於市井如於山巔。不知其何許人也。

我的程式源碼託管於 rocksources
rocksaying.tw
石頭閒語
部落格相簿
@tw_rocksaying

快報或告示

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

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

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

產生指定容量的 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 。若有一個元素的型別不合群,那編譯器就會拋出無法決定最適型別的錯誤。

分頁瀏覽
Programming
電腦技術
經濟學/奧地利經濟學派
閱讀隨筆
哲學/老子
休閒生活
快報記事