2016年9月21日 星期三

★ 用 Blynk 同時控制多個設備

昨天有網友問我是否可以用 App Inventor 2 設計一個 App 來同時控制多個設備, 以我的菜園灑水控制器來說, 若菜園有多處裝有 Arduino 灑水控制器, 希望在 App 上按一個按鈕就可以控制它們同時灑水或停止. 這讓我馬上想到 Blynk 應該可以輕易完成這個任務, 不需要花時間自行設計一個 App 才對.

以下使用我自行焊接的兩個 Arduino+ESP8266 物聯網模組來測試 Blynk 群控的功能, 利用 App 上的一個 Slider 滑桿元件同時控制 Arduino NANO 板上的 D13 LED 閃爍速度. 此 IOT 模組的製作方式參考 :

# 製作 Arduino Nano + ESP8266 物聯網模組 (四) : 完結篇

也可以根據下列電路圖用洞洞板連線 (AMS1117 可用 3.3V 穩壓模組取代) :


關於 Blynk 的用法, 參考之前的一系列實驗記錄 :

Blynk 應用 (一) : 用手機控制 Arduino
Blynk 應用 (二) : 在手機顯示即時溫溼度與光度
Blynk 的控制元件 (Controllers)
Blynk 的顯示元件 (Displays)
Blynk 的通知元件 (Notifications)
Blynk 的其他元件 (Others)
# Blynk 的虛擬腳位用法整理

在 Blynk App 上則是先新增一個專案, 在此專案中新增一個 Slider M 元件, 然後綁定一個虛擬腳位 V0, 修改值域為 100 ~ 1000, 代表 LED 閃爍的頻率 (其實是延遲時間), 100 表示快閃, 1000 表示慢閃.



此專案分享如下 :


測試程式如下 :

測試 1 :

#define BLYNK_PRINT Serial  //Comment this out to disable prints and save space
#include <SoftwareSerial.h>
#include <ESP8266_Lib.h>
#include <BlynkSimpleShieldEsp8266.h>

SoftwareSerial esp8266(7, 8); //(RX, TX)
ESP8266 wifi(&esp8266); //create wifi object

char ssid[]="H30-L02-webbot";
char pass[]="1234567890";
char auth[]="f4d4aa2dc86849adb0971d0xxxxxx371";
volatile int blinkRate=100;  //default blink rate

void setup() {
  Serial.begin(9600); //Set console baud rate
  esp8266.begin(9600); //Set ESP8266 baud rate
  Blynk.begin(auth, wifi, ssid, pass);
  }

void loop() {
  Blynk.run();
  blinkD13Led(blinkRate);
  }

BLYNK_WRITE(V0) { //called when V0 updated by App slider
  blinkRate=param.asInt(); //store value from App slider
  Serial.println(blinkRate);  //show current blink rate
  }

void blinkD13Led(int t) {
  digitalWrite(13, HIGH);
  delay(t);          
  digitalWrite(13, LOW);
  delay(t);          
  }

此處我們須準備一個特定的寫入事件處理函數 BLYNK_WRITE(V0) 讓 V0 腳位值更新時被呼叫, 因為手機 App 的 Slider 是一個控制元件, 當滑動滑桿時會將滑桿的值寫入伺服器中此專案之虛擬腳位 V0, 產生一個寫入事件, 會觸發設備中的寫入事件處理函數被呼叫一次. 在此函數中, 我們用特定的變數 param 取得最新的 V0 腳位之值, 用來更新全域變數 blinkRate, 此變數會被 blinkD13LED() 用來更改 LED 的閃爍頻率. 跟中斷事件類似, 由於 blinkRate 隨時會被更新, 因此要宣告為 volatile 以避免被編譯器優化.

這兩塊 IOT 模組都上傳相同的程式, 上電後, 由於 blinkRate 初始值設為 100, 因此會先快閃, 等我們滑動滑桿之後就會改變閃爍頻率 :


從上面影片可知, 滑動滑桿時, 兩個 NANO 板上的 D13 LED 都同時改變其閃爍頻率, 可見用 Blynk 可輕易達成群控之目的.

但上面測試 1 有個問題, 即每次重開機預設都是快閃 (blinkRate 預設 100), 必須在 App 上操作滑桿才會變更頻率. 要如何讓設備一開機或重新連線時能以最後一次滑桿之值閃爍呢? 這可以用特定之 BLYNK_CONNECTED() 函數來實現, 此函數會在設備重新與 Blynk Cloud 伺服器連線成功時被呼叫, 我們只要在此事件處理程序中呼叫 Blynk.syncVirtual(vPin) 即可取得伺服器上該虛擬腳位之值, 從而觸發虛擬腳位之寫入動作, 使 BLYNK_WRITE() 函數被呼叫, 這樣就會以上次的設定值閃爍了.

測試 2 :

#define BLYNK_PRINT Serial  //Comment this out to disable prints and save space
#include <SoftwareSerial.h>
#include <ESP8266_Lib.h>
#include <BlynkSimpleShieldEsp8266.h>

SoftwareSerial esp8266(7, 8); //(RX, TX)
ESP8266 wifi(&esp8266); //create wifi object
int blinkRate;

char ssid[]="H30-L02-webbot";
char pass[]="1234567890";
char auth[]="f4d4aa2dc86849adb0971d0xxxxxx371";

void setup() {
  Serial.begin(9600); //Set console baud rate
  esp8266.begin(9600); //Set ESP8266 baud rate
  Blynk.begin(auth, wifi, ssid, pass);
  }

void loop() {
  Blynk.run();
  blinkD13Led(blinkRate);
  }

BLYNK_WRITE(V0) { //called when V0 updated by App slider
  blinkRate=param.asInt(); //store value from App slider
  Serial.println(blinkRate);
  }

BLYNK_CONNECTED() { //get data stored in virtual pin V0 from server
  Blynk.syncVirtual(V0);
  }

void blinkD13Led(int t) {
  digitalWrite(13, HIGH);
  delay(t);        
  digitalWrite(13, LOW);
  delay(t);        
  }

此程式中的 BLYNK_CONNECTED() 會在設備連上 Blynk 伺服器時被呼叫 (全部大寫的函數都是事件處理函數), 在裡面我們呼叫了指定虛擬腳位的同步函數 Blynk.syncVirtual(V0) 向伺服器取得 V0 的值, 這會導致一個 V0 刷新動作, 使得 BLYNK_WRITE(V0) 被呼叫, 從而使 LED 以上次的設定閃爍. 以上測試 2 也同時回應了網友關於程式重新起始時, 滑桿之值不是停留在上一次設定值的問題.


15 則留言:

  1. 讚喔,程式這樣的寫法,就可解決我上次請教老師的兩個問題,一是Blynk Slider 初始值讀取的問題,另一個就是相同程式給不同 End User 使用,Blynk 雲端 Server 是否會有人數使用限制問題......

    但是老師曾提過, loop 迴圈內,儘量不要放太多執行程式,否則會造成系統崩潰,請問這程式 run 一陣子之後會 crash 嗎 ?

    謝謝指導, 打擾了....

    回覆刪除
  2. 為何不使用 setTimer 定時1秒的方式來寫,這樣就不需放在 loop 迴圈內了....

    回覆刪除
  3. 如果要固定時間週期觸發當然是要用 TIMER, 因為用 loop 控制時間得用 delay, 比較不專業. 但並不是說 loop 裡面不要放太多東西, 而是 Blynk.virtualWrite(vPin, value) 不要放在 loop 裡面, 除此之外放在 loop 本就天經地義啊. 當然全部邏輯都塞 loop 也不好閱讀, 可以寫成函數在 loop 內呼叫, 這樣較符合結構化要求.

    回覆刪除
  4. 目前使用 Blynk 時,發現尖峰使用時間,在程式的 termial 視窗監看, 常會出現 login timeout,造成程式就死當在那裏,雖然Blynk 會重覆 login , 但並不是每次都成功,這是因為 Blynk Server connection pool 已經超過負荷了嗎?,所以必需等別人logout,還是只有我會這樣子

    回覆刪除
  5. 是的, 我也有遇到這種情形. Blynk 伺服器似乎有時會 overloading, 可能連線數太多了. 比較保險是自建 Blynk 伺服器, 有空來研究在樹苺派上佈建自己的 Blynk 伺服器.

    回覆刪除
  6. 樹苺派與 arduino 有何不同,一直不太懂,太多新名詞了......

    回覆刪除
  7. 樹苺派是跑 Linux 的嵌入式設備, 具有 HDMI 等高階影音處理能力, 可執行 Python/Java/C++ 等程式, 還可以跑各種伺服器, Pi 3 甚至內建 wifi, 屬於迷你級電腦. 而且也有 GPIO 可像 Arduino 一樣接感測器或控制周邊. 通常低階簡易的控制用 Arduino+ESP8266 就綽綽有餘了, 需要影像處理或語音識別功能的話, Arduino 就很弱了, 必須用樹苺派才行.

    回覆刪除
  8. 老師再請教一下,這個問題不知要貼那兒,是有關於 MIT Inventor 2的,查詢 google , 看到的都是 bluetooth 的例題,一直找不到 Inventor 使用 WIFI Esp8266 的例子, 難到 Inventor 不支援 WIFI Esp8266 嗎 ?

    回覆刪除
  9. AI2 我一直沒時間學習, 所以此問題我也不清楚, Sorry. ESP8266 是後起之秀, 有可能 Google 尚未支援.

    回覆刪除
  10. 老師您好:
    想請教您,
    我使用Blynk做智慧電表的監控
    那監控的數據資料可以直接從Blynk撈取出來嗎?
    還是得自建Server才能?

    回覆刪除
  11. Sorry, 漏掉這條留言了. 所有的資料都儲存在 Blynk Cloud 伺服器中, 您可以用 History Graph 元件中的 Export to CSV 功能將該 Virtual Pin 的歷史資料寄到您的 Blynk 帳號登錄信箱. 除非您按下 Erase Data 鈕, 這些資料都會一直保存著. 參考 :
    http://yhhuang1966.blogspot.tw/2016/08/blynk-displays.html
    當然如果自建 Blynk Cloud, 就可以直接從資料庫中取得.

    回覆刪除
  12. 老師您好:
    我目前就是用History Graph這個元件
    但是我想從Blynk Cloud直接把我的資料撈出來做"即時"的呈現和後續分析
    簡單來說..就是我想從Blynk Cloud把數據抓出來也能同步在我的網站上
    利用API..?還是....?
    這樣的想法如果不自建Server有辦法達成嗎?

    回覆刪除
  13. 在它的 manual 裡面沒看到可以取得特定資料的 API 喔, 看來有此 REALTIME 需求的話可能得自建. 可以考慮用樹莓派來做.

    回覆刪除
  14. 好的,這樣我了解了
    謝謝老師您的回答
    我會自建Server來試試看
    謝謝 =)

    回覆刪除