วิธีติดตั้ง MicroPython บน Heltec WIFI LoRa 32(V2) และใช้งาน LoRaWAN, AHT10

Somsak Lima
7 min readFeb 24, 2024

--

ไฟล์ตัวอย่างทั้งหมดโหลดได้จาก คลิก

เนื่องจาก Lib ulora ที่ใช้นั้นสามารถ authen ได้เฉพาะวิธี ABP ดังนั้น Node นี้จะใช้ได้กับ TTN หรือ Chirpstack ไม่สามารถใช้กับ Helium Network ได้

อุปกรณ์ที่ใช้ เช่น

  1. Heltec WIFI LoRa 32(V2)
  2. Senser อุณหภูมิ และความชื้น AHT10
  3. Breadboard
  4. สายไฟ Jumper

โปรแกรมที่ใช้

  1. Thonny Version 4.1.4

ติดตั้ง Firmware MicroPython

เปิดโปรแกรม Thonny

ไปที่เมนู Tool/Option

คลิก Tab Interpreter

เลือก MicroPython(ESP32) และ Port CP2102 USB to UART Bridge หรือ Port ที่ Heltec เชื่อมสายอยู่

แล้วคลิก install or update MicroPython(esptool)

เลือก Option ตามภาพด้านล่าง

แล้วคลิก Install โปรแกรมจะเริ่ม Download Firmware อัตโนมัติ และเริ่มเขียน

หากเสร็จเรียบร้อยจะเห็นข้อความ Done! ให้คลิก Close แล้วคลิก OK เพื่อปิดหน้าต่าง

เริ่มต้นใช้งาน

เปิด Thonny ควรตั้งค่า View ของโปรแกรม Thonny ให้แสดงหน้าต่าง Files และหน้าต่าง Shell

ที่หน้าต่าง Files จะเห็น ไฟล์ boot.py อยู่หนึ่งไฟล์

หน้าจอ Shell จะเห็นข้อความ

คลิกซ้ายที่มุมขวาบนของ MicroPython Device รูปเส้นตรงสามขีด จะมี Option ให้เลือก เช่น Storage Space

เลือก Storage Space จะเห็นว่ามีพื้นที่มากถึง 2MB

Pin Out WIFI LoRa 32(V2)

เชื่อม Sensor BME280 ขา SCL เข้า Pin 15 ขาSDL เข้ากับ Pin4 ของ Heltec
และ เชื่อม 3.3V GND เข้ากับ Sensor แล้วเริ่มทดสอบโปรแกรมตัวอย่าง
ส่วน OLED โรงงาน เชื่อมขา SCL เข้า Pin 15 และขา SDL เข้ากับ Pin4 แต่จะเปิด OLED ให้ทำงานต้องตั้ง Pin16 เป็น High

Download File

Library ต่างๆ หรือ File ทั้งหมดตามตัวอย่าง
สามารถเลือก Download ได้จาก ลิ้งค์ คลิก

ตัวอย่างที่ 1.0 scanI2C.py

import machine
i2c = machine.SoftI2C(scl=machine.Pin(15), sda=machine.Pin(4), freq=20000) #heltec 5/4
pin16 = machine.Pin(16, machine.Pin.OUT)
pin16.value(1)

print('Scan i2c bus...')
devices = i2c.scan()

if len(devices) == 0:
print("No i2c device !")
else:
print('i2c devices found:',len(devices))

for device in devices:
print("Decimal address: ",device," | Hexa address: ",hex(device))

ผลการ RUN

>>> %Run -c $EDITOR_CONTENT
Scan i2c bus...
i2c devices found: 2
Decimal address: 56 | Hexa address: 0x38
Decimal address: 60 | Hexa address: 0x3c

ตัวอย่างที่ 2.0 แสดงค่า Temp และ humid จาก Sensor AHT10

import machine
import utime
from machine import Pin, SoftI2C
import ahtx0
i2c = machine.SoftI2C(scl=machine.Pin(15), sda=machine.Pin(4), freq=20000) #heltec 5/4
sensor = ahtx0.AHT10(i2c)
temp=round(sensor.temperature,2)
hum=round(sensor.relative_humidity,2)
print("Temp=",temp)
print("Humid=",hum)

*จำเป็นต้องติดตั้ง Lib ใช้งานด้วย คือ ahtx0.py

ผลการ RUN

>>> %run -c $EDITOR_CONTENT
Temp= 31.54
Humid= 69.22

ตัวอย่างที่ 3.0 แสดงข้อความ LoRaWAN Thailand ออกหน้าจอ OLED

ให้ copy file ssd1306.py ใส่ลงใน MicroPython Device ด้วย

import machine, ssd1306
oled_width = 128
oled_height = 64
i2c = machine.SoftI2C(scl=machine.Pin(15), sda=machine.Pin(4)) #heltec 5/4
pin16 = machine.Pin(16, machine.Pin.OUT)
pin16.value(1)
oled = ssd1306.SSD1306_I2C(oled_width, oled_height, i2c)

oled.fill(0)
oled.text("LoRaWAN Thailand 1", 0, 0)
oled.text("LoRaWAN Thailand 2!", 0, 10)
oled.text("LoRaWAN Thailand 3!", 0, 20)
oled.text("LoRaWAN Thailand 4!", 0, 30)
oled.text("LoRaWAN Thailand 4!", 0, 40)
oled.text("LoRaWAN Thailand 4!", 0, 50)
oled.show()

ผลการ RUN

ตัวอย่างที่ 4.0 ส่ง bytearray เข้า LoRaWAN Network Server

ให้ copy file ulora.py ulora_encryption.py ttn_as.py ใส่ลงใน MicroPython Device ด้วย

import utime, time
from ulora import TTN, uLoRa
#heltec
LORA_CS = const(18)
LORA_SCK = const(5)
LORA_MOSI = const(27)
LORA_MISO = const(19)
LORA_IRQ = const(26)

LORA_RST = const(14)
LORA_DATARATE = "SF7BW125" # Choose from several available
# From TTN console for device
DEVADDR = bytearray([0x26, 0x01, 0x15, 0x6A])

NWKEY = bytearray([0xA6, 0xC3, 0x0F, 0xB2, 0x91, 0xDB, 0x55, 0xC5,
0x31, 0x82, 0x53, 0xD4, 0x08, 0x08, 0x7A, 0x4E])
APP = bytearray([0x54, 0xBE, 0x2D, 0xE6, 0xB6, 0xB3, 0xF7, 0xC2,
0xD0, 0x33, 0x72, 0xB5, 0x27, 0x20, 0xD6, 0x20 ])

TTN_CONFIG = TTN(DEVADDR, NWKEY, APP, country="AS")
FPORT = 1
lora = uLoRa(
cs=LORA_CS,
sck=LORA_SCK,
mosi=LORA_MOSI,
miso=LORA_MISO,
irq=LORA_IRQ,
rst=LORA_RST,
ttn_config=TTN_CONFIG,
datarate=LORA_DATARATE,
fport=FPORT
)
# ...Then send data as bytearray
data = bytearray([0x01, 0x02, 0x03, 0x04])

counter = 0
while True:
lora.frame_counter=counter
lora.send_data(data, len(data), lora.frame_counter)
time.sleep(5)
counter += 1

ผลการ RUN

ตัวอย่าง Key ABP

#Device Address msb
DEVADDR = bytearray([0x26, 0x01, 0x15, 0x6A])
#NwkSKey msb
NWKEY = bytearray([0xA6, 0xC3, 0x0F, 0xB2, 0x91, 0xDB, 0x55, 0xC5,
0x31, 0x82, 0x53, 0xD4, 0x08, 0x08, 0x7A, 0x44])
#AppSkey msb
APP = bytearray([0x54, 0xBE, 0x2D, 0xE6, 0xB6, 0xB3, 0xF7, 0xC2,
0xD0, 0x33, 0x72, 0xB5, 0x27, 0x20, 0xD6, 0x22 ])

เทียบกับหน้าจอ TTN

ตัวอย่างที่ 5.0 ส่งข้อมูลจาก Sensor เข้า LoRaWAN Network Server ใช้วิธี Authen แบบ ABP ใช้รูปแบบข้อมูลแบบ CayenneLPP

import machine
import ahtx0
from cayennelpp import CayenneLPP
from machine import Pin,I2C
import utime, time, ssd1306
from ulora import TTN, uLoRa
#heltec
LORA_CS = const(18)
LORA_SCK = const(5)
LORA_MOSI = const(27)
LORA_MISO = const(19)
LORA_IRQ = const(26)
LORA_RST = const(14)

LORA_DATARATE = "SF7BW125" # Choose from several available


DEVADDR = bytearray([0x26, 0x01, 0x15, 0x6A])
NWKEY = bytearray([0xA6, 0xC3, 0x0F, 0xB2, 0x91, 0xDB, 0x55, 0xC5,
0x31, 0x82, 0x53, 0xD4, 0x08, 0x08, 0x7A, 0x4E])
APP = bytearray([0x54, 0xBE, 0x2D, 0xE6, 0xB6, 0xB3, 0xF7, 0xC2,
0xD0, 0x33, 0x72, 0xB5, 0x27, 0x20, 0xD6, 0x20 ])

TTN_CONFIG = TTN(DEVADDR, NWKEY, APP, country="AS")
FPORT = 1
lora = uLoRa(
cs=LORA_CS,
sck=LORA_SCK,
mosi=LORA_MOSI,
miso=LORA_MISO,
irq=LORA_IRQ,
rst=LORA_RST,
ttn_config=TTN_CONFIG,
datarate=LORA_DATARATE,
fport=FPORT
)

#SENSOR
i2c = machine.SoftI2C(scl=machine.Pin(15), sda=machine.Pin(4)) #heltec 5/4
pin16 = machine.Pin(16, machine.Pin.OUT)
pin16.value(1)

counter = 0
while True:
sensor = ahtx0.AHT10(i2c)
oled = ssd1306.SSD1306_I2C(128, 64, i2c, 60)

print( "------------------------------------")
print( "Packet #{}".format( counter ) )
print("AHT10 values:")
print("Temp=",(round(sensor.temperature,2)))
print("Humid=",(round(sensor.relative_humidity,2)))
print( "------------------------------------")

oled.text("Temp =",0,0)
oled.text(str(round(sensor.temperature,2)),50,0)
oled.text("Humid=",0,15)
oled.text(str(round(sensor.relative_humidity,2)),50,15)
oled.text("Packet No.",0,50)
oled.text(str(counter),85,50)
oled.show()


c = CayenneLPP()
c.addTemperature(1, round(sensor.temperature,2)) # Add temperature read to channel 1
c.addRelativeHumidity(2, round(sensor.relative_humidity,2)) # Add relative humidity read to channel 2
data = c.getBuffer() # Get bytes
lora.frame_counter=counter
lora.send_data(data, len(data), lora.frame_counter)
time.sleep(5)
counter += 1

ให้ copy file ulora.py ulora_encryption.py ttn_as.py cayennelpp.py ใส่ลงใน MicroPython Device ด้วย

ไฟล์ ttn_as.py หากเป็นความถี่ AS1 จะเป็นดังต่อไปนี้ ไฟล์เดิมด้านหลังเลขความถี่ตรง Comment ยังไม่ได้แก้ให้ถูกต้อง ในวงเล็บเป็นค่าที่ถูกต้อง

# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE."""
`ttn_as.py`
======================================================
AS920 The Things Network Frequency Plans
* Author(s): Brent Rubell
"""
TTN_FREQS = {0: (0xe6, 0xCC, 0xF4), # 868.1 MHz (923.2 Mhz)
1: (0xe6, 0xD9, 0xC0), # 868.3 MHz (923.4 Mhz)
2: (0xe6, 0x8C, 0xF3), # 863.5 MHz (922.2 Mhz)
3: (0xe6, 0x99, 0xC0), # 867.1 MHz (922.4 Mhz)
4: (0xe6, 0xA6, 0x8D), # 867.3 MHz (922.6 Mhz)
5: (0xe6, 0xB3, 0x5A), # 867.5 MHz (922.8 Mhz)
6: (0xe6, 0xC0, 0x27), # 867.7 MHz (923.0 Mhz)
7: (0xe6, 0x80, 0x27)} # 867.9 MHz (922.0 Mhz)

ถ้าจะใช้ความถี่ AS2 ให้ใช้ค่าดังต่อไปนี้

TTN_FREQS = {0: (0xe6, 0xCC, 0xF4), # 923.2 Mhz
1: (0xe6, 0xD9, 0xC0), # 923.4 Mhz
2: (0xe6, 0xe6, 0x66), # 923.6 Mhz
3: (0xe6, 0xf3, 0x33), # 923.8 Mhz
4: (0xe7, 0x00, 0x00), # 924.0 Mhz
5: (0xe7, 0x0C, 0xCC), # 924.2 Mhz
6: (0xe7, 0x19, 0x99), # 924.4 Mhz
7: (0xe7, 0x26, 0x66)} # 924.6 Mhz

ผลการ RUN

หากเปิดหน้า ถ้าใช้งาน Dragino LoRaWAN Gateway LPS8N-AS923-TH หากเปิดหน้า Gateway Traffic จะเห็นข้อมูลเข้า ซึ่งมี Dev Addr ตรงกับที่เราใส่ไว้ในโปรแกรม

ตัวอย่างที่ 6.0 Blink

from machine import Pin
from time import sleep
led = Pin(25, Pin.OUT)
while True:
led.value(not led.value())
sleep(0.5)

หมายเหตุ การใช้ LoRaWAN ตามตัวอย่างซึ่งใช้ ulora library ตามตัวอย่างนั้นมีข้อจำกัด เช่น

  • ใช้ได้เฉพาะการ Authen แบบ ABP ไม่รองรับ OTAA
  • ไม่รองรับการ Downlink
  • กลุ่มผู้ใช้ TTN หรือ TTS เห็นว่า lib ulora นั้นไม่ได้จัดการข้อมูล Downlink จาก TTN ทำให้ LoRaWAN Network Server ควบคุมการทำงานตัว Node ไม่ได้

แต่ก็ง่ายและสามารถนำไปใช้งานได้ดีระดับหนึ่งทีเดียว

  • **สำหรับMicropython รุ่นหลังๆ จะต้องแก้ ไฟล์ ulora.py บรรทัดที่ 118 จาก machine.SPI เป็น machine.SoftSPI

Troubleshooting

กรณีที่ส่งเข้า Gateway ได้บ้างไม่ได้บ้าง ให้ เช็ค 3 เรื่องคือ

  1. Gateway ได้ จำกัด Duty Cycle ไว้หรือไม่ ให้เอาคลิก Enforce Duty Cycle ออก แล้วคลิก Save (ใต้ LoRaWAN options ของ Gateway)

2. ถ้า Authen แบบ ABP ให้ เลือก Reset Frame Count ไว้ด้วย

ที่ Config Network Layer ของตัว Node ใต้ Advanced MAC setting ติกหน้า Resets frame counter แล้วคลิก Save

3.บางคั้งอาจจะต้อง Reset session และ MAC stats

--

--

Somsak Lima
Somsak Lima

Written by Somsak Lima

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

No responses yet