image.png

wifi配置

需要在app_config.h文件中定义USE_DEMO_WIFI_TEST,工程会在wifi_demo_task.c文件中自动启动wifi相关的任务, 我们将工程配置为连接外部网络STA模式
image.png
默认工程会使用如下账号密码
image.png
当wifi任务启动之后,我们可以通过调用如下函数,让芯片连接上外部的网络

  1. wifi_enter_sta_mode(str_ssid, str_pwd);

TCP通讯

socket初始化

首先需要初始化socket,并指定协议

  1. #define SERVER_TCP_IP "192.168.3.100" //服务端ip
  2. #define SERVER_TCP_PORT 9090 //服务端端口号
  3. static int tcp_client_init(const char *server_ip, const int server_port)
  4. {
  5. //struct sockaddr_in local;
  6. struct sockaddr_in dest;
  7. //创建socket
  8. sock = sock_reg(AF_INET, SOCK_STREAM, 0, NULL, NULL);
  9. if (sock == NULL) {
  10. printf("sock_reg fail.\n");
  11. return -1;
  12. }
  13. //连接指定地址服务端
  14. dest.sin_family = AF_INET;
  15. dest.sin_addr.s_addr = inet_addr(server_ip);
  16. dest.sin_port = htons(server_port);
  17. if (0 != sock_connect(sock, (struct sockaddr *)&dest, sizeof(struct sockaddr_in))) {
  18. printf("sock_connect fail.\n");
  19. sock_unreg(sock);
  20. return -1;
  21. }
  22. return 0;
  23. }

初始化调用的逻辑,很简单,只需要指定IP地址和端口号即可

  1. err = tcp_client_init(SERVER_TCP_IP, SERVER_TCP_PORT);
  2. if (err) {
  3. printf("tcp_client_init err!");
  4. return;
  5. }

发送数据

  1. //发送数据
  2. static int tcp_send_data(const void *sock_hdl, const void *buf, const u32 len)
  3. {
  4. return sock_send(sock_hdl, buf, len, 0);
  5. }

接收数据

  1. //接收数据
  2. static int tcp_recv_data(const void *sock_hdl, void *buf, u32 len)
  3. {
  4. return sock_recvfrom(sock_hdl, buf, len, 0, NULL, NULL);
  5. }

接收数据代码

  1. for (;;) {
  2. recv_len = tcp_recv_data(sock, recv_buf, sizeof(recv_buf));
  3. if ((recv_len != -1) && (recv_len != 0)) {
  4. recv_buf[recv_len] = '\0';
  5. printf("Received %d bytes, data: %s\n\r", recv_len, recv_buf);
  6. tcp_send_data(sock, "Data received successfully!", strlen("Data received successfully!"));
  7. } else {
  8. printf("sock_recvfrom err!");
  9. break;
  10. }
  11. }

完整示例代码:
客户端:

  1. #include "sock_api/sock_api.h"
  2. #include "app_config.h"
  3. #include "system/includes.h"
  4. #include "wifi/wifi_connect.h"
  5. #include "lwip.h"
  6. #include "lwip/sockets.h"
  7. #include "lwip/netdb.h"
  8. #ifdef USE_ICHEIMA_WIFI
  9. #include "itheima.h"
  10. static void *sock = NULL;
  11. #define SERVER_TCP_IP "192.168.3.100" //服务端ip
  12. #define SERVER_TCP_PORT 9090 //服务端端口号
  13. static int tcp_client_init(const char *server_ip, const int server_port)
  14. {
  15. //struct sockaddr_in local;
  16. struct sockaddr_in dest;
  17. //创建socket
  18. sock = sock_reg(AF_INET, SOCK_STREAM, 0, NULL, NULL);
  19. if (sock == NULL) {
  20. printf("sock_reg fail.\n");
  21. return -1;
  22. }
  23. //连接指定地址服务端
  24. dest.sin_family = AF_INET;
  25. dest.sin_addr.s_addr = inet_addr(server_ip);
  26. dest.sin_port = htons(server_port);
  27. if (0 != sock_connect(sock, (struct sockaddr *)&dest, sizeof(struct sockaddr_in))) {
  28. printf("sock_connect fail.\n");
  29. sock_unreg(sock);
  30. return -1;
  31. }
  32. return 0;
  33. }
  34. //发送数据
  35. static int tcp_send_data(const void *sock_hdl, const void *buf, const u32 len)
  36. {
  37. return sock_send(sock_hdl, buf, len, 0);
  38. }
  39. //接收数据
  40. static int tcp_recv_data(const void *sock_hdl, void *buf, u32 len)
  41. {
  42. return sock_recvfrom(sock_hdl, buf, len, 0, NULL, NULL);
  43. }
  44. //tcp client任务
  45. static void tcp_client_task(void *priv)
  46. {
  47. int err;
  48. char *payload = "Please send me some data!";
  49. char recv_buf[1024];
  50. int recv_len;
  51. int send_len;
  52. err = tcp_client_init(SERVER_TCP_IP, SERVER_TCP_PORT);
  53. if (err) {
  54. printf("tcp_client_init err!");
  55. return;
  56. }
  57. send_len = tcp_send_data(sock, payload, strlen(payload));
  58. if (send_len == -1) {
  59. printf("sock_sendto err!");
  60. sock_unreg(sock);
  61. return;
  62. }
  63. for (;;) {
  64. recv_len = tcp_recv_data(sock, recv_buf, sizeof(recv_buf));
  65. if ((recv_len != -1) && (recv_len != 0)) {
  66. recv_buf[recv_len] = '\0';
  67. printf("Received %d bytes, data: %s\n\r", recv_len, recv_buf);
  68. tcp_send_data(sock, "Data received successfully!", strlen("Data received successfully!"));
  69. } else {
  70. printf("sock_recvfrom err!");
  71. break;
  72. }
  73. }
  74. if (sock) {
  75. sock_unreg(sock);
  76. sock = NULL;
  77. }
  78. }
  79. // 将串口接收到的数据通过串口发送出去
  80. static void tcp_client_uart2wifi_task(void *priv){
  81. int len=0;
  82. uint8_t recv_buf[1024];
  83. printf("tcp_client_uart2wifi_task start>>>>>>>>>>>>>>>>>\r\n");
  84. while(1){
  85. len=icheima_uart_read_data(recv_buf);
  86. printf("\n uart recv len = %d\n", len);
  87. if(len > 0){
  88. printf("\n uart recv len = %d\n", len);
  89. recv_buf[len] = '\0';
  90. //把串口接收到的数据发送回去
  91. tcp_send_data(sock,recv_buf,len);
  92. memset(recv_buf, 0, sizeof(recv_buf));
  93. }else{
  94. //printf("uart recv error len = %d\n", len);
  95. }
  96. }
  97. }
  98. // 将wifi接收到的数据,发送给串口
  99. static void tcp_client_wifi2uart_task(void *priv)
  100. {
  101. int err;
  102. char *payload = "Please send me some data!";
  103. char recv_buf[1024];
  104. int recv_len;
  105. if(!sock){
  106. printf("tcp_client_wifi2uart_task sock error>>>>>>>>>>>>>>\r\n");
  107. }
  108. int send_len = tcp_send_data(sock, payload, strlen(payload));
  109. if (send_len == -1) {
  110. printf("sock_sendto err!");
  111. sock_unreg(sock);
  112. return;
  113. }
  114. printf("tcp_client_wifi2uart_task start>>>>>>>>>>>>>>\r\n");
  115. while(1){
  116. recv_len = tcp_recv_data(sock, recv_buf, sizeof(recv_buf));
  117. if ((recv_len != -1) && (recv_len != 0)) {
  118. recv_buf[recv_len] = '\0';
  119. // 将数据发送给串口
  120. icheima_uart_send_data(recv_buf, recv_len);
  121. printf("Received %d bytes, data:%s\n", recv_len, recv_buf);
  122. memset(recv_buf, 0, sizeof(recv_buf));
  123. } else {
  124. printf("sock_recvfrom err!");
  125. break;
  126. }
  127. }
  128. if (sock) {
  129. sock_unreg(sock);
  130. sock = NULL;
  131. }
  132. }
  133. static void tcp_client_start(void *priv)
  134. {
  135. enum wifi_sta_connect_state state;
  136. while (1) {
  137. printf("Connecting to the network...\n");
  138. state = wifi_get_sta_connect_state() ;
  139. if (WIFI_STA_NETWORK_STACK_DHCP_SUCC == state) {
  140. printf("Network connection is successful!\n");
  141. break;
  142. }
  143. os_time_dly(1000);
  144. }
  145. // wifi 初始化
  146. int err = tcp_client_init(SERVER_TCP_IP, SERVER_TCP_PORT);
  147. if (err) {
  148. printf("tcp_client_init err!");
  149. return;
  150. }
  151. // 初始化串口
  152. icheima_uart_init("uart1");
  153. os_task_create(tcp_client_wifi2uart_task, NULL, 1, 1000, 0, "tcp_client_wifi2uart_task");
  154. os_task_create(tcp_client_uart2wifi_task, NULL, 1, 1000, 0, "tcp_client_uart2wifi_task");
  155. /*
  156. if (thread_fork("tcp_client_uart2wifi_task", 10, 1024, 0, NULL, tcp_client_uart2wifi_task, NULL) != OS_NO_ERR) {
  157. printf("thread fork fail\n");
  158. }
  159. */
  160. }
  161. //应用程序入口,需要运行在STA模式下
  162. void c_main(void *priv)
  163. {
  164. if (thread_fork("tcp_client_start", 10, 512, 0, NULL, tcp_client_start, NULL) != OS_NO_ERR) {
  165. printf("thread fork fail\n");
  166. }
  167. }
  168. late_initcall(c_main);
  169. #endif

服务器端:

  1. import socket
  2. import threading
  3. import time
  4. # 处理客户端的请求操作
  5. def handle_client_request(service_client_socket, ip_port):
  6. # 循环接收客户端发送的数据
  7. while True:
  8. # 接收客户端发送的数据
  9. recv_data = service_client_socket.recv(1024)
  10. # 容器类型判断是否有数据可以直接使用if语句进行判断,如果容器类型里面有数据表示条件成立,否则条件失败
  11. # 容器类型: 列表、字典、元组、字符串、set、range、二进制数据
  12. if recv_data:
  13. print(recv_data.decode("utf8"), ip_port)
  14. # 回复
  15. service_client_socket.send("ok,hello...".encode("utf8"))
  16. time.sleep(3)
  17. else:
  18. print("客户端下线了:", ip_port)
  19. break
  20. # 终止和客户端进行通信
  21. service_client_socket.close()
  22. if __name__ == '__main__':
  23. # 创建tcp服务端套接字
  24. tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
  25. # 设置端口号复用,让程序退出端口号立即释放
  26. tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
  27. # 绑定端口号
  28. tcp_server_socket.bind(("", 9090))
  29. # 设置监听, listen后的套接字是被动套接字,只负责接收客户端的连接请求
  30. tcp_server_socket.listen(128)
  31. # 循环等待接收客户端的连接请求
  32. while True:
  33. # 等待接收客户端的连接请求
  34. service_client_socket, ip_port = tcp_server_socket.accept()
  35. print("客户端连接成功:", ip_port)
  36. # 当客户端和服务端建立连接成功以后,需要创建一个子线程,不同子线程负责接收不同客户端的消息
  37. sub_thread = threading.Thread(target=handle_client_request, args=(service_client_socket, ip_port))
  38. # 设置守护主线程
  39. sub_thread.setDaemon(True)
  40. # 启动子线程
  41. sub_thread.start()
  42. # tcp服务端套接字可以不需要关闭,因为服务端程序需要一直运行
  43. # tcp_server_socket.close()

MQTT协议

MQTT(Message Queuing Telemetry Transport)是一种轻量级的消息传输协议,设计用于在低带宽和不稳定网络环境下进行高效的通信。以下是MQTT协议的主要特点:

发布/订阅模式:MQTT采用发布/订阅模式,其中客户端可以订阅一个或多个主题(Topic),而服务器则负责将消息发布到这些主题。这种模式使得多个客户端可以同时接收到感兴趣的消息。

轻量级:MQTT协议非常轻量级,协议头部信息很小,有效减少了网络传输的开销和数据流量。这使得MQTT非常适合在低带宽和有限资源的设备上使用,例如物联网设备。

QoS级别:MQTT支持三个不同的消息传输质量(QoS)级别:0、1和2。QoS级别决定了消息传输的可靠性和保证程度。较高的QoS级别会增加通信开销,但可以提供更可靠的消息传输。

可靠性和持久性:MQTT协议具有可靠性和持久性机制。客户端可以选择是否要求服务器保留未传递的消息,以便在客户端重新连接时重新发送。这确保了即使在网络中断或重新连接时,消息也不会丢失。

安全性:MQTT协议支持使用TLS/SSL进行加密和身份验证,以确保通信的安全性。这对于保护敏感数据和防止未经授权的访问非常重要。

总结而言,MQTT协议是一种灵活、可靠且适用于物联网应用的通信协议。它具有低开销、轻量级和可扩展等特点,使得它成为物联网设备之间进行高效通信的理想选择。

阿里云配置

开通公共实例

image.png

新建产品

单击创建产品

image.png

填入产品名称

image.png

选择产品类别

image.png

image.png

Python设备

参考文档:
https://help.aliyun.com/zh/iot/developer-reference/configure-tsl-models-2?spm=a2c4g.11186623.0.0.47e03475UYpVCc
https://help.aliyun.com/zh/iot/use-cases/use-the-paho-mqtt-library-for-python-to-connect-a-device-to-iot-platform

参数定义

  1. productKey="k0ejuKHBeSm"
  2. deviceName="Dx2loZ2kr3e7EnhzBKZD"
  3. deviceSecret="7b62a2dbb171a55b0a3cb29c1427de2a"
  4. clientId = "Dx2loZ2kr3e7EnhzBKZD"
  5. subTopic = f"/sys/{productKey}/{deviceName}/thing/event/property/post_reply"
  6. pubTopic = f"/sys/{productKey}/{deviceName}/thing/event/property/post"

python发布

  1. def publish_message():
  2. # publish 5 messages to pubTopic("/a1LhUsK****/python***/user/update")
  3. data = {"id": "123",
  4. "version": "1.0",
  5. "params": {
  6. "PowerSwitch": 1,
  7. "CurrentTemperature": 27.6
  8. },
  9. "method": "thing.event.property.post"
  10. }
  11. for i in range(5):
  12. data["params"]["CurrentTemperature"] = 23.6+i
  13. message = json.dumps(data)
  14. client.publish(pubTopic, message)
  15. print("publish msg: " + str(i))
  16. print("publish msg: " + message)
  17. time.sleep(2)

python订阅

  1. def subscribe_topic():
  2. # subscribe to subTopic("/a1LhUsK****/python***/user/get") and request messages to be delivered
  3. client.subscribe(subTopic)
  4. print("subscribe topic: " + subTopic)

完整示例

  1. import json
  2. import time
  3. import paho.mqtt.client as mqtt
  4. from MqttSign import AuthIfo
  5. # set the device info, include product key, device name, and device secret
  6. productKey="k0ejuKHBeSm"
  7. deviceName="Dx2loZ2kr3e7EnhzBKZD"
  8. deviceSecret="7b62a2dbb171a55b0a3cb29c1427de2a"
  9. clientId = "Dx2loZ2kr3e7EnhzBKZD"
  10. # set timestamp, clientid, subscribe topic and publish topic
  11. timeStamp = str((int(round(time.time() * 1000))))
  12. subTopic = f"/sys/{productKey}/{deviceName}/thing/event/property/post_reply"
  13. subTopic1 = f"/sys/{productKey}/{deviceName}/thing/service/property/set"
  14. pubTopic = f"/sys/{productKey}/{deviceName}/thing/event/property/post"
  15. # set host, port
  16. host = productKey + ".iot-as-mqtt.cn-shanghai.aliyuncs.com"
  17. # instanceId = "***"
  18. # host = instanceId + ".mqtt.iothub.aliyuncs.com"
  19. port = 1883
  20. # set tls crt, keepalive
  21. tls_crt = "root.crt"
  22. keepAlive = 300
  23. # calculate the login auth info, and set it into the connection options
  24. m = AuthIfo()
  25. m.calculate_sign_time(productKey, deviceName, deviceSecret, clientId, timeStamp)
  26. m.calculate_sign(productKey,deviceName,deviceSecret,clientId)
  27. client = mqtt.Client(m.mqttClientId)
  28. client.username_pw_set(username=m.mqttUsername, password=m.mqttPassword)
  29. client.tls_set(tls_crt)
  30. print(f"clientid:{m.mqttClientId}")
  31. print(f"username:{m.mqttUsername}")
  32. print(f"password:{m.mqttPassword}")
  33. print(f"pub_topic:{pubTopic}")
  34. print(f"subTopic:{subTopic}")
  35. print(f"subTopic1:{subTopic1}")
  36. def on_connect(client, userdata, flags, rc):
  37. if rc == 0:
  38. print("Connect aliyun IoT Cloud Sucess")
  39. else:
  40. print("Connect failed... error code is:" + str(rc))
  41. def on_message(client, userdata, msg):
  42. topic = msg.topic
  43. payload = msg.payload.decode()
  44. print("receive message ---------- topic is : " + topic)
  45. print("receive message ---------- payload is : " + payload)
  46. if ("thing/service/property/set" in topic):
  47. on_thing_prop_changed(client, msg.topic, msg.payload)
  48. def on_thing_prop_changed(client, topic, payload):
  49. post_topic = topic.replace("service","event")
  50. post_topic = post_topic.replace("set","post")
  51. Msg = json.loads(payload)
  52. params = Msg['params']
  53. post_payload = "{\"params\":" + json.dumps(params) + "}"
  54. print("reveice property_set command, need to post ---------- topic is: " + post_topic)
  55. print("reveice property_set command, need to post ---------- payload is: " + post_payload)
  56. client.publish(post_topic, post_payload)
  57. def connect_mqtt():
  58. client.connect(host, port, keepAlive)
  59. return client
  60. def publish_message():
  61. # publish 5 messages to pubTopic("/a1LhUsK****/python***/user/update")
  62. data = {"id": "123",
  63. "version": "1.0",
  64. "params": {
  65. "PowerSwitch": 1,
  66. "CurrentTemperature": 27.6
  67. },
  68. "method": "thing.event.property.post"
  69. }
  70. for i in range(5):
  71. data["params"]["CurrentTemperature"] = 23.6+i
  72. message = json.dumps(data)
  73. client.publish(pubTopic, message)
  74. print("publish msg: " + str(i))
  75. print("publish msg: " + message)
  76. time.sleep(2)
  77. def subscribe_topic():
  78. # subscribe to subTopic("/a1LhUsK****/python***/user/get") and request messages to be delivered
  79. client.subscribe(subTopic)
  80. print("subscribe topic: " + subTopic)
  81. client.on_connect = on_connect
  82. client.on_message = on_message
  83. client = connect_mqtt()
  84. client.loop_start()
  85. time.sleep(2)
  86. subscribe_topic()
  87. publish_message()
  88. while True:
  89. time.sleep(1)

杰理设备

mqtt初始化

  1. static int mqtt_start(void* config)
  2. {
  3. Network network;
  4. MQTTPacket_connectData connectData = MQTTPacket_connectData_initializer;
  5. MQTTMessage message;
  6. int err;
  7. int loop_cnt = 0;
  8. int temperature = 0;
  9. int humidity = 0;
  10. struct icheima_iot_data* config_data = config;
  11. char *address = config_data->address;
  12. char *username = config_data->username;
  13. char *password = config_data->password;
  14. char *subscribeTopic = config_data->sub_topic; //订阅的主题
  15. char *publishTopic = config_data->pub_topic; //发布消息的主题
  16. char *clientID = config_data->clientId;
  17. printf("address=====>%s\r\n",address);
  18. printf("username=====>%s\r\n",username);
  19. printf("password=====>%s\r\n",password);
  20. printf("subscribeTopic=====>%s\r\n",subscribeTopic);
  21. printf("publishTopic=====>%s\r\n",publishTopic);
  22. printf("clientID=====>%s\r\n",clientID);
  23. _reconnect:
  24. //初始化网络接口
  25. NewNetwork(&network);
  26. SetNetworkRecvTimeout(&network, 1000);
  27. //初始化客户端
  28. MQTTClient(&client, &network, COMMAND_TIMEOUT_MS, send_buf, sizeof(send_buf), read_buf, sizeof(read_buf));
  29. //tcp层连接服务器
  30. err = ConnectNetwork(&network, address, 1883);
  31. if (err != 0) {
  32. printf("ConnectNetwork fail\n");
  33. return -1;
  34. }
  35. connectData.willFlag = 0;
  36. connectData.MQTTVersion = 3; //mqtt版本号
  37. connectData.clientID.cstring = clientID; //客户端id
  38. connectData.username.cstring = username; //连接时的用户名
  39. connectData.password.cstring = password; //连接时的密码
  40. connectData.keepAliveInterval = MQTT_KEEPALIVE_TIME / 1000; //心跳时间
  41. connectData.cleansession = 1; //是否使能服务器的cleansession,0:禁止, 1:使能
  42. //mqtt层连接,向服务器发送连接请求
  43. err = MQTTConnect(&client, &connectData);
  44. if (err != 0) {
  45. network.disconnect(&network);
  46. printf("MQTTConnect fail, err : 0x%x\n", err);
  47. return -1;
  48. }
  49. //订阅主题
  50. err = MQTTSubscribe(&client, subscribeTopic, QOS1, messageArrived);
  51. if (err != 0) {
  52. MQTTDisconnect(&client);
  53. network.disconnect(&network);
  54. printf("MQTTSubscribe fail, err : 0x%x\n", err);
  55. return -1;
  56. }
  57. message.qos = QOS1;
  58. message.retained = 0;
  59. #ifdef CONFIG_MP3_DEC_ENABLE
  60. post_msg_play_flash_mp3("NetConnting.mp3", 55);
  61. #endif
  62. // 如果当前是正常连接的状态,那么呼吸灯就开始工作
  63. extern void icheima_test_led_main();
  64. icheima_test_led_main();
  65. user_printf("{\"icheima_mqtt_connect\":1}\r\n");
  66. while (1) {
  67. os_time_dly(100);
  68. err = MQTTYield(&client, MQTT_TIMEOUT_MS);
  69. if (err != 0) {
  70. if (client.isconnected) {
  71. //断开mqtt层连接
  72. err = MQTTDisconnect(&client);
  73. if (err != 0) {
  74. user_printf("MQTTDisconnect fail\n");
  75. }
  76. //断开tcp层连接
  77. network.disconnect(&network);
  78. }
  79. user_printf("MQTT : Reconnecting\n");
  80. //重新连接
  81. goto _reconnect;
  82. }
  83. }
  84. return 0;
  85. }

mqtt发布

  1. int icheima_iot_pub_topic(char* topic,char* sendbuf){
  2. MQTTMessage message;
  3. message.qos = QOS1;
  4. message.retained = 0;
  5. message.payload = sendbuf;
  6. message.payloadlen = strlen(sendbuf) + 1;
  7. //发布消息
  8. int err = MQTTPublish(&client, topic, &message);
  9. if (err != 0) {
  10. printf("MQTTPublish fail, err : 0x%x\n", err);
  11. }
  12. printf("MQTTPublish payload:(%s)\n", sendbuf);
  13. }

mqtt订阅

  1. static void messageArrived(MessageData *data)
  2. {
  3. char temp[512] = {0};
  4. strncpy(temp, data->topicName->lenstring.data, data->topicName->lenstring.len);
  5. temp[data->topicName->lenstring.len] = '\0';
  6. printf("Message arrived on topic (len : %d, topic : %s)\n", data->topicName->lenstring.len, temp);
  7. memset(temp, 0, sizeof(temp));
  8. strncpy(temp, data->message->payload, data->message->payloadlen);
  9. temp[data->message->payloadlen] = '\0';
  10. //user_printf("message (len : %d, payload : %s)\n", data->message->payloadlen, temp);
  11. user_printf("%s",temp);
  12. //char fmt_str[512] = "{\"topic\":\"%s\",\"data\":\"%s\"}";
  13. //sprintf(temp,fmt_str,data->topicName->lenstring.data,data->message->payload);
  14. //printf("result:%s \n",temp);
  15. }

相关配置

https://doc.zh-jieli.com/AC79/zh-cn/master/module_example/system/printf.html

image.png