1.การใช้ LoRaWAN® กับมอดูล Maxiiot เบื้องต้น ตอน 1

Somsak Lima
25 min readMar 15, 2020

--

Maxiiot DL7612-AS923-TH (Updated 14 ตค.65)

มอดูล LoRaWAN® ของบริษัท MAXIIOT รุ่น DL7612-AS923-TH เป็นมอดูลที่ใช้ AT Command ในการสั่งงาน มอดูลมีขนาดเล็กเพียง 22.0x15.0x2.7 มม. และเนื่องจากใช้ AT Command จะทำให้ลดขั้นตอนในการเขียนโปรแกรมลงค่อนข้างมากจึงทำให้การเขียนโปรแกรมทำได้ง่ายขึ้น

มอดูลผลิตในประเทศจีนราคาจึงไม่แพงมาก สามารถรองรับการใช้งานในสภาพแวดล้อมอุณภูมิจาก -40 ถึง 85 องศา สามารถนำไปใช้ในโรงงานอุตสาหกรรมต่างๆ ได้ และที่สำคัญคือมอดูลนี้ผ่านการรับรองจาก กสทช. เป็นอุปกรณ์ Class A* หมายเลข A59004–20–1933 ให้ใช้งานความถี่ในประเทศไทย ย่าน 920–925 Mhz

กำลังส่งออกจากมอดูล 19.5dBm หรือ 89mW และหากต่อกับสายอากาศภายนอกขนาด 3 dBi จะทำให้มีกำลังออกอากาศ ที่ 22.5 dBm (eirp.) หรือ 178 mW ซึ่งจะมีระยะทางรับส่งการใช้งานประมาณ 3–5 กม.

สรุปหลักการใช้งานย่อๆ ตัวมอดูลจะมีหน่วยความจำเก็บค่า Config สำหรับการเชื่อมต่อไว้เมื่อเราสั่ง reboot มันจะเชื่อมต่ออัตโนมัติ เมื่อเชื่อมต่อแล้วก็สามารถเริ่มต้นส่งข้อมูล การใช้งานจึงต้องศึกษาวิธีเรียกดูค่าคอนฟิกและแก้ไขค่าคอนฟิกให้เป็นไปตามที่เราต้องการ

หมายเหตุ อุปกรณ์ Class A หรือ B ที่กำหนดโดย กสทช. คนละความหมายกับ Node Class A,B ของ LoRaWAN เป็นการบังเอิญที่ใช้ศัพท์ตรงกัน

รูปมอดูล Maxiiot DL7612-AS923-TH เทียบกับขนาดเหรียณบาท
คุณลักษณะของมอดูล ซึ่งประกอบจาก Semtech SX1276
แสดงขามองจากด้านบน

กรณีต้องการระยะทางในการสื่อสารมากขึ้นให้ใช้สายอากาศเกณฑ์ขยาย 3dBi ยาว19 ซม. ตามรูป หากใช้สายอากาศขนาดเล็กยาว 5 ซม. จะเพียงพอสำหรับทดสอบ indoor หรือระยะทางไม่เกิน 1 กม. เท่านั้น

ตัวมอดูลสามารถใช้บอร์ด Adapter เพื่อแปลงขา TX RX 3.3V GND เป็น Pin Header และเชื่อมเข้ากับ MCU ที่เราเลือกใช้ สามารถต่อผ่าน UART PORT เพื่อใช้งานได้ทันที จึงทำให้การใช้งานทำได้สดวกเหมาะกับ Maker นักพัฒนา หรือกลุ่ม SI (System Integrator) ทั่วไป

ค่าการสื่อสารผ่านโมดูลจะใช้ Baud rate 115200, Data 8 bit, Parity none, Stop 1 bit, Flow control none โดยใช้ไฟเลี้ยงที่ 3.3 V

มอดูลจะถูกตั้งความถี่มาจากโรงงานเป็น AS2 923–925Mhz (AT+ISMBAND=2) แต่เราก็สามารถจะสลับเลือกไปใช้ AS1 920–923Mhz ได้ (AT+ISMBAND=6) ซึ่งทั้ง AS1 และ AS2 อยู่ในช่วงความถี่ 920–925 Mhz ที่ กสทช. อนุญาติ ตามประการราชกิจจานุเบกษา — หลักเกณฑ์การอนุญาตให้ใช้คลื่นความถี่ย่าน 920–925MHz คลิ๊ก

AS1 (920–923Mhz)

Uplink:
923.2 — SF7BW125 to SF12BW125
923.4 — SF7BW125 to SF12BW125
922.2 — SF7BW125 to SF12BW125
922.4 — SF7BW125 to SF12BW125
922.6 — SF7BW125 to SF12BW125
922.8 — SF7BW125 to SF12BW125
923.0 — SF7BW125 to SF12BW125
922.0 — SF7BW125 to SF12BW125
922.1 — SF7BW250
921.8 — FSK
Downlink:
Uplink channels 1–10 (RX1)
923.2 — SF10BW125 (RX2)

AS2 (923–925Mhz)

Uplink:
923.2 — SF7BW125 to SF12BW125
923.4 — SF7BW125 to SF12BW125
923.6 — SF7BW125 to SF12BW125
923.8 — SF7BW125 to SF12BW125
924.0 — SF7BW125 to SF12BW125
924.2 — SF7BW125 to SF12BW125
924.4 — SF7BW125 to SF12BW125
924.6 — SF7BW125 to SF12BW125
924.5 — SF7BW250
924.8 — FSK
Downlink:
Uplink channels 1–10 (RX1)
923.2 — SF10BW125 (RX2)

วัตถุประสงค์ของบทความนี้

บทความนี้เป็นการเสนอวิธีการที่จะเชื่อมหรือประกอบใช้งานกับ MCU หรือ CPU แบบต่างๆ และการใช้เครื่องมือที่แตกต่างกันในการเข้าไปควบคุมการทำงานด้วยคำสั่ง AT Command จึงไม่ได้อธิบายการใช้งาน AT Command อย่างละเอียด และไม่ได้อธิบายการใช้งานในส่วน LoRaWAN® Server ผู้ใช้สามารถดูได้จากบทความที่เกี่ยวข้องอื่น ผู้สนใจใช้งานมอดูลกับ Hardware ตัวไหนสามารถแยกอ่านเป็นเรื่องๆ

โค้ดที่ให้ไว้ก็เขียนขึ้นแบบง่ายๆ แบบ Quick & Dirty เพื่อเป็นแนวทางให้ผู้สนใจพัฒนาใช้งานดูเป็นตัวอย่าง จึงอาจขาดความสมบูรณ์อยู่บ้าง เช่น ขาดการดัก error และ retry เป็นต้น

การใช้งานตามบทความนี้ต้องลงทะเบียนตัว Node กับ LoRaWAN® Server ของ TheThingsNetwork.org ก่อน การลงทะเบียน Node ทำเพื่อขออนุญาติให้ Node สามารถเชื่อมต่อเข้ากับ LoRaWAN® Network Server และเนื่องจาก TTN ปัจจุบันยังรองรับเพียง Node Class A การทดสอบจะทำการ Config มอดูล เป็น Node Class A

ลักษณะการทำงาน Node Class ต่างๆ

Class A หลังส่งจะรอข้อมูลกลับที่ความถี่ RX1 กับ RX2 ช่วงหนึ่ง (ประหยัดพลังงานเนื่องจากส่งแล้วเราสั่งมอดูล Sleep ได้แล้วค่อยตื่นมาส่งครั้งต่อไป)

Class B จะใช้จังหวะ Beacon เป็นตัวกำหนดเวลารับส่งให้ตรงกัน

Class C หลังจากส่งจะ Standby รอรับข้อมูลตลอดเวลา (ไม่ได้ประหยัดพลังงานเพราะจะคอยรับการส่งข้อมูลกลับตลอดในขนะที่ไม่ได้มีการส่งข้อมูล)

การลงทะเบียน Node จะต้องเลือกว่าเป็น Node ที่ใช้ระหัสผ่านแบบ ABP หรือ OTAA อย่างใดอย่างหนึ่ง

ตัวอย่าง KEY ที่ต้องแก้ใน SKETCH .ino โดยเลือกใช้ Authen ตัวใดตัวหนึ่ง

การ Authen กับ TTN แบบ OTAA
จะใช้ KEY คือ DEVEUI, APPKEY, APPEUI*** ให้เอา DEVEUI(R), APPKEY(RW),APPEUI(RW) จากมอดูลมาป้อนในหน้าเวป TTN

การ Authen แบบ ABP กับ TheThingsNetwork
จะใช ้KEY คือ DEVADDR, APPSKEY, NWKSKEY ให้เอา DEVADDR() APPSKEY(RW) และ NWKSKEY(RW) จากที่ TTN สร้างให้ Write ทับค่าในมอดูล

***APPEUI เปลี่ยนชื่อเรียกเป็น Join EUI ในบางแอป

*(วงเล็บ R คืออ่านค่า W คือเขียนค่าทับได้)

** lsb ย่อมาจาก Least Significant Byte
***msb ย่อมาจาก Most Significant Byte

ผุ้เขียนได้ทดสอบโปรแกรมทั้งหมดกับ LoRaWAN® Gateway ยี่ห้อ Dragino LG308-As923-TH ซึ่งเป็น Multi Channel Gateway อ่านรายละเอียด LoRaWAN® gateway นี้ได้ที่ คลิก

Dragino LG308-AS923-TH-EC25

ก่อนอื่นขออธิบายหลักการกว้างๆ ของการใช้มอดูลก่อนไม่ว่าจะใช้กับ Tool หรือโปรแกรมภาษาใดๆ ก็ตาม เราจะตั้งและ Save ค่าคอนฟิกในโมดูลตามที่เราต้องการไว้ก่อน ค่าหลักๆ ที่ตั้งไว้และ Save ไว้จะแสดงออกมาด้วยคำสั่ง AT+NCONFIG และเมื่อจะใช้งานเราจะ Reboot มอดูล มอดูลจะเริ่มทำการเชื่อมต่ออัตโนมัติตามที่เราตั้งค่าไว้ เมื่อเชื่อมต่อสำเร็จเราก็เริ่มส่ง Packet ได้

1.การใช้งานกับ ESP32 Dev Board

1.1 การเชื่อมต่อกับ Development Board ที่เป็นรุ่น ESP32 Wroom นั้น จะเชื่อมต่อนแบบอนุกรม (Serial) ผ่าน UART Port ของ ESP32 โดยวิธีนี้ใช้สายไฟเพียง 4 เส้น

ESP32 มี Hardware Serial UART อยู่ 3 ports คือ UART0, UART1,UART2 แต่ UART0 ได้ถูกนำไปใช้กับหน้าจอ Monitor หรือ Debug การทำงาน (เชื่อมต่อกับหน้าต่าง REPL หรือ Serial Monitor) ส่วน UART1 ขา RX ก็ถูกนำไปใช้กับ SPI ดังนั้นการใช้งาน Maxiiot Dl7612-AS923-TH จะต้องใช้กับ UART2

หากเราต้องการจะต่อมอดูล GPS เราสามารถใช้ ขา UART1 ได้หนึ่งขาที่ว่างคือ GPIO10 โดยเรียกใช้ด้วยคำสั่ง

uart = UART(1, 9600,timeout=20,rx=10)

หลังจากเชื่อม Hardware แล้วเราสามารถใช้ภาษา Micro Python หรือ C++ กับ Development Board ได้

1.2 ESP32 ที่ใส่ Firmware ภาษา MicroPython (ผู้ที่สนใจใช้งานกับภาษา C ให้ดูที่หัวข้อ 1.3)
ตัวอย่างต่อไปนี้เป็นโปรแกรมภาษา MicroPython

* วิธี Flash Firmware ESP32 Dev Board เพื่อให้ใช้ภาษา MicroPython ได้ทำได้ตาม ลิ้งค

1.2.1 ส่งข้อความ Hello
โปรแกรมจะส่งข้อความ Hello จำนวน 100 ข้อความ ไปยัง TheThingNetwork โดยโปรแกรมจะ Authen แบบ ABP หรือ OTA แล้วแต่ค่าที่เซฟ ไว้ใน Firmware ของมอดูล

from machine import UART 
# from pyb import UART
import time
uart = UART(2, 115200, timeout=2000)
uart.write("AT+NRB\r\n")
print(uart.read())
time.sleep(15.0)
uart.write("AT+ADDR=260118AA\r\n")
print(uart.read())
uart.write("AT+APPSKEY=1506BF244D60B5A46AB1AECA063723AA\r\n")
print(uart.read())
uart.write("AT+NWKSKEY=E23ACC607153466B0421B95589B2A3AA\r\n")
print(uart.read())
uart.write("AT+ACTIVATE=0\r\n") # ABP Activate
print(uart.read())
cnt = 1
while True:
print("Hello! #{}".format(cnt))
uart.write("AT+NCMGS=5, HELLO\r\n")
print(uart.read().decode('utf-8'))
if cnt >= 100:
break
cnt = cnt + 1
time.sleep(3.0)

1.2.2 ส่งค่าจากเซนเซอร์ BME280 ด้วยรูปแบบ CayenneLPP

ตัวอย่างต่อไปนี้เป็นการอ่านค่าจากเซนเซอร ์BME280 ซึ่งจะได้ค่าอุณหภูมิ ความชื้น และความดันบรรยากาศ แล้วส่งขึ้น TheThingsNetwork ใช้รูปแบบข้อมูล CayenneLPP

import bme280, time, ubinascii, machine
from machine import UART
from cayennelpp import CayenneLPP
temp = 0
pa = 0
hum = 0
i2c = machine.I2C(scl=machine.Pin(22), sda=machine.Pin(21))
bme = bme280.BME280(i2c=i2c)
uart = UART(2, 115200, timeout=2000)
uart.write('AT+NRB\r\n')
print(uart.read().decode('utf-8'))
time.sleep(20.0)
uart.write('AT\r\n')
print(uart.read().decode('utf-8'))
cnt = 1
while True:
print("********Packet No #{}".format(cnt))
temp, pa, hum = bme.values
print("********BME280 values:")
print('temp:', temp, ' Hum:', hum , 'PA:', pa)
c = CayenneLPP()
c.addTemperature(1, float(temp))
c.addRelativeHumidity(2, float(hum))
c.addBarometricPressure(3, float(pa))
d = (ubinascii.hexlify(c.getBuffer()))
print(' - - - - -Start Send Status - - - - - - ')
print("AT+NMGS={0},{1}\r\n".format(int(len(d)/2), (d.decode('utf-8'))))
uart.write("AT+NMGS={0},{1}\r\n".format(int(len(d)/2), (d.decode('utf-8'))))
# print(uart.read())
print(uart.read().decode('utf-8'))
print(' - - - - -End Send Status - - - - - - ')
cnt = cnt + 1
time.sleep(5.0)

*ดาวน์โหลด Lib CayenneLPP ได้ที่ คลิก
*ดาวน์โหลด Lib BME280 ได้ที่ คลิก

1.2.3 อ่านค่าจาก BME280 แสดงผลออกหน้าจอ OLED ส่งค่าที่อ่านได้ขึ้น TheThingsNetwork ด้วยรูปแบบ CayenneLPP และรับคำสั่ง Downlink มาควบคุมหลอด LED

เป็นตัวอย่างสำหรับการทำ Node ที่ต่อกับ เซนเซอร์ BME280 เพื่อส่งค่าอุณหภูมิ ความชื้น ความดันบรรยากาศ ขึ้น TheThingsNetwork โดยการ Authen แบบ OTAA และมีการตรวจเช็คคำสั่ง Downlink เพื่อมาควบคุม LED โดยหากมีการ Downlink ค่า HEX AA BB CC DD (อักษรตัวใหญ๋ทั้งหมด) และครบรอบส่ง Uplink ของโหนด Class A ตัวโหนดก็จะได้รับอักษรดังกล่าวมา หากโปรแกรมตรวจเช็คอักษรตรงกันก็จะไปเปิด LED แต่หาก LED เปิดอยู่ก็จะทำการปิด

# By Somsak Lima and Itti Srisumalai
# With suggestion from arjanvanb@TTN
import ure
import bme280, Assd1306, time, ubinascii, machine
from machine import UART, Pin
from cayennelpp import CayenneLPP
from time import sleep
led = Pin(2, Pin.OUT)
temp = 0
pa = 0
hum = 0
i2c = machine.I2C(scl=machine.Pin(22), sda=machine.Pin(21))
bme = bme280.BME280(i2c=i2c)
d = Assd1306.SSD1306_I2C(128, 64, i2c, 0x3c)
uart = UART(2, 115200, timeout=2000)
uart.write('AT+NRB\r\n')
print(uart.read().decode('utf-8'))
time.sleep(20.0)
uart.write('AT\r\n')
print(uart.read().decode('utf-8'))
cnt = 1
while True:
print("Packet No #{}".format(cnt))
temp, pa, hum = bme.values
print("**************")
print("BME280 values:")
print("**************")
print('temp:', temp, ' Hum:', hum , 'PA:', pa)
d.fill(0)
d.text("#", 95, 50)
d.text(str(cnt), 102, 50)
d.text("Temp. "+temp, 0, 0)
d.text("Hum. "+hum, 0, 10)
d.text("PA "+pa, 0, 20)
d.show()
c = CayenneLPP()
c.addTemperature(1, float(temp))
c.addRelativeHumidity(2, float(hum))
c.addBarometricPressure(3, float(pa))
b = (ubinascii.hexlify(c.getBuffer()))
print('---------Send Status------------')
print("AT+NMGS={0},{1}\r\n".format(int(len(b)/2), (b.decode('utf-8'))))
uart.write("AT+NMGS={0},{1}\r\n".format(int(len(b)/2), (b.decode('utf-8'))))
p = ure.search('FRMPayload:(.+?) \r\n', uart.read().decode('utf-8'))

try:
print(p.group(1))
pgroup = (p.group(1))
except AttributeError:
pgroup = ""
print('Not found Downlink Packet')
if pgroup == " aa bb cc":
print("Command1 Detected: On LED =============>")
led.value(not led.value())
sleep(0.5)
else:
print("No Known Command Detect")

print("++++++++++")
print('---------Send Status------------')
cnt = cnt + 1
time.sleep(5.0)
  • ตัว ssd1306 library ได้ ดาวน์โหลดจาก Github มาใช้งาน
    โดยได้ Rename ssd1306 เป็น Assd1306 แทน เพื่อไม่ให้สับสนกับ Lib ที่อยู่ใน Firmware ของ MicroPython ESP32

1.2.4 เพิ่มการแสดงผลบนหน้าจอ Dashboard Cayenne และเพิ่มไอคอนสั่ง DownLink เพิ่อปิดเปิดหลอด LED

# By Somsak Lima and Itti Srisumalai
import ure
import bme280, Assd1306, time, ubinascii, machine
import ssd1306
from machine import UART, Pin, I2C
from struct import unpack
from cayennelpp import CayenneLPP
from time import sleep
led = Pin(2, Pin.OUT)
temp = 0
pa = 0
hum = 0
i2c = machine.I2C(scl=machine.Pin(22), sda=machine.Pin(21))
bme = bme280.BME280(i2c=i2c)
d = Assd1306.SSD1306_I2C(128, 64, i2c, 0x3c)
uart = UART(2, 115200, timeout=2000)
uart.write('AT+NRB\r\n')
print(uart.read().decode('utf-8'))
time.sleep(20.0)
uart.write('AT\r\n')
print(uart.read().decode('utf-8'))
uart.write('AT+NCONFIG\r\n')
print(uart.read().decode('utf-8'))
cnt = 1
while True:
print("Packet No #{}".format(cnt))
temp, pa, hum = bme.values
print("**************")
print("BME280 values:")
print("**************")
print('temp:', temp, ' Hum:', hum , 'PA:', pa)
d.fill(0)
d.text("#", 95, 50)
d.text(str(cnt), 102, 50)
d.text("Temp. "+temp, 0, 0)
d.text("Hum. "+hum, 0, 10)
d.text("PA "+pa, 0, 20)
d.show()
c = CayenneLPP()
c.addTemperature(1, float(temp))
c.addRelativeHumidity(2, float(hum))
c.addBarometricPressure(3, float(pa))
c.addDigitalOutput(4, 1)
c.addAnalogOutput(5, 120.0)

b = (ubinascii.hexlify(c.getBuffer()))
print(' - - - - -Send Status - - - - - - ')
print("AT+NMGS={0},{1}\r\n".format(int(len(b)/2), (b.decode('utf-8'))))
uart.write("AT+NMGS={0},{1}\r\n".format(int(len(b)/2), (b.decode('utf-8'))))
p = ure.search('FRMPayload:(.+?) \r\n', uart.read().decode('utf-8'))

try:
print(p.group(1))
pgroup = (p.group(1))
except AttributeError:
pgroup = ""
print('Not found Downlink Packet')
if pgroup == " 04 00 64 ff":
print("Command1 Detected: On LED =============>")
led.value(1)
sleep(0.5)
elif pgroup==" 04 00 00 ff":
print("Command1 Detected: Off LED =============>")
led.value(0)
else:
print("No Known Command Detect")

print("++++++++++")
print(' - - - - -Send Status - - - - - - ')
cnt = cnt + 1
time.sleep(5.0)

สร้างปุ่ม Downlink โดยเพิ่มเติมบรรทัด

 c.addDigitalOutput(4, 1)
c.addAnalogOutput(5, 120.0)

และเพิ่มเงื่อนไขตรง elif เมื่อเปิด Cayenne.mydevices.com จะเห็นปุ่ม Switch Digital Output(4) และ Analog Output(5) โดยปุ่ม (4) หากกดปุ่ม On/Off Switch แล้ว Status ของตัวอักษรเปลี่ยนเป็นพื้นสีน้ำเงินก็จะเป็นการ On โดย Dashboard จะส่ง Downlink ค่า HAX ” 04 00 64 ff” มาที่ Node ซึ่งเราก็เขียนโปรแกรมเป็นเงื่อนไขกำหนดให้ LED เป็น 1 ซึ่งจะทำให้ LED ดวงสีน้ำเงินบน ESP32 สว่างขึ้น

หากเรากดปุ่ม On/Off Switch ให้พื้นเป็นสีเทา จะเป็นการส่ง Downlink ค่า HEX ” 04 00 00 ff” มาที่ Node เราก็เขียนเงื่อนไขโปรแกรมให้ LED เป็น 0 ซึ่งจะทำให้ LED สีน้ำเงินบน ESP32 ปิดลง

1.2.5 โปรแกรมเดียวกับหัวข้อ 1.2.4 แต่ดัดแปลงใช้ Function

# By Somsak Lima and Itti Srisumalai
import ure
import bme280, Assd1306, time, ubinascii, machine
from machine import UART, Pin
from cayennelpp import CayenneLPP
from time import sleep
led = Pin(2, Pin.OUT)
temp = 0
pa = 0
hum = 0
i2c = machine.I2C(scl=machine.Pin(22), sda=machine.Pin(21))
bme = bme280.BME280(i2c=i2c)
d = Assd1306.SSD1306_I2C(128, 64, i2c, 0x3c)
uart = UART(2, 115200, timeout=2000)
def sendATcommand(ATcommand):
print("Sending:{0}\r\n".format(ATcommand))
uart.write("{0}\r\n".format(ATcommand))
message = uart.read().decode('utf-8')
print(message)
return(message)
sendATcommand('AT+INFO')
sendATcommand('AT+NRB')
time.sleep(20.0)
sendATcommand('AT')
sendATcommand('AT+NCONFIG')
cnt = 1
while True:
print("Packet No #{}".format(cnt))
temp, pa, hum = bme.values
print("**************")
print("BME280 values:")
print("**************")
print('temp:', temp, ' Hum:', hum , 'PA:', pa)
d.fill(0)
d.text("#", 95, 50)
d.text(str(cnt), 102, 50)
d.text("Temp. "+temp, 0, 0)
d.text("Hum. "+hum, 0, 10)
d.text("PA "+pa, 0, 20)
d.show()
c = CayenneLPP()
c.addTemperature(1, float(temp))
c.addRelativeHumidity(2, float(hum))
c.addBarometricPressure(3, float(pa))
c.addDigitalOutput(4, 1)
c.addAnalogOutput(5, 120.0)
b = (ubinascii.hexlify(c.getBuffer()))
print(' - - - - -Sending Data Status - - - - - - ')
ATresp = sendATcommand("AT+NMGS={0},{1}".format(int(len(b)/2), (b.decode('utf-8'))))
p = ure.search('FRMPayload:(.+?) \r\n', ATresp)
try:
print(p.group(1))
pgroup = (p.group(1))
except AttributeError:
pgroup = ""
print('Not found Downlink Packet')
if pgroup == " 04 00 64 ff":
print("Command1 Detected: On LED =============>")
led.value(1)
sleep(0.5)
elif pgroup == " 04 00 00 ff":
print("Command1 Detected: Off LED =============>")
led.value(0)
else:
print("No Known Command Detect")

print(' - - - - -End Sending Data Status - - - - - - ')
cnt = cnt + 1
time.sleep(5.0)

1.3 การโปรแกรมภาษา C++ ด้วย Arduino IDE กับ ESP32 Dev Board ทั่วไป

1.3.1 หากเราต้องการใช ้Serial Terminal ของ Arduino IDE เพื่อป้อน AT Command โดยตรง จะต้อง Upload Sketch ชื่อ SerialPassthrough.ino โดยเชื่อมต่อขา TX2 (GPIO17) เข้าขา RX ของ DL7612 และขา RX2(GPIO16) เข้าขา TX ของ DL7612

// Serial Monitor Select Both NL & CR ,115200 baud
// ESP32 Pin Serial2 16/17
void setup() {
Serial.begin(115200);
Serial2.begin(115200);
}
void loop() {
if (Serial.available()) {
Serial2.write(Serial.read());
}
if (Serial2.available()) {
Serial.write(Serial2.read());
}
}
  • ด้านล่างของหน้าจอ Serial Terminal ให้เลือก เป็น Both NL & CR

บางครั้งเราอาจจะเข้า Debug โหมดของตัวโมดูล DL7612 และสั่งงาน AT Command ด้วยโปรแกรมนี้

วิธีนี้ดูไม่คล่องตัวเท่าไร เพราะต้องพิมพ์คำสั่งเอง ไม่มีการเก็บคำสั่งเก่าไว้ การใช้งานก็จะต้องลงโปรแกรมบนตัว MCU ก่อน ตอนจะใช้งาน MCU ก็ต้องใส่โปรแกรมที่เราเขียนขึ้นมาใหม่ทับลงไป ซึ่งจะเสียเวลาในการเขียนทับไปทับมา

1.3.2 โปรแกรมในการส่ง Hello ด้วยภาษา C++ เข้า TheThingsNetwork

เราจะต้อง Config ค่าต่างๆ เก็บไว้ใน มอดูลก่อน (ใช้ Serial Terminal tool) โดยเข้า debug โหมดของตัวโมดูล ตัวอย่างเช่น Config ให้ตอนรีบูทมอดูลทำงานในโหมด OTA (ใช้คำสั่ง AT+ACTIVATE=1) หากค่าเป็น 0 คือจะเลือกเป็น ABP ก่อนออกให้ใช้คำสั่ง AT+SAVE เพื่อเก็บค่าไว้ในตัวมอดูล เนื่องจาก TTN รองรับเฉพาะ Class A ให้ต้องค่าเป็น Class A ด้วย

AT+DEBUG=1
AT+ACTIVATE=1
AT+CLASS=A
AT+SAVE

ตรวจสอบ Key ที่มากับมอดูล เช่น APPEUI, DEVEUI และ APPKEY ด้วยคำสั่ง

AT+APPEUI
AT+DEVEUI
AT+APPKEY

ให้นำค่า KEY ต่างๆ ที่ได้จากมอดูลไปลงทะเบียนใน TheThingsNetwork โดยลงทะเบียนสร้าง Application ก่อนจากค่า APPEUI แล้วลงทะเบียน Device ภายใต้ Application ด้วย DeviceEUI และ APPKEY

ในช่อง APP Key ให้คลิกเครื่องหมายดินสอเพื่อให้เราสามารถป้อนข้อมูลเองได้

หลังจากนั้นตอนใช้งานก็เขียนโปรแกรมภาษา C++ ดังนี้ ใช้กับ ESP32 ดังนี้

*หมายเหตุ หากใน Arduino IDE ยังไม่มี board ESP32 ให้เลือกตอน Compile ให้ติดตั้งบอร์ด เพิ่มโดยทำตามบทความนี้ คลิก

เป็นตัวอย่างส่งข้อความ Hello เข้า TheThingsNetwork.org

กรณีต่อมอดูลเข้ากับ Hardware Serial2

String response = ""; 
void loop() {
sendCommand("AT+INFO\r\n");
sendCommand("AT+CGATT\r\n");
sendData(5,"HELLO");
delay(10000);
}
void setup() {
Serial.begin(115200);
Serial2.begin(115200);
sendCommand("AT\r\n");
sendCommand("AT+INFO\r\n");
sendCommand("AT+NCONFIG\r\n");
sendCommand("AT+DEVEUI\r\n");
sendCommand("AT+APPKEY\r\n");
sendCommand("AT+APPEUI\r\n");
sendCommand("AT+NRB\r\n");
delay(40000);
}
void sendCommand(String atComm){
response = "";
Serial2.print(atComm);
Serial.println("*******AT Command Sent");
Serial.print(atComm);
delay(300);
while(Serial2.available()){
char ch = Serial2.read();
//delay(500);
response += ch;
}
Serial.println(response);
}
void sendData(int type, String data){
String command = (String)"AT+NCMGS=" + type + "," +data + (String)"\r\n";
sendCommand(command);
}

ตัวอย่างดังกล่าวยังไม่ได้มีการดัก Error ต่างๆ เช่นหาก OTA ไม่สำเร็จให้มี Retry

1.3.3 ตัวอย่างโปรแกรมภาษา C ใช้ส่งข้อมูลรูปแบบ Cayenne เข้า TheThingNetworks.org โดบใช้ข้อมูลที่เรากำหนดเองคือ Temp และ Humid มอดูล DL7612-AS923-TH ต่ออยู่ที่ Hardware Serial2

#include <CayenneLPP.h>#include <stdio.h>#include <string.h>CayenneLPP lpp(51);
void loop() {
int dlen;
sendCommand("AT+CGATT");
lpp.reset(); // clear the buffer
lpp.addTemperature(2, 31.1);
lpp.addRelativeHumidity(3, 51.2);
dlen = lpp.getSize();
Serial.println(lpp.getSize());
char hex_str[(dlen * 2) + 1];
Serial.println("+++++++++++Show Data++++++++++++");
//Convert STRING Data to HEX
string2hexString((char * ) lpp.getBuffer(), hex_str, dlen); //ascii_str, hex_str
Serial.println(hex_str);
Serial.println("+++++++++++SEND Data++++++++++++");
sendHexData(dlen, hex_str);
delay(10000);
}
void setup() {
Serial.begin(115200);
Serial2.begin(115200);
sendCommand("AT");
sendCommand("AT+INFO");
sendCommand("AT+NCONFIG");
sendCommand("AT+DEVEUI");
sendCommand("AT+APPKEY");
sendCommand("AT+APPEUI");
sendCommand("AT+NRB");
delay(40000);
}
void sendCommand(String atComm) {
String response;
Serial2.print(atComm + "\r\n");
Serial.println("*******AT Command Sent");
Serial.print(atComm + "\r\n");
delay(300);
while (Serial2.available()) {
char ch = Serial2.read();
response += ch;
}
Serial.println(response);
}
void sendData(int type, String data) {
Serial.println("*******TEXT Build");
String command = (String)
"AT+NCMGS=" + type + "," + data + (String)
"\r\n";
sendCommand(command);
}
void sendHexData(int type, String data) {
Serial.println("*******HEX Build");
String command = (String)
"AT+NMGS=" + type + "," + data + (String)
"\r\n";
sendCommand(command);
}
void string2hexString(char * input, char * output, int dlen) {
int loop = 0;
int i = 0;
int count = dlen;
Serial.println("count");
Serial.println(count);
while (loop < count) {
sprintf((char * )(output + i), "%02X", input[loop]);
loop += 1;
i += 2;
}
//insert NULL at the end of the output string
output[i++] = '\0';
}

2.การใช้งานกับ Pyboard Board ที่ติดตั้ง MicroPython

ตัวอย่างการใช้ PyBoard เชื่อมเข้ากับ DL7612-AS923-TH ผ่าน Adapter
ตัวอย่างการเชื่อมกับ PyBoard อีกรุ่น

ก่อนอื่นให้เช็คก่อนว่า Firmware ที่ติดมากับ PyBoard นั้งเป็นเวอร์ชั่นอะไร เก่าไปหรือเปล่า

เช็คได้โดย ย้าย Cursor มาอยู่ในหน้าต่าง REPL แล้วให้กด CTRL-D ซึ่งจะทำให้ PyBoard ทำการ Soft Reboot และแสดง Welcome Screen ออกมา โดยจะมีรายละเอียดที่เราต้องการ เช่น

MPY: sync filesystems
MPY: soft reboot
MicroPython v1.12–331-ge97bb58f0 on 2020–04–04; PYBv1.1 with STM32F405RG
Type “help()” for more information.

หรืออาจใช้คำสั่ง

>>> import os; print (os.uname())
(sysname=’pyboard’, nodename=’pyboard’, release=’1.12.0', version=’v1.12–331-ge97bb58f0 on 2020–04–04', machine=’PYBv1.1 with STM32F405RG’)

ก็จะแสดง System Name และอื่นออกมาให้ทราบ ดูจากเวอร์ชั่นและวันที่ หากเห็นว่าเป็น Firmware ที่เก่าไปแนะนำให้ Upgrade Firmware ใหม ่โดยสามารถดาวน์โหลด Firmware ใหม่ๆ ได้จาก เวป www.micropython.org (อ่านบทความวิธีลง Firmware ใหม่ คลิก) โดยดูในส่วนของ Pyboard ตามรุ่น Hardware ที่เราใช้ จากรูปตัวอย่างด้านบนจะเป็น Hardware รุ่น PYBv.1.1 ใช้ MCU STM32F405RG ซึ่งเป็น ARM®32-bit Cortex®-M4 CPU with FPU คลิกดู Spec ละเอียด

กรณีที่เราต้องการใช้กับ PyBoard มักจะต้องเพิ่มบรรทัด import pyb ในตัวโปรแกรมเพื่อเพิ่มคำสั่งเฉพาะที่แตกต่างไปของ PyBoard

การเชื่อมกับมอดูล Maxiiot DL7612-AS923-TH ทำโดย เชื่อมสาย TX จากมอดูลเข้ากับขา X4 และ RX จากมอดูลเชื่อมเข้ากับขา X3

ส่วน Sensor BME280 ให้เชื่อม Vin เข้ากับ 3V3, ขา GND เข้ากับ GND, SCL เข้ากับ X9, SDA เข้ากับ X10 ซึ่งจะเป็น I2C1

อาจเลือกใช้ I2C2 โดยเปลี่ยนเป็นขา Y9 และ Y10 แทน

Pyboard PYBv1.1 ต่อกับ DL7612-AS923-TH และ ฺBME280

2.1 โปรแกรมอ่านค่า Sensor BME280 แปลงรูปแบบข้อมูลเป็น CayenneLPP แล้วส่งขึ้น TheThingsNetwork.org และส่งข้อมูลต่อไปยัง Cayenne Dashboard หาก กด On/Off Switch(4) จะส่งคำสั่งกลับมาควบคุมหลอด LED บน PyBoard

# By Somsak Lima and Itti Srisumalai
import ure, machine, pyb
import bme280, time, ubinascii
from machine import UART
from cayennelpp import CayenneLPP
from time import sleep
temp = 0
hum = 0
pa = 0
i2c = machine.I2C(1) # pyboard
bme = bme280.BME280(i2c=i2c)
uart = UART(2, 115200, timeout=2000)
led = pyb.LED(3) # 3 is the yellow LED
def sendATcommand(ATcommand):
print("Sending:{0}\r\n".format(ATcommand))
uart.write("{0}\r\n".format(ATcommand))
message = uart.read().decode('utf-8')
print(message)
return(message)
sendATcommand('AT+INFO')
sendATcommand('AT+NRB')
time.sleep(20.0)
sendATcommand('AT')
sendATcommand('AT+NCONFIG')
sendATcommand('AT+CHSET')
cnt = 1
while True:
print("\r\n\r\nPacket No #{}".format(cnt))
temp, pa, hum = bme.values
print("****************************")
print("BME280 values:")
print('temp:', temp, ' Hum:', hum , 'PA:', pa)
c = CayenneLPP()
c.addTemperature(1, float(temp))
c.addRelativeHumidity(2, float(hum))
c.addBarometricPressure(3, float(pa))
c.addDigitalOutput(4, 1)
c.addAnalogOutput(5, 120.0)

b = (ubinascii.hexlify(c.getBuffer()))
print(' - - - - -Sending Data Status - - - - - - ')
ATresp = sendATcommand("AT+NMGS={0},{1}".format(int(len(b)/2), (b.decode('utf-8'))))
p = ure.search('FRMPayload:(.+?) \r\n', ATresp)

try:
print(p.group(1))
pgroup = (p.group(1))
except AttributeError:
pgroup = ""
print('Not found Downlink Packet')
if pgroup == " 04 00 64 ff":
print("Command1 Detected: On LED =============>")
led = pyb.LED(2) # 2 is the GREEN LED
led.on()
sleep(0.5)
elif pgroup == " 04 00 00 ff":
print("Command1 Detected: Off LED =============>")
led = pyb.LED(2)
led.off()
else:
print(" No Known Command Detect")

print(" - - - -End Sending & Receiving Data Status - - - - ")
cnt = cnt + 1
time.sleep(5.0)

3. การนำไปใช้กับ Raspberry Pi

ขาที่นำไปใช้งานของ RPI

ขาของ RPI ที่ต่อไปใช้งาน 3V GND TX RX

ตัวอย่างรูปการต่อกับ Raspberry Pi4

อาจจะใช้กับ Board Adapter แบบ Pi Hat สามารถนำไปเสียบได้โดยตรงบน Pin ของ Raspberry Pi ตามรูป

การนำไปใช้กับ Raspberry Pi 0 W ด้วย PiHAT

ปัจจุบัน Raspberry Pi 0WH (รุ่นมี Wifi และบัดกรี Pin Header) หรือ Raspberry Pi 0W ราคาถูกลงค่อนข้างมาก อาจจะหาซื้อได้ในราคาที่ต่ำกว่า 300-400 บาท จึงมีความเป็นไปได้ที่จะนำมาทำเป็น Node มากขึ้น

กรณีต่อผ่าน Adapter Serial

หรือตามรูปด้านบนซึ่งต่อผ่าน Adapter Serial

3.1 จัดการ Port Serial บน Raspberry Pi
ปรกติแล้ว UART0 ของ Raspberry Pi เมื่อลง Raspbian เสร็จใหม่ๆ จะเตรียมไว้สำหรับต่อ Dump Terminal เช่น VT100 หรือ VT220 เป็นต้น เราต้องปิด Serial Terminal Service ก่อนแล้ว Enable Serial Port แทน

3.1.1 ทำโดยใช้ Raspi-conf

เรียกเมนู raspi-config ด้วยคำสั่ง sudo raspi-config แล้วเลือก เมนู 5 Interfacing Options

เลือก Menu P6 Serial

ต้องการมี Login Shell หรือเปล่า ให้ตอบ No

ต้องการใช้ Serial Port hardware หรือเปล่าให้ตอบ Yes

โปรแกรมจะให้เรา Confirm อีกครั้งให้ตอบ OK

3.1.2 ใช้ GUI ของ Raspbian ตั้งค่า Serial Port

3.2 เริ่มใช้งานบน Raspberry

3.2.1 ใช้ Terminal Program ชื่อ Cutecom

ตอนจะทดสอบคำสั่ง AT Command สามารถใช้โปรแกรม Cutecom ติดตั้งโดยใช้

sudo apt-get install cutecom

เรียกใช้ cutecom ได้ที่ System Tools/CuteCom เลือก Port ที่มอดูลต่ออยู่ และหลัง input ให้เลือก CR/LF ป้อนคำสั่งในช่องหลัง Input

ลองเปิด Port /dev/ttyS0 และใช้คำสั่ง AT+NRB เพื่อ Reboot มอดูล หากมอดูล SAVE ค่า Activation เป็น OTAA ไว ้และได้นำ KEY ลงทะเบียนไว้กับ LoRaWAN® Network Server ไว้แล้ว ก็จะได้ Message OTAA OK กลับมาแสดงว่าสามารถเชื่อมต่อได้สำเร็จ สามารถเริ่มต้นส่งข้อมูลได้

** ถ้าไม่มี /dev/ttyS0 ให้เลือก แสดงว่ายังไม่ได้แก้ไขใน raspi-config ที่กล่าวข้างต้น

3.2.2 ใช้ Shell ของ raspberry

stty -F /dev/ttyS0 115200
echo -e “AT\r\n” > /dev/ttyS0
cat /dev/ttyS0
echo -e “AT+NCONFIG\r\n” > /dev/ttyS0
cat /dev/ttyS0

เปิดหน้าต่าง Shell แล้วใช้คำสั่ง stty,echo และ cat

3.2.2 ใช้ภาษา Python บน Raspberry Pi

อาจใช้ mu หรือ thonny ทั้งสองโปรแกรมติดตั้งมากับ OS Raspbian ของ raspberry Pi อยู่แล้ว เรียนใช้โปแกรมโดยเข้าที่ Programming

3.2.2.1 การส่งข้อมูลติดต่อกับ Serial เช่น

import serial
import time
ser = serial.Serial("/dev/ttyS0", 115200, timeout=1)
ser.write(str.encode('AT+INFO\r\n'))
received = ser.read()
time.sleep(0.03)
data_left = ser.inWaiting()
received += ser.read(data_left)
print(received)
ser.write(str.encode('AT+CHSET\r\n'))
received = ser.read()
time.sleep(0.03)
data_left = ser.inWaiting()
received += ser.read(data_left)
print(received)

3.2.2.2 ตัวอย่างต่อไปนี้จะส่ง Hello ไปยัง TTN จำนวน 100 ครั้ง

ตัวอย่างการ Run โปรแกรม MicroPython ด้วย Thornny
import serial
import time
ser = serial.Serial("/dev/ttyS0", 115200, timeout=1)
ser.write(str.encode('AT+INFO\r\n'))
time.sleep(1)
received = ser.read(200)
print(received)
ser.write(str.encode('AT+NRB\r\n'))
received = ser.read(500)
print(received)
time.sleep(25)
cnt = 1
while True:
print("Hello! #{}".format(cnt))
ser.write(str.encode('AT+NCMGS=5,HELLO\r\n'))
received = ser.read(500)
print(received)
if cnt >= 100:
break
cnt = cnt + 1
time.sleep(3.0)

3.2.3 ใช้ภาษา C++ บน Raspberry Pi

สามารถใช้โปรแกรม GUI Geany ในการเขียนภาษา C++ ได้ ดูวิธีตั้งค่าและใช้งานได้ ที่ คลิก หรือ คลิก

ตั้งค่า Geany ให้ใช้ภาษา C++ โดยไปที่ Document/Set Filetype เลือก C++ source file

เช็คดูว่ามีการติดตั้ง wirePi ไว้แล้วหรือไม่โดยใช้คำสั่ง

$ gpio -v
$ gpio readall

ใช้คำสั่งเพื่อดูขา wPi เทียบกับ BCM ดังนี้

$ gpio readall

เพิ่ม link ใน Build Option โดย เติม -lwiringPi ต่อท้าย ทั้งตอน Compile และ Build

3.2.3.1 โปรแกรมทดสอบ พิมพ์ Hello, World ออกหน้าจอ

#include <stdio.h>
int main()
{
printf(“Hello, World! \n”);
return 0;
}

3.2.3.2 โปรแกรมทดสอบ ส่ง AT command ไปที่โมดูล Maxiiot DL7612-AS923-TH

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <wiringPi.h>
#include <wiringSerial.h>
int main ()
{
int fd;
// Setup serial port on ODROID
if ((fd = serialOpen ("/dev/ttyS0",115200)) < 0) {
fprintf (stderr, "Unable to open serial device: %s\n", strerror (errno)) ;
return 1 ;
}
if (wiringPiSetup () == -1) {
fprintf (stdout, "Unable to start wiringPi: %s\n", strerror (errno)) ;
return 1 ;
}
serialPrintf(fd,"AT+NCONFIG\r\n"); // send enter key to read data from sensor
delay(1000);
while (serialDataAvail (fd)) {
printf ("%c", serialGetchar(fd));
}
serialClose(fd);
}

3.2.3.3 โปรแกรมทดสอบ เปิดปิด LED จากดูรายละเอียดเพิ่มเติมได้จากลิ้งค์ คลิก

#include <iostream>
#include <wiringPi.h>
using namespace std;
int ledPin = 29; //Correspond à la pin 40void setup(){pinMode(ledPin,OUTPUT);
cout<<"Hello World" << endl;
}
void loop(){
digitalWrite(ledPin,HIGH);
delay(100);
digitalWrite(ledPin,LOW);
delay(100);
cout<<"Blink the LED" << endl;
}
int main(void)//(int argc, char **argv)
{
if(wiringPiSetup()<0){
cout<<"setup wiring pi failed"<<endl;
return 1;
}
setup();
while(1){
loop();
}

return 0;
}

3.2.4 การใช้ I2C Sensor กับ Raspberry Pi

ให้เปิด Port I2C ใน Raspberry Pi ให้ทำงานก่อน โดยใช้คำสั่ง

sudo raspi-config

เข้าเมนู 5 interface option เลือก F5 I2C แล้วให้ enable I2C ให้ทำงาน

อาจจะต้องติดตั้ง i2ctools ถ้ายังไม่ได้ติดตั้ง

sudo apt-get install i2c-tools

ลองใช้คำสั่ง

sudo i2cdetect -y 0 
หรือ
sudo i2cdetect -y 1

เชื่อมต่อสายเข้ากับ Sensor BME280 ดังภาพ เราสามารถเขียนโปรแกรมเพื่ออ่านค่า Sensor ที่ใช้การเชื่อมต่อแบบ I2C แล้วส่งผ่าน LoRaWAN ได้ไม่ยากนัก

4. การเชื่อมใช้งาน PC Desktop ที่ใช้ MS Windows 10

เชื่อมผ่านอุปกรณ์ USB to UART ตามภาพ ต้องระวังให้ตั้งค่า Jumper เป็น 3.3 V

4.1 ใช้ผ่าน Powershell

คลิก Search Windows ด้านล่างซ้าย รูปแว่นขยาย

พิมพ์ powershell แล้ว Enter จะมีหน้าต่าง Popup ขึ้นมาเป็นหน้าต่าง Windows PowerShell ตามรูป

คำสั่งตรวจสอบว่ามี com port อะไรที่เชื่อมต่ออยู่แล้วบ้าง
[System.IO.Ports.SerialPort]::getportnames()

และคำสั่งต่อไปเป็นตัวอย่างการใช้งาน ส่ง AT Command ไปยัง มอดูล

$port= new-Object System.IO.Ports.SerialPort COM6,115200,None,8,one
$port.open()
$port.Write("AT`r`n")
$port.ReadLine()

จะเห็นว่าโมดูลตอบกลับมาว่า OK แสดงว่าใช้งานได้

ใช้คำสั่ง $port.close() เพื่อปิด Port

4.2 ใช้โปรแกรม Tera Term
นอกจากการใช้ PowerShell แล้ว เรายังสามารถใช้ Terminal Program เพื่อเชื่อมต่อกับ Serial Port ได้ โปรแกรมที่ใช้งานได้มีหลายตัว ขอยกตัวอย่างการใช้โปรแกรมชื่อ Tera Term

เมื่อเปิดโปรแกรมขึ้นมาให้เลือกที่ Serial และเลือก com port ให้ถูกต้อง

และในหน้าจอ Setup/Terminal

ให้เลือก Local echo และ Transmit เป็น CR+LF อาจจะต้องเข้าไปดูว่าตรงเมนู Setup/Serial Port ค่า Speed ตรงกับ Module ตั้งมาจากโรงงานหรือเปล่า คือต้องตั้งเป็น Baud rate 115200, Data 8 bit, Parity none, Stop 1 bit, Flow control none

4.2 การใช้กับโปรแกรม Serial Debugger

ตัวอย่างตามภาพเป็น SSCOM version 5.13.1

4.3 ใช้โปรแกรม YAT

สามารถ Download โปรแกรม YAT(Yet Another Terminal) ได้จาก เวป คลิก
กรณีในเครื่องยังไม่มี .NET ให้เลือกตัวติดตั้งที่มี .NET Runtime

4.4 ใช้โปรแกรม Termite

สามารถ Download ได้จาก คลิก โหลดแล้วแตกไฟล์ เรียกใช้โปรแกรมได้เลย

Setting คลิกเลือก Append CR+LF และเลือก COM Port Baud ให้ตรง

ฺBaud rate:115200
Data bits:8
Stop bits: 1
Parity: None
Flow Control: None
Forward: None

5. การเชื่อมใช้งานกับ Arduino Pro Mini (3V)***

Arduino Pro mini ในตลาดมีรุ่น 5V กับ 3V เนื่องจากมอดูล Maxiiot DL7612-AS923-TH จะใช้ไฟ 3V จึงต้องเลือก Arduino Pro Mini รุ่นที่เป็น 3 V และ Arduino Pro Mini ไม่มี Port Hardware Serial เราจะใช้งานโดยใช้ Library Software Serial

*** การใช้มีข้อจำกัดอยู่บ้างเนื่องจาก Software Serial TX ทำได้ที่ความเร็ว 115200 แต่ RX ได้เพียง 57600

// Serial Monitor Select Both NL & CR ,115200 baud
// Serial2 16/17
#include <SoftwareSerial.h>
SoftwareSerial Serial2(2, 3); // RX, TX
void setup() {
Serial.begin(115200);
Serial2.begin(115200);
}
void loop() {
if (Serial.available()) {
Serial2.write(Serial.read());
}
if (Serial2.available()) {
Serial.write(Serial2.read());
}
}

หลังจากนั้นก็สามารถดัดแปลงโปรแกรมที่ใช้กับ ESP32 หัวข้อ 1.3.2 มาใช้ส่งข้อความทดสอบ Hello ขึ้น TheThingsNetwork ได้

6. กรณีใช้ กับ Arduino UNO R3***

ให้ใช้ผ่าน Logic Level Converter เนื่องจาก Logic Level จาก Arduino จะเป็น 5V

*** การใช้มีข้อจำกัดอยู่บ้างเนื่องจาก Software Serial TX ทำได้ที่ความเร็ว 115200 แต่ RX ได้เพียง 57600

***ข้อจำกัดของ SoftwareSerial ของ Arduino มีที่กล่าวไว้ตาม link คือ ถึงแม้ TX ได้ที่ Speed 115200 bps แต่ RX จะจำกัดอยู่เพียง 57600 bps

อาจะหลีกเลี่ยงใช้ Arduino ที่ไม่มี Hardware Serial ถ้าจำเป็นต้องมีการใช้ RX หรือมี Downlink

6.1 SerialPassthrough.ino ใช้ Software Serial


/*
Receives from the hardware serial, sends to software serial.
Receives from software serial, sends to hardware serial.
The circuit:
* RX is digital pin 2 (connect to TX of other device)
* TX is digital pin 3 (connect to RX of other device)
*/
// Serial Monitor Select Both NL & CR ,115200 baud
// Serial2 ESP32 16/17
#include <SoftwareSerial.h>
SoftwareSerial Serial2(2, 3); // RX, TXvoid setup() {
Serial.begin(115200);
Serial2.begin(115200);
}
void loop() {
if (Serial.available()) {
Serial2.write(Serial.read());
}
if (Serial2.available()) {
Serial.write(Serial2.read());
}
}

6.2 โปรแกรม Loop ส่งข้อความ Hello เข้า TheThingsNetwork

/*
The circuit:
* RX is digital pin 2 (connect to TX of other device)
* TX is digital pin 3 (connect to RX of other device)
*/
#include <SoftwareSerial.h>
SoftwareSerial Serial2(2, 3); // RX, TX
String response = "";
void setup() {
Serial.begin(115200);
Serial2.begin(115200);
}
void loop() {
sendCommand("AT\r\n");
delay(20000);
sendCommand("AT+NCMGS=5,HELLO\r\n");
Serial.print(“\r\n”);
delay(5000);
}
void sendCommand(String atComm){
response = "";
Serial2.print(atComm);
Serial.println("*******AT Command Sent");
Serial.println(atComm);
delay(300);
while(Serial2.available()){
char ch = Serial2.read();
//delay(500);
response += ch;
}
Serial.println(response);
response = "";
}

6.3 โปรแกรมเดียวกับ 6.2 แต่เขียนด้วย Function sendcommand

#include <SoftwareSerial.h>
SoftwareSerial Serial2(2, 3);
void loop() {
sendCommand("AT\r\n");
sendCommand("AT+NCMGS=5,HELLO\r\n");
Serial.print("\r\n");
delay(5000);
}
void setup() {
Serial.begin(115200);
Serial2.begin(115200);
}
void sendCommand(String atComm){
Serial2.print(atComm);
Serial.println("*******AT Command Sent");
Serial.print(atComm);
delay(500);
while (Serial2.available()) {
Serial.write(Serial2.read());
}
while (Serial.available()) {
Serial2.write(Serial.read());
}
}

การใช้ library SoftwareSerial กับ Speed ที่ 115200 เพื่อเชื่อมต่อกับมอดูล ตอนอ่านค่าที่มอดูลส่งกลับมา CPU UNO หรือ Arduino pro Mini อาจประมวลผลไม่ทัน จะเห็นอักษรขยะประกฎขึ้นบ้างบนหน้าจอ Serial Monitor

6.4 Module Maxiiot DL7612-AS923-TH ใช้กับ ESP32 ลง MicroPython

ตัวอย่างดังต่อไปนี้เป็น Node Class C และ ใช้ Thread ในการรอรับคำสั่ง Downlink เพื่อปิดเปิด LED หากมี LED ต่ออยู่ที่ขา 12 จะทำงานเมื่อใช้ร่วมกับ Multi Channel Gateway

การใช้งานตามตัวอย่างนี้ ค่าที่ Save ไว้ในมอดูลเป็นดังนี้ เช่น Class C, Activate =1 และ NNMI=0

ส่ง “BABk/w==” แบบ BASE64 เพื่อเปิด LED
ส่ง “BAAA/w==” แบบ BASE64 เพื่อปิด LED

# By Somsak Lima and Itti  Srisumalai
# VOLT to Pin 34
import machine
import CCS811
import bme280, time, ubinascii
from machine import UART, Pin, ADC
from cayennelpp import CayenneLPP
from micropython import const
from pms7003 import PMS7003
from aqi import AQI
import utime as time
import _thread # for multi-threading
from Fssd1306 import SSD1306_I2C
u2 = machine.UART(1, baudrate=9600, rx=32, tx=33)
pms = PMS7003(u2)
pms_data = pms.read()
aqi = AQI.aqi(pms_data['PM2_5_ATM'], pms_data['PM10_0_ATM'])
stop = False
LED_GPIO = const(2) # define a constant
led = machine.Pin(LED_GPIO, mode=machine.Pin.OUT) # GPIO output
led = Pin(2, Pin.OUT)
relay1 = Pin(12, Pin.OUT)
pot = ADC(Pin(34))
pot.atten(ADC.ATTN_11DB) # Full range: 3.3v
temp = 0
pa = 0
hum = 0
i2c = machine.I2C(scl=machine.Pin(22), sda=machine.Pin(21))
# CCS811 sensor
s = CCS811.CCS811(i2c)
bme = bme280.BME280(i2c=i2c)
oled = SSD1306_I2C(128, 64, i2c)
uart = UART(2, 115200, timeout=300)
rstr = ""
def sendATcommand(ATcommand):
print("Command: {0}\r\n".format(ATcommand))
print(ATcommand)
uart.write("{0}\r\n".format(ATcommand))
rstr = uart.read().decode('utf-8')
print(rstr)
return (rstr)
def check_downlink(led):
global stop
rstr = ""
while not stop:
rstr = sendATcommand('AT+NMGR')
print("--Downlink Message--: {0}\r\n".format(rstr))
time.sleep(5)
if "NNMI" in rstr:
if "040064ff" in rstr: # BABk/w==
print("Command1 Detected: On LED =============>")
relay1.value(1)
time.sleep(5)
elif "040000ff" in rstr: # BAAA/w==
print("Command1 Detected: Off LED =============>")
relay1.value(0)
time.sleep(5)
else:
print("No Known Command Detect")
def Oledhello():
oled.show_text(0, 0, "Hello", 12)
oled.show_text(0, 17, "LoRaWAN Thailand", 16)
oled.show_text(0, 32, "Start OTA Join", 16)
oled.show_text(0, 49, "Waiting......", 12)
oled.show()
Oledhello()
sendATcommand('AT')
sendATcommand('AT+INFO')
sendATcommand('AT+APPEUI')
sendATcommand('AT+DEVEUI')
sendATcommand('AT+APPKEY')
sendATcommand('AT+NCONFIG')
sendATcommand('AT+CHSET')
# LOOP OTAA
sendATcommand('AT+NRB')
time.sleep(20.0)
rstr = sendATcommand("AT+CGATT")
tryno = 1
while rstr != "+CGATT:1":
rstr = sendATcommand("AT+CGATT")
print("Respond String")
print(rstr)
if rstr.startswith("+CGATT:1"):
print("*******OTAA OK*******")
break
print("Retry OTAA Continue")
b = str(tryno)
print(b[-1:])
if b[-1:] == "0":
print("YES")
sendATcommand('AT+NRB')
else:
print("NO")
tryno = tryno+1
time.sleep(20.0)
print("Join Success")
# END LOOP OTAA
oled.clear()
oled.show_text(0, 24, "Join Success", 16)
oled.show()
time.sleep(5.0)
_thread.start_new_thread(check_downlink, (led,))cnt = 1
while True:
print("\r\n\r\nPacket No #{}".format(cnt))
pot_value = pot.read()
inputvolt = pot_value*3.3/4095
print("********Voltage values:")
print("**************")
print("BME280 values:")
print("**************")
temp, pa, hum = bme.values
print('temp:', temp, ' Hum:', hum , 'PA:', pa)
oled.clear()
oled.show_text(0, 0, "#", 12)
oled.show_text(10, 0, str(cnt), 12)
oled.show_text(0, 15, "Temp.:"+temp, 16)
oled.show_text(0, 33, "Hum. :"+hum, 16)
oled.show_text(0, 50, "PA :"+pa, 16)
oled.show()
time.sleep(5)
if s.data_ready():
print(" ")
print("**************")
print("CSS811 values:")
print("**************")
print('eCO2: %d ppm, TVOC: %d ppb' % (s.eCO2, s.tVOC))
print(" ")
oled.clear()
oled.show_text(0, 0, "Page# 2")
oled.show_text(0, 15, "eCO2:"+str(s.eCO2), 16)
oled.show_text(0, 33, "TVOC:"+str(s.tVOC), 16)
oled.show()
time.sleep(5)

print("***************")
print("PMS7003 values:")
print("***************")
print('PM 1.0:', pms_data['PM1_0_ATM'])
print('PM 2.5:', pms_data['PM2_5_ATM'])
print('PM 10.0:', pms_data['PM10_0_ATM'])
print('AQI :', aqi)

c = CayenneLPP()
c.addAnalogInput(1, inputvolt)
c.addTemperature(2, float(temp))
c.addRelativeHumidity(3, float(hum))
c.addBarometricPressure(4, float(pa))
c.addLuminosity(5, s.eCO2)
c.addLuminosity(6, s.tVOC)
c.addAnalogInput(7, pms_data['PM1_0_ATM'])
c.addAnalogInput(8, pms_data['PM2_5_ATM'])
c.addAnalogInput(9, pms_data['PM10_0_ATM'])
c.addAnalogInput(10, aqi)
b = (ubinascii.hexlify(c.getBuffer()))
print('************ Sending Data Status **************')
led.value(1)
ATresp = sendATcommand("AT+NMGS={0},{1}".format(int(len(b)/2), (b.decode('utf-8'))))
print('********Finish Sending & Receiving Data Status******')
led.value(0)
cnt = cnt + 1
time.sleep(10.0)

ตัวอย่าง Dashboard บนโปรแกรม Grafana ที่ได้จาก Sensor Node ที่ใช้ภาษา MicroPython ทั้งสาม Node

7. การใช้มอดูลด้วย ภาษา C กับ บอร์ด ATMEGA2560 Pro

ส่งด้วยรูปแบบ Cayenne โดยทดสอบส่งค่า คงที่ Temp 31.1, Humid 51.2 ต่อมอดูลเข้ากับขา TXD1(18), RXD1(19)

#include <CayenneLPP.h>
#include <stdio.h>
#include <string.h>
CayenneLPP lpp(51);
void loop() {
int dlen;
sendCommand("AT+CGATT");
lpp.reset(); // clear the buffer lpp.addTemperature(2, 31.1);
lpp.addRelativeHumidity(3, 51.2);
dlen = strlen(lpp.getBuffer());
Serial.println (dlen);
char hex_str[(dlen * 2) + 1];
Serial.println("+++++++++++Show Data++++++++++++");
//Convert STRING Data to HEX
string2hexString((char * ) lpp.getBuffer(), hex_str); //ascii_str, hex_str
Serial.println("+++++++++++SEND Data++++++++++++");
sendHexData(dlen, hex_str);
delay(10000);
}
void setup() {
Serial.begin(115200);
Serial1.begin(115200);
sendCommand("AT");
sendCommand("AT+INFO");
sendCommand("AT+NCONFIG");
sendCommand("AT+DEVEUI");
sendCommand("AT+APPKEY");
sendCommand("AT+APPEUI");
sendCommand("AT+NRB");
delay(40000);
}
void sendCommand(String atComm) {
String response;
Serial1.print(atComm + "\r\n");
Serial.println("*******AT Command Sent");
Serial.print(atComm + "\r\n");
delay(300);
while (Serial1.available()) {
char ch = Serial1.read();
response += ch;
}
Serial.println(response);
}
void sendData(int type, String data) {
Serial.println("*******TEXT Build");
String command = (String)
"AT+NCMGS=" + type + "," + data + (String)
"\r\n";
sendCommand(command);
}
void sendHexData(int type, String data) {
Serial.println("*******HEX Build");
String command = (String)
"AT+NMGS=" + type + "," + data + (String)
"\r\n";
sendCommand(command);
}
void string2hexString(char * input, char * output) {
int loop = 0;
int i = 0;
int count = strlen(input);
Serial.println ("count");
Serial.println (count);
while (loop < count) {
sprintf((char * )(output + i), "%02X", input[loop]);
loop += 1;
i += 2;
}
//insert NULL at the end of the output string
output[i++] = '\0';
}

8. คำสั่ง AT Command ที่ควรทราบ

AT ตรวจสอบการเชื่อมต่อ
AT+INFO ดูข้อมูล Model ของมอดูล
AT+NCONFIG แสดงค่าคอนฟิคปัจจุบันในมอดูล
AT+DEBUG=1 เข้าโหมดแก้ไขค่าคอนฟิค
AT+SAVE เก็บค่าคอนฟิคปัจจุบันลงในมอดูล
AT+ACTIVATE=1 เลือก Authen แบบ ABP (0) หรือ OTAA (1)
AT+CLASS=A เลือกเป็น Sensor Node CLass A หรือ C
AT+CLAC ดูคำสั่ง AT Command ที่ใช้งานได้

AT+DEVEUI ใช้แสดงค่า DEVEUI หรือตั้งค่า DEVEUI (OTAA)
AT+APPEUI ใช้แสดงค่า APPEUI หรือตั้งค่า APPEUI (OTAA)
AT+APPKEYใช้แสดงค่า APPKEY หรือตั้งค่า APPKEY (OTAA)

AT+ADDR แสดงค่า DEVADDR หรือตั้งค่า DEVADDR (ABP)
AT+APPSKEY แสดงค่า APPSKEY หรือตั้งค่า APPSKEY (ABP)
AT+NWKSKEY แสดงค่า AT+NWKSKEY หรือตั้งค่า NWKSKEY (ABP)

AT+ISMBAND=6 เลือกความถี่ AS1 (Default ISMBAND=2 คือ AS2)
AT+CHSET แสดงช่องความถี่ใช้งาน
AT+CGATT แสดงสถานะการเชื่อมต่อกับ LoRaWAN Network Server หากเป็น 1 คือเชื่อมต่อสำเร็จ
AT+NMGS=5,AA112233BB ส่งข้อมูล HEX จำนวน 5 ตัว
AT+NCMGS=5,HELLO ส่งข้อมูล TEXT จำนวน 5 ตัวอักษร
AT+NRB รีบูทมอดูลและเริ่มเชื่อมต่อ

AT+RESTORE สำหรับใช้เรียกกลับคืนค่า Default ของ Firmware มาจาก โรงงาน โดยค่าจากโรงงานจะเป็นดังนี้

+NCONFIG:CLASS,A
+NCONFIG:ISMBAND,2
+NCONFIG:CHMASK,00ff,0000,0000,0000,0000,0000
+NCONFIG:RXWIN2,923200000,2
+NCONFIG:ACTIVATE,1
+NCONFIG:POWER,0
+NCONFIG:PORT,2
+NCONFIG:ADR,1
+NCONFIG:DR,2,10,0,0
+NCONFIG:CFM,1
+NCONFIG:NNMI Enable,1
+NCONFIG:PNMI Enable,1

โปรแกรมบน Windows ที่สามารถใช้งานเชื่อมต่อกับ Maxiiot DL7612-As923-TH และใช้คำสั่ง AT Command ได้ เช่น โปรแกรม Termite และ โปรแกรม Serial Port Utility อ่านวิธีการใช้งานเพิ่มเติมได้ ที่ คลิก และ คลิก

ตัวอย่างข้อมูลทดสอบที่เป็นรูปแบบ Cayenne

หากเชื่อมต่อสำเร็จค่า AT+CGATT จะเป็น 1 เราสามารถลองส่งข้อมูลรูปแบบ Cayenne ได้ตามตัวอย่างดังต่อไปนี้ แต่ก่อนอื่นให้ตั้งค่าในเวป TTN ตรง Application/ Integrations เป็น Mydevices

ให้เข้าไปที่หน้า Application แล้วเลือก Integration

คลิก Add Integration ตรงมุมขวา

เลื่อนหาแล้วคลิกที่ myDevices

ใส่ชื่อ Process ID อะไรก้ได้แล้วเลือก Access Key เป็น default key เสร็จแล้วคลิก Add integration มุมขวาล่าง

จะปรากฎบรรทัด MyDevices ตามรูปขึ้น

หลังจากเพิ่ม Integration แล้วใช้คำสั่ง ที่ มอดูล

1. AT+NMGS=18,016701120268950373006406010107032ee0

ในหน้าเวป TTN ตรง TAB Data จะมี Data Field ปรากฎขึ้นดังภาพ

2.AT+NMGS=29,01670111026892037300640488021b450f563afffdbc06010107032ee0

ในหน้าเวป TTN ตรง TAB Data จะมี Data Field ปรากฎขึ้นดังภาพ

9. ตัวอย่างขั้นตอนการใช้คำสั่ง AT COMMAND

การใช้งานมอดูลบางครั้งจะต้องเข้าใจการทำงานของคำสั่งที่สั่งไปด้วย เช่น หากเราตั้งค่า CFM=1 ในมอดูลหรือคือ จะรอ Confirm จาก gateway ส่งกลับมา แต่หากเราเขียนโปรแกรมให้ Loop ส่งถี่มากเกิน ก่อนที่จะได้รับข้อมูล Confirm ตัวมอดูลจะไม่นับ Frame Counter เพิ่ม จะมีการส่งซ้ำ Frame เดิมซ้ำ ดังนั้นถ้าเราจะตั้ง CFM=1 จะต้องเว้นระยะห่างของการส่งให้เหมาะสม เป็นต้น

AT Command บางคำสั่งจะใช้ควบคู่กันถึงจะทำงาน เช่น

9.1 การตั้งค่าในมอดูล จะต้องเข้า Debug Mode ก่อน ถัดไปก็สั่งตั้งค่าแล้วจบด้วยคำสั่ง SAVE

AT+DEBUG=1
AT+CLASS=C
AT+SAVE
AT+NRB
AT+NCONFIG

หลังจากการใช้คำสั่งตั้งค่า AT+CLASS=C และ AT+SAVE หากเราเช็คด้วยคำสั่ง AT+NCONFIG เลย ในบางครั้งอาจจะพบว่าค่าตัวแปร CLASS ยังไม่ได้ถูกแก้ไข ให้ทำการ Reboot มอดูลด้วยคำสั่ง AT+NRB ก่อน มอดูลจึงจะอ่านค่าใหม่ที่ตั้งค่าไว้ขึ้นมาแสดง

9.2 ดูว่าใน ISMBAND ที่เราใช้งานอยู่มี DR (Data Rate) อะไรบ้าง และ DR ที่กำหนดมีค่า SF เท่าไร ให้ใช้คำสั่ง AT+DR=LIST

AT+ISMBAND
AT+DR=LIST

จะเห็น DR ที่กำหนดไว้มีการคอนฟิกไว้ที่ SF เท่าไร เช่น DR4 จะหมายถึง SF8, 0 ที่ตามหลังมาคือ BW ที่ 125KHZ หากเป็น 1 คือ BW 250KHz

AT+DR=LIST
+DRLIST ISM Band:2
+DR0,12,0
+DR1,11,0
+DR2,10,0
+DR3,9,0
+DR4,8,0
+DR5,7,0
+DR6,7,1
+DR7,FSK
+DR8,DFU
+DR9,DFU
+DR10,DFU
+DR11,DFU
+DR12,DFU
+DR13,DFU
+DR14,DFU
+DR15,DFU
OK

Tip! กรณีที่จะนำไปใช้กับเครือข่าย LoRa ของ CAT Telecom ให้ใช้ DR=3 โดยใช้คำสั่ง
AT+DEBUG=1
AT+DR=3
AT+SAVE

ระยะทางโดยประมาณที่แต่ละ SF เป็นไปตามรูป เช่น SF8 จะได้ระยะทางประมาณ 4 กม.

หมายเหตุ ระยะทางที่ได้ขึ้นอยู่กับสิ่งขีดขวางและความสูงของ gateway ด้วย

Cr.Semtech

กรณี Node ใช้ SF12 (ซึ่งทำได้ในโหมด ADR=1 และสั่งงานมาจาก LNS) มีความเป็นไปได้ที่จะได้ระยะทางถึง 14 กม. หากอยู่นอกเมืองและมักขึ้นอยู่กับตำแหน่งติดตั้ง LoRaWAN Gateway และสภาพแวดล้อมอื่นๆ SF ยิ่งสูงยิ่งเปลืองพลังงานมากและ BITRATE ก็ต่ำลง

เงื่อนไขของการใช้ DR จะถูกกำหนดโดย LoRaWAN Network Server ที่ Node เชื่อมต่อ และมักเป็นไปตาม Lora Alliance กำหนด เช่น นโยบาย Devices with fixed hardcoded data rates of SF12 or SF11 must not be allowed to join the network

กรณีเราใช้ TTN อาจจะต้องอิงตาม Fair Access Policy คลิก

และสามารถศึกษาข้อจำกัดจำนวน Maximum ของการใช้ LoRaWAN data rate, spreading factor และ application packet sizes จากเอกสารที่เกี่ยวข้องอื่นๆ

Dwell Time หรือ Time on air โดยประมาณที่ Spread Factor ต่างๆ เป็นไปตามตาราง

หากพิจารณาจาก Fair Accept Policy ของ TTN คือ
“An average of 30 seconds uplink time on air, per 24 hours, per device.”

หากการเชื่อมต่อเป็นแบบ SF12 เวลา uplink Payload 51 bytes = 1400*51/10 =7140 ms ใน 1 วันใช้ได้ 30 s หรือคือสามารถส่งได้จำนวนครั้งต่อวัน=30/7.14 คือประมาณ 4 ครั้ง อย่างไรก็ดีข้อกำหนด FAP ของ TTN ก็ไม่ได ้ตั้ง Lock ไว้แต่อย่างไดเป็นแต่เพียงแนวทางปฎิบัติที่ควรปฎิบัติเท่านั้น

10. การใช้ในลักษณะ P2P

ผู้เขียนไม่ค่อยอยากแนะนำวิธีการใช้แบบ P2P นัก เนื่องจากจะขาดการใช้ฟังค์ชั่นที่มีประสิทธิภาพอื่นๆ ของ LoRaWAN ไป แต่บางท่านอาจสนใจเลยมาแนะนำไว้ เพื่อเป็นความรู้

การใช้ P2P จะติดต่อระหว่างกันที่ความถี่ RX2 Node ทุกตัวจะรับข้อความได้ คำสั่งที่ใช้ เช่น

และ

หมายเหตุ การใช้ P2P นั้นจะต้องเข้าใจลักษณะของการตั้งค่า มอดูล DL7612-AS923-TH ว่าเราตั้งเป็นอุปกรณ์ Class ไหน เช่น หากเป็น Class A การรับค่า จะทำก็ต่อเมื่อมีการส่งข้อมูลและรับมาหลังการส่งข้อมูลเสร็จ แต่หากเป็น Class C จะรับก็จะ Standby รับข้อมูลตลอดเวลา แต่จะเก็บในความจำมอดูล จนกว่าจะเรียกมาแสดง Class C เราจำเป็นจะต้องส่งข้อมูลเพื่อให้มีการติดต่อสื่อสารกันหนึ่งครั้งก่อนแล้วมอดูลจะ Standby รับข้อมูลตลอด

12.LOW POWER

กรณีที่ไม่ต้องการให้เปลืองกระแส อาจจะใส่ R Poll up ที่ขา RXD และ TXD เป็นค่าที่เหมาะสม

13. กรณี เจอข้อความ uplink channel not found Drop join request ไม่สามารถ Join OTAA ได้

สาเหตุเนื่องจาก TTN V.3 จะ Strict ในการขอ Join Request มากกว่า V.2 คือให้ Join Request เฉพาะสองช่องเท่านั้น คือ 923.2 Mhz และ 923.4?Mhz

ให้แก้ไขโดย เพิ่มความถี่ดังต่อไปนี้

แก้ไขที่ General Setting/Network Layer คลิก Expand/ Advance MAC Settings

14. การใช้ MicroPython กับจอ OLED มักเจอข้อความ no attribute ‘SSD1306_I2C’

เนื่องจาก MicroPython จะมี Standard lib ssd1306 อยู่แล้ว การเรียกใช้อาจจะเรียกไม่ถูกตัวเนื่องจากใช้ชื่อเดียวกัน

ตอนเรียกใช้มักจะเจอ ERROR ดังนี้
oled = ssd1306.SSD1306_I2C(128, 64, i2c) # → at this point i get an error saying:
Traceback (most recent call last):
File “<stdin>”, line 1, in <module>
AttributeError: ‘module’ object has no attribute ‘SSD1306_I2C’
>>>

อาจแก้ไขโดย

ลองเพิ่มบรรทัด
import ssd1306
from ssd1306 import SSD1306_I2C

เช่น

from machine import Pin
from machine import I2C
from machine import SoftI2C
from ssd1306 import SSD1306_I2C

15. Reboot MicroPython

import machine
machine.reset()

สรุป

ผู้สนใจจะพัฒนา LoRaWAN® Node โดยการใช้ Maxiiot DL7612-AS923-TH สามารถใช้ AT Command ได้ง่ายๆ ผ่านวิธีการหรือ hardware ที่ยกตัวอย่างข้างต้น สามารถนำวิธีการพื้นฐานเหล่านี้ไปประยุกต์ใช้ในด้านต่างๆ รวมถึงการควบคุมต่างๆ ตามตัวอย่าง 6.4 โดยสามารถพัฒนาระบบให้มีความสมบูรณ์มากขึ้นตามความจำเป็นของงานได้ในอนาคต

หมายเหตุ

  • บางครั้ง Medium.com เปลี่ยนอักษรที่พิมพ์เข้าไปอัตโนมัติ เช่นจาก ฟันหนูตรงๆ เป็น “” ซึ่งทำให้ภาษา C หากเกิด Error ตอน Compile ให้แก้ Smart Quatation mark จาก “” เป็น ฟันหนูตรงๆ ทั้งด้านหน้าและด้านหลังข้อความ
""

- ดู Data Sheet ได้ที่ คลิก
- ดู Reference ของ AT Commandได้ที่ คลิก
- Software หรือเอกสารทั้งหมด ดาวน์โหลดได้จาก ลิ้งค์
(โปรแกรม sscom32E อยู่ใน Serial debugging tool sscom5-DL7X1X-LRWAN102-eng.zip การใช้งานเวอร์ชั่นนี้ มักจะมีการ Hang ตอนออกจากโปรแกรม ควร Close Port Serial ก่อนออกจากโปรแกรม แต่หากมีการ Hang อาจจะใช้ Kill Process ช่วย)
- Multi Channel Gateway Dragino LG308-AS923-TH-EC25 ลิ้งค์
- Arduino Serial Port คลิก
- การใช้ UART คลิก
- การใช้ MicroPython กับ Thonny คลิก

--

--

Somsak Lima
Somsak Lima

Written by Somsak Lima

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

No responses yet