使用mqtt与onenet服务器通讯(实现发布与订阅)

使用mqtt与onenet服务器通讯

根据上一篇文章使用mqtt.fx与onenet服务器模拟通讯已经了解了设备与onenet的通信流程,接下来记录一下通过代码来实现。
参考资料:
1.MQTT指令
2.ESP8266代码编写

一、使用AT指令对MQTT进行设置

/*******************************************************************************
*	func name	:	ESP8266_Init
*	function	:	ESP8266初始化
*	argument	:	void
*	retval		:	void
*	note		:	倒数第四句中的xx是热点名称,yyyyy是热点密码
					(名称和热点最好不要有中文字或特殊符号,容易连接不上)
*	author	 	:	lu.ciana.598393@gmail.com
*	data  	 	:	2025/06/13
*
 ********************************************************************************/
void ESP8266_Init(void)
{
	ESP8266_Clear();
	usart1_send_str( "0. AT+RST\r\n");
	while(ESP8266_SendCmd("AT+RST\r\n", "OK"))	//AT测试
		delay_ms(500);
	
	usart1_send_str( "1. AT\r\n");
	while(ESP8266_SendCmd("AT\r\n", "OK"))	//AT测试
		delay_ms(500);
	
	usart1_send_str("2. CWMODE\r\n");		
	while(ESP8266_SendCmd("AT+CWMODE=1\r\n", "OK"))	//STA模式
	delay_ms(500);
	
	usart1_send_str("3. AT+CWDHCP\r\n");
	while(ESP8266_SendCmd("AT+CWDHCP=1,1\r\n", "OK")) //启用 Station 的 DHCP
		delay_ms(500);
	
	usart1_send_str("4. CWJAP\r\n");
	while(ESP8266_SendCmd("AT+CWJAP=\"xx\",\"yyyyyyy\"\r\n", "GOT IP"))	//连接路由器
		delay_ms(500);
	
	usart1_send_str("5. ESP8266 Init OK\r\n");

}

二、设备连接成功后尝试连接onenet平台

image
!!!注意:该地方et为过期时间的时间戳,需要进行转化为当前时间后的时间或则日期,转化链接:时间戳转换工具

/*******************************************************************************
 *
 *	func name	:	OneNet_SendData
 *	function	:	onenet初始化
 *	argument	:	void
 *	retval		:	void
 *	note		:	在第三行代码中,aaaaa写入自己的设备名称,bbbbbbb写入自己的产品ID,
					cccccc填入自己的password,password的获取请看上一篇文章
					[使用mqtt.fx与onenet服务器模拟通讯]
 *	author	 	:	lu.ciana.598393@gmail.com
 *	data  	 	:	2025/06/17
 *
 *
 ********************************************************************************/


void OneNet_SendData(void)
{
	ESP8266_Clear();
	usart1_send_str("6. connect my device\r\n");
	while(ESP8266_SendCmd("AT+MQTTUSERCFG=0,1,\"aaaaa\",\"bbbbbb\",\"cccccc\",0,0,\"\"\r\n", "OK"))	//AT测试
	
	ESP8266_Clear();
	usart1_send_str("7. MQTTCONN\r\n");
	while(ESP8266_SendCmd("AT+MQTTCONN=0,\"mqtts.heclouds.com\",1883,1\r\n", "OK"));	//连接onenet云平台
}

三、设备发布消息

image

/*******************************************************************************
 *
 *	func name	:	extract_value
 *	function	:	解析onnet下发的JSON数据
 *	argument	:	const char* json:储存onenet回复的指令
 					const char* key: 需要查找的值
 *	retval		:	@char*:返回需要查找的数值
 *	note		:	例:extract_value(buf,id);
 					在储存onnet1回复指令buf中查找id的值,以便于下面订阅时需要用到id
 *	author	 	:	lu.ciana.598393@gmail.com
 *	data  	 	:	2025/06/17
 *
 ********************************************************************************/
char* extract_value(const char* json, const char* key)
{
    char search_key[20]; // 用于存储构造的关键字
    const char* start;   // 用于指向关键字的起始位置
    const char* end;     // 用于指向值的结束位置
    int length;          // 用于存储值的长度
    char* value;         // 用于存储提取的值

    // 构造查找的关键字,例如 "id" 或 "power"
    snprintf(search_key, sizeof(search_key), "\"%s\":", key);

    // 查找关键字
    start = strstr(json, search_key);
    if (start == NULL)
    {
//        printf("Key '%s' not found in JSON\n", key);
        return NULL;
    }

    // 跳过关键字,找到值的开始位置
    start += strlen(search_key);

    // 检查值是否被引号包围(字符串类型)
    if (*start == '"')
    {
        start++; // 跳过开头的引号
        end = strchr(start, '"'); // 找到结尾的引号
        if (end == NULL)
        {
//            printf("Invalid JSON format for key '%s'\n", key);
            return NULL;
        }
        length = end - start; // 计算值的长度
        value = (char*)malloc(length + 1); // 分配内存
        if (value == NULL)
        {
//            printf("Memory allocation failed\n");
            return NULL;
        }
        strncpy(value, start, length); // 复制值
        value[length] = '\0'; // 添加字符串结束符
    }
    else // 数字类型
    {
        end = start;
        while (*end >= '0' && *end <= '9') // 找到数字的结束位置
        {
            end++;
        }
        length = end - start; // 计算数字的长度
        value = (char*)malloc(length + 1); // 分配内存
        if (value == NULL)
        {
//            printf("Memory allocation failed\n");
            return NULL;
        }
        strncpy(value, start, length); // 复制数字
        value[length] = '\0'; // 添加字符串结束符
    }

    return value;
}

/*******************************************************************************
 *	func name	:	OneNet_Pub
 *	function	:	设备设置为发布模式并发布数据
 *	argument	:	@temp :填写自己所要发布的数据
 *	retval		:	void
 *	note		:	在第三行代码中,aaaaa写入自己的设备名称,bbbbbbb写入自己的产品ID,
 					这里我需要发布检测到的温度发送到onenet,通过传参的方式传进来发布
 *	author	 	:	lu.ciana.598393@gmail.com
 *	data  	 	:	2025/06/13
 *
 ********************************************************************************/
void OneNet_Pub(float temp)
{
	ESP8266_Clear();
	usart1_send_str("8. sub reply topic\r\n");
	while(ESP8266_SendCmd("AT+MQTTSUB=0,\"$sys/bbbbbbb/aaaaa/thing/property/post/reply\",0\r\n", "OK"))	//AT发布数据
	
	ESP8266_Clear();
	usart1_send_str("9. pub temp\r\n");
	snprintf(buf, sizeof(buf),"AT+MQTTPUB=0,\"$sys/bbbbbb/aaaaa/thing/property/post\",\"{\\\"id\\\":\\\"123\\\"\\,\\\"params\\\":{\\\"temp\\\":{\\\"value\\\":%.1f\\}}}\",0,0\r\n",temp);
	usart1_send_str(buf);
	while(ESP8266_SendCmd(buf, "OK"))
	usart1_send_str("10. Pub OK\r\n");
	
}

四、设备订阅消息

image

/*******************************************************************************
 *
 *	func name	:	OneNet_Sub
 *	function	:	设备设置为订阅模式
 *	argument	:	void
 *	retval		:	void
 *	note		:	在第三行代码中,aaaaa写入自己的设备名称,bbbbbbb写入自己的产品ID
 *	author	 	:	lu.ciana.598393@gmail.com
 *	data  	 	:	2024/04/22
 *
 *
 ********************************************************************************/
void OneNet_Sub(void)
{
	
	ESP8266_Clear();
	usart1_send_str("8. sub topic\r\n");
	while(ESP8266_SendCmd("AT+MQTTSUB=0,\"$sys/bbbbbbb/aaaaa/thing/property/set\",0\r\n", "OK"))	//AT订阅消息
	usart1_send_str("9. Sub OK\r\n");
	
}

/*******************************************************************************
 *
 *	func name	:	OneNet_WaitMessage
 *	function	:	等待订阅的下发数据
 *	argument	:	void
 *	retval		:	void
 *	note		:	进入循环等待订阅下发的指令调节灯泡亮度,在onenet中定义的标识符为power,
 					因此解析JSON格式发过来的指令得到power的数据
 *	author	 	:	lu.ciana.598393@gmail.com
 *	data  	 	:	2024/04/22
 *
 ********************************************************************************/
 void OneNet_WaitMessage(void)
{
	
	char *result1 = NULL;
	char *result2 = NULL;
	int id =0 ;
	int power =0;
	if(strstr((const char*)esp8266_buf,"power") != '\0')
	{
		printf("%s\r\n",esp8266_buf);
		result1 = extract_value((const char*)esp8266_buf,"id");
		result2 = extract_value((const char*)esp8266_buf,"power");
		id = atoi(result1);
		power = atoi(result2);
//		ESP8266_Clear();
		OneNet_Sub_Reply(id);
		printf("id = %d\r\n",id);
		printf("power = %d\r\n",power);
		TIM_SetCompare4(TIM3,power);	
		delay_ms(20);		
		ESP8266_Clear();
	}
}


posted @ 2025-06-17 10:03  luxiaolim  阅读(1673)  评论(0)    收藏  举报