2023. 3. 8. 15:52ㆍ개발/Arduino
현재 연구팀에서 Lora 통신을 활용해
다양한 센서들을 웹 페이지에 등록하고
실시간 모니터링/제어 하는 시스템 구현중이다.
웹 페이지 등록전에
센서값을 일단 받아와야 한다.
보드는 위 Heltec WiFi Lora 32(v3) 를 사용했다.
기존에 ESP32(Dev module), ESP8266(D1 mini)를 사용해서
다양한 센서들을 등록했었다.
위 보드에 새로 다 등록을 하는 과정을 거친다.
1. 센서 데이터 추출
[Hunan Rika]RK520 토양센서를 보드와 연동해
온도/습도 데이터를 받아온다.
https://www.rikasensor.com/rk520-11-all-in-one-soil-sensor.html
Rk520-11 All-in-one Soil Sensor | Rika Sensors
Looking for soil temperature moisture sensor? Details about RK520-11 All-in-one Soil Sensor, soil ph probe, on Rika Sensors, Ask online!
www.rikasensor.com
위 링크 Data sheet에 485 프로토콜 정보가 자세하게 나와있다.
RS-485 데이터패킷을 아두이노에서 센서쪽으로 출력해
센서값을 시리얼 모니터에 받아온다.
#include "CRC.h"
unsigned int counter = 0;
unsigned long previousMillis = 0;
const long interval = 2000;
String inputString = ""; // 받은 문자열
float temp=0.,humi=0.;
void setup() {
Serial.begin(9600);
//Serial1.begin(19200, SERIAL_8N1, 6, 5);
Serial2.begin(9600, SERIAL_8N1, 6, 5);
}
void loop() {
tick();
serial2Event();
}
void tick() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
Serial.println("tick");
crd16Rtu();
}
}
void serial2Event() {
if(Serial2.available() == false)
return;
while (Serial2.available()) {
// get the new byte:
char inChar = (char)Serial2.read();
//Serial.print(inChar,HEX);
// add it to the inputString:
inputString += inChar;
}
Serial.println("");
Serial.println(inputString);
if(inputString.length() >= 9) {
String ss="";
ss=((float)inputString.charAt(3)*255+(float)inputString.charAt(4))/10;
temp=ss.toFloat();
Serial.println("온도 : "+ss+" 도");
ss=((float)inputString.charAt(5)*255+(float)inputString.charAt(6))/10;
humi=ss.toFloat();
Serial.println("함수율 : "+ss+" %");
inputString="";
Serial.println("");
}
}
// 아두이노에서 RS485 출력을 내보낸다.
void crd16Rtu() {
//char str[24] = {0x00,0x03,0x00,0x01,0x00,0x01,0x00,0x00,0x00}; //Read station number
char str[24] = {0x01, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00}; //Read Date
String s;
int si,sj,len;
len=6;
uint8_t * data = (uint8_t *) &str[0];
si=crc16(data, len, 0x8005, 0xFFFF, 0x0000, true, true );
sj=si&0xff;
str[len]=sj;
sj=si>>8;
str[len+1]=sj;
//Serial.println("");
for(int i=0;i<len+2;i++) {
Serial2.print (str[i]);
}
}
crd16Rtu() 함수에서
Serial2 포트로 RS-485 데이터를 출력한다.
void crd16Rtu() {
//char str[24] = {0x00,0x03,0x00,0x01,0x00,0x01,0x00,0x00,0x00}; //Read station number
char str[24] = {0x01, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00}; //Read Date
String s;
int si,sj,len;
len=6;
uint8_t * data = (uint8_t *) &str[0];
si=crc16(data, len, 0x8005, 0xFFFF, 0x0000, true, true );
sj=si&0xff;
str[len]=sj;
sj=si>>8;
str[len+1]=sj;
//Serial.println("");
for(int i=0;i<len+2;i++) {
Serial2.print (str[i]);
}
}
데이터값 계산하기
- Example
응답 예시 프로토콜
Example respond | 01 03 04 01 23 01 64 0A7E |
4,5번째 바이트: 01 23
6,7번째 바이트: 01 64
- Temperature = 0x0123 / 10 = 291 / 10 = 29.1
- Humidity = 0x0164 / 10 = 356 / 10 = 35.6
데이터를 출력하면 위와 같이 16진수값이
센서로부터 출력된다.
바이트 연산을 거쳐서 온도/습도 값을 알 수 있다.
센서 데이터를 시리얼 모니터에 정상적으로 출력했다.
2. Lora 송/수신
Client 소스 ( RK520 센서 데이터값 받아오는 보드 )
// 2023-03-08 RK520 센서 추가
#include <Wire.h>
#include "LoRaWan_APP.h"
#include "Arduino.h"
#include <ArduinoJson.h>
#include "CRC.h"
#include "SPIFFS.h"
#include "HT_SSD1306Wire.h"
SSD1306Wire displayOled(0x3c, 500000, SDA_OLED, SCL_OLED, GEOMETRY_128_64, RST_OLED); // addr , freq , i2c group , resolution , rst
#define RF_FREQUENCY 923000000 // Hz
#define TX_OUTPUT_POWER 5 // dBm
#define LORA_BANDWIDTH 0 // [0: 125 kHz,
// 1: 250 kHz,
// 2: 500 kHz,
// 3: Reserved]
#define LORA_SPREADING_FACTOR 7 // [SF7..SF12]
#define LORA_CODINGRATE 1 // [1: 4/5,
// 2: 4/6,
// 3: 4/7,
// 4: 4/8]
#define LORA_PREAMBLE_LENGTH 8 // Same for Tx and Rx
#define LORA_SYMBOL_TIMEOUT 0 // Symbols
#define LORA_FIX_LENGTH_PAYLOAD_ON false
#define LORA_IQ_INVERSION_ON false
#define RX_TIMEOUT_VALUE 1000
#define BUFFER_SIZE 200 // Define the payload size here
#define TRIGGER_PIN 37 // trigger pin GPIO37
char txpacket[BUFFER_SIZE];
char rxpacket[BUFFER_SIZE];
static RadioEvents_t RadioEvents;
void OnTxDone( void );
void OnTxTimeout( void );
void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr );
void display(int no);
void tick();
void changeLoraTo();
typedef enum
{
LOWPOWER,
STATE_RX,
STATE_TX
}States_t;
int16_t txNumber=0;
States_t state;
bool sleepMode = false;
int16_t Rssi,rxSize;
class Lora {
public:
String mac;
int dire=0;
int rssi=-200; //-80 보다 크면 아주 양호 -80~-90 양호 -90~-100 불량 -100보다 작음 나쁨
int layer=100;
};
Lora loraC; // lora Client
Lora loraF; // lora onReceive 함수에서 From 임시로 전달받은 로라, 통시방향 관계없이 전달된 값
Lora loraT; // lora To 나에게 링크되어 메세지 서버쪽으로 전달할 로라
//String packet;
int packSize = 0;
String msgTo;
int msgType=0; //0=measure 1=전달(packet 을 lora로 보냄)
int type=13;
unsigned int counter = 0;
unsigned long previousMillis = 0;
const long interval = 5000;
String inputString = "";
char mac[20]; //mac address
float temp=0.,humi=0.,pres=0.;
//json을 위한 설정
StaticJsonDocument<200> doc;
DeserializationError error;
JsonObject root;
void setup() {
pinMode(TRIGGER_PIN, INPUT_PULLUP);
Serial.begin(115200);
Serial2.begin(9600, SERIAL_8N1, 6, 5);
Serial.println("mac address");
//이름 자동으로 생성
uint64_t chipid;
chipid=ESP.getEfuseMac();//The chip ID is essentially its MAC address(length: 6 bytes).
loraC.mac=String(((uint16_t)(chipid>>32)),HEX)+String(((uint32_t)chipid),HEX);
Serial.println(loraC.mac);
Mcu.begin();
Rssi=0;
RadioEvents.TxDone = OnTxDone;
RadioEvents.TxTimeout = OnTxTimeout;
RadioEvents.RxDone = OnRxDone;
Radio.Init( &RadioEvents );
Radio.SetChannel( RF_FREQUENCY );
Radio.SetTxConfig( MODEM_LORA, TX_OUTPUT_POWER, 0, LORA_BANDWIDTH,
LORA_SPREADING_FACTOR, LORA_CODINGRATE,
LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON,
true, 0, 0, LORA_IQ_INVERSION_ON, 3000 );
Radio.SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR,
LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH,
LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON,
0, true, 0, 0, LORA_IQ_INVERSION_ON, true );
state=STATE_RX;
displayOled.init();
displayOled.setFont(ArialMT_Plain_10);
displayOled.setTextAlignment(TEXT_ALIGN_LEFT);
displayAct(0);
readConfig();
}
void OnTxDone( void )
{
Serial.print("TX done......");
state=STATE_RX;
}
void OnTxTimeout( void )
{
Radio.Sleep( );
Serial.print("TX Timeout......");
state=STATE_TX;
}
// 메세지 전달할 mac rssi 현재 lora의 layer 저장
void changeLoraTo() {
//if(macFrom.length() !=12) return;
loraT.mac="";
loraT.mac+=loraF.mac;
loraT.rssi=loraF.rssi;
loraC.layer=loraF.layer+1;
saveConfig();
}
void displayAct(int no) {
displayOled.clear();
displayOled.drawString(0, 0, "Lola Client");
displayOled.drawString(0, 10, "mac: "+loraC.mac);
if(no==0) { //lora 시작
displayOled.drawString(0, 20, "Start");
}
else if(no==1) {
displayOled.drawString(0, 0, "Lora Start");
}
else if(no==2) {
displayOled.drawString(0, 20, "temp "+String(counter));
}
else if(no==3) {
displayOled.drawString(0, 20, "rxpacket");
}
else if(no==4) {
displayOled.drawString(0, 20, "Out Out");
}
else if(no==5) {
displayOled.drawString(0, 20, "Lora Reset");
}
displayOled.display();
}
void tickMeasure() {
//온도 습도 측정
//crd16Rtu();
//측정값 로라로 전송
//temp=0.,humi=0.,pres=0.;
DynamicJsonDocument doc(1024);
doc["mac"] = loraC.mac;
doc["dire"] = -1;
doc["macTo"] = loraT.mac;
doc["macFrom"] = loraF.mac;
//doc["macFrom"] = loraC.mac;
doc["type"] = type;
doc["layer"] = loraC.layer;
doc["rssi"] = loraF.rssi;
doc["count"] = counter;
doc["temp"] = temp;
doc["humi"] = humi;
doc["pres"] = pres;
msgTo="";
serializeJson(doc, msgTo);
//Serial.println(msgTo);
}
//LORA로 메세지 받으면 동작
//전달할 데이타중 조건에 맞으면 loraT로 SPIFF에 저장
//새로이 전달되어온 데이타는 loraF에 저장
void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr )
{
Rssi=rssi;
rxSize=size;
memcpy(rxpacket, payload, size );
rxpacket[size]='\0';
Radio.Sleep( );
state=STATE_RX;
//Serial.println(rxpacket);
loraF.rssi=rssi;
displayAct(3);
String packet(rxpacket);
deserializeJson(doc,packet);
root = doc.as<JsonObject>();
String macObj = root["macObj"];
String macC = root["mac"];
String macFrom = root["macFrom"];
String macTo = root["macTo"];
int dire = root["dire"];
int layerIn = root["layer"];
int func = root["func"];
loraF.mac = "";
loraF.mac += macFrom;
loraF.dire = dire;
loraF.layer = layerIn;
//loraT.mac이 비어있으면 전송된 데이터를 loraT.mac으로 입력
if( (loraT.mac.length()<6) && (loraF.rssi > -90)) {
changeLoraTo();
}
if(dire==-1) {
if(loraC.mac==macTo && loraC.layer!=0){
packet.replace("\"layer\":"+String(layerIn),"\"layer\":"+String(loraC.layer));
packet.replace("\"macFrom\":\""+macFrom,"\"macFrom\":\""+loraF.mac);
packet.replace("\"macTo\":\""+macTo,"\"macTo\":\""+loraT.mac);
packet.replace("\"mac\":\""+macC,"\"mac\":\""+loraC.mac);
msgTo="";
msgTo+=packet;
msgType=1;
Serial.println("Bridge(-전달) "+msgTo);
state=STATE_TX;
//msgType=0;
}
}
if(dire==1) {
//입력된 macTo 가 없을 때 macFrom 을 macTo로 입력
// 더 좋은 수신호가 있을 때 macTo로 입력
if((loraF.rssi-loraT.rssi) > 10 && (layerIn-loraC.layer) <= -1) {
changeLoraTo();
}
// 메세지 전달 자기와 링크된 로라의 msg만 전달한다.
if(loraF.mac==loraT.mac && macObj!=loraC.mac){
//delay(random(0,3000));
packet.replace("\"layer\":"+String(layerIn),"\"layer\":"+String(loraC.layer));
packet.replace("\"macFrom\":\""+loraF.mac,"\"macFrom\":\""+loraC.mac);
msgTo="";
msgTo+=packet;
msgType=1;
Serial.println("Bridge(+전달) "+msgTo);
state=STATE_TX;
//msgType=0;
}
//명령수행
//if(macObj==loraC.mac|| macObj=="ffffffffffff"){
if(macObj==loraC.mac){
Serial.println("msgFrom: "+packet);
displayAct(4);
if(func==255)
factoryDefault();
}
}
}
void loop()
{
tick();
serial2Event();
switch(state)
{
case STATE_TX:
//Serial.println(msgTo);
txNumber++;
msgTo.toCharArray(txpacket,msgTo.length());
Radio.Send( (uint8_t *)txpacket, strlen(txpacket) );
msgType=0;
state=LOWPOWER;
break;
case STATE_RX:
Serial.println("into RX mode");
Radio.Rx( 0 );
state=LOWPOWER;
break;
case LOWPOWER:
Radio.IrqProcess( );
break;
default:
break;
}
if ( digitalRead(TRIGGER_PIN) == LOW )
factoryDefault();
}
void serial2Event() {
if(Serial2.available() == false)
return;
while (Serial2.available()) {
// get the new byte:
char inChar = (char)Serial2.read();
//Serial.print(inChar,HEX);
// add it to the inputString:
inputString += inChar;
}
Serial.println("");
if(inputString.length() >= 9) {
String ss="";
ss=((float)inputString.charAt(3)*255+(float)inputString.charAt(4))/10;
temp=ss.toFloat();
Serial.println("온도 : "+ss+" 도");
ss=((float)inputString.charAt(5)*255+(float)inputString.charAt(6))/10;
humi=ss.toFloat();
Serial.println("함수율 : "+ss+" %");
inputString="";
Serial.println("");
}
}
void tick() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
crd16Rtu();
if(msgType==0) {
tickMeasure();
state=STATE_TX;
displayAct(2);
counter++;
}
}
}
void crd16Rtu() {
//char str[24] = {0x00,0x03,0x00,0x01,0x00,0x01,0x00,0x00,0x00}; //Read station number
char str[24] = {0x01, 0x03, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00}; //Read Date
String s;
int si,sj,len;
len=6;
uint8_t * data = (uint8_t *) &str[0];
si=crc16(data, len, 0x8005, 0xFFFF, 0x0000, true, true );
sj=si&0xff;
str[len]=sj;
sj=si>>8;
str[len+1]=sj;
//Serial.println("");
for(int i=0;i<len+2;i++) {
Serial2.print (str[i]);
}
}
gateway 소스
/* 프로토콜 설명
PC에서 오는 프로토콜
mac: 이 프로그램이 동작하는 CPU mac address
macObj:메세지 전송할 특정한 lora 주소
func:명령번호
lora 에서 추가되는 프로토콜
layer: 서버는 0이고 lora를 거쳐서 전달할 때 +1 씩 증가한다.
dire: 1=서버에서 lora로 전송 -1=lora 에서 서버로 전송
macFrom:말단방향 lora 로부터 전송받은 lora mac 주소
macTo: 서버방향르로 전송할 lora mac 주소
*/
#include <Wire.h>
#include "LoRaWan_APP.h"
#include "Arduino.h"
#include <ArduinoJson.h>
#include "CRC.h"
#include "SPIFFS.h"
#include "HT_SSD1306Wire.h"
#include <PubSubClient.h>
#include <WiFi.h>
#include <WiFiUdp.h>
SSD1306Wire displayOled(0x3c, 500000, SDA_OLED, SCL_OLED, GEOMETRY_128_64, RST_OLED); // addr , freq , i2c group , resolution , rst
#define RF_FREQUENCY 923000000 // Hz
#define TX_OUTPUT_POWER 5 // dBm
#define LORA_BANDWIDTH 0 // [0: 125 kHz,
// 1: 250 kHz,
// 2: 500 kHz,
// 3: Reserved]
#define LORA_SPREADING_FACTOR 7 // [SF7..SF12]
#define LORA_CODINGRATE 1 // [1: 4/5,
// 2: 4/6,
// 3: 4/7,
// 4: 4/8]
#define LORA_PREAMBLE_LENGTH 8 // Same for Tx and Rx
#define LORA_SYMBOL_TIMEOUT 0 // Symbols
#define LORA_FIX_LENGTH_PAYLOAD_ON false
#define LORA_IQ_INVERSION_ON false
#define RX_TIMEOUT_VALUE 1000
#define BUFFER_SIZE 200 // Define the payload size here
#define TRIGGER_PIN 37 // trigger pin GPIO37
//HardwareSerial serial485(2);
char txpacket[BUFFER_SIZE];
char rxpacket[BUFFER_SIZE];
static RadioEvents_t RadioEvents;
void OnTxDone( void );
void OnTxTimeout( void );
void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr );
void display(int no);
void callback(char* topic, byte* payload, unsigned int length);
void displayAct(int no);
void readConfig();
void saveConfig();
void factoryDefault();
void bootWifiStation();
void tick();
void reconnect();
void udpEvent();
typedef enum
{
LOWPOWER,
STATE_RX,
STATE_TX
}States_t;
int16_t txNumber;
States_t state;
bool sleepMode = false;
int16_t Rssi,rxSize;
class Lora {
public:
String mac;
int dire=0;
int rssi=-200; //-80 보다 크면 아주 양호 -80~-90 양호 -90~-100 불량 -100보다 작음 나쁨
int layer=100;
};
Lora loraC; // lora Client
Lora loraF; // lora onReceive 함수에서 From 임시로 전달받은 로라, 통시방향 관계없이 전달된 값
Lora loraT; // lora To 나에게 링크되어 메세지 서버쪽으로 전달할 로라
//String packet;
int packSize = 0;
String msgTo;
unsigned int counter = 0;
unsigned long previousMillis = 0;
const long interval = 5000;
char mac[20]; //mac address
int mqttConnected=0; // 1=연결 0=끊김
float temp=0.,humi=0.,pres=0.;
//json을 위한 설정
StaticJsonDocument<200> doc;
DeserializationError error;
JsonObject root;
WiFiUDP Udp;
unsigned int localUdpPort = 4210; // local port to listen on
char incomingPacket[255]; // buffer for incoming packets
char ssid[40] = "와이파이 이름";
char password[50] = "비밀번호";
int type=999; // 999=lora gate way
const char* outTopic = "/i2r/outTopic"; // 이름이 중복되지 않게 설정 기록
const char* inTopic = "/i2r/inTopic"; // 이름이 중복되지 않게 설정 기록
char clientName[30] = {0}; // setup 함수에서 자동생성
char ipMqtt[40]="";
char msg[500];
WiFiClient espClient;
PubSubClient client(espClient);
void setup() {
pinMode(TRIGGER_PIN, INPUT_PULLUP);
Serial.begin(115200);
//serial485.begin(115200, SERIAL_8N1, 5, 6);
Serial.println("mac address");
//이름 자동으로 생성
uint64_t chipid;
chipid=ESP.getEfuseMac();//The chip ID is essentially its MAC address(length: 6 bytes).
loraC.mac=String(((uint16_t)(chipid>>32)),HEX)+String(((uint32_t)chipid),HEX);
loraC.mac.toCharArray(clientName,loraC.mac.length()+1);
Serial.println(loraC.mac);
Serial.println(clientName);
bootWifiStation();
Udp.begin(localUdpPort);
Mcu.begin();
txNumber=0;
Rssi=0;
RadioEvents.TxDone = OnTxDone;
RadioEvents.TxTimeout = OnTxTimeout;
RadioEvents.RxDone = OnRxDone;
Radio.Init( &RadioEvents );
Radio.SetChannel( RF_FREQUENCY );
Radio.SetTxConfig( MODEM_LORA, TX_OUTPUT_POWER, 0, LORA_BANDWIDTH,
LORA_SPREADING_FACTOR, LORA_CODINGRATE,
LORA_PREAMBLE_LENGTH, LORA_FIX_LENGTH_PAYLOAD_ON,
true, 0, 0, LORA_IQ_INVERSION_ON, 3000 );
Radio.SetRxConfig( MODEM_LORA, LORA_BANDWIDTH, LORA_SPREADING_FACTOR,
LORA_CODINGRATE, 0, LORA_PREAMBLE_LENGTH,
LORA_SYMBOL_TIMEOUT, LORA_FIX_LENGTH_PAYLOAD_ON,
0, true, 0, 0, LORA_IQ_INVERSION_ON, true );
state=STATE_RX;
displayOled.init();
displayOled.setFont(ArialMT_Plain_10);
displayOled.setTextAlignment(TEXT_ALIGN_LEFT);
displayAct(0);
readConfig();
// mqtt 설정
client.setServer(ipMqtt, 1883);
client.setCallback(callback);
}
void loop()
{
tick();
switch(state)
{
case STATE_TX:
txNumber++;
msgTo.toCharArray(txpacket,msgTo.length());
Radio.Send( (uint8_t *)txpacket, strlen(txpacket) );
state=LOWPOWER;
break;
case STATE_RX:
Serial.println("into RX mode");
Radio.Rx( 0 );
state=LOWPOWER;
break;
case LOWPOWER:
Radio.IrqProcess( );
break;
default:
break;
}
if (!client.connected()) {
reconnect();
}
else
client.loop();
udpEvent();
if ( digitalRead(TRIGGER_PIN) == LOW )
factoryDefault();
}
void bootWifiStation() {
//referance: https://www.arduino.cc/en/Reference/WiFiStatus
//WL_NO_SHIELD:255 WL_IDLE_STATUS:0 WL_NO_SSID_AVAIL:1 WL_SCAN_COMPLETED:2
//WL_CONNECTED:3 WL_CONNECT_FAILED:4 WL_CONNECTION_LOST:5 WL_DISCONNECTED:6
//WiFi 연결
//bootMode=0; //0:station 1:AP
Serial.println("Station Mode");
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
//공장리셋
if ( digitalRead(TRIGGER_PIN) == LOW )
factoryDefault();
}
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP().toString());
}
void udpEvent() {
int packetSize = Udp.parsePacket();
if(packetSize) {
// receive incoming UDP packets
Serial.printf("Received %d bytes from %s, port %d\n", packetSize, Udp.remoteIP().toString().c_str(), Udp.remotePort());
int len = Udp.read(incomingPacket, 255);
if(len > 0) {
incomingPacket[len] = 0;
}
Serial.printf("UDP packet contents: %s\n", incomingPacket);
deserializeJson(doc,incomingPacket);
root = doc.as<JsonObject>();
String mqttIp = root["mqttIp"];
mqttIp.toCharArray(ipMqtt, mqttIp.length()+1);
Serial.println(ipMqtt);
saveConfig();
}
}
// mqtt 통신에 지속적으로 접속한다.
void reconnect() {
if(String(ipMqtt).length()<2) {
displayAct(4);
return;
}
Serial.println("reconnect");
Serial.println(ipMqtt);
//if(WiFi.status() == WL_DISCONNECTED)
// return;
//Serial.println("====================================");
//Serial.println(countMqtt);
// Loop until we're reconnected
while (!client.connected()) {
Serial.print("Attempting MQTT connection...");
// Attempt to connect
if (client.connect(clientName)) {
Serial.println("connected");
// Once connected, publish an announcement...
//client.publish(outTopic, "Reconnected");
// ... and resubscribe
client.subscribe(inTopic);
mqttConnected=1;
displayAct(2);
} else {
Serial.print("failed, rc=");
Serial.print(client.state());
Serial.println(" try again in 180 seconds");
mqttConnected=0;
displayAct(3);
// Wait 5 seconds before retrying
//delay(5000);
delay(500);
}
}
}
void OnTxDone( void )
{
Serial.print("TX done......");
state=STATE_RX;
}
void OnTxTimeout( void )
{
Radio.Sleep( );
Serial.print("TX Timeout......");
state=STATE_TX;
}
void displayAct(int no) {
displayOled.clear();
displayOled.drawString(0, 0, "Lola Gateway");
displayOled.drawString(0, 10, "mac: "+loraC.mac);
if(no==0) { //lora 시작
displayOled.drawString(0, 20, "Start");
}
else if(no==1) {
displayOled.drawString(0, 0, "Lora Start");
}
else if(no==2) {
displayOled.drawString(0, 20, "connected "+String(counter));
}
else if(no==3) {
displayOled.drawString(0, 20, "mqtt connect fail");
}
else if(no==4) {
displayOled.drawString(0, 20, "no Mqtt server IP");
}
else if(no==5) {
displayOled.drawString(0, 20, "Lora Reset");
}
displayOled.display();
}
void tick() {
unsigned long currentMillis = millis();
if (currentMillis - previousMillis >= interval) {
previousMillis = currentMillis;
/*
msgTo="count: "+ counter;
state=STATE_TX;
displayAct(2);
counter++;
*/
/*
//서버로 전송 테스트
if(client.connected()) {
Serial.println(counter++);
sprintf(msg, "%d", counter);
client.publish(outTopic, msg);
//client.publish(outTopic, "test");
}
*/
}
}
//LORA로 메세지 받으면 동작
//전달할 데이타중 조건에 맞으면 loraT로 SPIFF에 저장
//새로이 전달되어온 데이타는 loraF에 저장
void OnRxDone( uint8_t *payload, uint16_t size, int16_t rssi, int8_t snr )
{
Rssi=rssi;
rxSize=size;
memcpy(rxpacket, payload, size );
rxpacket[size]='\0';
Radio.Sleep( );
state=STATE_RX;
//Serial.println(rxpacket);
loraF.rssi=rssi;
displayAct(3);
Serial.println(rxpacket);
//if((macTo == loraC.mac) && dire==-1) {
client.publish(outTopic, rxpacket);
//}
}
// 와이파이 통신에서 문자가 들어오면 이 함수의 payload 배열에 저장된다.
void callback(char* topic, byte* payload, unsigned int length) {
Serial.print("Message arrived [");
Serial.print(topic);
Serial.print("] ");
String sMsg="";
for (int i = 0; i < length; i++) {
//Serial.print((char)payload[i]);
sMsg+=(char)payload[i];
}
//Serial.println(sMsg);
// json {}로 수신되어야 한며 }를 추가 메세지를 붙여서 보낸다.
deserializeJson(doc,payload);
root = doc.as<JsonObject>();
String macIn = root["mac"];
String sAdd=",\"mac\":\""+loraC.mac+"\",\"dire\":1,\"layer\":0}";
sMsg.replace("}",sAdd);
msgTo=sMsg;
Serial.println(msgTo);
state=STATE_TX;
}
COM11에 연결된 보드가 RK520 센서의
온도/습도 값을 받아온 뒤 Lora 통신을 사용해
gateway로 데이터를 전송한다.
COM14에 연결된 gateway 보드가
Lora통신값을 정상적으로 받아온다.
진행하면서
초기에
보드가 센서값을 못 읽어오는 오류가 발생했었는데
단순하게 센서의 입력전압을 높여줬더니
해결됐었다.
3일동안 고뇌하고 고뇌했는데
단순한 문제였다
'개발 > Arduino' 카테고리의 다른 글
Xiaomi Flower care + ESP32 / BLE통신 (0) | 2023.03.13 |
---|---|
ESP32 BLE & RS-232 RS-485통신 (0) | 2023.03.02 |
ESP32 web server (0) | 2023.02.28 |
성능지표 테스트 (0) | 2023.01.10 |
성능지표 및 Arduino 함수 트리거 처리 (2) | 2023.01.04 |