wifi配置
需要在app_config.h文件中定义USE_DEMO_WIFI_TEST,工程会在wifi_demo_task.c文件中自动启动wifi相关的任务, 我们将工程配置为连接外部网络STA模式
默认工程会使用如下账号密码
当wifi任务启动之后,我们可以通过调用如下函数,让芯片连接上外部的网络
wifi_enter_sta_mode(str_ssid, str_pwd);
TCP通讯
socket初始化
首先需要初始化socket,并指定协议
#define SERVER_TCP_IP "192.168.3.100" //服务端ip
#define SERVER_TCP_PORT 9090 //服务端端口号
static int tcp_client_init(const char *server_ip, const int server_port)
{
//struct sockaddr_in local;
struct sockaddr_in dest;
//创建socket
sock = sock_reg(AF_INET, SOCK_STREAM, 0, NULL, NULL);
if (sock == NULL) {
printf("sock_reg fail.\n");
return -1;
}
//连接指定地址服务端
dest.sin_family = AF_INET;
dest.sin_addr.s_addr = inet_addr(server_ip);
dest.sin_port = htons(server_port);
if (0 != sock_connect(sock, (struct sockaddr *)&dest, sizeof(struct sockaddr_in))) {
printf("sock_connect fail.\n");
sock_unreg(sock);
return -1;
}
return 0;
}
初始化调用的逻辑,很简单,只需要指定IP地址和端口号即可
err = tcp_client_init(SERVER_TCP_IP, SERVER_TCP_PORT);
if (err) {
printf("tcp_client_init err!");
return;
}
发送数据
//发送数据
static int tcp_send_data(const void *sock_hdl, const void *buf, const u32 len)
{
return sock_send(sock_hdl, buf, len, 0);
}
接收数据
//接收数据
static int tcp_recv_data(const void *sock_hdl, void *buf, u32 len)
{
return sock_recvfrom(sock_hdl, buf, len, 0, NULL, NULL);
}
接收数据代码
for (;;) {
recv_len = tcp_recv_data(sock, recv_buf, sizeof(recv_buf));
if ((recv_len != -1) && (recv_len != 0)) {
recv_buf[recv_len] = '\0';
printf("Received %d bytes, data: %s\n\r", recv_len, recv_buf);
tcp_send_data(sock, "Data received successfully!", strlen("Data received successfully!"));
} else {
printf("sock_recvfrom err!");
break;
}
}
完整示例代码:
客户端:
#include "sock_api/sock_api.h"
#include "app_config.h"
#include "system/includes.h"
#include "wifi/wifi_connect.h"
#include "lwip.h"
#include "lwip/sockets.h"
#include "lwip/netdb.h"
#ifdef USE_ICHEIMA_WIFI
#include "itheima.h"
static void *sock = NULL;
#define SERVER_TCP_IP "192.168.3.100" //服务端ip
#define SERVER_TCP_PORT 9090 //服务端端口号
static int tcp_client_init(const char *server_ip, const int server_port)
{
//struct sockaddr_in local;
struct sockaddr_in dest;
//创建socket
sock = sock_reg(AF_INET, SOCK_STREAM, 0, NULL, NULL);
if (sock == NULL) {
printf("sock_reg fail.\n");
return -1;
}
//连接指定地址服务端
dest.sin_family = AF_INET;
dest.sin_addr.s_addr = inet_addr(server_ip);
dest.sin_port = htons(server_port);
if (0 != sock_connect(sock, (struct sockaddr *)&dest, sizeof(struct sockaddr_in))) {
printf("sock_connect fail.\n");
sock_unreg(sock);
return -1;
}
return 0;
}
//发送数据
static int tcp_send_data(const void *sock_hdl, const void *buf, const u32 len)
{
return sock_send(sock_hdl, buf, len, 0);
}
//接收数据
static int tcp_recv_data(const void *sock_hdl, void *buf, u32 len)
{
return sock_recvfrom(sock_hdl, buf, len, 0, NULL, NULL);
}
//tcp client任务
static void tcp_client_task(void *priv)
{
int err;
char *payload = "Please send me some data!";
char recv_buf[1024];
int recv_len;
int send_len;
err = tcp_client_init(SERVER_TCP_IP, SERVER_TCP_PORT);
if (err) {
printf("tcp_client_init err!");
return;
}
send_len = tcp_send_data(sock, payload, strlen(payload));
if (send_len == -1) {
printf("sock_sendto err!");
sock_unreg(sock);
return;
}
for (;;) {
recv_len = tcp_recv_data(sock, recv_buf, sizeof(recv_buf));
if ((recv_len != -1) && (recv_len != 0)) {
recv_buf[recv_len] = '\0';
printf("Received %d bytes, data: %s\n\r", recv_len, recv_buf);
tcp_send_data(sock, "Data received successfully!", strlen("Data received successfully!"));
} else {
printf("sock_recvfrom err!");
break;
}
}
if (sock) {
sock_unreg(sock);
sock = NULL;
}
}
// 将串口接收到的数据通过串口发送出去
static void tcp_client_uart2wifi_task(void *priv){
int len=0;
uint8_t recv_buf[1024];
printf("tcp_client_uart2wifi_task start>>>>>>>>>>>>>>>>>\r\n");
while(1){
len=icheima_uart_read_data(recv_buf);
printf("\n uart recv len = %d\n", len);
if(len > 0){
printf("\n uart recv len = %d\n", len);
recv_buf[len] = '\0';
//把串口接收到的数据发送回去
tcp_send_data(sock,recv_buf,len);
memset(recv_buf, 0, sizeof(recv_buf));
}else{
//printf("uart recv error len = %d\n", len);
}
}
}
// 将wifi接收到的数据,发送给串口
static void tcp_client_wifi2uart_task(void *priv)
{
int err;
char *payload = "Please send me some data!";
char recv_buf[1024];
int recv_len;
if(!sock){
printf("tcp_client_wifi2uart_task sock error>>>>>>>>>>>>>>\r\n");
}
int send_len = tcp_send_data(sock, payload, strlen(payload));
if (send_len == -1) {
printf("sock_sendto err!");
sock_unreg(sock);
return;
}
printf("tcp_client_wifi2uart_task start>>>>>>>>>>>>>>\r\n");
while(1){
recv_len = tcp_recv_data(sock, recv_buf, sizeof(recv_buf));
if ((recv_len != -1) && (recv_len != 0)) {
recv_buf[recv_len] = '\0';
// 将数据发送给串口
icheima_uart_send_data(recv_buf, recv_len);
printf("Received %d bytes, data:%s\n", recv_len, recv_buf);
memset(recv_buf, 0, sizeof(recv_buf));
} else {
printf("sock_recvfrom err!");
break;
}
}
if (sock) {
sock_unreg(sock);
sock = NULL;
}
}
static void tcp_client_start(void *priv)
{
enum wifi_sta_connect_state state;
while (1) {
printf("Connecting to the network...\n");
state = wifi_get_sta_connect_state() ;
if (WIFI_STA_NETWORK_STACK_DHCP_SUCC == state) {
printf("Network connection is successful!\n");
break;
}
os_time_dly(1000);
}
// wifi 初始化
int err = tcp_client_init(SERVER_TCP_IP, SERVER_TCP_PORT);
if (err) {
printf("tcp_client_init err!");
return;
}
// 初始化串口
icheima_uart_init("uart1");
os_task_create(tcp_client_wifi2uart_task, NULL, 1, 1000, 0, "tcp_client_wifi2uart_task");
os_task_create(tcp_client_uart2wifi_task, NULL, 1, 1000, 0, "tcp_client_uart2wifi_task");
/*
if (thread_fork("tcp_client_uart2wifi_task", 10, 1024, 0, NULL, tcp_client_uart2wifi_task, NULL) != OS_NO_ERR) {
printf("thread fork fail\n");
}
*/
}
//应用程序入口,需要运行在STA模式下
void c_main(void *priv)
{
if (thread_fork("tcp_client_start", 10, 512, 0, NULL, tcp_client_start, NULL) != OS_NO_ERR) {
printf("thread fork fail\n");
}
}
late_initcall(c_main);
#endif
服务器端:
import socket
import threading
import time
# 处理客户端的请求操作
def handle_client_request(service_client_socket, ip_port):
# 循环接收客户端发送的数据
while True:
# 接收客户端发送的数据
recv_data = service_client_socket.recv(1024)
# 容器类型判断是否有数据可以直接使用if语句进行判断,如果容器类型里面有数据表示条件成立,否则条件失败
# 容器类型: 列表、字典、元组、字符串、set、range、二进制数据
if recv_data:
print(recv_data.decode("utf8"), ip_port)
# 回复
service_client_socket.send("ok,hello...".encode("utf8"))
time.sleep(3)
else:
print("客户端下线了:", ip_port)
break
# 终止和客户端进行通信
service_client_socket.close()
if __name__ == '__main__':
# 创建tcp服务端套接字
tcp_server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
# 设置端口号复用,让程序退出端口号立即释放
tcp_server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, True)
# 绑定端口号
tcp_server_socket.bind(("", 9090))
# 设置监听, listen后的套接字是被动套接字,只负责接收客户端的连接请求
tcp_server_socket.listen(128)
# 循环等待接收客户端的连接请求
while True:
# 等待接收客户端的连接请求
service_client_socket, ip_port = tcp_server_socket.accept()
print("客户端连接成功:", ip_port)
# 当客户端和服务端建立连接成功以后,需要创建一个子线程,不同子线程负责接收不同客户端的消息
sub_thread = threading.Thread(target=handle_client_request, args=(service_client_socket, ip_port))
# 设置守护主线程
sub_thread.setDaemon(True)
# 启动子线程
sub_thread.start()
# tcp服务端套接字可以不需要关闭,因为服务端程序需要一直运行
# 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协议是一种灵活、可靠且适用于物联网应用的通信协议。它具有低开销、轻量级和可扩展等特点,使得它成为物联网设备之间进行高效通信的理想选择。
阿里云配置
开通公共实例
新建产品
单击创建产品
填入产品名称
选择产品类别
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
参数定义
productKey="k0ejuKHBeSm"
deviceName="Dx2loZ2kr3e7EnhzBKZD"
deviceSecret="7b62a2dbb171a55b0a3cb29c1427de2a"
clientId = "Dx2loZ2kr3e7EnhzBKZD"
subTopic = f"/sys/{productKey}/{deviceName}/thing/event/property/post_reply"
pubTopic = f"/sys/{productKey}/{deviceName}/thing/event/property/post"
python发布
def publish_message():
# publish 5 messages to pubTopic("/a1LhUsK****/python***/user/update")
data = {"id": "123",
"version": "1.0",
"params": {
"PowerSwitch": 1,
"CurrentTemperature": 27.6
},
"method": "thing.event.property.post"
}
for i in range(5):
data["params"]["CurrentTemperature"] = 23.6+i
message = json.dumps(data)
client.publish(pubTopic, message)
print("publish msg: " + str(i))
print("publish msg: " + message)
time.sleep(2)
python订阅
def subscribe_topic():
# subscribe to subTopic("/a1LhUsK****/python***/user/get") and request messages to be delivered
client.subscribe(subTopic)
print("subscribe topic: " + subTopic)
完整示例
import json
import time
import paho.mqtt.client as mqtt
from MqttSign import AuthIfo
# set the device info, include product key, device name, and device secret
productKey="k0ejuKHBeSm"
deviceName="Dx2loZ2kr3e7EnhzBKZD"
deviceSecret="7b62a2dbb171a55b0a3cb29c1427de2a"
clientId = "Dx2loZ2kr3e7EnhzBKZD"
# set timestamp, clientid, subscribe topic and publish topic
timeStamp = str((int(round(time.time() * 1000))))
subTopic = f"/sys/{productKey}/{deviceName}/thing/event/property/post_reply"
subTopic1 = f"/sys/{productKey}/{deviceName}/thing/service/property/set"
pubTopic = f"/sys/{productKey}/{deviceName}/thing/event/property/post"
# set host, port
host = productKey + ".iot-as-mqtt.cn-shanghai.aliyuncs.com"
# instanceId = "***"
# host = instanceId + ".mqtt.iothub.aliyuncs.com"
port = 1883
# set tls crt, keepalive
tls_crt = "root.crt"
keepAlive = 300
# calculate the login auth info, and set it into the connection options
m = AuthIfo()
m.calculate_sign_time(productKey, deviceName, deviceSecret, clientId, timeStamp)
m.calculate_sign(productKey,deviceName,deviceSecret,clientId)
client = mqtt.Client(m.mqttClientId)
client.username_pw_set(username=m.mqttUsername, password=m.mqttPassword)
client.tls_set(tls_crt)
print(f"clientid:{m.mqttClientId}")
print(f"username:{m.mqttUsername}")
print(f"password:{m.mqttPassword}")
print(f"pub_topic:{pubTopic}")
print(f"subTopic:{subTopic}")
print(f"subTopic1:{subTopic1}")
def on_connect(client, userdata, flags, rc):
if rc == 0:
print("Connect aliyun IoT Cloud Sucess")
else:
print("Connect failed... error code is:" + str(rc))
def on_message(client, userdata, msg):
topic = msg.topic
payload = msg.payload.decode()
print("receive message ---------- topic is : " + topic)
print("receive message ---------- payload is : " + payload)
if ("thing/service/property/set" in topic):
on_thing_prop_changed(client, msg.topic, msg.payload)
def on_thing_prop_changed(client, topic, payload):
post_topic = topic.replace("service","event")
post_topic = post_topic.replace("set","post")
Msg = json.loads(payload)
params = Msg['params']
post_payload = "{\"params\":" + json.dumps(params) + "}"
print("reveice property_set command, need to post ---------- topic is: " + post_topic)
print("reveice property_set command, need to post ---------- payload is: " + post_payload)
client.publish(post_topic, post_payload)
def connect_mqtt():
client.connect(host, port, keepAlive)
return client
def publish_message():
# publish 5 messages to pubTopic("/a1LhUsK****/python***/user/update")
data = {"id": "123",
"version": "1.0",
"params": {
"PowerSwitch": 1,
"CurrentTemperature": 27.6
},
"method": "thing.event.property.post"
}
for i in range(5):
data["params"]["CurrentTemperature"] = 23.6+i
message = json.dumps(data)
client.publish(pubTopic, message)
print("publish msg: " + str(i))
print("publish msg: " + message)
time.sleep(2)
def subscribe_topic():
# subscribe to subTopic("/a1LhUsK****/python***/user/get") and request messages to be delivered
client.subscribe(subTopic)
print("subscribe topic: " + subTopic)
client.on_connect = on_connect
client.on_message = on_message
client = connect_mqtt()
client.loop_start()
time.sleep(2)
subscribe_topic()
publish_message()
while True:
time.sleep(1)
杰理设备
mqtt初始化
static int mqtt_start(void* config)
{
Network network;
MQTTPacket_connectData connectData = MQTTPacket_connectData_initializer;
MQTTMessage message;
int err;
int loop_cnt = 0;
int temperature = 0;
int humidity = 0;
struct icheima_iot_data* config_data = config;
char *address = config_data->address;
char *username = config_data->username;
char *password = config_data->password;
char *subscribeTopic = config_data->sub_topic; //订阅的主题
char *publishTopic = config_data->pub_topic; //发布消息的主题
char *clientID = config_data->clientId;
printf("address=====>%s\r\n",address);
printf("username=====>%s\r\n",username);
printf("password=====>%s\r\n",password);
printf("subscribeTopic=====>%s\r\n",subscribeTopic);
printf("publishTopic=====>%s\r\n",publishTopic);
printf("clientID=====>%s\r\n",clientID);
_reconnect:
//初始化网络接口
NewNetwork(&network);
SetNetworkRecvTimeout(&network, 1000);
//初始化客户端
MQTTClient(&client, &network, COMMAND_TIMEOUT_MS, send_buf, sizeof(send_buf), read_buf, sizeof(read_buf));
//tcp层连接服务器
err = ConnectNetwork(&network, address, 1883);
if (err != 0) {
printf("ConnectNetwork fail\n");
return -1;
}
connectData.willFlag = 0;
connectData.MQTTVersion = 3; //mqtt版本号
connectData.clientID.cstring = clientID; //客户端id
connectData.username.cstring = username; //连接时的用户名
connectData.password.cstring = password; //连接时的密码
connectData.keepAliveInterval = MQTT_KEEPALIVE_TIME / 1000; //心跳时间
connectData.cleansession = 1; //是否使能服务器的cleansession,0:禁止, 1:使能
//mqtt层连接,向服务器发送连接请求
err = MQTTConnect(&client, &connectData);
if (err != 0) {
network.disconnect(&network);
printf("MQTTConnect fail, err : 0x%x\n", err);
return -1;
}
//订阅主题
err = MQTTSubscribe(&client, subscribeTopic, QOS1, messageArrived);
if (err != 0) {
MQTTDisconnect(&client);
network.disconnect(&network);
printf("MQTTSubscribe fail, err : 0x%x\n", err);
return -1;
}
message.qos = QOS1;
message.retained = 0;
#ifdef CONFIG_MP3_DEC_ENABLE
post_msg_play_flash_mp3("NetConnting.mp3", 55);
#endif
// 如果当前是正常连接的状态,那么呼吸灯就开始工作
extern void icheima_test_led_main();
icheima_test_led_main();
user_printf("{\"icheima_mqtt_connect\":1}\r\n");
while (1) {
os_time_dly(100);
err = MQTTYield(&client, MQTT_TIMEOUT_MS);
if (err != 0) {
if (client.isconnected) {
//断开mqtt层连接
err = MQTTDisconnect(&client);
if (err != 0) {
user_printf("MQTTDisconnect fail\n");
}
//断开tcp层连接
network.disconnect(&network);
}
user_printf("MQTT : Reconnecting\n");
//重新连接
goto _reconnect;
}
}
return 0;
}
mqtt发布
int icheima_iot_pub_topic(char* topic,char* sendbuf){
MQTTMessage message;
message.qos = QOS1;
message.retained = 0;
message.payload = sendbuf;
message.payloadlen = strlen(sendbuf) + 1;
//发布消息
int err = MQTTPublish(&client, topic, &message);
if (err != 0) {
printf("MQTTPublish fail, err : 0x%x\n", err);
}
printf("MQTTPublish payload:(%s)\n", sendbuf);
}
mqtt订阅
static void messageArrived(MessageData *data)
{
char temp[512] = {0};
strncpy(temp, data->topicName->lenstring.data, data->topicName->lenstring.len);
temp[data->topicName->lenstring.len] = '\0';
printf("Message arrived on topic (len : %d, topic : %s)\n", data->topicName->lenstring.len, temp);
memset(temp, 0, sizeof(temp));
strncpy(temp, data->message->payload, data->message->payloadlen);
temp[data->message->payloadlen] = '\0';
//user_printf("message (len : %d, payload : %s)\n", data->message->payloadlen, temp);
user_printf("%s",temp);
//char fmt_str[512] = "{\"topic\":\"%s\",\"data\":\"%s\"}";
//sprintf(temp,fmt_str,data->topicName->lenstring.data,data->message->payload);
//printf("result:%s \n",temp);
}
相关配置
https://doc.zh-jieli.com/AC79/zh-cn/master/module_example/system/printf.html