lora氣象站

Posted on Mon, Apr 4, 2022 C++

接收端

#include "heltec.h" 
//#include "images.h"
#include "WiFi.h"
#include "Arduino.h" 
#include "ThingSpeak.h"

WiFiClient  client;

#define BAND    923E6  //you can set band here directly,e.g. 868E6,915E6
String rssi = "RSSI --";
String packSize = "--";
String packet ;
const char * myWriteAPIKey = "M7BF4VYE73RGWXS9";

void WIFISetUp(void)
{
  // Set WiFi to station mode and disconnect from an AP if it was previously connected
  Heltec.display -> clear();
  WiFi.disconnect(true);
  delay(100);
  WiFi.mode(WIFI_STA);
  WiFi.setAutoConnect(true);
  WiFi.begin("D-Link-79-7","26802248");//fill in "Your WiFi SSID","Your Password"
  delay(100);

  byte count = 0;
  while(WiFi.status() != WL_CONNECTED && count < 7)
  {
    count ++;
    delay(2000);
    Heltec.display -> drawString(0, 0, "Connecting...");
    Heltec.display -> display();
  }

  Heltec.display -> clear();
  if(WiFi.status() == WL_CONNECTED)
  {
    Heltec.display -> drawString(0, 0, "Connecting...OK.");
    Heltec.display -> display();
//    delay(500);
  }
  else
  {
    Heltec.display -> clear();
    Heltec.display -> drawString(0, 0, "Connecting...Failed");
    Heltec.display -> display();
    //while(1);
  }
  Heltec.display -> drawString(0, 10, "WIFI Setup done");
  Heltec.display -> display();
  delay(500);
}



void LoRaData(int x,float volt,float temp,float p){
  Heltec.display->clear();
  Heltec.display->setTextAlignment(TEXT_ALIGN_LEFT);
  Heltec.display->setFont(ArialMT_Plain_10);
  Heltec.display->drawString(0 , 15 , "Received "+ packSize + " bytes");
  Heltec.display->drawStringMaxWidth(0 , 26 , 128, packet);
  Heltec.display->drawString(0, 0, rssi);  
  if(x == 200){
    Serial.println("Channel update successful.");
    Heltec.display->drawString(0, 37, "update successful.");
  }
   else{
    Serial.println("Problem updating channel. HTTP error code " + String(x));
    Heltec.display->drawString(0, 37, "HTTP error code "+ String(x));
  }
  Heltec.display->drawString(0, 48, "t"+String(temp));
  Heltec.display->display();
}

void cbk(int packetSize) {
  float volt = 0;
  float temp = 0;
  float p = 0;
  packet ="";
  packSize = String(packetSize,DEC);
  for (int i = 0; i < packetSize; i++) { packet += (char) LoRa.read(); }
  int i = 1;
    while(packet[i]!='t'){ 
      volt = volt*10 +(packet[i] - '0');
      i++;
    }
    i++;
    while(packet[i]!='p'){ 
      temp = temp*10 +(packet[i] - '0');
      i++;
    }
    i++;
    while(i<packetSize){ 
      p = p*10 +(packet[i] - '0');
      i++;
    }
  volt/=1000.0;
  temp/=100.0;
  p/=100.0;
  rssi = "RSSI " + String(LoRa.packetRssi(), DEC) ;
  if(WiFi.status() != WL_CONNECTED){
    WIFISetUp();
  }
  ThingSpeak.setField(1, volt);
  ThingSpeak.setField(2, temp);
  ThingSpeak.setField(3, p);
  ThingSpeak.setField(4, LoRa.packetRssi());
  int x = ThingSpeak.writeFields(2, myWriteAPIKey);
  LoRaData(x,volt,temp,p);
}

void setup() { 
   //WIFI Kit series V1 not support Vext control
  Heltec.begin(true /*DisplayEnable Enable*/, true /*Heltec.Heltec.Heltec.LoRa Disable*/, true /*Serial Enable*/, true /*PABOOST Enable*/, BAND /*long BAND*/);
  LoRa.setSyncWord(0x12);
  LoRa.setSpreadingFactor(8);
  LoRa.setSignalBandwidth(125E3);
  LoRa.setCodingRate4(5);
  LoRa.setPreambleLength(8);
  WIFISetUp();
  Heltec.display->init();
  Heltec.display->flipScreenVertically();  
  Heltec.display->setFont(ArialMT_Plain_10);
  //logo();
  //delay(1500);
  Heltec.display->clear();
  
  Heltec.display->drawString(0, 0, "Heltec.LoRa Initial success!");
  Heltec.display->drawString(0, 10, "Wait for incoming data...");
  Heltec.display->display();
  delay(1000);
  //LoRa.onReceive(cbk);
  LoRa.receive();
  ThingSpeak.begin(client); 
}

void loop() {
  int packetSize = LoRa.parsePacket();
  if (packetSize) { cbk(packetSize);  }
  delay(10);
}

發送端

#include <BMP180.h>
#include "LoRaWan_APP.h"
#include "Arduino.h"

BMP085 bmp;

#ifndef LoraWan_RGB
#define LoraWan_RGB 0
#endif

#define RF_FREQUENCY                                923000000 // Hz
#define TX_OUTPUT_POWER                             14        // dBm
#define LORA_BANDWIDTH                              0         // [0: 125 kHz,
#define LORA_SPREADING_FACTOR                       8         // [SF7..SF12]
#define LORA_CODINGRATE                             4         // [1: 4/5,
#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                                 30 // Define the payload size here

char txPacket[BUFFER_SIZE];

static RadioEvents_t RadioEvents;
void OnTxDone( void );
void OnTxTimeout( void );

typedef enum
{
    LOWPOWER,
    ReadVoltage,
    TX
}States_t;

States_t state;
bool sleepMode = false;
int16_t rssi,rxSize;
uint16_t voltage;
int temp, pressure, alt;

void setup() {
    Serial.begin(115200);
    pinMode(Vext,OUTPUT);
    digitalWrite(Vext,LOW);
    if (!bmp.begin()) {
    Serial.println("Could not find a valid BMP085 sensor, check wiring!");
    }
    voltage = 0;
    rssi=0;
    RadioEvents.TxDone = OnTxDone;
    RadioEvents.TxTimeout = OnTxTimeout;
    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 );
    state=ReadVoltage;
}



void loop()
{
  switch(state)
  {
    case TX:
    {
      sprintf(txPacket,"%s","v");
      sprintf(txPacket+strlen(txPacket),"%d",voltage);
      sprintf(txPacket+strlen(txPacket),"%s","t");
      sprintf(txPacket+strlen(txPacket),"%d",temp);
      sprintf(txPacket+strlen(txPacket),"%s","p");
      sprintf(txPacket+strlen(txPacket),"%d",pressure);
      //turnOnRGB(COLOR_SEND,0);
      Serial.printf("\r\nsending packet \"%s\" , length %d\r\n",txPacket, strlen(txPacket));
      Radio.Send( (uint8_t *)txPacket, strlen(txPacket) );
      state=LOWPOWER;
      break;
    }
    case LOWPOWER:
    {
      lowPowerHandler();
      delay(100);
      //turnOffRGB();
      delay(15000);
      //delay(5*60000);  //LowPower time
      state = ReadVoltage; 
      break;
    }
    case ReadVoltage:
    {
      pinMode(VBAT_ADC_CTL,OUTPUT);
      digitalWrite(VBAT_ADC_CTL,LOW);
      voltage = analogRead(ADC);
      pinMode(VBAT_ADC_CTL, INPUT);
      temp = bmp.readTemperature()*100;
      pressure = bmp.readPressure();
      //alt = bmp.readAltitude(101600);
      state = TX;
      break;
    }
     default:
          break;
  }
  Radio.IrqProcess();
}

void OnTxDone( void )
{
  Serial.print("TX done!");
  turnOnRGB(0,0);
}

void OnTxTimeout( void )
{
    Radio.Sleep( );
    Serial.print("TX Timeout......");
    state=ReadVoltage;
}

參考資料:

ESP32 Publish Sensor Readings to ThingSpeak (easiest way) | Random Nerd Tutorials

In this guide, you'll learn how to send sensor readings with the ESP32 to ThingSpeak. For demonstration purposes, we'll use a BME280 sensor, but you can easily modify the examples to use any other sensor. The ESP32 board will be programmed using the Arduino core.