ทำ LoRaWAN node วัดอุณหภูมิและความชื้น ด้วย Heltec ESP32 Wifi LoRa Oled V.2 ใช้ได้กับ TheThings หรือ Helium (สำเนา)

Somsak Lima
8 min readJun 16, 2023

--

  • *หมายเหตุ แนะนำให้ใช้ PlatformIO แทน ArduinoIDE และ Lib ของ heltecโดยทำตามบทความ คลิก เนื่องจากพบว่าหากทำตามบทความนี้โดยใช้ Arduino IDE Version 2.X แล้ว Heltec จะ reboot ตลอด****

การติดตั้งเพื่อให้มีตัวเลือก Board ของ heltec ทำได้ตามบทความ คลิก

เพื่อให้เป็นไปตามข้อกำหนดของ กสทช. การทำอุปกรณ์โดยไม่ต้องขอใบอนุญาติจะต้องกำหนดกำลังส่งออกอากาศไม่เกิน 50mW (eirp)

อุปกรณ์ที่ใช้
1.Heltec ESP32 Wifi LoRa Oled V.2 ราคาประมาณ 800 บาท ให้เลือก บอร์ด Heltec ESP32 ที่มี Chip SX1276 ซึ่งรองรับความถี่ 868Mhz , 915Mhz รวมถึงความถี่ 923Mhz ซึ่งอนุญาติให้ใช้ในประเทศไทย (ไม่ใช่รุ่นที่ราคาถูกกว่าที่ใช้ Chip SX1278 ซึ่งจะทำงานที่ความถี่ต่ำกว่าคือที่ 433 Mhz)
2.Sensor วัดอุณหภูมิ ความชื้นและความดันบรรยากาศ รุ่น BME280 ราคาประมาณ 120 บาท
3.Breadboard แบบสั้น ราคาประมาณ 60 บาท
4.สาย Jumper Dupont ผู้-ผู้

ความรู้พื้นฐานที่จำเป็น
1. การใช้ Arduino IDE
2. วิธีการลง Library คลิก
3. วิธีลง Board ด้วย Board Manager คลิก

อ่านค่า Chip ID จาก Heltec Board โดย Compile และ run โปรแกรมต่อไปนี้ คลิก

/* The true ESP32 chip ID is essentially its MAC address.
This sketch provides an alternate chip ID that matches
the output of the ESP.getChipId() function on ESP8266
(i.e. a 32-bit integer matching the last 3 bytes of
the MAC address. This is less unique than the
MAC address chip ID, but is helpful when you need
an identifier that can be no more than a 32-bit integer
(like for switch…case).
created 2020–06–07 by cweinhofer
with help from Cicicok */

uint64_t chipId = 0;
void setup() {
Serial.begin(115200);
}
void loop() {
// chipId |= ((ESP.getEfuseMac() >> (40 — i)) & 0xff) << i;
chipId=ESP.getEfuseMac();//The chip ID is essentially its MAC address(length: 6 bytes).
Serial.printf(“ESP32ChipID=%04X”,(uint16_t)(chipId>>32));//print High 2 bytes
Serial.printf(“%08X\n”,(uint32_t)chipId);//print Low 4bytes.
// Serial.printf(“ESP32 Chip model = %s Rev %d\n”, ESP.getChipModel(), ESP.getChipRevision());
// Serial.printf(“This chip has %d cores\n”, ESP.getChipCores());
// Serial.print(“Chip ID: “); Serial.println(chipId);

delay(3000);
}

เปิด Serial monitor และกดปุ่ม Reset บน Heltec PCB จะเห็น ID ตามภาพ

นำ ChipID ป้อนในหน้าเวป คลิก

คลิก Confirm จะได้ License Key มานำไปแก้ไขใช้งานใน Sketch

ติดตั้งอุปกรณ์บน breadboard และ Jump สายไฟตามภาพ

โปรแกรมที่ใช้
1.ลง Library https://github.com/HelTecAutomation/ESP32_LoRaWAN Library ตัวนี้จะใช้ได้ต้องมี License ถูกต้องโดยการแก้ตัวแปร uint32_t license[4] ให้ตรงกับที่เราได้จากเวปบริษัทมาข้างต้น (วิธีติดตั้ง คลิกที่ Code /Download Zip ได้ไฟล์แล้วแตกลงใน Dir ชื่อ Libraries)

2.ลง Library Adafruit_BME280 ตอนติดตั้งให้เลือกติดตั้ง Adafruit_Unified_Sensor และ Adafruit_BusIOด้วย

3.ลง Library CayenneLLP ตอนลงให้เลือกลง ArduinoJSON ด้วย

4.ลง Board Heltec LoRa V.2

Sketch ที่ใช้เป็นการ Authentication แบบ OTAA (ตัวแปรค่า Key ABP จำเป็นต้องใส่ไว้เพื่อให้ Compile ผ่าน) มีดังนี้

/*
* HelTec Automation(TM) LoRaWAN 1.0.2 OTAA example use OTAA, CLASS A
*
* Function summary:
*
* — use internal RTC(150KHz);
*
* — Include stop mode and deep sleep mode;
*
* — 15S data send cycle;
*
* — Informations output via serial(115200);
*
* — Only ESP32 + LoRa series boards can use this library, need a license
* to make the code run(check you license here: http://www.heltec.cn/search/);
*
* You can change some definition in “Commissioning.h” and “LoRaMac-definitions.h”
*
* HelTec AutoMation, Chengdu, China.
* https://heltec.org
* support@heltec.cn
*
*this project also release in GitHub:
*https://github.com/HelTecAutomation/ESP32_LoRaWAN
*/

#include <Wire.h>
#include <ESP32_LoRaWAN.h>
#include "Arduino.h"
#include <CayenneLPP.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME280.h>
#define SEALEVELPRESSURE_HPA (1006.0)
Adafruit_BME280 bme; // I2C
float temp, pa, humid, alt;
CayenneLPP lpp(51); // create a buffer of 51 bytes to store the payload
unsigned long delayTime;
/*license for Heltec ESP32 LoRaWan, quary your ChipID relevant license: http://resource.heltec.cn/search */
uint32_t license[4] = { 0x1F080831, 0xC69EE6B7, 0x9D3C59B9, 0xC5406CA6 };
/* OTAA parametros*/
uint8_t DevEui[] = { 0xF1, 0x8F, 0xDA, 0xBB, 0xDD, 0x70, 0x3F, 0x11 };
uint8_t AppEui[] = { 0x8B, 0x65, 0x00, 0xF0, 0x7E, 0xD5, 0xB3, 0x11 };
uint8_t AppKey[] = { 0xDA, 0x5A, 0x42, 0xB8, 0x71, 0x50, 0x2E, 0xBA, 0x68, 0x38, 0xC5, 0x28, 0xDE, 0x07, 0xC2, 0x11 };
/* ABP para* Need for Compile */
uint8_t NwkSKey[] = { 0x15, 0xb1, 0xd0, 0xef, 0xa4, 0x63, 0xdf, 0xbe, 0x3d, 0x11, 0x18, 0x1e, 0x1e, 0xc7, 0xda, 0x11 };
uint8_t AppSKey[] = { 0xd7, 0x2c, 0x78, 0x75, 0x8c, 0xdc, 0xca, 0xbf, 0x55, 0xee, 0x4a, 0x77, 0x8d, 0x16, 0xef, 0x11 };
uint32_t DevAddr = (uint32_t)0x007e6a11;
/*LoraWan channelsmask, default channels 0–7*/
uint16_t userChannelsMask[6] = {
0x00FF, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
};
/*LoraWan Class, Class A and Class C are supported*/
DeviceClass_t loraWanClass = CLASS_A;
/*the application data transmission duty cycle. value in [ms].*/
uint32_t appTxDutyCycle = 30000;
/*OTAA or ABP*/
bool overTheAirActivation = true;
/*ADR enable*/
bool loraWanAdr = true;
/* Indicates if the node is sending confirmed or unconfirmed messages */
bool isTxConfirmed = false;
/* Application port */
uint8_t appPort = 2;
/*!
* Number of trials to transmit the frame, if the LoRaMAC layer did not
* receive an acknowledgment. The MAC performs a datarate adaptation,
* according to the LoRaWAN Specification V1.0.2, chapter 18.4, according
* to the following table:
*
* Transmission nb | Data Rate
* — — — — — — — — | — — — — — -
* 1 (first) | DR
* 2 | DR
* 3 | max(DR-1,0)
* 4 | max(DR-1,0)
* 5 | max(DR-2,0)
* 6 | max(DR-2,0)
* 7 | max(DR-3,0)
* 8 | max(DR-3,0)
*
* Note, that if NbTrials is set to 1 or 2, the MAC will not decrease
* the datarate, in case the LoRaMAC layer did not receive an acknowledgment
*/
uint8_t confirmedNbTrials = 8;
/*LoraWan debug level, select in arduino IDE tools.
* None : print basic info.
* Freq : print Tx and Rx freq, DR info.
* Freq && DIO : print Tx and Rx freq, DR, DIO0 interrupt and DIO1 interrupt info.
* Freq && DIO && PW: print Tx and Rx freq, DR, DIO0 interrupt, DIO1 interrupt and MCU deepsleep info.
*/
uint8_t debugLevel = LoRaWAN_DEBUG_LEVEL;
/*LoraWan region, select in arduino IDE tools*/
LoRaMacRegion_t loraWanRegion = ACTIVE_REGION;
// Add your initialization code here
void setup() {

Serial.begin(115200);
unsigned status;
status = bme.begin(0x76);
if (!status) {
Serial.println("Could not find a valid BME280 sensor, check wiring, address, sensor ID!");
}

while (!Serial)
;

temp = bme.readTemperature();
humid = bme.readHumidity();
pa = bme.readPressure() / 100.0F;
alt = bme.readAltitude(SEALEVELPRESSURE_HPA);
SPI.begin(SCK, MISO, MOSI, SS);
Mcu.init(SS, RST_LoRa, DIO0, DIO1, license);

deviceState = DEVICE_STATE_INIT;
}
// The loop function is called in an endless loop
void loop() {
switch (deviceState) {
case DEVICE_STATE_INIT:
{
#if (LORAWAN_DEVEUI_AUTO)
LoRaWAN.generateDeveuiByChipID();
#endif
LoRaWAN.init(loraWanClass, loraWanRegion);
break;
}
case DEVICE_STATE_JOIN:
{
LoRaWAN.displayJoining();
LoRaWAN.join();
break;
}
case DEVICE_STATE_SEND:
{
LoRaWAN.displaySending();
prepareTxFrame(appPort);
LoRaWAN.send(loraWanClass);
deviceState = DEVICE_STATE_CYCLE;
break;
}
case DEVICE_STATE_CYCLE:
{
// Schedule next packet transmission
txDutyCycleTime = appTxDutyCycle + randr(-APP_TX_DUTYCYCLE_RND, APP_TX_DUTYCYCLE_RND);
LoRaWAN.cycle(txDutyCycleTime);
deviceState = DEVICE_STATE_SLEEP;
break;
}
case DEVICE_STATE_SLEEP:
{
LoRaWAN.sleep(loraWanClass, debugLevel);
break;
}
default:
{
deviceState = DEVICE_STATE_INIT;
break;
}
}
}
static void prepareTxFrame(uint8_t port) {
Serial.print("Time:");
Serial.println(millis());
Serial.print("Temperature = ");
Serial.print(temp);
Serial.println(" °C");

Serial.print("Humidity = ");
Serial.print(humid);
Serial.println(" % ");
Serial.print("Pressure = ");
Serial.print(pa);
Serial.println(" hPa");
Serial.print("Approx. Altitude = ");
Serial.print(alt);
Serial.println(" m");
Serial.println();

lpp.reset(); // clear the buffer
lpp.addTemperature(2, temp);
lpp.addRelativeHumidity(3, humid);
//lpp.addBarometricPressure(4, pa / 1000);
lpp.addAnalogInput(5, alt);
appDataSize = lpp.getSize();
uint8_t lppBuffer[128];
memcpy(lppBuffer, lpp.getBuffer(), 128);
memcpy(appData, lppBuffer, lpp.getSize());
}

ตอน Compile เลือก Parameter ให้ถูกต้อง เช่น

ก่อน Compile อาจดูค่า Default ไฟล์คอนฟิก Commissioning.h” และ “RegionAS923.h” เพื่อกำหนดค่าที่เราต้องการ

หลัง Compile เสร็จเปิด Serial Monitor ดูจะเห็นข้อความว่า Join TTN ได้หากมีการลงทะเบียนไว้แล้วและใช้ KEY OTAA ถูกต้อง เช่น

หาก Key ถูกต้องและ Join Request สำเร็จจะเห็นข้อความ Joined และ Node จะเริ่มส่งข้อมูลจาก Sensor

เพิ่ม End Devices หรือ Node ที่หน้าเวป TTN V.3

สำหรับการ Authentication แบบ OTAA ต้องกำหนดค่า Key ให้ตรงกัน 3 Keys คือ DevEui, AppEui, AppKey หรือตรงกันในหน้าเวป Admin ของ TTN กับใน Sketch

เลือก Payload Format ตอน Upload เป็น CayenneLLP

ส่งข้อมูลต่อไปให้ Cayenne.mydevice.com ด้วยวิธีการ Integration แบบ Webhook ใส่ Webhook ID อะไรก็ได้ที่ต้องการ

แสดงข้อมูลบน Dashboard

เพิ่ม Dashboard ในหน้า Cayenne ทำได้โดย Add Wedget เลือก LoRa /The Things Network/ CayenneLLP แล้วนำ Dev EUI มาป้อน เมื่อเวป Cayenne ได้รับข้อมูลจะแสดง Dashboard อัตโนมัติตามรูปแบบ Cayenne

เราสามารถปรับเปลี่ยน Graph จากที่แสดงตัวเลขเฉยๆ เป็น กราฟ เส้นตรงหรือกราฟรูปแบบอื่นๆ ได้ โดยคลิกรูปฟันเฟืองตรงมุมขวาบนของ Widget แต่ละตัว

หากใช้กับ Helium

เข้า Console ที่ https://staging-console.helium.wtf/

(ปรกติเป็น Console https://console.helium.com/)

ให้เพิ่ม Device ใต้หัวข้อ Node

นำค่า Key จาก Node มาป้อนสามค่าคือ Dev EUI, App EUI, App Key ก่อนป้อน App Key ให้คลิกที่ดวงตาก่อน

เมื่อเพิ่มแล้วจะเห็นบรรทัด Device Name เพิ่มขึ้น

เมื่อเปิด LoRaWAN Node ให้เริ่มส่งข้อมูล จะเห็นข้อมูล Live Data เข้า เช่น

และเห็น Join Request, Join Accept ก่อนจะเริ่มเห็นข้อมูล Live Data

แสดงข้อมูลบน Dashboard Cayenne

เพิ่ม Function Cayenne

เพิ่ม Integration Cayenne

สร้าง Flow เพิ่ม เช่น ตามตัวอย่าง

แล้ว นำ DevEUI ไปเพิ่มบนเวป https://cayenne.mydevices.com/
ก็จะเห็นข้อมูลแสดงบน Dashboard

เมื่อข้อมูล Push ไป Cayenne สำเร็จจุดสีแดงจะกลายเป็นสีฟ้า

จับลงกล่อง

อาจถอด Breadboard ด้านข้างออกทั้งสองข้างให้มีขนาดเล็กลง ตามตัวอย่างจะเชื่อมต่อกับ Sensor AM2315 ซึ่งเป็น Sensor อุณหภมิภายนอกเพิ่ม แล้วใส่ในกล่องที่ใช้กับ Sonoff ตามภาพ

หมายเหตุ
1.Source Code ที่ให้นอกจากจะใช้กับ TTN แล้ว ยังสามารถใช้กับ Helium Network ได้เช่นกัน
2.ค่า MAX TX Power, Dwell time กำหนดที่ RegionAS923.h

ลิ้งค์บทความนี้ คลิก

--

--

Somsak Lima
Somsak Lima

Written by Somsak Lima

สนับสนุนและส่งเสริมให้ผู้สนใจสามารถใช้งานเทคโนโลยี LoRa และ LoRaWAN ได้ โดยนำความรู้ที่ได้ไปต่อยอดเพื่อใช้งาน

No responses yet