Seeed의 LoRa-E5 모듈을 활용한 LoRaWAN 네트워크용 풍속/풍향 센서 개발하기

설명

이 프로젝트는 Seeed LoRa-E5 기반의 Arduino 풍속/풍향 센서를 개발하고 이를 디지키 본사 건물 지붕에 설치된 웨더 플랫폼에 부착할 수 있도록 실외용 케이스에 장착하는 과정을 다룹니다. LoRa 센서는 Seeeduino XIAO, Grove LoRa-E5 무선 기판, 그리고 Sparkfun의 Weather Meter Kit에 포함된 풍속계 및 풍향계 하드웨어를 사용합니다.
또한, 이 프로젝트는 기존의 ChirpStack 기반 전용 LoRaWAN 네트워크 및 Machinechat의 JEDI Pro IoT 소프트웨어 플랫폼에 센서 노드를 추가하는 과정도 다룹니다. LoRaWAN 네트워크는 Seeed의 IP67 등급 산업용 LoRaWAN 게이트웨이를 사용해 LoRa 센서 패킷을 우분투 리눅스가 설치된 Seeed ReServer에서 실행되고 있는 전용 ChirpStack LoRaWAN 네트워크 서버로 전달합니다. Machinechat의 JEDI Pro IoT 플랫폼 역시 동일한 ReServer에서 실행됩니다.

하드웨어

  • Seeed reServer
    reServer는 ODYSSEY X86 v2 기판을 기반으로 하며 Intel® Core™ 11세대 i3 프로세서와 Intel UHD Graphics 48EU로 구동
  • Seeed SenseCAP 실외용 게이트웨이 - LoRaWAN US915MHz
    SenseCAP LoRaWAN 게이트웨이는 LoRaWAN® 프로토콜을 기반으로 하며 환경 데이터의 저전력, 장거리 수집 및 모니터링에 적합
  • Seeed Grove LoRa-E5 기판
    STM32WLE5JC 및 SX126x LoRa RF 트랜시버를 탑재한 Grove 플랫폼 평가용 확장 기판
  • Seeed Seeeduino XIAO 기판
    32비트 ARM® Cortex®-M0 MCU인 SAMD21G18 칩을 탑재한 Seeeduino XIAO 시리즈 임베디드 평가 기판
  • Sparkfun Weather Meter Kit
    이 키트는 세 가지 핵심 기상 측정 요소인 풍속, 풍향 및 강우량을 측정할 수 있습니다.
    (참고: 본 프로젝트에서는 풍속계와 풍향계 센서를 사용합니다. 강우계 센서는 향후 다른 게시글에서 다뤄볼 예정입니다)

소프트웨어

  • JEDI Pro(Linux) 또는 JEDI Pro SSE주)
    IoT 데이터 수집, 시각화, 모니터링 및 저장을 위한 적응형 소프트웨어로, IoT 솔루션에 통합할 수 있습니다. 주요 기능에는 센서, 장치 및 기계로부터 데이터 수집, 직관적인 실시간 및 과거 데이터/시스템 관찰 대시보드 구축, 데이터 상태를 자동으로 감시하고 대응하는 규칙 생성, 그리고 이메일 및 SMS를 통한 경보 알림 수신 등이 있습니다. JEDI Pro SSE는 Seeed Studio Edition 버전의 JEDI Pro로 Seeed의 SenseCAP LoRaWAN 센서 제품군용 데이터 수집기가 추가된 버전입니다.
  • ChirpStack
    오픈 소스인 ChirpStack의 LoRaWAN 네트워크 서버 스택은 LoRaWAN 네트워크를 위한 오픈 소스 구성 요소를 제공합니다. 모듈형 아키텍처로 기존 인프라와 통합이 가능합니다.
  • Arduino
    Arduino는 사용하기 쉬운 하드웨어 및 소프트웨어 기반의 오픈 소스 전자 플랫폼입니다.

주) JEDI Pro SSE는 단종되었으며, 리눅스용 JEDI Pro(MC-JEDIPRO-LIN)는 현재 디지키에서 취급하고 있지 않습니다.

배경

이 게시글은 디지키에서 판매하고 있는 하드웨어와 소프트웨어를 사용하여 전용 LoRaWAN IoT 센서 네트워크를 구축하는 방법을 상세히 설명한 테크포럼 게시글 Machinechat과 Seeed SenseCAP을 활용한 전용 LoRaWAN 센서 네트워크 구축의 후속 프로젝트입니다. 해당 프로젝트에서는 Machinechat의 JEDI Pro 소프트웨어와 ChirpStack의 LoRaWAN 네트워크 서버 소프트웨어를 사용하였으며, 하드웨어로는 Seeed reServer x86 서버와 SenseCAP 실외용 LoRaWAN 게이트웨이를 사용하였습니다. 본 게시글에서는 LoRaWAN 네트워크를 통해 풍속과 풍향을 보고할 수 있도록 Seeeduino XIAO, Grove LoRa-E5 기판, 그리고 Sparkfun Weather Meter Kit을 설정하였습니다.

Sparkfun Weather Meter Kit 풍속/풍향계
풍속은 컵형 풍속계를 통해 측정하며, 바람이 컵을 움직이면 컵이 회전하면서 내부의 자석도 함께 회전하고, 자석이 회전할 때마다 리드 스위치의 접점이 닫히도록 설계되어 있습니다. 접점이 초당 1회 닫히면, 풍속으로는 2.4 km/h에 해당합니다. 접점이 닫히는 것은 풍속계 케이블의 RJ-11 커넥터 안쪽 두 개의 핀, 핀 2번과 3번을 통해 감시할 수 있습니다.
풍향계 내부에는 여덟 개의 리드 스위치가 각기 다른 저항을 통해 45도 간격으로 연결되어 있습니다. 풍향계 내부의 자석이 풍향에 따라 리드 스위치의 접점을 닫으며, 스위치들은 서로 가까이 위치해 있어서 두 개의 스위치가 동시에 닫힐 수도 있습니다. 외부 저항을 사용해 전압 분배 회로를 구성하면 출력 전압을 감시하여 풍향계의 위치를 판단할 수 있습니다. RJ-11 커넥터 바깥쪽 두 개의 핀, 핀 1번과 4번이 풍향 측정에 사용됩니다. 자세한 내용은 Sparkfun Weather Meter Hookup Guide에서 확인할 수 있습니다.

디지키 웨더 플랫폼
디지키 웨더 플랫폼에 대한 자세한 내용은 디지키의 웨더 플랫폼(Weather Platform)에서 확인할 수 있습니다.

구현

이 프로젝트에서는 외부 USB 5V 전원 공급 장치가 Seeeduino XIAO에 전원을 공급하며, XIAO의 3V3 출력이 Grove LoRa-E5 기판 및 풍속/풍향계에 전원을 공급합니다. XIAO의 UART는 Grove LoRa-E5의 TX/RX 핀에 연결하고, XIAO의 입력 핀 1과 2는 풍속/풍향계에 연결합니다.
XIAO와 LoRa-E5 기판을 실외용 케이스(부품 번호 RL6225)에 장착하고, +5V 전원과 풍속/풍향계는 M8 패널 장착형 커넥터와 케이블 조립품을 통해 케이스에 연결합니다.
LoRa-E5에 AT 명령을 전송하고 입력 핀 1과 2를 감시하기 위한 아두이노 응용 프로그램이 Seeeduino XIAO에서 실행됩니다. 이 응용 프로그램은 LoRa 네트워크에 접속하여, 입력 핀을 감시 및 풍속과 풍향을 계산하고, 해당 데이터를 CayenneLPP 형식으로 인코딩하여 LoRa를 통해 전송한 다음, 일정 시간 지연 후 처음으로 되돌아가 다음 측정을 수행합니다. 회로가 연결되고 구현된 방식을 아래 회로도에서 보여주고 있습니다(Scheme-it 프로젝트: LoRaE5_Xiao_WindSensorM8cables를 참고하십시오).

아래는 풍속/풍향계의 커넥터 J1과 모듈 사이의 전기적 연결을 보여줍니다:

Seeeduino XIAO 핀 Grove LoRa-E5 커넥터 풍속/풍향계 커넥터 J1
GND GND 1
3V3 VCC 2
1 4(풍향계)
2 3(풍속계)
6 RX
7 TX

Seeeduino XIAO, Grove LoRa-E5 및 풍속/풍향계 설정하기

1 - Seeeduino XIAO에 아두이노 환경을 설정합니다. 참조: Getting started with Seeeduino Xiao

2 - 응용 프로그램에 필요한 라이브러리를 설치합니다. 아두이노 IDE의 라이브러리 관리자를 통해 다음 라이브러리를 추가합니다:

3 - 코드 설명 (파일명: Xiao_LoraE5CayenneLPP_AnemRunAvg.ino)
초기 설정

// below code is based on Seeed LoRaE5 example code and modified to NOT use the display on the Seeeduino Xiao expansion board (just uses a Xiao connected to a LoRaE5 
// Grove expansion board. Seeed example code at https://wiki.seeedstudio.com/Grove_LoRa_E5_New_Version/
//
//note: all Seeed LoRaE5 Grove boards have example code App key of "2B7E151628AED2A6ABF7158809CF4F3C" so needs to be changed
// this version changes out the DHT11 sensor for Sparkfun weather meter kit for wind speed and direction

// Anemometer measuring code based on below:
//More Information at: https://www.aeq-web.com/
//Version 2.0 | 11-NOV-2020
//
//SBR modifications
//SensorPin is connected to RC pulldown circuit on anemometer switch
//Wind vane pin is connected to voltage divider circuit for vane resistors


#include <Arduino.h>
#include <CayenneLPP.h>


// anemometer and direction parameters
const int RecordTime = 3; //Define Measuring Time (Seconds)
const int SensorPin = 2;     // the number of the sensorpin
const int VanePin = 1;      // pin# connected to wind vane
const int ledPin =  13;      // the number of the LED pin
int InterruptCounter;
float WindSpeed;
float DirWind;   //wind direction voltage
float angleWind; //wind vane angle
  

CayenneLPP lpp(51);   //setup Cayenne LPP (low power payload) buffer - per documentation 51 bytes is safe to send
 
static char recv_buf[512];
static bool is_exist = false;
static bool is_join = false;
static int led = 0;

int buf_size;  //Cayenne LPP buffer payload size
int Pointer;   //pointer used in Cayenne LPP buffer
int Offset = 12;    //offset to where Cayenne LPP payload data starts
int Loop1;       //loop counter in LoRa payload builder
int Loop2;       //loop counter in LoRa payload builder
int Loop3 = 0;       //loop counter in LoRa parameter send

 
static int at_send_check_response(char *p_ack, int timeout_ms, char *p_cmd, ...)
{
    int ch;
    int num = 0;
    int index = 0;
    int startMillis = 0;
    va_list args;
    memset(recv_buf, 0, sizeof(recv_buf));
    va_start(args, p_cmd);
    Serial1.printf(p_cmd, args);
    Serial.printf(p_cmd, args);
    va_end(args);
    delay(200);
    startMillis = millis();
 
    if (p_ack == NULL)
    {
        return 0;
    }
 
    do
    {
        while (Serial1.available() > 0)
        {
            ch = Serial1.read();
            recv_buf[index++] = ch;
            Serial.print((char)ch);
            delay(2);
        }
 
        if (strstr(recv_buf, p_ack) != NULL)
        {
            return 1;
        }
 
    } while (millis() - startMillis < timeout_ms);
    return 0;
}
 
static void recv_prase(char *p_msg)
{  
    if (p_msg == NULL)
    {
        return;
    }
    char *p_start = NULL;
    int data = 0;
    int rssi = 0;
    int snr = 0;
 
    p_start = strstr(p_msg, "RX");
    if (p_start && (1 == sscanf(p_start, "RX: \"%d\"\r\n", &data)))
    {
        Serial.println(data);
        led = !!data;
        if (led)
        {
            digitalWrite(LED_BUILTIN, LOW);
        }
        else
        {
            digitalWrite(LED_BUILTIN, HIGH);
        }
    }
 
    p_start = strstr(p_msg, "RSSI");
    if (p_start && (1 == sscanf(p_start, "RSSI %d,", &rssi)))
    {
         Serial.println(rssi);
    }
    p_start = strstr(p_msg, "SNR");
    if (p_start && (1 == sscanf(p_start, "SNR %d", &snr)))
    {
        Serial.println(snr);
    }
}

 
void setup(void)
{
    Serial.begin(9600);
    pinMode(LED_BUILTIN, OUTPUT);
    digitalWrite(LED_BUILTIN, HIGH);

    // anemeometer and wind vane setup
    pinMode(SensorPin, INPUT); //use input to count interrupts of anemometer
    pinMode(VanePin, INPUT); //use input to read analog voltage of wind vane output
 
    Serial1.begin(9600);                  //UART serial1 connection to LoRaE5
    Serial.print("E5 LORAWAN TEST\r\n");
 
    if (at_send_check_response("+AT: OK", 100, "AT\r\n"))
    {
        is_exist = true;
        at_send_check_response("+ID: AppEui", 1000, "AT+ID\r\n");
        at_send_check_response("+MODE: LWOTAA", 1000, "AT+MODE=LWOTAA\r\n");
        //at_send_check_response("+DR: EU868", 1000, "AT+DR=EU868\r\n");  //original
        at_send_check_response("+DR: US915", 1000, "AT+DR=US915\r\n"); 
        //at_send_check_response("+CH: NUM", 1000, "AT+CH=NUM,0-2\r\n");  //original
        at_send_check_response("+CH: NUM", 1000, "AT+CH=NUM,8-15,65\r\n"); // configure channels to match chirpstack
        at_send_check_response("+KEY: APPKEY", 1000, "AT+KEY=APPKEY,\"2B7E151628AED2A6ABF7158809CF4F3C\"\r\n");
        at_send_check_response("+CLASS: C", 1000, "AT+CLASS=A\r\n");
        at_send_check_response("+PORT: 8", 1000, "AT+PORT=8\r\n");
        delay(200);
        is_join = true;
    }
    else
    {
        is_exist = false;
        Serial.print("No E5 module found.\r\n");
    }
 
}
 

메인 루프 - 풍속과 풍향을 계산하여, CayenneLPP 형식으로 인코딩한 후, LoRa 페이로드 데이터로 전송합니다.

void loop(void)
//void loop()
{
     
    // measure windspeed
    measure();
    // measure wind vane voltage
    DirWind = analogRead(VanePin)*3.33;
    // calculate wind direction in degrees
    vaneAngle();
    
    
    Serial.print("Windspeed: ");
    Serial.print(WindSpeed);
    Serial.print(" mph ");
    Serial.print("Wind Direction: ");
    Serial.print(angleWind);
    Serial.println(" degrees");


//***************** start of Cayenne LPP code **************************
    // due to character byte limitatations in LoRa payload buffer, need to alternate between 
    // the two wind parameters when sending out parameter payload
    
    Serial.print("Loop3 = ");  //debug code
    Serial.println(Loop3);    //debug code

    if (Loop3 == 0)
    {
      lpp.reset();
      lpp.addAnalogOutput(1, WindSpeed);  //channel 1, windspeed value
      Loop3 = 1;
    }
    else
    {
      lpp.reset();
      lpp.addAnalogOutput(2, angleWind);  //channel 2, wind direction value
      Loop3 = 0;
    }
   

    buf_size = lpp.getSize();
    Serial.print("Cayenne LPP buffer size = ");
    Serial.println(buf_size);

    uint8_t *payload = lpp.getBuffer();
    char cmd[128];
    
    // Lmsg is just test code that probably can be deleted?
    char Lmsg[4];
    for (unsigned char i = 0; i < lpp.getSize(); i++)
    {
      sprintf(Lmsg, "%02X", (char)payload[i]);
      Serial.print(Lmsg);
    }

    Serial.println(" payload"); 

//**************end of payload builder code**************************

    // start of LoRa communication code 
    if (is_exist)
    {
        int ret = 0;
        if (is_join)
        {
 
            ret = at_send_check_response("+JOIN: Network joined", 12000, "AT+JOIN\r\n");
            if (ret)
            {
                is_join = false;   //resets join check?
            }
            else
            {
                at_send_check_response("+ID: AppEui", 1000, "AT+ID\r\n");
                Serial.print("JOIN failed!\r\n\r\n");
                delay(5000);
            }
        }
        else
        {
            char cmd[128]; 
            //sprintf(cmd, "AT+CMSGHEX=\"%04X%04X\"\r\n", (int)temp, (int)humi); //original
            //****** add in CayenneLPP ecoding ******
            sprintf(cmd, "AT+CMSGHEX=\"%02X\"\r\n", (char)payload[0]);  //first part of confirmed message
            Serial.println("debug - print cmd at start of loop");
            Serial.println(cmd);
            // add data payload to LoRa message by looping thru Cayenne LPP data buffer
            char TestMsg[2];   
            for (Loop1 = 0; Loop1 < buf_size; Loop1++)
              {
                Pointer = (Loop1*2) + Offset;
                sprintf(TestMsg, "%02X", (char)payload[Loop1]);
                // write data buffer character to LoRa message
                for (Loop2 = 0; Loop2 < 2; Loop2++)
                  {
                     cmd[Loop2 + Pointer] = TestMsg[Loop2];
                  }
              }            
            // create end of message characters for LoRa message (need ",return,null characters)
            char EndMsg[20];
            sprintf(EndMsg, "test\"%02X\"\r\n", (char)payload[0]);
            // add ", return and null characters to end of LoRa message
            for (unsigned char i = 2; i < 7; i++)  
              {
                cmd[Pointer + i] = EndMsg[5 + i];
              }            
            Serial.println("debug - print cmd at end of loop");
            Serial.println(cmd);
            //******** end of CayenneLPP encodeding *********
            ret = at_send_check_response("Done", 12000, cmd);        //sends cmd command over LoRa - increase time from 5000 to 12000
            if (ret)
            {
                recv_prase(recv_buf);
            }
            else
            {
                Serial.print("Send failed!\r\n\r\n");
            }
            delay(5000); 
        }
    Serial.println(" in main loop checking LoRa then wait 5 minutes");   
    delay(300000); //main delay 300 seconds 
    }
    else
    {
        delay(1000);
    }
}

센서 서브루틴

//count anemometer pulses and calculate windspeed
void measure() {
  InterruptCounter = 0;
  attachInterrupt(digitalPinToInterrupt(SensorPin), countup, RISING);
  delay(1000 * RecordTime);
  detachInterrupt(digitalPinToInterrupt(SensorPin));
  WindSpeed = (float)InterruptCounter / (float)RecordTime * 2.4;
}

void countup() {
  InterruptCounter++;
}

//determine wind direction angle based on measured wind vane voltage
void vaneAngle() {
  angleWind = 99.9;
  if (DirWind < 270)
    {
      angleWind = 112.5;
    }
  else if ((DirWind >= 270) and (DirWind <= 310))
    {
      angleWind = 67.5  ;
    } 
   else if ((DirWind > 310) and (DirWind <= 400))
    {
      angleWind = 90.0  ;
    }    
  else if ((DirWind >= 400) and (DirWind < 600))
    {
      angleWind = 157.5  ;
    }    
  else if ((DirWind >= 600) and (DirWind < 750))
    {
      angleWind = 135.0  ;
    }    
  else if ((DirWind >= 750) and (DirWind < 850))
    {
      angleWind = 202.5  ;
    }    
  else if ((DirWind >= 850) and (DirWind < 1150))
    {
      angleWind = 180.0  ;
    }    
   else if ((DirWind >= 1150) and (DirWind < 1450))
    {
      angleWind = 22.5  ;
    }    
   else if ((DirWind >= 1450) and (DirWind < 1900))
    {
      angleWind = 45.0  ;
    }    
  else if ((DirWind >= 1900) and (DirWind < 2050))
    {
      angleWind = 247.5  ;
    }    
   else if ((DirWind >= 2050) and (DirWind < 2250))
    {
      angleWind = 225.0  ;
    }    
  else if ((DirWind >= 2250) and (DirWind < 2500))
    {
      angleWind = 337.5;
    }
  else if ((DirWind >= 2500) and (DirWind < 2700))
    {
      angleWind = 0.0;
    }
  else if ((DirWind >= 2700) and (DirWind < 2850))
    {
      angleWind = 292.5;
    }
  else if ((DirWind >= 2850) and (DirWind < 3000))
    {
      angleWind = 315.0;
    }
  else if (DirWind >= 3000)
    {
      angleWind = 270.0;
    }
}  

Xiao_LoraE5CayenneLPP_WindRev1.ino 응용 프로그램의 최신 소스 코드를 아래 GitHub 링크에서 확인하실 수 있습니다:

Grove LoRa-E5 기판의 장치 EUI 확인하기

아두이노에서 Xiao_LoraE5CayenneLPP_WindRev1.ino 코드를 컴파일해 Seeeduino XIAO로 업로드한 후 시리얼 모니터를 활성화합니다. 시리얼 모니터 출력을 확인하여 Grove LoRa-E5 기판의 장치 EUI를 확인합니다.

image

LoRa-E5 기반 센서 노드를 ChirpStack LoRaWAN 네트워크 서버에 추가하기

(참고: 이 프로젝트와 이하의 단계들은 ChirpStack 기반의 전용 LoRaWAN 네트워크가 활성화되어 있고 LoRa-E5 센서 노드의 통신 범위 내에 있는 것을 전제하고 있습니다. 그렇지 않은 경우, 테크포럼 게시글 Machinechat과 Seeed SenseCAP을 활용한 전용 LoRaWAN 센서 네트워크 구축을 참조하시기 바랍니다)

1 - ChirpStack에서, Device-profiles를 선택하고 Create를 누릅니다. Device-profile name은 "Seeed LoRaE5"로 지정하고, LoRaWAN MAC version은 "1.0.2"를, LoRaWAN Regional Parameters version은 "A"를, 그리고 ADR algorithm은 "Default ADR algorithm"을 선택하고, Uplink interval에는 "3600"을 입력합니다. JOIN(OTAA / ABP) 탭에서 “Device supports OTAA” 옵션을 체크합니다. CODEC 탭의 CODEC 드롭다운 목록에서 "Cayenne LPP"를 선택합니다.

2 - ChirpStack에서, Applications를 선택하고 Create를 누릅니다. Application name에 "FarmTest"를, Application description에는 "description"을 입력하고, Service-profile은 "STM32WL"를 선택합니다.

3 - ChirpStack에서, Applications를 선택한 다음 "FarmTest"를 선택하고 Create를 누릅니다. Device name에는 "LoRaE5wind"를, Device description에는 “description”을, Device EUI에는 위 “Grove LoRa-E5 기판의 장치 EUI 확인하기" 단계에서 확인된 Grove LoRa-E5 보드의 EUI를, Device-profile에는 "STM32WL Sensors"를 입력하고, CREATE DEVICE를 선택합니다. (참고: 초기 테스트 및 데모를 위해 Disable frame-counter validation 체크박스를 선택해 프레임 카운터 유효성 검사를 비활성화할 수 있습니다)

4 - 생성한 장치에 Application key를 추가합니다. KEYS(OTAA) 탭에서, Application key에 “2B7E151628AED2A6ABF7158809CF4F3C”(참고: 이는 LoRa-E5의 기본 키로, 변경하려면 LoRa-E5 AT Command Specification의 KEY 부분을 참고하십시오)를 입력하고 SET DEVICE-KEYS를 누릅니다.

ChirpStack의 HTTP 통합 기능을 설정하고 JEDI Pro용 Generic LoRaWAN Custom Data Collector 플러그인으로 테스트하기

LoRaWAN 메타와 센서 데이터를 지정된 IP 주소로 전달하기 위해 HTTP 통합 기능을 추가하도록 ChirpStack을 수정하였습니다. Machinechat의 Generic LoRaWAN Custom Data Collector 플러그인은 지정된 IP 주소로부터 데이터를 수신하고, (디버그가 활성화된 경우) 데이터를 검토하거나 JEDI Pro 플랫폼에서 사용하기 위해 LoRaWAN 데이터를 파싱하는 데 사용됩니다.
(참고: Custom Data Collector 플러그인은 lorawan-linux.bin 및 config.yml 두 파일로 구성되며, Machinechat의 다음 링크를 통해 제공됩니다: https://support.machinechat.io/hc/en-us/articles/6046199010327-Generic-LoRaWAN-Custom-Data-Collector-Beta-for-JEDI-PRO-Linux-x86)

1 - ChirpStack에서 HTTP 통합 활성화
ChirpStack에서, Applications를 선택한 다음 "FarmTest"를 선택하고 INTEGRATIONS 탭에서 HTTP 아래 "ADD"를 선택합니다.

2 - HTTP 통합 설정
Payload marshaler는 JSON을 선택하고, Endpoint URL에는 config.yml 파일에 설정된 IP 주소와 동일한 주소를 입력한 후, ADD INTEGRATION을 누릅니다.

3 - lorawan-linux.binconfig.yml 파일을 JEDI Pro가 설치된 Ubuntu Linux 미니 PC의 ~/jedi/plugins 디렉토리에 복사합니다. config.yml 파일을 수정하여 디버그를 활성화하고 IP 수신 주소를 지정합니다.
(참고: 기존에 다른 센서용으로 lorawan-linux.binconfig.yml 파일을 이미 설치하였다면, 5단계에서 설명한 대로 config.yml만 수정하여 풍속과 풍향 파라미터 정보를 추가하는 것입니다)

4 - Ubuntu Linux 미니 PC 터미널의 명령줄에서 "./lorawan-linux.bin ./config.yml"를 사용하여 Custom Data Collector 플러그인을 실행하고 출력 데이터를 확인합니다. 데이터는 아래와 유사하게 표시되어야 합니다(참고: lorawan-linux.bin 파일에 실행 권한을 부여해야 합니다):

5 - config.yml 파일을 편집하여 LoRaWAN 데이터를 JEDI Pro 데이터 파라미터에 매핑하고 디버깅을 비활성화합니다. 이 프로젝트 예제의 경우, LoRaWAN cSproperty: "anslogOutput.1"mcProperty: "WindSpeed"에 매핑되도록, 그리고 LoRaWAN cSproperty: "analogOutput.2"mcProperty: "WindAngle"에 매핑되도록 propertyNames을 편집합니다. 디버깅을 비활성화하기 위해 "setDebug:"를 false로 설정하고 파일을 저장합니다.

JEDI Pro용 Custom Data Collector 및 Data Dashboard 설정하기

JEDI Pro에서 “Settings” 탭을 선택한 다음, "Data Collectors"를 선택하고 "Add Collector"를 누릅니다.
(참고: 이전에 LoRaWAN Custom Data Collector를 JEDI 응용 프로그램에 추가한 적이 있다면 이 단계는 필요하지 않습니다)

아래와 같이 Collector를 설정합니다. Collector Name에는 “LoRaWAN” (또는 원하는 다른 이름)을 입력, Collector Type은 "Custom Plug-In"을 선택, Plug-In Executable은 “lorawan-linux.bin” 파일을 선택, Plug-in Options에는 config.yml 파일의 위치(예: “/home/scottr/jedi/plugins/config.yml”)를 입력, “Run As Background Process and Monitor” 체크박스를 선택한 다음, "VALIDATE PLUG-IN"을 눌러 기능을 확인합니다.

JEDI Pro에서 "Data Dashboards"를 선택한 다음, "+"를 눌러 새 차트를 추가합니다.

WindSpeed와 WindAngle에 대한 데이터 차트를 설정하고 "Add"를 눌러 Data Dashboard에 포함시킵니다(아래 예시 참조).

결론

Arduino, Seeeduino XIAO, LoRa-E5 무선 모듈, 그리고 Sparkfun의 weather meter kit 조합은 LoRa를 통해 풍속 및 풍향 데이터를 제공하는 유연하고 견고한 풍속 센서 플랫폼을 가능하게 합니다. 이후 IoT 데이터 수집, 시각화, 모니터링 및 데이터 저장을 위해 풍속 센서 데이터를 JEDI Pro로 전송할 수 있도록 ChirpStack의 HTTP 통합 기능과 Machinechat의 Generic LoRaWAN Custom Data Collector 플러그인을 설정하였습니다. 예제 코드는 필요에 따라 다른 센서에 맞게 쉽게 수정할 수 있습니다.

참고자료



영문 원본: Developing a Wind Speed/Direction Sensor using Seeed’s LoRa-E5 module for a LoRaWAN network