用LoRa實現的物聯網應用,到底好在哪里?


騰訊雲loT應用創新大賽自開啟以來,收到了眾多小伙伴們的投稿作品,本文是對其中的一篇優秀作品的摘錄。LoRa作為一種遠距離無線電技術,具有功耗低、傳播距離遠等優點,適合部署在機房、智慧建築等物聯網應用中。本期讓我們跟隨文章作者,通過LoRa技術實現對機房的環境檢測與控制。

點擊視頻鏈接,查看詳情

PPT講解+實驗演示+機房現場測試

一、概述
 

LoRa是semtech公司創建的低功耗局域網無線標准,我們知道,低功耗一般很難覆蓋遠距離,而遠距離一般功耗高,LoRa的名字翻譯就是遠距離無線電(Long Range Radio),它最大特點就是在同樣的功耗條件下比其他無線方式傳播的距離更遠,實現了低功耗和遠距離的統一,它在同樣的功耗下比傳統的無線射頻通信距離擴大3-5倍。

 

LoRa在物聯網應用中的無線技術有多種,可組成局域網或廣域網。LoRa網絡主要由終端(可內置LoRa模塊)、網關(或稱基站)、Server和雲四部分組成。

 

LoRaWAN的數據傳輸速率范圍為0.3 kbps至37.5 kbps,為了最大化終端設備電池的壽命和整個網絡容量,LoRaWAN網絡服務器通過一種速率自適應(Adaptive Data Rate , ADR)方案來控制數據傳輸速率和每一終端設備的射頻輸出功率。

 

二、方案設計
 

本案例將通過LoRa技術實現對機房的環境檢測與控制。

 

一般情況下,一個企業的機房很少連接網絡,即使連接網絡了,也要花費不小的費用進行設備和線路的安裝。例如使用寬帶時要走網線,距離短,機房少可能還好,如果機房較多,距離較長,那么安裝成本和人工成本就會迅速增加。如果安裝無線路由器,方法雖然可行,但是穿透力差,信號有時連接不上,想要增強信號,就要增加設備。

 

至於NB模組,如果信號良好,會是不錯之選。目前仍然有許多城市或者鄉鎮沒有覆蓋NB-IoT信號。所以NB模組適用於一些大城市。我們要想知道是否覆蓋物聯網信號,就看這個城市是否有共享單車。比如我所在的海南省,除了地級市,其他縣級市基本沒有覆蓋物聯網,因為那里沒有共享單車。

 

LoRa有遠距離、低功耗以及低成本等優勢。LoRa的傳輸距離范圍長達15至20公里,低功耗的特性延長了電池使用壽命,免牌照的頻段、基礎設施以及節點/終端的低成本,以上特性都使LoRa的使用成本大幅降低。

 

所以就機房或者整棟建築大樓這個特定區域來講,采用LoRa技術來實現對機房的環境參數的采集與控制是最節省資源的辦法。它的穿透力適合布局到整個辦公大樓。從而把它變成智慧建築是可行的。

 

LoRa網絡拓補圖

 

設計框架

 

智慧建築

 

三、方案實現

 

首先參考教程基於 TencentOS tiny 的 LoRaWAN 開發入門指南[1] 的介紹完成開發環境搭建,包括 MDK 軟件的安裝及配置、ST-Link 驅動安裝、串口軟件的安裝。

 

1. 硬件設計

 

(1)LoRa套件

 

本方案采用P-NUCLEO-LRWAN3套件,包括網關和節點,可用於評估LoRaWAN網絡。使用該套件,用戶可以輕松設置LPWAN網絡,幫助用戶學習LoRaWAN技術,了解如何在自己的應用程序中使用LoRaWAN技術。LoRa網關套件由ST Nucleo-F746ZG底板和瑞興恆方基於SX1301的LRWAN_GS模塊組成。

 

ST Nucleo LoRa節點套件由LRWAN_NS1擴展板和ST Nucleo-L073底板組成。其中 LRWAN_NS1擴展板集成瑞興恆方的RHF0M003 LoRaWAN模組,並集成了溫濕度傳感器HTS221、氣壓傳感器LPS22HB、3軸磁力傳感器LIS3MDL、6軸姿態傳感器LSM6DS3共4個I2C傳感器件。

 

LoRa節點采集的數據通過LoRa網關將數據上傳到物聯網雲平台,實現對終端設備的控制和數據監控。

 

LoRa套件

 

(2)LCD顯示

 

液晶屏是ST7735R,用於顯示實時采集的數據。例如溫度度,壓強,海拔等,以及控制的狀態指示。采用模擬I2C的方式來實現寫指令。

 

LCD顯示采集的數據和控制狀態

 

(3)繼電器設計

 

繼電器模塊主要用於220V交流電的開關,實現對電機或電燈的電源控制。電路中采用的是光耦進行電氣隔離,防止回流時對MCU的沖擊。依據這個電路,可以擴展出多路繼電器,實現控制各類設備。

 

繼電器電路

 

繼電器電路實物

 

(4)E53模塊應用

 

采用E53 SC1模塊,我是從小熊派物聯網開發套件中拿來用的。這個擴展模塊集成有LED路燈,光照強度傳感器BH1750以及EEPROM芯片24Cxx。我的設計思想是,通過光照強度傳感器檢測機房亮暗度來決定是否開啟應急燈的充電或開啟機房燈光,保證應急搶修的需要。同時把相關控制信息存儲到EEPROM,實現歷史記錄的查詢。以下是模塊原理圖:

 

擴展模塊接口原理圖

 

光照強度傳感器原理圖

 

EEPROM原理圖

 

E53智慧路燈擴展模塊

 

(5)LoRa節點整體外觀

 

右邊的兩個黑色按鍵和開發板上的藍色按鍵分別實現LED路燈、繼電器和LCD背光的本地控制。設計思路是脫離網絡方便本地控制。

 

各個模塊拼湊起來的LoRa控制電路

 

2. 軟件設計

 

(1)LoRa源碼實現

 

該套件可以很快實現上雲,通過官方提供的教程LoRa 溫濕度傳感器接入指引[2],打通數據連接,隨后就是修改TencentOS tiny源碼中的LoRa案例。

 

以下是需要要上報雲端的參數,需要注意的是參數的順序要和雲端解析順序一致,否則會解碼失敗而讀到錯誤的數據。

 

uint16_t report_period = 1;
 bool    report_power_switch=0;
 bool    report_motor_fan=0; 
 float   report_pressure=0;
 float   report_height=0;
 float   first_pressure=0;
 float   first_height=0;
 extern float pressure_hPa;
 extern float temperature_degC;
 extern float height;
​ typedef struct device_data_st {    
     uint8_t     temperature;
     uint8_t     humidity;
     uint16_t    period; 
     unsigned int quantity;
     bool   power_switch;
     bool   motor_fan;
     float  pressure;
     float  height;
} __PACKED__ dev_data_t; 

 

以下是按鍵任務,功能是進行普通的按鍵掃描,檢測到相應按鍵后進行相應控制,同時把相關的控制狀態通過LCD顯示出來並反饋到雲端。

void key_task(void *arg){  
   int lcd_back_flag=1;  
   while(1)  {    
        tos_task_delay(10); 
        if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==GPIO_PIN_RESET)    
          {        
               tos_task_delay(100);
               if(HAL_GPIO_ReadPin(KEY1_GPIO_Port,KEY1_Pin)==GPIO_PIN_RESET) 
                 {              
                      lcd_back_flag=~lcd_back_flag; 
                      if(lcd_back_flag==1)         
                         {                    
                              LCD_LED_CLR;//關閉LCD背光 
                        }         
                       else          
                          {                   
                              LCD_LED_SET;//開LCD背光  
                         }       
                   }    
             }    
          if(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin)==GPIO_PIN_RESET)   
             {        tos_task_delay(100);
                      if(HAL_GPIO_ReadPin(KEY2_GPIO_Port,KEY2_Pin)==GPIO_PIN_RESET)
                        {                 
                           if(report_power_switch==1)         
                              {                        
                                   report_power_switch=0;    
                                   HAL_GPIO_WritePin(LD2_GPIO_Port,LD2_Pin,GPIO_PIN_RESET); 
                                   printf("LED OFF: %d\n",report_power_switch);
                                   Gui_DrawFont_GBK16(5,125,RED,BLACK ,(uint8_t*)"LED:OFF"); 
                               }           
                            else            
                               {                      
                                    report_power_switch=1;
                                    HAL_GPIO_WritePin(LD2_GPIO_Port,LD2_Pin,GPIO_PIN_SET);
                                    printf("LED OFF: %d\n",report_power_switch);
                                    Gui_DrawFont_GBK16(5,125,GREEN,BLACK ,(uint8_t*)"LED:ON");
                               }        
                         }    
               }    
         if(HAL_GPIO_ReadPin(KEY3_GPIO_Port,KEY3_Pin)==GPIO_PIN_RESET) 
               {        tos_task_delay(100);  
                        if(HAL_GPIO_ReadPin(KEY3_GPIO_Port,KEY3_Pin)==GPIO_PIN_RESET)  
                          {                 
                              if(report_motor_fan==1)          
                                {                         
                                     report_motor_fan=0; 
                                     HAL_GPIO_WritePin(MOTOR_GPIO_Port,MOTOR_Pin,GPIO_PIN_RESET);
                                     printf("motor_fan OFF: %d\n", report_motor_fan); 
                                     Gui_DrawFont_GBK16(5,140,RED,BLACK,(uint8_t*)"Motor:OFF  "); 
                                }          
                              else           
                                {                    
                                     report_motor_fan=1;
                                     HAL_GPIO_WritePin(MOTOR_GPIO_Port,MOTOR_Pin,GPIO_PIN_SET); 
                                     printf("motor_fan ON: %d\n", report_motor_fan);  
                                     Gui_DrawFont_GBK16(5,140,GREEN,BLACK,(uint8_t*)"Motor:ON  ");  
                                 }       
                           }     
                   }  
              }
       } 

 

主任務函數,該任務實現LoRa連接到網關,檢測連接狀態,定時上報數據以及一些需要換算的參數。

 

void application_entry(void *arg)
    {  
        printf("APP RUNNING...\r\n");
        float report_temperature;
        int16_t  temperature;
        int16_t report_humidity;
        unsigned int quantity=0;
        uint16_t sum1=0;
        char temp[]={0};
        Lcd_Init();
        LCD_LED_SET;
        Lcd_Clear(BLACK);
        Gui_DrawFont_GBK16(10,5,RED,BLACK ,"TencentOS Tiny");
        Gui_DrawFont_GBK16(10,20,YELLOW,BLACK,"LoRa Node NO.1");
        LPS22HB_Init(); 
        HTS221_Init();
        #ifdef LORA_REPORT  Gui_DrawFont_GBK16(5,35,RED,BLACK,"LoRa Linking...");
        rhf76_lora_init(HAL_UART_PORT_1);
        tos_lora_module_recvcb_register(recv_callback);  
        if(tos_lora_module_join_otaa("8cf957200000f87e", "8cf957200000f87e9239aaaaad204a72")==-1) 
           {         
                Gui_DrawFont_GBK16(5,35,RED,BLACK,  " Link GW Error!   ");
                report_period=60;       
           }   
        else 
           {         
                Gui_DrawFont_GBK16(5,35,GREEN,BLACK," Link GW OK!     "); 
           }   
        Gui_DrawFont_GBK16(5,125,RED,BLACK,"LED:OFF        ");
        Gui_DrawFont_GBK16(5,140,RED,BLACK,"Motor:OFF  ");
        #endif   example_main_one_shot_lps22hb();
        first_pressure=pressure_hPa;
        first_height=height; 
        while (1)   
           { 
                printf("------LoRawan sensor board data------\n");
                Gui_DrawFont_GBK16(5,50,YELLOW,BLACK,"---------------");
                example_main_one_shot_lps22hb();
                HTS221_Get_Temperature(&temperature); 
                HTS221_Get_Humidity(&report_humidity); 
                report_temperature= temperature_degC; 
                report_height=(height-first_height)*1000;
                if(pressure_hPa<0)       
                report_pressure=-pressure_hPa*100;
                else       
                report_pressure=pressure_hPa*100; 
                sprintf(temp,"Temp:%2.1f   ",report_temperature);
                Gui_DrawFont_GBK16(5,65,WHITE,BLACK,temp);
                sprintf(temp,"Humi:%2.1f     ", report_humidity / 10.0);
                Gui_DrawFont_GBK16(5,80,WHITE,BLACK,temp);
                sprintf(temp,"Pa:%2.2f    ",pressure_hPa);
                Gui_DrawFont_GBK16(5,95,WHITE,BLACK,temp);
                sprintf(temp,"Height:%d    ", (int)report_height);
                Gui_DrawFont_GBK16(5,110,WHITE,BLACK,temp); 
                printf("LPS22HB_pressure[hPa]:%0.2f,height[mm]:%d\r\n", pressure_hPa,(int)report_height);
                printf("LPS22HB_temperature [degC]:%0.2f\r\n",report_temperature);
                printf("HTS221_temperature : %2.1f\n", temperature/10.0);
                printf("HTS221_humidity    : %2.1f\n", report_humidity / 10.0); 
                sum1++; 
                printf("sum:%d\r\n",sum1); 
                tos_task_delay(500); 
                #ifdef LORA_REPORT       if(sum1>=report_period) 
                    {                        
                        sum1=0;
                        quantity++;  
                        printf("quantity    : %d\n", quantity); 
                        printf("LED_Status  : %d\n",report_power_switch);
                        printf("motor_Status: %d\n",report_motor_fan); 
                        dev_data_wrapper.u.dev_data.temperature = report_temperature; 
                        dev_data_wrapper.u.dev_data.humidity    = report_humidity / 10; 
                        dev_data_wrapper.u.dev_data.period      = report_period; 
                        dev_data_wrapper.u.dev_data.quantity    = quantity; 
                        dev_data_wrapper.u.dev_data.power_switch= report_power_switch; 
                        dev_data_wrapper.u.dev_data.motor_fan   = report_motor_fan; 
                        dev_data_wrapper.u.dev_data.pressure    = report_pressure; 
                        dev_data_wrapper.u.dev_data.height      = report_height;  
                        tos_lora_module_send(dev_data_wrapper.u.serialize, sizeof(dev_data_t)); 
                    }   
              #endif     
         }
    }

 

(2)雲平台實現

登陸iotexplorer平台即可快速創建LoRa項目

建立項目

 

定義屬性

 

數據解析

 

實時查看數據變化

 

(3)微信小程序實現

 

小程序集成了LoRa設備和NB設備,這樣就可以切換頁面查看並控制不同終端設備。這個小程序是通過官方提供demo進行二次開發的。

 

小程序主頁面

 

LoRa模組小程序頁面

 

NB模組小程序頁面

 

四、總結
 

利用LoRa極強的穿透力,實現對樓層中的機房環境進行監控。它安裝方便,節省了人力物力和財力。所以LoRa物聯網應用於機房或建設智慧建築有先天的優勢。如果使用NB模組,每年都要換卡或者繳費。使用WIFI設備呢,穿透力不夠強,距離沒有LoRa傳輸得遠。

 

本案例需要增強改進的地方是,檢測機房斷路器通斷,交流接觸器動作等器件的工作狀態。也可以直接和PLC控制器進行通訊,直接讀取PLC采集的數據,然后通過LoRa上傳數據。

 

參考資料:

[1] 基於 TencentOS tiny 的 LoRaWAN 開發入門指南:

https://github.com/Tencent/TencentOS-tiny/blob/master/doc/16.TencentOS_tiny_LoRaWAN_Getting_Started_Guide.md

 

[2] LoRa 溫濕度傳感器接入指引:

https://cloud.tencent.com/document/product/1081/41112?from=10680

 

[3] LoRa節點源碼和微信小程序源碼及PPT鏈接:

https://share.weiyun.com/5u2vejl 密碼:8szgyr  

 

[4] 源碼說明:源碼中需要搭配TencentOS tiny的框架,只需要覆蓋原來原來的lorawan案例的源碼和rhf76的頭文件。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM