玩轉OneNET物聯網平臺之MQTT服務⑦ —— 遠端控制LED(數量無限制)+ Android App控制 優化第一版
阿新 • • 發佈:2019-10-31
授人以魚不如授人以漁,目的不是為了教會你具體專案開發,而是學會學習的能力。希望大家分享給你周邊需要的朋友或者同學,說不定大神成長之路有博哥的奠基石。。。
QQ技術互動交流群:ESP8266&32 物聯網開發 群號622368884,不喜勿噴
一、你如果想學基於Arduino的ESP8266開發技術
一、基礎篇
- ESP8266開發之旅 基礎篇① 走進ESP8266的世界
- ESP8266開發之旅 基礎篇② 如何安裝ESP8266的Arduino開發環境
- ESP8266開發之旅 基礎篇③ ESP8266與Arduino的開發說明
- ESP8266開發之旅 基礎篇④ ESP8266與EEPROM
- ESP8266開發之旅 基礎篇⑤ ESP8266 SPI通訊和I2C通訊
- ESP8266開發之旅 基礎篇⑥ Ticker——ESP8266定時庫
二、網路篇
- ESP8266開發之旅 網路篇① 認識一下Arduino Core For ESP8266
- ESP8266開發之旅 網路篇② ESP8266 工作模式與ESP8266WiFi庫
- ESP8266開發之旅 網路篇③ Soft-AP——ESP8266WiFiAP庫的使用
- ESP8266開發之旅 網路篇④ Station——ESP8266WiFiSTA庫的使用
- ESP8266開發之旅 網路篇⑤ Scan WiFi——ESP8266WiFiScan庫的使用
- ESP8266開發之旅 網路篇⑥ ESP8266WiFiGeneric——基礎庫
- ESP8266開發之旅 網路篇⑦ TCP Server & TCP Client
- ESP8266開發之旅 網路篇⑧ SmartConfig——一鍵配網
- ESP8266開發之旅 網路篇⑨ HttpClient——ESP8266HTTPClient庫的使用
- ESP8266開發之旅 網路篇⑩ UDP服務
- ESP8266開發之旅 網路篇⑪ WebServer——ESP8266WebServer庫的使用
- ESP8266開發之旅 網路篇⑫ 域名服務——ESP8266mDNS庫
- ESP8266開發之旅 網路篇⑬ SPIFFS——ESP8266 Flash檔案系統
- ESP8266開發之旅 網路篇⑭ web配網
- ESP8266開發之旅 網路篇⑮ 真正的域名服務——DNSServer
- ESP8266開發之旅 網路篇⑯ 無線更新——OTA韌體更新
三、應用篇
- ESP8266開發之旅 應用篇① 區域網應用 ——炫酷RGB彩燈
- ESP8266開發之旅 應用篇② OLED顯示天氣屏
- ESP8266開發之旅 應用篇③ 簡易版WiFi小車
四、高階篇
- ESP8266開發之旅 進階篇① 程式碼優化 —— ESP8266記憶體管理
- ESP8266開發之旅 進階篇② 閒聊Arduino IDE For ESP8266配置
- ESP8266開發之旅 進階篇③ 閒聊 ESP8266 Flash
- ESP8266開發之旅 進階篇④ 常見問題 —— 解決困擾
- ESP8266開發之旅 進階篇⑤ 程式碼規範 —— 像寫文章一樣優美
- ESP8266開發之旅 進階篇⑥ ESP-specific APIs說明
1.前言
在前面的博文 玩轉OneNET物聯網平臺之MQTT服務④ —— 遠端控制LED(數量無限制)+ Android App控制 中,博主只是大體上講述了整個小專案的構造。但是,如果作為一個產品來開發的話,還是存在不少問題。這裡羅列幾個我認為比較重要的問題點:
- 問題1:App作為一個特殊的裝置,理論上也應該支援自注冊功能,不應該由開發者或者使用者額外去呼叫API除錯工具建立裝置,起碼得簡化這個流程;
- 問題2:App沒有處理裝置從線上狀態切換成離線狀態的過程,需要實時更新裝置狀態;
接下來,博主就會針對這兩個重要的問題點進行解決思路以及解決步驟的講解,請讀者邊思考邊實驗。
2.解決問題點1
App作為一個特殊的裝置,理論上也應該支援自注冊功能,不應該由開發者或者使用者額外去呼叫API除錯工具建立裝置,起碼得簡化這個流程
2.1 解決思路
- 我們目的無非是為了得到一個真實存在的DeviceID,既然OneNet 平臺給我們提供了 新增裝置 的API,那麼我們可以通過它來建立裝置並且獲取裝置ID。
因為建立裝置需要裝置唯一性標識,而android手機上唯一性東西非常多,我們這裡考慮用裝置序列號
Android系統2.3版本以上可以通過下面的方法得到Serial Number,且非手機裝置也可以通過該介面獲取。
String serial= android.os.Build.SERIAL;
2.2 解決步驟
- 修改app邏輯,加上註冊方法
/**
* 新增OneNet裝置
*/
public class RegisterOneNetDeviceEntity extends BaseResponseEntity {
public dataModel data;
public static class dataModel{
public String device_id;
}
@Override
protected String createArgs(Object... params) {
OneNetDeviceModel model = (OneNetDeviceModel) params[0];
JSONObject object = new JSONObject();
try {
object.put("title",model.getTitle());
object.put("auth_info",model.getAuth_info());
} catch (JSONException e) {
e.printStackTrace();
}
return object.toString();
}
@Override
protected String makeUrl() {
return API_POST_REGISTER_DEVICE;
}
public String request(OneNetDeviceModel model) {
method = HttpUtilCore.Method.Post;
String json = requestJson(model);
//內部消化
return handleResponse(json, new OnResponseListener<RegisterOneNetDeviceEntity>() {
@Override
public void onSuccess(String json, RegisterOneNetDeviceEntity response) {
data = response.data;
}
@Override
public void onFailed(String reason) {
Logger.d(reason);
}
@Override
public void onTimeout() {
Logger.d("請求超時");
}
});
}
}
- 使用者點選註冊,加上裝置序列號
@Override
public void onInitView(Bundle savedInstanceState) {
PreferenceUtil preference = PreferenceUtil.getInstance();
if(!TextUtils.isEmpty(preference.getDeviceId())){
this.onConfigConfirm();
return;
}
getDefaultNavigation().setTitle("配置智慧燈");
getDefaultNavigation().getLeftButton().hide();
etDevice.setText("Android_" + android.os.Build.SERIAL);
etProduct.setText(preference.getProductId());
etApikey.setText(preference.getApiKey());
}
- 新增成功之後,儲存伺服器返回的device_id
@Override
public void register(Context context, final OneNetConfigDALEx config, final ICallBack<String> callBack) {
if(task != null && task.getStatus()== AsyncTask.Status.RUNNING){
task.cancel(true);
}
task = new SimpleTask() {
OneNetDeviceModel device;
RegisterOneNetDeviceEntity entity;
@Override
protected void onPreExecute() {
PreferenceUtil preference = PreferenceUtil.getInstance();
preference.writePreferences(PreferenceUtil.ApiKey,config.getApikey());
preference.writePreferences(PreferenceUtil.ProductId,config.getProductId());
entity = new RegisterOneNetDeviceEntity();
device = new OneNetDeviceModel();
device.setTitle(config.getDeviceId());
device.setAuth_info(config.getDeviceId());
}
@Override
protected Object doInBackground(String... strings) {
return entity.request(device);
}
@Override
protected void onPostExecute(Object o) {
String result = (String) o;
PreferenceUtil preference = PreferenceUtil.getInstance();
if("200".equals(result)){//儲存裝置id
preference.writePreferences(PreferenceUtil.DeviceId,entity.data.device_id);
callBack.onSuccess("");
}else {
callBack.onFaild(result);
}
}
};
task.startTask();
- 這樣就完成了手機自注冊裝置功能
這種方案有個好處就是:
- 非常適合多個成員同時控制一組智慧燈,並且不會產生掉線的情況。
但是,請讀者注意:
如果你先註冊了一次,然後解除安裝app,再重新註冊,這個時候會失敗的(原因請讀者自行分析)。這個時候請到後臺手動刪除Android_xxxx的裝置。
App下載地址
3.解決問題點2
- 問題點:App沒有處理裝置從線上狀態切換成離線狀態的過程,需要實時更新裝置狀態
3.1 解決方案
目前大概有幾種方案:
- 方案a:手機端不斷輪詢批量獲取裝置列表介面,可以設定較大的時間間隔,這個方案准確性高,但是耗費流量。目前這個方案相對靠譜。
- 方案b:esp8266端釋出裝置狀態topic和資訊,手機端訂閱該topic,通過mqtt來更新狀態;
- 方案c:利用mqtt的遺囑訊息,但是這個博哥驗證了OneNet的,感覺不好用。
- 方案d:如果mqtt的遺囑訊息比較快速實時,可以考慮方案b+c的組合,個人覺得這個是比較理想的方案。(不過,目前我還沒有很好實現)
- 方案e:本專案不追求實時性,我們可以手動下拉重新整理或者在activity的onshow自動刷一遍,基本上滿足要求,採取該方案。
4.總結
- 問題1:App作為一個特殊的裝置,理論上也應該支援自注冊功能,不應該由開發者或者使用者額外去呼叫API除錯工具建立裝置,起碼得簡化這個流程;可以解決。
- 問題2:App沒有處理裝置從線上狀態切換成離線狀態的過程,需要實時更新裝置狀態;贊未完美解決,只能兜底方案。
- 但是,我們離產品化越來越近了。