moved project source base

This commit is contained in:
strawmanbobi
2025-09-15 18:58:08 +08:00
parent b03bbae742
commit cd1aca92b3
681 changed files with 1 additions and 50 deletions

1
lib/AliyunIoTSDK/.piopm Normal file
View File

@@ -0,0 +1 @@
{"type": "library", "name": "AliyunIoTSDK", "version": "0.3.0", "spec": {"owner": "xinyu198736", "id": 6674, "name": "AliyunIoTSDK", "requirements": null, "url": null}}

View File

@@ -0,0 +1,3 @@
0.1
*

View File

@@ -0,0 +1,20 @@
Copyright (c) 2008-2015 Nicholas O'Leary
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.

192
lib/AliyunIoTSDK/README.md Normal file
View File

@@ -0,0 +1,192 @@
# Arduino TopLevel Client for aliyun IoT Platform
`AliyunIoTSDK` 可以帮助你快速连接阿里云 IoT 平台,通过和阿里云物联网开发平台配合,可快速实现各种硬件应用,包括了很上层的封装,无需自己解析数据体,绑定事件即可,在 esp8266 平台充分测试NodeMCU 1.0
## update
- v0.2 增加属性发送 buffer5秒一次或者10条buffer满才会一起发送数据节省请求次数
- v0.1 上线
## Usage 使用示例
```c++
// 引入 wifi 模块,并实例化,不同的芯片这里的依赖可能不同
#include <ESP8266WiFi.h>
static WiFiClient espClient;
// 引入阿里云 IoT SDK
#include <AliyunIoTSDK.h>
// 设置产品和设备的信息,从阿里云设备信息里查看
#define PRODUCT_KEY "xxx"
#define DEVICE_NAME "Device_D"
#define DEVICE_SECRET "xxxxxxxxxxxxxx"
#define REGION_ID "cn-shanghai"
// 设置 wifi 信息
#define WIFI_SSID "xxxxx"
#define WIFI_PASSWD "xxxxx"
void setup()
{
Serial.begin(115200);
// 初始化 wifi
wifiInit(WIFI_SSID, WIFI_PASSWD);
// 初始化 iot需传入 wifi 的 client和设备产品信息
AliyunIoTSDK::begin(espClient, PRODUCT_KEY, DEVICE_NAME, DEVICE_SECRET, REGION_ID);
// 绑定一个设备属性回调,当远程修改此属性,会触发 powerCallback
// PowerSwitch 是在设备产品中定义的物联网模型的 id
AliyunIoTSDK::bindData("PowerSwitch", powerCallback);
// 发送一个数据到云平台LightLuminance 是在设备产品中定义的物联网模型的 id
AliyunIoTSDK::send("LightLuminance", 100);
}
void loop()
{
AliyunIoTSDK::loop();
}
// 初始化 wifi 连接
void wifiInit(const char *ssid, const char *passphrase)
{
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, passphrase);
while (WiFi.status() != WL_CONNECTED)
{
delay(1000);
Serial.println("WiFi not Connect");
}
Serial.println("Connected to AP");
}
// 电源属性修改的回调函数
void powerCallback(JsonVariant p)
{
int PowerSwitch = p["PowerSwitch"];
if (PowerSwitch == 1)
{
// 启动设备
}
}
```
## API 可用方法
```c++
// 在主程序 loop 中调用,检查连接和定时发送信息
static void loop();
/**
* 初始化程序
* @param ssid wifi名
* @param passphrase wifi密码
*/
static void begin(Client &espClient,
const char *_productKey,
const char *_deviceName,
const char *_deviceSecret,
const char *_region);
/**
* 发送数据
* @param param 字符串形式的json 数据,例如 {"${key}":"${value}"}
*/
static void send(const char *param);
/**
* 发送 float 格式数据
* @param key 数据的 key
* @param number 数据的值
*/
static void send(char *key, float number);
/**
* 发送 int 格式数据
* @param key 数据的 key
* @param number 数据的值
*/
static void send(char *key, int number);
/**
* 发送 double 格式数据
* @param key 数据的 key
* @param number 数据的值
*/
static void send(char *key, double number);
/**
* 发送 string 格式数据
* @param key 数据的 key
* @param text 数据的值
*/
static void send(char *key, char *text);
/**
* 发送事件到云平台(附带数据)
* @param eventId 事件名,在阿里云物模型中定义好的
* @param param 字符串形式的json 数据,例如 {"${key}":"${value}"}
*/
static void sendEvent(const char *eventId, const char *param);
/**
* 发送事件到云平台(空数据)
* @param eventId 事件名,在阿里云物模型中定义好的
*/
static void sendEvent(const char *eventId);
/**
* 绑定回调,所有云服务下发的数据都会进回调
*/
// static void bind(MQTT_CALLBACK_SIGNATURE);
/**
* 绑定事件回调,云服务下发的特定事件会进入回调
* @param eventId 事件名
*/
// static void bindEvent(const char * eventId, MQTT_CALLBACK_SIGNATURE);
/**
* 绑定属性回调,云服务下发的数据包含此 key 会进入回调,用于监听特定数据的下发
* @param key 物模型的key
*/
static int bindData(char *key, poniter_fun fp);
/**
* 卸载某个 key 的所有回调(慎用)
* @param key 物模型的key
*/
static int unbindData(char *key);
```
## Examples 示例
buiding...
## Limitations 使用限制和说明
- 本库不包含 wifi 连接的代码,需先建立连接,然后将 client 传入
- 依赖 PubSubClient ,在使用前,请务必修改 PubSubClient 的连接参数,否则无法使用
- PubSubClient 中的 MQTT_MAX_PACKET_SIZE 修改为 1024
- PubSubClient 中的 MQTT_KEEPALIVE 修改为 60
- 掉线后会一直尝试重新连接,可能会触发阿里云的一些限流规则(已经做了规避),并且会导致挤掉其他同设备 ID 的设备
- 默认 5000ms 检测一次连接状态,可以通过 CHECK_INTERVAL 修改此值
## Compatible Hardware 适用硬件
本 SDK 基于 PubSubClient 底层库开发,兼容列表与 PubSubClient 相同。
The library uses the Arduino Ethernet Client api for interacting with the underlying network hardware. This means it Just Works with a growing number of boards and shields, including:
- Arduino Ethernet
- Arduino Ethernet Shield
- Arduino YUN use the included YunClient in place of EthernetClient, and be sure to do a Bridge.begin() first
- Arduino WiFi Shield - if you want to send packets > 90 bytes with this shield, enable the MQTT_MAX_TRANSFER_SIZE define in PubSubClient.h.
- Sparkfun WiFly Shield library
- TI CC3000 WiFi - library
- Intel Galileo/Edison
- ESP8266
- ESP32
The library cannot currently be used with hardware based on the ENC28J60 chip such as the Nanode or the Nuelectronics Ethernet Shield. For those, there is an alternative library available.
## License
This code is released under the MIT License.

View File

@@ -0,0 +1,23 @@
#######################################
# Syntax Coloring Map For AliyunIoTSDK
#######################################
#######################################
# Datatypes (KEYWORD1)
#######################################
AliyunIoTSDK KEYWORD1
#######################################
# Methods and Functions (KEYWORD2)
#######################################
begin KEYWORD2
send KEYWORD2
sendEvent KEYWORD2
bindData KEYWORD2
unbindData KEYWORD2
#######################################
# Constants (LITERAL1)
#######################################

View File

@@ -0,0 +1,25 @@
{
"name": "AliyunIoTSDK",
"keywords": "ethernet, aliyun, mqtt, m2m, iot",
"description": "A toplevel client library for aliyun MQTT messaging. 此库可以帮助你快速连接阿里云 IoT 平台,通过和阿里云物联网开发平台配合,可快速实现各种硬件应用,包括了很上层的封装,无需自己解析数据体,绑定事件即可。",
"repository": {
"type": "git",
"url": "https://github.com/xinyu198736/AliyunIoTSDK-Esp8266"
},
"version": "0.3",
"examples": "examples/*/*.ino",
"frameworks": "arduino",
"platforms": ["espressif8266", "espressif32"],
"dependencies": [
{
"name": "PubSubClient",
"platforms": ["espressif8266", "espressif32"]
},
{
"name": "ArduinoJson"
},
{
"name": "Crypto"
}
]
}

View File

@@ -0,0 +1,9 @@
name=AliyunIoTSDK
version=0.3
author=yutou <xinyu198736@gmail.com>
maintainer=yutou <xinyu198736@gmail.com>
sentence=A toplevel client library for aliyun MQTT messaging.
paragraph=此库可以帮助你快速连接阿里云 IoT 平台,通过和阿里云物联网开发平台配合,可快速实现各种硬件应用,包括了很上层的封装,无需自己解析数据体,绑定事件即可。
category=Communication
url=https://github.com/xinyu198736/arduino-aliyun-iot-sdk
architectures=*

View File

@@ -0,0 +1,358 @@
/**
*
* Filename: AliyunIoTSDK.cpp
*
* Description: basic SDK for ESP32
*
* Created by strawmanbobi 2022-01-03
*
* Copyright (c) 2016-2022 IRext
*
**/
#include "AliyunIoTSDK.h"
#include <PubSubClient.h>
#include <SHA256.h>
#define CHECK_INTERVAL 30000
#define MESSAGE_BUFFER_SIZE 10
#define MQTT_CONNECT_RETRY_MAX 3
static const char *deviceName = NULL;
static const char *productKey = NULL;
static const char *deviceSecret = NULL;
static const char *region = NULL;
struct DeviceProperty {
String key;
String value;
};
DeviceProperty PropertyMessageBuffer[MESSAGE_BUFFER_SIZE];
#define MQTT_PORT 1883
#define SHA256HMAC_SIZE 32
#define DATA_CALLBACK_SIZE 20
#define MQTT_WAIT_GENERIC (10000)
#define ALINK_BODY_FORMAT "{\"id\":\"123\",\"version\":\"1.0\",\"method\":\"thing.event.property.post\",\"params\":%s}"
#define ALINK_EVENT_BODY_FORMAT "{\"id\": \"123\",\"version\": \"1.0\",\"params\": %s,\"method\": \"thing.event.%s.post\"}"
static unsigned long lastMs = 0;
static PubSubClient *client = NULL;
// bind callbacks, support at most 28 callbacks
static pointerDesc pointerArray[20];
static pPointerDesc pPointerArray;
char AliyunIoTSDK::clientId[256] = "";
char AliyunIoTSDK::mqttUsername[100] = "";
char AliyunIoTSDK::mqttPwd[256] = "";
char AliyunIoTSDK::domain[150] = "";
char AliyunIoTSDK::ALINK_TOPIC_PROP_POST[150] = "";
char AliyunIoTSDK::ALINK_TOPIC_PROP_SET[150] = "";
char AliyunIoTSDK::ALINK_TOPIC_EVENT[150] = "";
static String hmac256(const String &signcontent, const String &ds) {
byte hashCode[SHA256HMAC_SIZE] = { 0 };
SHA256 sha256;
const char *key = ds.c_str();
size_t keySize = ds.length();
#if defined SIGN_DEBUG_VERBOSE
Serial.print("DEBUG\tAliot sign src = ");
Serial.print(signcontent.length());
Serial.print(" : ");
Serial.println(signcontent.c_str());
Serial.print("DEBUG\tAliot sign key = ");
Serial.print(keySize);
Serial.print(" : ");
Serial.println(key);
#endif
sha256.resetHMAC(key, keySize);
sha256.update((const byte *)signcontent.c_str(), signcontent.length());
sha256.finalizeHMAC(key, keySize, hashCode, sizeof(hashCode));
String sign = "";
for (byte i = 0; i < SHA256HMAC_SIZE; ++i) {
sign += "0123456789ABCDEF"[hashCode[i] >> 4];
sign += "0123456789ABCDEF"[hashCode[i] & 0xf];
}
return sign;
}
static void parmPass(JsonVariant parm) {
for (int i = 0; i < DATA_CALLBACK_SIZE; i++) {
if (pointerArray[i].key) {
bool hasKey = parm["params"].containsKey(pointerArray[i].key);
if (hasKey) {
pointerArray[i].fp(parm["params"]);
}
}
}
}
static void callback(char *topic, byte *payload, unsigned int length) {
Serial.print("INFO\tMessage arrived [");
Serial.print(topic);
Serial.print("] ");
payload[length] = '\0';
Serial.println((char *)payload);
if (strstr(topic, AliyunIoTSDK::ALINK_TOPIC_PROP_SET)) {
StaticJsonDocument<200> doc;
DeserializationError error = deserializeJson(doc, payload);
if (!error) {
parmPass(doc.as<JsonVariant>());
}
}
}
static bool mqttConnecting = false;
int AliyunIoTSDK::mqttCheckConnect() {
int mqttStatus = 0;
int connectRetry = 0;
Serial.println("INFO: Alink MQTT connection checking...");
if (client != NULL && false == mqttConnecting) {
Serial.print("INFO: Alink MQTT client state = ");
Serial.println(client->state());
if (MQTT_CONNECTED != client->state()) {
connectRetry = 0;
while (false == client->connected()) {
client->disconnect();
Serial.print("INFO: Connecting to Aliyun MQTT Server, clientId = ");
Serial.print(clientId);
Serial.print(", mqttUserName = ");
Serial.print(mqttUsername);
Serial.print(", mqttPwd = ");
Serial.println(mqttPwd);
mqttConnecting = true;
if (client->connect(clientId, mqttUsername, mqttPwd)) {
Serial.println("INFO: MQTT Connected!");
} else {
Serial.print("ERROR: MQTT Connect err: ");
Serial.println(client->state());
client->disconnect();
delay(MQTT_WAIT_GENERIC);
connectRetry++;
Serial.print("INFO: Aliot connection retry: ");
Serial.println(connectRetry);
mqttStatus = -1;
if (connectRetry > MQTT_CONNECT_RETRY_MAX) {
Serial.println("ERROR: Max connect retry times reached");
break;
}
}
mqttConnecting = false;
}
}
}
return mqttStatus;
}
int AliyunIoTSDK::begin(PubSubClient &mqtt_client,
const char *_productKey,
const char *_deviceName,
const char *_deviceSecret,
const char *_region) {
if (NULL == client) {
client = &mqtt_client;
}
productKey = _productKey;
deviceName = _deviceName;
deviceSecret = _deviceSecret;
region = _region;
long times = millis();
String timestamp = String(times);
String deviceId = String(productKey) + String(".") + String(deviceName);
sprintf(clientId, "%s.%s|securemode=2,signmethod=hmacsha256,timestamp=%s|", productKey, deviceName, timestamp.c_str());
String signcontent = "clientId";
signcontent += deviceId;
signcontent += "deviceName";
signcontent += deviceName;
signcontent += "productKey";
signcontent += productKey;
signcontent += "timestamp";
signcontent += timestamp;
String pwd = hmac256(signcontent, deviceSecret);
strcpy(mqttPwd, pwd.c_str());
sprintf(mqttUsername, "%s&%s", deviceName, productKey);
sprintf(ALINK_TOPIC_PROP_POST, "/sys/%s/%s/thing/event/property/post", productKey, deviceName);
sprintf(ALINK_TOPIC_PROP_SET, "/sys/%s/%s/thing/service/property/set", productKey, deviceName);
sprintf(ALINK_TOPIC_EVENT, "/sys/%s/%s/thing/event", productKey, deviceName);
sprintf(domain, "%s.iot-as-mqtt.%s.aliyuncs.com", productKey, region);
client->setServer(domain, MQTT_PORT);
#if defined USE_STANDARD_THING_MODEL_TOPIC
client.setCallback(callback);
#endif
Serial.print("INFO\tConnection check in begin\n");
return mqttCheckConnect();
}
int AliyunIoTSDK::loop() {
int mqttStatus = 0;
client->loop();
unsigned long thisMs = millis();
if (thisMs - lastMs >= CHECK_INTERVAL) {
mqttStatus = mqttCheckConnect();
lastMs = thisMs;
}
if (0 == mqttStatus) {
messageBufferCheck();
}
return mqttStatus;
}
void AliyunIoTSDK::sendEvent(const char *eventId, const char *param) {
char topicKey[156];
snprintf(topicKey, sizeof(topicKey) - 1, "%d/%s/post", 0, eventId);
char jsonBuf[1024];
sprintf(jsonBuf, ALINK_EVENT_BODY_FORMAT, param, eventId);
Serial.print("INFO\t");
Serial.println(jsonBuf);
boolean d = client->publish(topicKey, jsonBuf);
Serial.print("INFO\tpublish: 0 successfully: ");
Serial.println(d);
}
void AliyunIoTSDK::sendEvent(const char *eventId) {
sendEvent(eventId, "{}");
}
boolean AliyunIoTSDK::subscribe(const char* topic, int qos) {
return client->subscribe(topic, qos);
}
void AliyunIoTSDK::registerCustomCallback(MQTT_CALLBACK_SIGNATURE) {
client->setCallback(callback);
}
unsigned long lastSendMS = 0;
// check data sending buffer
void AliyunIoTSDK::messageBufferCheck() {
int bufferSize = 0;
for (int i = 0; i < MESSAGE_BUFFER_SIZE; i++) {
if (PropertyMessageBuffer[i].key.length() > 0) {
bufferSize++;
}
}
if (bufferSize > 0) {
if (bufferSize >= MESSAGE_BUFFER_SIZE) {
sendBuffer();
} else {
unsigned long nowMS = millis();
// send every 5 seconds
if (nowMS - lastSendMS > 5000) {
sendBuffer();
lastSendMS = nowMS;
}
}
}
}
// send data in buffer
void AliyunIoTSDK::sendBuffer() {
int i;
String buffer;
for (i = 0; i < MESSAGE_BUFFER_SIZE; i++) {
if (PropertyMessageBuffer[i].key.length() > 0) {
buffer += "\"" + PropertyMessageBuffer[i].key + "\":" + PropertyMessageBuffer[i].value + ",";
PropertyMessageBuffer[i].key = "";
PropertyMessageBuffer[i].value = "";
}
}
buffer = "{" + buffer.substring(0, buffer.length() - 1) + "}";
send(buffer.c_str());
}
void addMessageToBuffer(char *key, String value) {
int i;
for (i = 0; i < MESSAGE_BUFFER_SIZE; i++) {
if (PropertyMessageBuffer[i].key.length() == 0) {
PropertyMessageBuffer[i].key = key;
PropertyMessageBuffer[i].value = value;
break;
}
}
}
void AliyunIoTSDK::send(const char *param) {
char jsonBuf[1024];
sprintf(jsonBuf, ALINK_BODY_FORMAT, param);
Serial.print("INFO\t");
Serial.println(jsonBuf);
boolean d = client->publish(ALINK_TOPIC_PROP_POST, jsonBuf);
Serial.print("INFO\tpublish:0 sucessfully:");
Serial.println(d);
}
void AliyunIoTSDK::send(char *key, float number) {
addMessageToBuffer(key, String(number));
messageBufferCheck();
}
void AliyunIoTSDK::send(char *key, int number) {
addMessageToBuffer(key, String(number));
messageBufferCheck();
}
void AliyunIoTSDK::send(char *key, double number) {
addMessageToBuffer(key, String(number));
messageBufferCheck();
}
void AliyunIoTSDK::send(char *key, char *text) {
addMessageToBuffer(key, "\"" + String(text) + "\"");
messageBufferCheck();
}
#if defined USE_STANDARD_THING_MODEL_TOPIC
int AliyunIoTSDK::bindData(char *key, pFuncPointer fp) {
int i;
for (i = 0; i < DATA_CALLBACK_SIZE; i++) {
if (!pointerArray[i].fp) {
pointerArray[i].key = key;
pointerArray[i].fp = fp;
return 0;
}
}
return -1;
}
int AliyunIoTSDK::unbindData(char *key) {
int i;
for (i = 0; i < DATA_CALLBACK_SIZE; i++) {
if (!strcmp(pointerArray[i].key, key)) {
pointerArray[i].key = NULL;
pointerArray[i].fp = NULL;
return 0;
}
}
return -1;
}
#endif

View File

@@ -0,0 +1,162 @@
/**
*
* Filename: AliyunIoTSDK.h
*
* Description: header file of basic SDK for ESP32
*
* Created by strawmanbobi 2022-01-03
*
* Copyright (c) 2016-2022 IRext
*
**/
#ifndef ALIYUN_IOT_SDK_H
#define ALIYUN_IOT_SDK_H
#include <Arduino.h>
#include <ArduinoJson.h>
#include <PubSubClient.h>
#include "Client.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef void (*funcPointer)(JsonVariant ele);
typedef struct {
char *key;
funcPointer fp;
} pointerDesc, *pPointerDesc;
#ifdef __cplusplus
}
#endif
class AliyunIoTSDK {
private:
// MQTT client related parameters
static char mqttPwd[256];
static char clientId[256];
static char mqttUsername[100];
static char domain[150];
static void messageBufferCheck();
static void sendBuffer();
public:
// MQTT keep alive handler
static int mqttCheckConnect();
// offical defined topic templates (not used)
static char ALINK_TOPIC_PROP_POST[150];
static char ALINK_TOPIC_PROP_SET[150];
static char ALINK_TOPIC_EVENT[150];
// MQTT keep alive task
static int loop();
/**
* Initialize and connect to AliyunIoT
* @param espClient : WiFi client
* @param _productKey : AliyunIoT product key
* @param _deviceName : AliyunIoT device name
* @param _deviceSecret : AliyunIoT device secret
* @param _region : AliyunIoT region
*/
static int begin(PubSubClient &mqtt_client,
const char *_productKey,
const char *_deviceName,
const char *_deviceSecret,
const char *_region);
/**
* Send data
* @param param : JSON formated string with key and value : {"${key}":"${value}"}
*/
static void send(const char *param);
/**
* Send single data in float
* @param key : key
* @param number : value
*/
static void send(char *key, float number);
/**
* Send single data in integer
* @param key : key
* @param number : value
*/
static void send(char *key, int number);
/**
* Send single data in double
* @param key : key
* @param number : value
*/
static void send(char *key, double number);
/**
* Send single data in string
* @param key : key
* @param text : value
*/
static void send(char *key, char *text);
/**
* Send standard thing model data
* @param eventId : eventId predefined in AliyunIoT
* @param param : JSON formated string with key and value : {"${key}":"${value}"}
*/
static void sendEvent(const char *eventId, const char *param);
/**
* Send empty thing model data
* @param eventId : eventId predefined in AliyunIoT
*/
static void sendEvent(const char *eventId);
/**
* Subscribe MQTT topic for Aliot
*
* @param topic : topic in string
* @param qos : MQTT qos param
* @return if succeeded
*/
static boolean subscribe(const char* topic, int qos);
/**
* Register customized MQTT message callback
*
* @param callback : callback pointer
*/
static void registerCustomCallback(MQTT_CALLBACK_SIGNATURE);
#if defined USE_STANDARD_THING_MODEL_TOPIC
/**
* Register callback for downstream MQTT message
*/
static void bind(MQTT_CALLBACK_SIGNATURE);
/**
* Register callback for downstream MQTT message with specific eventId
* @param eventId : eventId predefined in AliyunIoT
*/
static void bindEvent(const char * eventId, MQTT_CALLBACK_SIGNATURE);
/**
* Register callback for downstream MQTT message with specific key
* @param key : key predefined in thing model
*/
static int bindData(char *key, funcPointer fp);
/**
* Unregister callback for specified key
* @param key : key predefined in thing model
*/
static int unbindData(char *key);
#endif
};
#endif /* ALIYUN_IOT_SDK_H */