树莓派如何与物联网平台交互(搭建一个树莓派网关)

Posted 三明治开发社区

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树莓派如何与物联网平台交互(搭建一个树莓派网关)相关的知识,希望对你有一定的参考价值。

树莓派如何与物联网平台交互(搭建一个树莓派网关)(二)

六、程序设计

​ 程序设计大致分为两部分,一部分是树莓派和485子设备通信的程序,另外一部分是树莓派和涂鸦云平台进行交互的程序。

1、连接涂鸦云平台

(1)程序设计简单概述

​ 树莓派和涂鸦云平台进行数据交互的时候采用c语言编写的。

(2)程序设计逻辑分析

​ 在平台上创建网关设备时,下载“C TuyaLink SDK”开发包,在此demo上移植自己想要实现的功能。

在data_model_basic_demo.c实现整个控制逻辑:

#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>  

#include "cJSON.h"
#include "tuya_cacert.h"
#include "tuya_log.h"
#include "tuya_error_code.h"
#include "system_interface.h"
#include "mqtt_client_interface.h"
#include "tuyalink_core.h"

const char productId[] = "t1tlm6p13aouheta";
const char deviceId[] = "6cf918e90b12f7b1ffwiuz";
const char deviceSecret[] = "a5f23a3fb341edbd";

tuya_mqtt_context_t client_instance;

//写文件
int write_file(char str[])

    FILE *fp = NULL; 
    fp = fopen("/tmp/from_platform.txt", "w");
    fprintf(fp, "%s", str);
    fclose(fp);
    printf("deviceid_action_time: %s\\n", str); 
    return 0;


//读文件
int read_file(int num,char return_data[])

    FILE *fp = NULL;
  switch (num)
    
    case 1:
        fp = fopen("/tmp/1.txt", "r");
        if(fp == NULL)
        
           printf("open /tmp/1.txt error!\\n");
           return 0;
        
        fgets(return_data, 255, (FILE*)fp);
        fclose(fp);
        break;
    case 2:
        fp = fopen("/tmp/2.txt", "r");
        if(fp == NULL)
        
           printf("open /tmp/2.txt error!\\n");
           return 0;
        
        fgets(return_data, 255, (FILE*)fp);
        fclose(fp);
        break;
    case 3:
        fp = fopen("/tmp/3.txt", "r");
        if(fp == NULL)
        
           printf("open /tmp/3.txt error!\\n");
           return 0;
        
        fgets(return_data, 255, (FILE*)fp);  
        fclose(fp); 
        break;
    default:
        break;
    
    printf("return_data:%s\\n",return_data);
    return 0;


//写一个线程函数 void *函数名(void *arg)
void *thread_worker1(void *arg) 
  
    char json_temp_hum[255];
    char json_door_state[255];
    char json_data[255];
    char json_data1[255];
        while(1)
          
            if(read_file(2,json_data) == 0)
            
                sprintf(json_temp_hum,"%s",json_data);
                printf("json_temp_hum:%s\\r\\n",json_temp_hum);
                tuyalink_thing_property_report_with_ack(arg, NULL, json_temp_hum);
                memset(json_data, 0, sizeof(json_data));  
                
            
            else
            
                printf("read temp_hum error\\r\\n");

            
            if(read_file(3,json_data1) == 0)
            
                sprintf(json_door_state,"%s",json_data1);
                printf("json_door_state:%s\\r\\n",json_door_state);
                tuyalink_thing_event_trigger(arg, NULL, json_door_state); 
                memset(json_data1, 0, sizeof(json_data1));  
            
            else
            
                printf("read door_state error\\r\\n");

            
            sleep(2); 
          


void on_connected(tuya_mqtt_context_t* context, void* user_data)
 
    int error=0;
    pthread_t t1;
    tuyalink_subdevice_bind(context, "[\\"productId\\":\\"snigjkwkheaxueqa\\",\\"nodeId\\":\\"255\\",\\"clientId\\":\\"1\\"]");//继电器
    tuyalink_subdevice_bind(context, "[\\"productId\\":\\"dtoqgbr5azgwvga3\\",\\"nodeId\\":\\"254\\",\\"clientId\\":\\"2\\"]");//门磁
    tuyalink_subdevice_bind(context, "[\\"productId\\":\\"6jmmnuwavyxkcv1x\\",\\"nodeId\\":\\"1\\",\\"clientId\\":\\"3\\"]");//温湿度
    error=pthread_create(&t1,NULL,thread_worker1,context);
    if(error)
       
          printf("create pthread error!\\n");
          return;     
        
    


void on_disconnect(tuya_mqtt_context_t* context, void* user_data)

    TY_LOGI("on disconnect");



void on_messages(tuya_mqtt_context_t* context, void* user_data, const tuyalink_message_t* msg)

    char json_relay_state[255];
    TY_LOGI("on message id:%s, type:%d, code:%d", msg->msgid, msg->type, msg->code);
    switch (msg->type) 
        case THING_TYPE_MODEL_RSP:
            TY_LOGI("Model data:%s", msg->data_string);
            break;

        case THING_TYPE_PROPERTY_SET:
            TY_LOGI("property set:%s", msg->data_string);
            break;

        case  THING_TYPE_PROPERTY_REPORT_RSP:
           break;

        case THING_TYPE_ACTION_EXECUTE:
              TY_LOGI("action execute:%s", msg->data_string);
              if(write_file(msg->data_string) == 0)
                 
                    printf ("write ok\\r\\n");
                    printf ("data_string:%s\\r\\n",msg->data_string);
                 
             else
                
                    printf ("write error\\r\\n");
                
                 if(read_file(1,json_relay_state) == 0)
                 
                   sprintf(msg->data_string,"%s",json_relay_state);
                   printf("json_relay_state:%s\\r\\n",json_relay_state);
                   tuyalink_thing_property_report(context, NULL, msg->data_string);  
                   memset(json_relay_state, 0, sizeof(json_relay_state));      
                 
                 else
                 
                  printf ("read relay_state error\\r\\n");
                      
            break;   

        default:
            break;
    
    printf("\\r\\n");


int main(int argc, char** argv)

    int ret = OPRT_OK;
    tuya_mqtt_context_t* client = &client_instance;
    ret = tuya_mqtt_init(client, &(const tuya_mqtt_config_t) 
        .host = "m2.tuyacn.com",
        .port = 8883,
        .cacert = tuya_cacert_pem,
        .cacert_len = sizeof(tuya_cacert_pem),
        .device_id = deviceId,
        .device_secret = deviceSecret,
        .keepalive = 60,
        .timeout_ms = 2000,
        .on_connected = on_connected,
        .on_disconnect = on_disconnect,
        .on_messages = on_messages
    );
    assert(ret == OPRT_OK);
    ret = tuya_mqtt_connect(client);
    assert(ret == OPRT_OK);
      for (;;) 
       
        /* Loop to receive packets, and handles client keepalive */
        tuya_mqtt_loop(client);
       
    return ret;
 

(3)程序函数功能解析

注意:下文会提到"树莓派网关",以及"c端"和"python端"词,具体所指含义如下:

树莓派做成网关,里面跑了两个进程,一个是采用python语言处理子设备数据收发,以及json数据解析(python端);另外一个进程是采用c语言处理和涂鸦云平台进行交互(c端)。

  • 下面是在平台上创建网关设备时候的参数,填入对应的位置即可。
const char productId[] = "t1tlm6p13aouheta";
const char deviceId[] = "6cf918e90b12f7b1ffwiuz";
const char deviceSecret[] = "a5f23a3fb341edbd";
  • 在main函数里面实例化和初始化一个设备对象 tuya_mqtt_context_t,用来初始化产品 ID 和授权信息等配置参数以及循环接收数据包,并处理客户端保持连接。
int main(int argc, char** argv)

    int ret = OPRT_OK;
    tuya_mqtt_context_t* client = &client_instance;
    ret = tuya_mqtt_init(client, &(const tuya_mqtt_config_t) 
        .host = "m2.tuyacn.com",
        .port = 8883,
        .cacert = tuya_cacert_pem,
        .cacert_len = sizeof(tuya_cacert_pem),
        .device_id = deviceId,
        .device_secret = deviceSecret,
        .keepalive = 60,
        .timeout_ms = 2000,
        .on_connected = on_connected,
        .on_disconnect = on_disconnect,
        .on_messages = on_messages
    );
    assert(ret == OPRT_OK);
    ret = tuya_mqtt_connect(client);
    assert(ret == OPRT_OK);
      for (;;) 
       
        /* Loop to receive packets, and handles client keepalive */
        tuya_mqtt_loop(client);
       
    return ret;
       

启动 TuyaOS SDK 服务。

ret = tuya_mqtt_connect(client);
//TuyaOS SDK 服务任务,数据接收处理,设备在线保活等任务处理:

循环调用将当前线程产生给底层的 Link SDK 客户端。

tuya_mqtt_loop(client);
  • 定义应用层事件回调,on_messages回调函数用于应用层接收 SDK 事件通知,如数据功能点(DP)下发,云端连接状态通知。平台下发指令在此函数中实现。
void on_messages(tuya_mqtt_context_t* context, void* user_data, const tuyalink_message_t* msg)

    char json_relay_state[255];
    TY_LOGI("on message id:%s, type:%d, code:%d", msg->msgid, msg->type, msg->code);
    switch (msg->type) 
        case THING_TYPE_MODEL_RSP:
            TY_LOGI("Model data:%s", msg->data_string);
            break;

        case THING_TYPE_PROPERTY_SET:
            TY_LOGI("property set:%s", msg->data_string);
            break;

        case  THING_TYPE_PROPERTY_REPORT_RSP:
           break;

        case THING_TYPE_ACTION_EXECUTE:
              TY_LOGI("action execute:%s", msg->data_string);
              if(write_file(msg->data_string) == 0)
                 
                    printf ("write ok\\r\\n");
                    printf ("data_string:%s\\r\\n",msg->data_string);
                 
             else
                
                    printf ("write error\\r\\n");
                
                 if(read_file(1,json_relay_state) == 0)
                 
                   sprintf(msg->data_string,"%s",json_relay_state);
                   printf("json_relay_state:%s\\r\\n",json_relay_state);
                   tuyalink_thing_property_report(context, NULL, msg->data_string);  
                   memset(json_relay_state, 0, sizeof(json_relay_state));      
                 
                 else
                 
                  printf ("read relay_state error\\r\\n");
                      
            break;   

        default:
            break;
    
    printf("\\r\\n");

  • THING_TYPE_ACTION_EXECUTE主题中,树莓派网关从平台上获取的指令(json格式)存入文件中,供python端调用(python端处理后控制继电器动作)。树莓派网关同时从相应文件中读取设备数据值(python端获取设备值,处理成json格式存入文件中供c端调用),C端处理成json格式的字符串上报到云端。
 case THING_TYPE_ACTION_EXECUTE:
              TY_LOGI("action execute:%s", msg->data_string);
              if(write_file(msg->data_string) == 0)
                 
                    printf ("write ok\\r\\n");
                    printf ("data_string:%s\\r\\n",msg->data_string);
                 
             else
                
                    printf ("write error\\r\\n");
                
                 if(read_file(1,json_relay_state) == 0)
                 
                   sprintf(msg->data_string,"%s",json_relay_state);
                   printf("json_relay_state:%s\\r\\n",json_relay_state);
                   tuyalink_thing_property_report(context, NULL, msg->data_string);  
                   memset(json_relay_state, 0, sizeof(json_relay_state));      
                 
                 else
                 
                  printf ("read relay_state error\\r\\n");
                      
            break;   
  • 网关发现子设备,请求云端激活子设备并建立topo关系。适用于设备无法预先在云端注册,也无法烧录,网关发现子设备后,请求云端注册并绑定到当前网关下。在mqtt连接成功回调函数里面绑定了三个子设备,子设备的productId从平台上获取;nodeId是设备的节点id(至少保证网关下唯一,可以是子设备的地址);clientId是设备端唯一id(子设备硬件的唯一标示,可以是设备的 uuid、mac、sn等,至少保证产品下唯一)。

  • 在mqtt连接成功回调函数中创建了一个子线程。


线程函数具体实现功能:用于不断获取温湿度的数据以及门磁状态的数据,同时上报到云平台。

//写一个线程函数 void *函数名(void *arg)
void *thread_worker1(void *arg) 
  
    char json_temp_hum[255];
    char json_door_state[255];
    char json_data[255];
    char json_data1[255];
        while(1)
          
            if(read_file(2,json_data) == 0)
            
                sprintf(json_temp_hum,"%s",json_data);
                printf("json_temp_hum:%s\\r\\n",json_temp_hum);
                tuyalink_thing_property_report_with_ack(arg, NULL, json_temp_hum);
                memset(json_data, 0, sizeof(json_data));  
                
            
            else
            
                printf("read temp_hum error\\r\\n");

            
            if(read_file(3,json_data1) == 0)
            
                sprintf(json_door_state,"%s",json_data1);
                printf("json_door_state:%s\\r\\n",json_door_state);
                tuyalink_thing_event_trigger(arg, NULL, json_door_state); 
                memset(json_data1, 0, sizeof(json_data1));  
            
            else
            
                printf("read door_state error\\r\\n");

            
            sleep(2); 
          

  • 下面是读文件函数,主要用于读取python端获取子设备的数据值,然后放于数组 return_data中。read_file函数传入了两个参数,一个是num,用于区分读取的文件(三个文件分别存入三个不同设备的数据值);另外一个是数组return_data,用于存储读取文件的数据(供c端调用)。
   //读文件
int read_file(int num,char return_data[])

    FILE *fp = NULL;
  switch (num)
   
    case 1:
        fp = fopen("/tmp/1.txt", "r");
        if(fp == NULL)
        
           printf("open /tmp/1.txt error!\\n");
           return 0;
        
        fgets(return_data, 255, (FILE*)fp);
        fclose(fp);
        break;
    case 2:
        fp = fopen("/tmp/2.txt", "r");
        if(fp == NULL)
        
           printf("open /tmp/2.txt error!\\n");
           return 0;
        
        fgets(return_data, 255, (FILE*)fp);
        fclose(fp);
        break;
    case 3:
        fp = fopen("/tmp/3.txt", "r");
        if(fp == NULL)
        
           printf("open /tmp/3.txt error!\\n");
           return 0;
        
        fgets(return_data, 255, (FILE*)fp);  
        fclose(fp); 
        break;
    default:
        break;
    
    printf("return_data:%s\\n",return_data);
    return 0;

  • 下面是写文件函数,主要存储从云端获取的指令,然后供python端调用。
//写文件
int write_file(char str[])

    FILE *fp = NULL; 
    fp = fopen("/tmp/from_platform.txt", "w");
    fprintf(fp, "%s", str);
    fclose(fp);
    printf("deviceid_action_time: %s\\n", str); 
    return 0;

(4)调试过程中注意点

  • 如果调试过程中报段错误,首先应该想到段错误的定义,从它出发考虑引发错误的原因。

a.在使用指针时,定义了指针后记得初始化指针,在使用的时候记得判断是否为NULL。

b.在使用数组时,注意数组是否被初始化,数组下标是否越界,数组元素是否存在等。

c.在访问变量时,注意变量所占地址空间是否已经被程序释放掉。

d.在处理变量时,注意变量的格式控制是否合理等。

  • 在调试的过程中由于没有对打开文件为空时进行处理,导致出现了段错误,后面如下图修改解决了此问题。

2、485子设备通信

(1)程序设计简单概述

​ 树莓派和485子设备通信采用python语言来编写的。

(2)程序设计逻辑分析

在new_temp_hum_door.py文件中实现整个控制逻辑:

  • 温湿度和门磁状态获取函数里面引用类(从new_relay_control文件中引用relay ),执行相应的控制逻辑;While循环读取文件中存储的数据(平台下发的指令,json格式),指令解析之后,控制继电器动作以及循环获取温湿度数据和门磁的状态,处理成json格式的字符串存入文件中(供c端读取)。
# -*- coding: utf-8 -*-
from new_relay_control import relay
from time import sleep
import json

#温湿度获取
def temp_hum_sensor_get():
    temp_hum = relay()
    temp_hum.all_relay = 3
    temp_hum.relay_all_on_order = ['01 04 00 00 00 02 71 CB']
    return_str = temp_hum.ALL_ON()
    return return_str

#门磁状态获取
def door_sensor_get():
    door_sensor = relay()
    door_sensor.all_relay = 3 
    door_sensor.relay_all_on_order = ['FE 01 00 00 00 02 A9 C4']
    return_str = door_sensor.ALL_ON()
    return return_str

id_value = 2
time = 1

while True:
    try:
        #读文件(读平台下发的指令)
        fp = open('/tmp/from_platform.txt', 'r')
        str_read = fp.read()
        # "inputParams":"relay_action":true,"actionCode":"relay"
        recv_json = json.loads(str_read)
        relay_action = recv_json['inputParams']['action']
        action_code = recv_json['actionCode']
        print(relay_action)
        print(action_code)
        print("read from platform: %s " % str_read)
        print("data type: %s" % (type(str_read)))



        if action_code == "relay":
            relay_open = relay()
            if relay_action == True:
                return_str = relay_open.ALL_ON()
            else:
                return_str = relay_open.ALL_OFF()

            relay_str = return_str[8:12]
            upload_to_platform = 0
            print(relay_str)
            if relay_str != "0000":
                upload_to_platform = 1

            string = "\\"actionCode\\": \\"relay\\", \\"actionTime\\": 1626197189630,\\"outputParams\\": \\"relaystate\\":0"
            new_json = json.loads(string)
            new_json['outputParams']['relaystate'] = upload_to_platform
            final_str3 = json.dumps(new_json)
            print(final_str3)

            f = open('/tmp/1.txt', 'w')
            f.write(final_str3)
            f.close()

    except FileNotFoundError:
            print ("File is not found")

    if id_value == 2:
        return_str = temp_hum_sensor_get()
        print(return_str)
        get_str1 = return_str[6:10]
        get_str2 = return_str[10:14]
            
        try:
            # temp_value = (int(get_str1, 16))/10
            temp_value = int(get_str1, 16)
            # hum_value = (int(get_str2, 16)) / 10
            hum_value = int(get_str2, 16)
        except ValueError:
            pass    
      
        print(temp_value)
        print(hum_value)
        print(get_str1)
        print(get_str2)

        string1 = "\\"temp\\":\\"value\\":\\"temp_value\\",\\"time\\":1631708204231,\\"hum\\":\\"value\\":\\"hum_value\\",\\"time\\":1631708204231"
        new_json1 = json.loads(string1)
        new_json1['temp']['value'] = temp_value
        new_json1['hum']['value'] = hum_value
        final_str4 = json.dumps(new_json1)
        print(final_str4)

        f = open('/tmp/2.txt', 'w')
        f.write(final_str4)
        f.close()


    #if id_value == 3:
        return_str = door_sensor_get()
        get_str3 = return_str[6:8]
        door_upload_to_platform = 0
        if get_str3 == "00":
           door_upload_to_platform = 0
        else:
           door_upload_to_platform = 1

        string2 = "\\"eventCode\\":\\"door\\",\\"eventTime\\":1626197189630,\\"outputParams\\":\\"doorsate\\":0"
        new_json2 = json.loads(string2)
        new_json2['outputParams']['doorsate'] = door_upload_to_platform
        final_str5 = json.dumps(new_json2)
        print(get_str3)
        print(final_str5)
        f = open('/tmp/3.txt', 'w')
        f.write(final_str5)
        f.close()
    sleep(time)
  • 使用class定义类,实现继电器的控制逻辑。类里面定义了串口收发的函数relay_send(self, send_order)以及继电器打开与关闭的控制逻辑。
# -*- coding: utf-8 -*-
import RPi.GPIO as GPIO
import serial
from time import sleep

'''2路继电器开关控制函数,单独继电器开关控制和全部开关控制'''
    
class relay(object):
    def __init__(self):
        self.relay_all_on_order = ['02 05 00 00 FF 00 8C 09', '02 05 00 01 FF 00 DD C9', '02 0F 00 00 00 08 01 FF FE C0']
        self.relay_all_off_order = ['02 05 00 00 00 00 CD F9', '02 05 00 01 00 00 9C 39', '02 0F 00 00 00 08 01 00 BE 80']
        self.relay1 = 1
        self.relay2 = 2
        self.all_relay = 3
        self.port = '/dev/ttyAMA0'
        
    def relay_send(self, send_order):

       if self.port:
           relay_serial = serial.Serial(self.port, 9600)
           GPIO.setmode(GPIO.BCM)
           GPIO.setup(17, GPIO.OUT)
           if not relay_serial.isOpen():
               relay_serial.Open()
           while True:
               GPIO.output(17, GPIO.HIGH)
               sleep(0.01)
               relay_serial.write(bytes.fromhex(send_order))
               #relay_serial.write(bytes(send_order))
               sleep(0.01)
               GPIO.output(17, GPIO.LOW)
               count = relay_serial.inWaiting()
               if count > 0:
                   GPIO.output(17, GPIO.LOW)
                   sleep(0.01)
                   recv = relay_serial.read(count)
                   GPIO.output(17, GPIO.HIGH)
                   sleep(0.01)
                   print("recv: ", recv)
                   # recv_bytes = binascii.b2a_hex(recv)
                   # recv_str = binascii.b2a_hex(recv_bytes).decode('utf-8')
                   recv_str = str(recv.hex())
                   print("recv_str: ", recv_str)
                   print("recv_str: ", recv_str)
                   if recv_str == "00":
                        print("error")
                   else:
                        return recv_str
               sleep(0.5)
               #relay_serial.close()

    def ALL_ON(self):
        send_order = self.relay_all_on_order[self.all_relay - 3]
        print(send_order)
        get_return = self.relay_send(send_order)
        print("继电器控制: ALL_RELAY_ON")
        return get_return

    def ALL_OFF(self):
        send_order = self.relay_all_off_order[self.all_relay - 3]
        get_return = self.relay_send(send_order)
        print("继电器控制: ALL_RELAY_OFF")
        return get_return

    def RELAY1_ON(self):
        send_order = self.relay_all_on_order[self.relay1  - 1]
        get_return = self.relay_send(send_order)
        print("继电器控制: RELAY1_ON")
        return get_return

    def RELAY1_OFF(self):
        send_order = self.relay_all_off_order[self.relay1 - 1]
        get_return = self.relay_send(send_order)
        print("继电器控制: RELAY1_OFF")
        return get_return

    def RELAY2_ON(self):
        send_order = self.relay_all_on_order[self.relay2 - 1]
        get_return = self.relay_send(send_order)
        print("继电器控制: RELAY2_ON")
        return get_return

    def RELAY2_OFF(self):
        send_order = self.relay_all_off_order[self.relay2 - 1]
        get_return = self.relay_send(send_order)
        print("继电器控制: RELAY2_OFF")
        return get_return

if __name__ == "__main__":
    relay = relay()
    relay.port = '/dev/ttyAMA0'

(3)调试过程中注意点

子设备通信程序需要在python3以上版本进行编译运行,如果低版本,编译运行时会报错。

有些写法,低版本的不支持。例如下面写法,python2.7版本会报错,python3以上版本则不会。

        temp_value = int(get_str1, 16)
        hum_value = int(get_str2, 16)

下面编码声明在python3以上版本则不用,在低版本需要声明,不然运行会报错。

# -*- coding: utf-8 -*-

下面写法同样在python3以上版本适用,在低版本中则不支持,不然运行会报错。

 recv_str = str(recv.hex())

若出现下面读文件错误,导致编译运行中断,则是由于当文件不存在时,没有进行异常处理。(由于收到平台指令开始创建文件的,所以没有指令下发时,文件则没有创建,导致运行python端程序时会报错)

可以参照下图进行解决:(添加捕获异常处理)

七、编译执行(linux)

1、安装 make 等相关环境依赖。

sudo apt-get install make cmake 

2、新建一个文件夹开始编译。

mkdir build && cd build
cmake ..
make


3、运行 Demo。

./bin/data_model_basic_demo


4、在设备端查看运行接口。
以下日志显示设备与 Tuya 云连接成功。

5、设备成功连接到涂鸦云平台后,单击进行刷新,设备状态会显示为在线。

八、在线调试

(1)在平台上查看上报的消息以 及对设备下发相应指令


2、温湿度值上报云平台(属性)

数据有没有上报成功,看code值:

3、门磁设备上报数据到云平台(事件)

数据有没有上报成功,看code值:

4、平台下发指令,继电器动作(动作)

九、结果展示

十、注意事项

硬件注意事项:

(1)树莓派的引脚短路,特别是VCC和GND,短路会造成芯片烧毁无法恢复。

(2)树莓派启动需要几十秒时间,打开电源后1分钟内不可以关闭电源,会影响树莓派的使用寿命。

(3)SD卡烧录系统完成时,系统会提示格式化,此时不需要格式化,点击取消即可。若点了格式化后树莓派会提示缺失文件,需要重新烧录系统。

(4)树莓派4B的HDMI接口变成两个micro-HDMI接口(hdmi0和hdmi1),可以接入两个显示器。如果只连接一个显示器,一定要插入hdmi0接口,也就是靠近type-C电源接口的那一个,才可以正常显示;如果只插入hdmi1接口,会出现显示器无法显示的情况。

注意!!hdmi线反接会导致接口损坏!!!

(5)拆插设备前需要先断电。

软件注意事项:

(1)由于树莓派跑了两个进程,因此整个过程中需要两个程序同时运行。

(2)软件调试过程中其它注意事项已在“程序设计”中具体指出。

以上是关于树莓派如何与物联网平台交互(搭建一个树莓派网关)的主要内容,如果未能解决你的问题,请参考以下文章

markdown 树莓派零usb + wlan双网络添加网关联网

树莓派编译安装 EMQ 服务器

《树莓派4B家庭服务器搭建指南》第七期:使用树莓派解锁网易云灰色音乐

阿里云物联网平台体验(树莓派+Python篇)

阿里云物联网平台体验(树莓派+Python篇)

环境搭建--使用pytharm远程调试树莓派