星期六, 12月 08, 2018

Line Messaging API 在 Messaging Settings 頁面設定 Webhooks 時的陷阱

不知道從什麼時候開始, Line的 Messaging API在 Messaging Settings 頁面上出現一個古怪的陷阱:
如果您先設定 Use webhooks 為 Enabled, 然後才填入 Webhook URL,那麼剛剛修改的 Use webhooks就會被暗地設回 Disabled, 但是看到的仍然是 Enabled, 像是這樣:
實際上 webhook 並沒有生效, 會讓你的 Line Chatbot 已讀不回。這時候只要按 F5 重新載入頁面, 就會看到暗中被設回 Disabled 的 Use webhooks 選項:
 只要重新再設定為 Enabled 就好了。

星期四, 11月 08, 2018

使用 Python 從 excel 檔終結取資料

由於需要從大量的 excel 檔中擷取資料,就想是否可以用程式的方式來解決,一查知下, 果然有個 xlrd 模組可以讀寫 excel 檔。例如, 我想從當前資料夾下一個個打開 excel 檔,並且檢查每一筆資料中, 若第 B 欄的內容符合條件, 就將同一列 B 欄與 D欄的資料寫入輸出檔案中, 就可以撰寫類似以下的程式:
import glob
import xlrd

with open('result.txt', mode='w', encoding='utf-8') as of:
  for xlsfile in glob.iglob("order*.xls"):
    wb = xlrd.open_workbook(xlsfile)
    for i in range(wb.nsheets):
      st = wb.sheet_by_index(i)
      if st.nrows > 1:
        for r in range(st.nrows):
          if st.cell(r, 1).value in ('table','chair'):
            of.write(st.cell(r, 1).value + ',' + 
              st.cell(r, 3).value + "\n")
要注意的是, 這個套件中不論是列編號或是欄編號都是從 0 開始, 因此 excel 檔中的第 1 列編號為 0, 第 B 欄編號為 1, 所以上面程式中 cell(r, 1) 就是 excel 檔中第 r+1 列的第 B 欄。詳細的用法可以參考該模組的說明文件, 或是參考這一份簡單的教學

從 eml 檔擷取郵件夾檔

最近遇到一個需求, 需要從一大堆的 eml 檔把郵件中的夾檔抽出來,因此找到一個 outlook add-on, 叫做 Ourlook Save Attachments from EML files, 可以針對特定的資料夾中的 eml 檔把其中的夾檔通取出存檔。

這個 add-on 其實跟 outlook一點都沒關係, 但是因為不是獨立的執行檔, 所以還是得要有 outlook 才行, 這是唯一美中不足之處。

星期三, 10月 10, 2018

雷射模組 (KY-008) 的 3 根針腳

同事因為專案使用了市面上極容易買到的 KY-008 模組:


大部分的使用案例都會告訴你 S 接數位輸出控制開關, 中間腳接 5V, - 腳接地, 測試後發現怪怪的, S 的電壓會影響雷射的亮度, 並不是單純的開關;而且, 如果 S 腳完全不接, 似乎雷射會有微光。經過檢查模組上的線路後, 是這樣:


所以其實 S 和 - 就是供電控制雷射開關, 因此 S 的電壓會影像雷射光的亮度, 只要這兩隻腳就可以控制雷射。那麼為什麼要從 S 接一個 10KΩ電阻到中間腳呢?網路上有人稱呼中間腳為『神秘』腳, 因為不知道做什麼用途?根據這一篇文章的說明, 中間腳應該是模組的輸出腳位, 10KΩ電阻是為了限流, 可以讓你監控供給模組的電壓, 比方說偵測電源中斷、或是電壓意外陡降或是不穩等等, 至於實際上的用法, 就有待各位自行發想囉。

星期五, 8月 31, 2018

Arduino 1.8.6 無法上傳程式到 Arduino Nano 控制板

同事因為用到 Arduino Nano 控制板, 卻發現 Arduino 1.8.6 版無法上傳程式, 總是會有以下的錯誤訊息:


查了官網的資料後, 發現在 Arduino Nano 的 Getting started 文章中, 有以下的補充:

NOTE: We have updated the NANO board with a fresh bootloader. Boards sold from us from January 2018 have this new bootloader, while boards manufactured before that date have the old bootloader. First, make sure you have the Arduino AVR Core 1.16.21 or later looking at the Board Manager. Then, to program the NEW Arduino NANO boards you need to chose Processor > "ATmega328P". To program old boards you need to choose Processor > "ATmega328P (Old Bootloader)". If you get an error while uploading or you are not sure which bootloader you have, try each type of processor 328P until your board gets properly programmed.

也就是說, 2018 年 1 月開始, 官方售出的 Arduino Nano 控制板上方的 bootloader 是新版的, 所以 Arduino 1.8.6 預設是配合此新版的 bootloader, 如果是之前買到的 Arduino Nano 控制板, 在上傳程式時就必須選取『工具/處理器/ATmega328P (Old Bootloader)』選項, 才能正確上傳:

星期一, 8月 06, 2018

firebase-arduino 程式庫無法更新資料

如果您有使用 firebase-arduino 程式庫由 ESP8266 控制板上傳資料到 Firebase 的資料庫, 會發現從約莫上週五開始, 就會失敗, 這是因為 Firebase 更新了他們的數位指紋 (fingerprint), 為此 firebase-arduino 也在幾天前修改了程式庫內容 (可參考這一篇文章)。您可以重新下載程式庫, 安裝到 Arduino 開發環境中就可以解決, 或者也可以直接修改 FirebaseHttpClient.h 檔, 將 kFirebaseFingerprint 字串的內容修改為 "6F D0 9A 52 C0 E9 E4 CD A0 D3 02 A4 B7 A1 92 38 2D CA 2F 26" , 再重新編譯程式執行即可。

星期三, 7月 11, 2018

MicroPyton 執行 UTF-8 with BOM 格式的檔案會出錯

在執行 MicroPython 的程式檔時,如果檔案是以 UTF-8 with BOM 的格式儲存, 例如以下的閃爍 LED 程式:


執行時就會發生錯誤:


這時只要將檔案另存新檔, 選取 UTF-8 格式即可, 以下使用 Visual Studio Code 為例:



另存後可以看到檔案格式已經變更:


重新執行就不會發生錯誤了:


星期五, 4月 27, 2018

App Inventor BLE 元件錯誤 "failed resolution Lcom/google/common/collect/List"

在測試 App Inventor 2 的 BLE 元件時, 遇到奇怪的問題, 執行到 WriteBytes 函式, 傳給 values 參數 list (清單) 資料, 就會發生以下的執行時期錯誤:
查了網路上發現這個討論串, 提出的臨時替代方案就是改用 WriteStrings, 並且直接傳送字串給 values 參數, 而不是內含個別字串的清單, App Inventor 會把這個字串轉成由個別字元組成的清單, 一一將字元傳送出去。因此, 如果你本來要送出 12,14 這 2 個位元組, 就要改成送出字串, 其中第一個字元字碼 (ASCII code) 是 12、第二個字元字碼是 14。

不過 App Inventor 並沒有指定字碼傳回對應字元的積木, 因此就有聰明的人想出對策, 由於在 Web(網路) 元件中有提供解譯 HTML entity 成對應字元的功能, 也就是把像是 "&#65" 這樣的字串轉譯為字碼 65 的字元 'A', 藉由此法, 我們就可以撰寫一個傳回指定字碼對應字元的函式:


如此就可以在 WriteStrings 中使用上述函式來組合多個位元組資料了。

星期二, 3月 13, 2018

ESP8266 MicroPython 使用 poll() 出現 Fatal exception 28(LoadProhibitedCause)

由於 MicroPython 預設並沒有像是 ESP8266 Arduino Core 提供有 ESP8266WebServer 程式庫那樣的簡易 Web Server, 所以打算撰寫一個超級簡易版來用。在設計的過程中, 發現 socket 的 accept() 在沒有新連線的情況下並不會返回, 這樣程式流程就會被凍結在這裡無法進行其他的工作, 根據 MicroPythono 文件的說明, 建議你改用 uselect 模組的 poll 類別, 於是我大概寫了這樣的程式:
server.bind(('0.0.0.0', port))
server.listen(1)
poller.register(server, uselect.POLLIN)

where True:
  res = poller.poll(0)
  if res:
    (socket, sockaddr) = server.accept()
    handle(socket)
    ...
程式運作基本上都很好, 但是會在某個沒有規律的神奇時間出現嚴重例外而重置, 出現以下訊息:
Fatal exception 28(LoadProhibitedCause):
epc1=0x4025681d, epc2=0x00000000, epc3=0x00000000, 
excvaddr=0x00000010, depc=0x00000000

 ets Jan  8 2013,rst cause:2, boot mode:(3,6)
...
經過反覆實驗, 發現只要叫用 poll() 時不要給 0 作為 timeout, 就可以避免了。因此最後修改的程式就把 poll(0) 改為 poll(1) 即可。

我寫好的 Web Server 可以參考這裡

星期五, 2月 09, 2018

APDS9960、APDS9930、APDS9900 傻傻分不清楚

同事買了一個號稱使用 APDS9960 感測器的模組, 這感測器可以測環境光線、接近距離、RGB 顏色、手勢, 看起來超威, 趕快找了對應的程式庫, 可是測了半天, 除了環境光線沒問題外, 其他怎麼測都不行。經過網路耙梳, 發現有一篇文章的回應中提到, 他在某處購買了好幾個也是號稱使用同一型號感測器的模組, 但其實使用的是舊款的 APDS9930 感測器, 因為根據 APDS9960 規格書上說明, APDS9960 的 device id 應該是 0xAB, 但他讀到的 device id 是 0x39, 和 APDS9930 規格書上標示的相同。經過這一提醒, 我就改用 APDS9930 的程式庫測試, 果然發現同事買的這一款模組並不是使用 APDS9960, 當 APDS9930 測試就成功了。而手勢偵測、RGB 顏色識別都是 APDS9960 才有的功能, 接近感測的資料取得方式也不一樣。

為了確認這一款模組到底是不是使用 APDS9930, 只好去讀取它的 device id, 一讀不得了, 既不是 APDS9960 的 0xAB、也不是 APDS9930 的 0x39, 而是讀到 0x29, 上網路查才真相大白, 原來這個模組使用的是型號更舊的 APDS9900, 規格書上標明的 device id 正是 0x29。這時我再回頭看原本 APDS9960 的測試程式, 發現其實程式一開始執行時就已經有訊息告訴我初始程序有地方出錯, 如果早點注意到, 我們就不會花這麼多時間找問題了。不過淘寶賣家你們也幫幫忙, 不要亂來好嗎?好啦, 我知道那是製造商的問題, 因為他們在電路板背面大剌剌的印了APDS9960:
註:這一篇文章有市面上幾款模組的樣子, 不仔細分辨還真不容易搞清楚。

星期五, 2月 02, 2018

D1 Mini Motor Shield I2C 通訊問題

因為開發產品的緣故, 同事購買了 D1 Mini Motor Shield 來控制直流馬達, 不過實際使用時發現奇特的現象, 閒置一會兒就無法控制馬達。經過簡單的除錯步驟, 發現如果 D1 Mini 與 Motor Shield 間一段時間 (實際測試約 10 秒) 沒有進行 I2C 通訊, Motor Shield 的 I2C 就會沒有任何反應。解決的方法就是每隔一小段時間, 例如 5 秒鐘, 就進行一次 I2C 通訊, 就可以維持 Motor Shield 的 I2C 正常運作。

網路上也有善心人士針對此問題, 撰寫了修正版本的 Motor Shield 韌體, 如果覺得上述手動修改程式定時進行 I2C 通訊的方式很麻煩, 也可以是是看燒錄修正版本的韌體。

星期五, 1月 26, 2018

ESP8266 Arduino Core 2.4.0 min() 與 max() 問題

ESP8266 Arduino Core 在更新到 2.4.0 時, 把原本是使用巨集定義的 min() 和 max() 改成使用 C++ 標準的 std::min() 和 std::max() 樣板 (template), 這使得許多使用到 min() 和 max() 的函式庫編譯錯誤, 這主要是因為原本巨集的版本大概如下 (以下均以 min() 為例, max() 的情況相同):
#define min(x, y) ((x) < (y) ? (x) : (y))
其中 x 與 y 可以是任意型別, 因此如果 x 是浮點數、y 是整數也可以成功編譯。可是改用了 std::min() 樣板, 它的原型如下 (事實上有多個版本, 但都有類似的問題):
template< class T > const T& min( const T& a, const T& b );
由於樣板中兩個比較的對象其資料型別都必須式樣板參數 T, 因此以下的程式編譯時就會有問題:
float val = 200;
void setup() {
  // put your setup code here, to run once:
  Serial.begin(115200);
}

void loop() {
  // put your main code here, to run repeatedly:
  val = min(val, 210);
  Serial.print("min = ");
  Serial.println(val++);
  delay(200);
}
你會看到錯誤訊息為:
no matching function for call to 'min(float&, int)'
這是因為 val 是 float, 但是 210 是 int, 兩者型別不同, 所以無法用 std::min() 樣板建立對應呼叫的函式實體。要解決這個問題, 有兩種方法:一是在你的程式中自行定義巨集版本的 min(), 或者是在程式中強制轉型, 讓兩個比較的參數都是相同的型別, 例如:
 val = min((int)val, 210);
就可以成功編譯, 也可以正確執行了。