5. 12 更新:
需要注意调用 cJSON_Print 函数将 JSON 体转化为字符串时, 会开辟内存, 转化后使用完毕后需要调用 cJSON_free 函数将内存释放掉, 否则会导致内存泄漏. 一旦内存泄漏会导致系统宕机.
本项目使用了 W801 以一机一密的方式连接至阿里云物联网平台, 定时发送数据并实现了反向控制.
因为使用阿里云物联网平台, 因此需要提前创建好一个设备, 这个网上的示例和阿里云自己的文档已经十分完整, 因此不多赘述, 可以自行查阅. 创建完设备的 MQTT 链接参数是用来进行链接的关键, 如下图所示.
概述: SDK 中提供的 MQTT 链接示例基本是可用的, 但是连接阿里云时需要做如下修改.
(1) 修改 MQTT 链接参数, 同时要添加 Username 以及 password 的宏定义, 订阅和发布的 topic 根据自己的设备来添加
(2) 修改 MQTT 的 client, username 等的数组长度, SDK 中的数据范围太小, 而阿里云的链接参数由于经过加密因此比较长无法满足要求, 需要对以下几个位置进行修改.
(3) 修改原 MQTTdemo 里面的 mqtt_demo_init 函数, 原函数没有账户密码登录的步骤, 但是提供了相应函数, 因此需要进行补充.
(1) 概述: 在原 demo 上修改, 添加了一个硬件定时器, 定时 5s 后在中断服务函数, 向队列里添加一个 MQTT_MSG_PUBLISH_CB 标志, 主循环读取到这个标志后会进行 mqtt 消息发送, 这边还涉及到一个数据处理成为 JSON 格式, 我这里只发送一个温度信息, 格式为{"temperature": "20"}, 用的就是 cJSON 库, 这个参考下网上其他文章即可.
(2) 代码如下:
//mqtt 消息发送函数
static int mqtt_msg_pub (void)
{
char *temperature_msg;
temperature_msg = datatoJSON (temp_label, temperature) ;
mqtt_publish (&mqtt_demo_mqtt_broker, (const char *) MQTT_DEMO_RX_PUB_TOPIC, (const char *) temperature_msg, strlen (temperature_msg) , 0) ;
tls_os_queue_send (mqtt_demo_task_queue, (void *) MQTT_DEMO_CMD_LOOP, 0) ;
cJSON_free (temperature_msg) ;
return 0;
}
//demo 中原来的主循环
static void mqtt_demo_task (void *p)
{
int ret;
void *msg;
struct tls_ethif *ether_if = tls_netif_get_ethif () ;
if (ether_if- status)
{
wm_printf ("sta ip: %v\n", ether_if- ip_addr. addr) ;
tls_os_queue_send (mqtt_demo_task_queue, (void *) MQTT_DEMO_CMD_START, 0) ;
}
for ( ; ; )
{
ret = tls_os_queue_receive (mqtt_demo_task_queue, (void **) &msg, 0, 0) ;
if (! ret)
{
switch ( (u32) msg)
{
case MQTT_DEMO_CMD_START:
do
{
ret = mqtt_demo_init () ;
if (ret)
break;
tls_os_queue_send (mqtt_demo_task_queue, (void *) MQTT_DEMO_CMD_LOOP, 0) ;
timer_pub () ;
}
while (0) ;
break;
case MQTT_DEMO_CMD_HEART:
//wm_printf ("send heart ping\r\n") ;
mqtt_ping (&mqtt_demo_mqtt_broker) ;
break;
case MQTT_DEMO_CMD_LOOP:
mqtt_demo_loop () ;
break;
case MQTT_MSG_PUBLISH_CB: //添加一个新的标志, 读取到这个标志时候, 进行消息发送
mqtt_msg_pub () ;
break;
default:
break;
}
}
}
}
//中断函数中向队列添加标志
static void timer_pub_irq (u8 *arg)
{
//printf ("timer irq\n") ;
tls_os_queue_send (mqtt_demo_task_queue, (void *) MQTT_MSG_PUBLISH_CB, 0) ;
}
//上传数据硬件定时器
int timer_pub (void)
{
u8 timer_id;
struct tls_timer_cfg timer_cfg;
timer_cfg. unit = TLS_TIMER_UNIT_MS;
timer_cfg. timeout = 5000;
timer_cfg. is_repeat = 1;
timer_cfg. callback = (tls_timer_irq_callback) timer_pub_irq;
timer_cfg. arg = NULL;
timer_id = tls_timer_create (&timer_cfg) ;
tls_timer_start (timer_id) ;
return WM_SUCCESS;
}
(1) 阿里云实际上可以采用物模型进行反向控制, 但是那个相对比较麻烦, 这里我采用一个比较通用的办法, w801 订阅了一个 topic 接受该 topic 命令并解析, 再进行对应操作. 这一部分逻辑与我前一篇文章, 蓝牙反向控制相似, 这里给出链接可以作为参考.
w801 通过蓝牙更新 wifi 并自动重连
(2) 代码:
static int mqtt_demo_loop (void)
{
int packet_length = 0;
int counter = 0;
counter++;
packet_length = mqtt_demo_read_packet (0, 1) ;
if (packet_length 0)
{
if (MQTTParseMessageType (mqtt_demo_packet_buffer) == MQTT_MSG_PUBLISH)
{
uint8_t topic[100], *msg;
uint16_t len;
len = mqtt_parse_pub_topic (mqtt_demo_packet_buffer, topic) ;
topic[len] = '\0'; // for printf
len = mqtt_parse_publish_msg (mqtt_demo_packet_buffer, &msg) ;
msg[len] = '\0'; // for printf
//wm_printf ("recvd: %s %s\n", topic, msg) ;
aliyun_cmd_excute (msg) ;
}
tls_os_queue_send (mqtt_demo_task_queue, (void *) MQTT_DEMO_CMD_LOOP, 0) ;
}
else if (packet_length == MQTT_DEMO_READ_TIMEOUT)
{
tls_os_queue_send (mqtt_demo_task_queue, (void *) MQTT_DEMO_CMD_LOOP, 0) ;
}
else if (packet_length == -1)
{
wm_printf ("mqtt error: (%d) , stop mqtt demo! \n", packet_length) ;
tls_os_timer_stop (mqtt_demo_heartbeat_timer) ;
mqtt_demo_close_socket (&mqtt_demo_mqtt_broker) ;
}
return 0;
}
int aliyun_cmd_excute (char *cmd)
{
//解析 Json 字符串
cJSON *str_json, *str_cmd;
str_json = cJSON_Parse (cmd) ;
if (! str_json)
{
printf ("[INFO]: JSON 格式错误: %s\r\n", cJSON_GetErrorPtr () ) ;
}
else
{
str_cmd = cJSON_GetObjectItem (str_json, "cmd") ;
if (str_cmd- type == cJSON_Number)
{
//printf ("[INFO]: cmd: %d\r\n", str_cmd- valueint) ;
if (str_cmd- valueint == 1)
{
temperature++;
printf ("[CMD_ALIYUN]: Temperature rise by aliyun, the current temp is %d\n", temperature) ;
}
else if (str_cmd- valueint == 2)
{
temperature--;
printf ("[CMD_ALIYUN]: Temperature drops by aliyun, the current temp is %d\n", temperature) ;
}
}
}
cJSON_delete (str_json) ;
return WM_SUCCESS;
}
谢谢, 学习了
使用后, 提示 MQTT_MSG_PUBLISH_CB 未声明, 怎么改?