From 2bc257b1095a4610545200d308ab0d8dab82d58a Mon Sep 17 00:00:00 2001 From: strawmanbobi Date: Wed, 16 Feb 2022 11:28:46 +0800 Subject: [PATCH] implemented alink connecting with credential fetch --- .vscode/extensions.json | 17 +++++----- .vscode/settings.json | 5 ++- lib/AliyunIoTSDK/src/AliyunIoTSDK.cpp | 20 +++++++++--- lib/AliyunIoTSDK/src/AliyunIoTSDK.h | 4 +-- src/IRbaby.cpp | 35 +++++++++++++++++---- src/IRbaby.h | 29 +++++++++++++++++ src/IRbabyAlink.cpp | 41 +++++++++++++++++------- src/IRbabyGlobal.cpp | 3 +- src/IRbabyHttp.cpp | 45 +++++++++++++++++++++------ src/IRbabyHttp.h | 5 ++- 10 files changed, 160 insertions(+), 44 deletions(-) create mode 100644 src/IRbaby.h diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 0f0d740..080e70d 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,7 +1,10 @@ -{ - // See http://go.microsoft.com/fwlink/?LinkId=827846 - // for the documentation about the extensions.json format - "recommendations": [ - "platformio.platformio-ide" - ] -} +{ + // See http://go.microsoft.com/fwlink/?LinkId=827846 + // for the documentation about the extensions.json format + "recommendations": [ + "platformio.platformio-ide" + ], + "unwantedRecommendations": [ + "ms-vscode.cpptools-extension-pack" + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json index 89f6be4..d32b6d2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -8,6 +8,9 @@ "vector": "cpp", "string_view": "cpp", "initializer_list": "cpp", - "ranges": "cpp" + "ranges": "cpp", + "memory": "cpp", + "random": "cpp", + "optional": "cpp" } } \ No newline at end of file diff --git a/lib/AliyunIoTSDK/src/AliyunIoTSDK.cpp b/lib/AliyunIoTSDK/src/AliyunIoTSDK.cpp index 177db8d..5e3919f 100644 --- a/lib/AliyunIoTSDK/src/AliyunIoTSDK.cpp +++ b/lib/AliyunIoTSDK/src/AliyunIoTSDK.cpp @@ -103,7 +103,9 @@ static void callback(char *topic, byte *payload, unsigned int length) { } static bool mqttConnecting = false; -void AliyunIoTSDK::mqttCheckConnect() { +int AliyunIoTSDK::mqttCheckConnect() { + int mqttStatus = 0; + Serial.println("INFO:\tAlink MQTT connection checking..."); if (client != NULL && false == mqttConnecting) { @@ -125,11 +127,13 @@ void AliyunIoTSDK::mqttCheckConnect() { Serial.print("ERROR:\tMQTT Connect err:"); Serial.println(client->state()); delay(60000); + mqttStatus = -1; } mqttConnecting = false; } } } + return mqttStatus; } void AliyunIoTSDK::begin(Client &espClient, @@ -176,13 +180,21 @@ void AliyunIoTSDK::begin(Client &espClient, mqttCheckConnect(); } -void AliyunIoTSDK::loop() { +int AliyunIoTSDK::loop() { + int mqttStatus = 0; client->loop(); if (millis() - lastMs >= CHECK_INTERVAL) { lastMs = millis(); - mqttCheckConnect(); + mqttStatus = mqttCheckConnect(); + } + Serial.print("MQTT connect return: "); + Serial.println(mqttStatus); + + if (0 == mqttStatus) { messageBufferCheck(); } + + return mqttStatus; } void AliyunIoTSDK::sendEvent(const char *eventId, const char *param) { @@ -192,7 +204,7 @@ void AliyunIoTSDK::sendEvent(const char *eventId, const char *param) { sprintf(jsonBuf, ALINK_EVENT_BODY_FORMAT, param, eventId); Serial.println(jsonBuf); boolean d = client->publish(topicKey, jsonBuf); - Serial.print("publish:0 successfully:"); + Serial.print("publish: 0 successfully: "); Serial.println(d); } diff --git a/lib/AliyunIoTSDK/src/AliyunIoTSDK.h b/lib/AliyunIoTSDK/src/AliyunIoTSDK.h index 9d1e8e7..f8e0b41 100644 --- a/lib/AliyunIoTSDK/src/AliyunIoTSDK.h +++ b/lib/AliyunIoTSDK/src/AliyunIoTSDK.h @@ -46,7 +46,7 @@ private: public: // MQTT keep alive handler - static void mqttCheckConnect(); + static int mqttCheckConnect(); // offical defined topic templates (not used) static char ALINK_TOPIC_PROP_POST[150]; @@ -54,7 +54,7 @@ public: static char ALINK_TOPIC_EVENT[150]; // MQTT keep alive task - static void loop(); + static int loop(); /** * Initialize and connect to AliyunIoT diff --git a/src/IRbaby.cpp b/src/IRbaby.cpp index 4566a31..a423c4f 100644 --- a/src/IRbaby.cpp +++ b/src/IRbaby.cpp @@ -44,10 +44,20 @@ #include "IRbabyIRIS.h" #include "IRbabyRF.h" +#include "IRbaby.h" + +#define CREDENTIAL_INIT_RETRY_MAX (3) extern char iris_server_address[]; extern char iris_credential_token[]; +extern String g_product_key; +extern String g_device_name; +extern String g_device_secret; + +int credential_init_retry = 0; + + void uploadIP(); // device info upload to devicehive void IRAM_ATTR resetHandle(); // interrupt handle @@ -95,7 +105,7 @@ void setup() { wifi_manager.addParameter(&credential_token); wifi_manager.autoConnect(); - + memset(iris_server_address, 0, URL_SHORT_MAX); strcpy(iris_server_address, server_address.getValue()); @@ -107,18 +117,26 @@ void setup() { do { if(WiFi.status()== WL_CONNECTED) { - if (0 == fetchIrisCredential(iris_credential_token)) { + if (0 == fetchIrisCredential(iris_credential_token, + g_product_key, + g_device_name, + g_device_secret)) { break; } - } else { - delay(1000); } + credential_init_retry++; + if (credential_init_retry >= CREDENTIAL_INIT_RETRY_MAX) { + ERRORLN("retried fetch credential for 3 times, reset WiFi"); + wifiReset(); + } + delay(1000); } while (1); - INFOF("credential matched : %s\n", iris_credential_token); + INFOF("credential get : %s\n", iris_credential_token); settingsLoad(); // load user settings form fs - delay(5); + delay(1000); + connectToAliyunIoT(); #ifdef USE_RF initRF(); // RF init @@ -135,6 +153,11 @@ void setup() { saveDataTask.attach_scheduled(SAVE_DATA_INTERVALS, settingsSave); } +void wifiReset() { + WiFi.disconnect(); + ESP.reset(); +} + void loop() { /* IR receive */ recvIR(); diff --git a/src/IRbaby.h b/src/IRbaby.h new file mode 100644 index 0000000..6ba6586 --- /dev/null +++ b/src/IRbaby.h @@ -0,0 +1,29 @@ +/** + * + * Copyright (c) 2020-2022 IRbaby-IRext + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +#ifndef IRBABY_H +#define IRBABY_H + +void wifiReset(); + +#endif // IRBABY_H \ No newline at end of file diff --git a/src/IRbabyAlink.cpp b/src/IRbabyAlink.cpp index 3dca057..2165f2b 100644 --- a/src/IRbabyAlink.cpp +++ b/src/IRbabyAlink.cpp @@ -22,19 +22,21 @@ */ #include +#include #include "IRbabySerial.h" #include "IRbabyAlink.h" #include "IRbabyGlobal.h" -#define TOPIC_NAME_MAX (64) +#include "IRbaby.h" -#define PRODUCT_KEY "a1WlzsJh50b" -#define DEVICE_NAME "IRIS_Kit_Dev" -#define DEVICE_SECRET "9df2c6b48e4c66519718cc236fc9fb79" -#define REGION_ID "cn-shanghai" +#define TOPIC_NAME_MAX (64) +#define IOT_RETRY_MAX (3) -#define USER_NAME "strawmanbobi@irext.net" +String g_product_key = ""; +String g_device_name = ""; +String g_device_secret = ""; +String g_region_id = "cn-shanghai"; static AliyunIoTSDK iot; static char IRIS_UPSTREAM_TOPIC[TOPIC_NAME_MAX] = { 0 }; @@ -42,20 +44,35 @@ static ep_state_t endpoint_state = FSM_IDLE; static void registerCallback(); static void irisAlinkCallback(const char *topic, uint8_t *data, int length); + +static int iot_retry = 0; + static void sendIrisKitHeartBeat(); void connectToAliyunIoT() { - INFOLN("Try connecting to Aliyun IoT"); - iot.begin(wifi_client, PRODUCT_KEY, DEVICE_NAME, DEVICE_SECRET, REGION_ID); + INFOF("Try connecting to Aliyun IoT : %s, %s, %s, %s\n", + g_product_key.c_str(), g_device_name.c_str(), g_device_secret.c_str(), g_region_id.c_str()); + iot.begin(wifi_client, g_product_key.c_str(), g_device_name.c_str(), g_device_secret.c_str(), g_region_id.c_str()); INFOLN("Aliyun IoT connect done"); - snprintf(IRIS_UPSTREAM_TOPIC, TOPIC_NAME_MAX - 1, "/%s/%s/user/iris/upstream", PRODUCT_KEY, - DEVICE_NAME); + snprintf(IRIS_UPSTREAM_TOPIC, TOPIC_NAME_MAX - 1, "/%s/%s/user/iris/upstream", + g_product_key.c_str(), g_device_name.c_str()); registerCallback(); } void checkAlinkMQTT() { - iot.loop(); - sendIrisKitHeartBeat(); + int mqttStatus = 0; + mqttStatus = iot.loop(); + + if (0 == mqttStatus) { + iot_retry = 0; + sendIrisKitHeartBeat(); + } else { + iot_retry++; + } + if (iot_retry >= IOT_RETRY_MAX) { + ERRORLN("Alink could not established, something went wrong, reset..."); + wifiReset(); + } } // not only for IRIS related topic based session diff --git a/src/IRbabyGlobal.cpp b/src/IRbabyGlobal.cpp index f856646..91e5cf3 100644 --- a/src/IRbabyGlobal.cpp +++ b/src/IRbabyGlobal.cpp @@ -26,7 +26,8 @@ StaticJsonDocument<1024> recv_msg_doc; StaticJsonDocument<1024> send_msg_doc; -StaticJsonDocument<1024> http_json_doc; +StaticJsonDocument<1024> http_request_doc; +StaticJsonDocument<1024> http_response_doc; WiFiManager wifi_manager; WiFiClient wifi_client; diff --git a/src/IRbabyHttp.cpp b/src/IRbabyHttp.cpp index fb99d1b..43e8ee6 100644 --- a/src/IRbabyHttp.cpp +++ b/src/IRbabyHttp.cpp @@ -39,36 +39,61 @@ #define DOWNLOAD_SUFFIX ".bin" -extern StaticJsonDocument<1024> http_json_doc; +extern StaticJsonDocument<1024> http_request_doc; +extern StaticJsonDocument<1024> http_response_doc; char iris_server_address[URL_SHORT_MAX] = { 0 }; -int fetchIrisCredential(String credential_token) { +int fetchIrisCredential(String credential_token, + String& product_key, + String& device_name, + String& device_secret) { int ret = -1; - HTTPClient http_client; + String device_sn("IRbaby_"); String fetch_credential_url(iris_server_address); + HTTPClient http_client; + int tsi = 0; int response_code = 0; fetch_credential_url.concat(String(FETCH_CREDENTIAL_SUFFIX)); + device_sn.concat(String(ESP.getChipId(), HEX)); INFOF("fetch credential URL = %s\n", fetch_credential_url.c_str()); + if (credential_token.isEmpty()) { + ERRORLN("credential token is empty"); + return -1; + } + tsi = credential_token.indexOf(","); + if (-1 == tsi) { + ERRORLN("credential token format error"); + return -1; + } + product_key = credential_token.substring(0, tsi); + device_name = credential_token.substring(tsi + 1); http_client.begin(wifi_client, fetch_credential_url); http_client.addHeader("Content-Type", "application/json"); - http_json_doc.clear(); - http_json_doc["endpointSN"] = String(ESP.getChipId(), HEX); - http_json_doc["credentialToken"] = credential_token; + http_request_doc.clear(); + http_request_doc["endpointSN"] = device_sn; + http_request_doc["credentialToken"] = credential_token; String request_data = ""; - serializeJson(http_json_doc, request_data); + serializeJson(http_request_doc, request_data); response_code = http_client.POST(request_data); - if (response_code > 0) { - INFOF("HTTP response code: %d\n", response_code); + if (200 == response_code) { + INFOF("HTTP response code = %d\n", response_code); String payload = http_client.getString(); INFOF("HTTP response payload = %s\n", payload.c_str()); - ret = 0; + http_response_doc.clear(); + if (OK == deserializeJson(http_response_doc, payload.c_str())) { + String ds = http_response_doc["entity"]; + device_secret = ds; + INFOF("HTTP response deserialized, PK = %s, DN = %s, DS = %s\n", + product_key.c_str(), device_name.c_str(), device_secret.c_str()); + ret = 0; + } } http_client.end(); diff --git a/src/IRbabyHttp.h b/src/IRbabyHttp.h index 0a28902..ab262b4 100644 --- a/src/IRbabyHttp.h +++ b/src/IRbabyHttp.h @@ -29,7 +29,10 @@ #define URL_SHORT_MAX (128) -int fetchIrisCredential(String credential_token); +int fetchIrisCredential(String credential_token, + String& product_key, + String& device_name, + String& device_secret); void downLoadFile(String file, String path);