/** * * 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. */ #include #include #include #include #include #include #include "defines.h" #include "IRISKitGlobal.h" #include "IRISKitSerials.h" #include "IRISKitIoT.h" #include "IRISKitHttp.h" #include "IRISKitIR.h" #include "IRISKitIRbaby.h" extern StaticJsonDocument<1024> http_request_doc; extern StaticJsonDocument<1024> http_response_doc; extern StaticJsonDocument<1024> iris_msg_doc; extern StaticJsonDocument<1024> iris_ind_doc; extern StaticJsonDocument<1024> emit_code_doc; extern String g_product_key; extern String g_device_name; extern String g_upstream_topic; extern int g_app_id; char iris_credential_token[CREDENTIAL_MAX] = { 0 }; char iris_server_address[URL_SHORT_MAX] = { 0 }; char iris_user_name[USER_NAME_MAX] = { 0 }; char iris_password[PASSWORD_MAX] = { 0 }; // private function declarations static int processEvent(String event_name, String product_key, String device_name, String content); static String buildConnect(); static String buildHeartBeat(); static int handleConnected(String product_key, String device_name, String content); static int handleHartBeat(String product_key, String device_name, String content); static int handleEmit(String product_key, String device_name, String content); static int handleNotifyStatus(String product_key, String device_name, String content); static int hb_count = 0; // private variable definitions event_handler_t event_handler_table[] = { { "__connected", handleConnected, }, { "__hb_response", handleHartBeat, }, { "__emit_code", handleEmit, }, { "__notify_status", handleNotifyStatus, } }; // public function definitions int getIRISKitVersion(char *buffer, int buffer_size) { if (NULL == buffer) { return -1; } memset(buffer, 0, buffer_size); snprintf(buffer, buffer_size - 1, "%s_r%d", FIRMWARE_VERSION, VERSION_CODE); return strlen(buffer); } String getDeviceID() { String device_id("IRISKit_"); device_id.concat(String(ESP.getChipId(), HEX)); return device_id; } int authIrisKitAccount(String credential_token, String password, String& product_key, String& device_name, String& device_secret, int& app_id) { int ret = -1; int tsi = -1; bool protocol_prefix = false; String fetch_credential_url; String request_data = ""; String response_data = ""; String device_name_temp = ""; http_error_t http_ret = HTTP_ERROR_GENERIC; if (NULL != strstr(iris_server_address, "http://")) { protocol_prefix = true; } if (protocol_prefix) { fetch_credential_url = String(iris_server_address); } else { fetch_credential_url = String("http://"); fetch_credential_url.concat(iris_server_address); } fetch_credential_url.concat(String(GET_IRIS_KIT_ACCOUNT_SUFFIX)); 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_temp = credential_token.substring(tsi + 1); tsi = device_name_temp.indexOf(","); device_name = device_name_temp.substring(0, tsi); http_request_doc.clear(); http_request_doc["deviceID"] = getDeviceID(); http_request_doc["credentialToken"] = credential_token; http_request_doc["password"] = password; serializeJson(http_request_doc, request_data); http_ret = httpPost(fetch_credential_url, request_data, response_data); if (HTTP_ERROR_SUCCESS == http_ret) { http_response_doc.clear(); if (DeserializationError::Ok == deserializeJson(http_response_doc, response_data)) { int resultCode = http_response_doc["status"]["code"]; if (0 == resultCode) { INFOLN("response valid, try getting entity"); device_secret = (const char*) http_response_doc["entity"]["deviceSecret"]; app_id = (int) http_response_doc["entity"]["appId"]; 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; } else { INFOF("response invalid, code = %d\n", resultCode); } } } return ret; } bool downloadBin(int remote_id) { bool ret = false; bool protocol_prefix = false; String save_file = ""; String download_bin_url; http_error_t http_ret = HTTP_ERROR_GENERIC; if (NULL != strstr(iris_server_address, "http://")) { protocol_prefix = true; } if (protocol_prefix) { download_bin_url = String(iris_server_address); } else { download_bin_url = String("http://"); download_bin_url.concat(iris_server_address); } download_bin_url.concat(String(DOWNLOAD_BIN_SUFFIX)); if (-1 != remote_id) { INFOF("notified to download bin: %d", remote_id); save_file = String("ir_") + String(remote_id); String temp = String(SAVE_PATH) + String("/") + save_file; if (!LittleFS.exists(temp)) { downLoadFile(download_bin_url, save_file, SAVE_PATH); ret = true; } } return ret; } void sendIrisKitConnect() { String connectMessage = buildConnect(); sendData(g_upstream_topic.c_str(), (uint8_t*) connectMessage.c_str(), connectMessage.length()); } void sendIrisKitHeartBeat() { INFOF("send iris kit heart beat[%d]\n", hb_count++); String heartBeatMessage = buildHeartBeat(); sendData(g_upstream_topic.c_str(), (uint8_t*) heartBeatMessage.c_str(), heartBeatMessage.length()); } void handleIrisKitMessage(const char* data, int length) { int ret = 0; char* payload = (char*) malloc(length + 1); if (NULL != payload) { strncpy(payload, data, length); payload[length] = '\0'; INFOF("--> %s\n", payload); if (DeserializationError::Ok == deserializeJson(iris_ind_doc, payload)) { String event_name = iris_ind_doc["eventName"]; String product_key = iris_ind_doc["productKey"]; String device_name = iris_ind_doc["deviceName"]; String content = iris_ind_doc["content"]; INFOF("received ind : %s\n", event_name.c_str()); ret = processEvent(event_name.c_str(), product_key, device_name, content); INFOF("event handle result = %d\n", ret); } } if (NULL != payload) { free(payload); } } // private function definitions static int processEvent(String event_name, String product_key, String device_name, String content) { int event_table_length = sizeof(event_handler_table) / sizeof(event_handler_table[0]); for (int i = 0; i < event_table_length; i++) { if (0 == strcmp(event_name.c_str(), event_handler_table[i].event_name)) { INFOF("call event handler with payload : %s, %s\n", product_key.c_str(), device_name.c_str()); return event_handler_table[i].handler(product_key, device_name, content); } } return -1; } static String buildConnect() { String connectMessage = ""; iris_msg_doc.clear(); iris_msg_doc["eventName"] = String(EVENT_NAME_CONNECT); iris_msg_doc["productKey"] = g_product_key; iris_msg_doc["deviceName"] = g_device_name; serializeJson(iris_msg_doc, connectMessage); return connectMessage; } static String buildHeartBeat() { String heartBeatMessage = ""; iris_msg_doc.clear(); iris_msg_doc["eventName"] = String(EVENT_HEART_BEAT_REQ); iris_msg_doc["productKey"] = g_product_key; iris_msg_doc["deviceName"] = g_device_name; iris_msg_doc["appId"] = g_app_id; serializeJson(iris_msg_doc, heartBeatMessage); return heartBeatMessage; } static int handleConnected(String product_key, String device_name, String content) { return 0; } static int handleHartBeat(String product_key, String device_name, String content) { INFOF("received heartbeat : %s, %s\n", product_key.c_str(), device_name.c_str()); return 0; } static int handleEmit(String product_key, String device_name, String content) { INFOF("received emit code : %s, %s, %s\n", product_key.c_str(), device_name.c_str(), content.c_str()); emit_code_doc.clear(); if (DeserializationError::Ok == deserializeJson(emit_code_doc, content)) { int remote_id = emit_code_doc["remoteId"]; String key_name = emit_code_doc["keyName"]; String key_value = emit_code_doc["keyValue"]; INFOF("will emit key : %s for remote %d = %s\n", key_name.c_str(), remote_id, key_value.c_str()); emitIR(key_value); } else { INFOF("deserialize failed\n"); } return 0; } static int handleNotifyStatus(String product_key, String device_name, String content) { INFOF("received emit code : %s, %s, %s\n", product_key.c_str(), device_name.c_str(), content.c_str()); return 0; }