Air700E 기반 4G 환경 모니터링 노드(온도·습도·기압 등)를 MQTT로 알리바바 IoT 플랫폼에 업로드
소개
Air700E 4G 모듈이 센서(온습도、기압 등) 데이터를 읽어 MQTT 프로토콜로 알리바바 클라우드 IoT 플랫폼에 전송하며, 동시에 0.96인치 OLED 화면에 U8g2 그래픽 라이브러리로 표시합니다.
ESP32C3 WiFi 모듈은 MQTT로 4G 노드가 올린 데이터를 구독해 LCD 화면에 LVGL로 표시합니다.
이 프로젝트는 제 수업 설계로, 대충 만들어서 완벽하지 않습니다.
과제 요구사항: 무선 통신 시스템을 설계·제작하고, 지난 학기 지식을 활용해 온·습도/초음파 거리 등을 로컬에서 수집 후 무선으로 송신하여 수신단 LCD에 표시.
⑴ 블루투스 무선 전송
⑵ WiFi 무선 전송
⑶ 지그비 무선 전송
⑷ GPRS/GSM 무선 전송
⑸ 4G 무선 전송
⑹ NB-IoT/LoRa 무선 전송
힌트: 8/16/32비트 프로세서로 메인 컨트롤러 선정, (1)(2)(3) 중 1개, (4)(5)(6) 중 1개 이상 완수.
Air700E·ESP32C3 모두 LuatOS + Lua 스크립트 방식으로 개발했습니다.
LuatOS 펌웨어는 Air700E 클라우드 빌드로 생성했습니다.
ESP32C3 기본 4MB flash를 8MB로 교체했으며, LVGL·폰트 포함으로 펌웨어 크기가 4MB를 초과합니다.
알리바바 클라우드 학생 할인: https://www.aliyun.com/daily-act/ecs/activity_share?userCode=jdjc69nf
주의: 알리바바 IoT 플랫폼은 디바이스 간 토픽 구독이 불가능하므로 메시지 전달→클라우드 제품 전달 규칙을 추가해 4G 노드가 발행한 메시지를 WiFi 노드 토픽으로 전달해야 합니다.
LCSC 오픈소스 링크: https://oshwhub.com/zeruns/wen-shi-du-cai-ji-4g-shang-chuan
전자/MCU 기술 단톡: 2169025065
Air700E 소개
Air700E는 Luat에서 출시한 LTE Cat.1 bis 통신 모듈로 EC618 칩셋 기반, LTE 3GPP Rel.13 지원. LTE TDD 밴드만 남겨 중국 이동통신 주파에 최적화, 초소형·초저가로 소형·비용 민감 제품에 적합.
주요 특징
- 1.8/3.3V USIM
- 1.8/3.3V 설정 가능 UART
- USB 2.0
- OTA 펌웨어 업그레이드
- PSM 디지털 음성 인터페이스
- USB 넷동/AT/LuatOS/C-SDK 등 다양한 개발 방식 지원
Air700E는 풍부한 네트워크 프로토콜·산업 표준 인터페이스를 내장, Windows/Linux/Android 드라이버 지원으로 CPE·라우터·데이터카드·태블릿·차량·보안·산업 PDA 등 M2M 응용 확장 가능.
기술 사양
LTE-TDD 밴드: B34/B38/B39/B40/B41
LTE-TDD 속도: DL 8Mbps(配比2) / 6Mbps(配比1), UL 2Mbps(配比2) / 4Mbps(配比1)
인터페이스: USB 2.0 480Mbps, (U)SIM, NETLIGHT, I2S, 3×UART, PWRKEY, 2×ADC, 13×GPIO+2×인터럽트, I2C
ESP32-C3 소개
CORE ESP32-C3 코어 보드는 21mm×51mm 초소형 스탬프홀 설계. UART/GPIO/SPI/I2C/ADC/PWM 등 인터페이스 지원.
하드웨어 리소스
- 21mm×51mm
- 4MB SPI FLASH(최대 16MB 지원)
- 2×UART(UART0=다운로드)
- 5채널 12비트 ADC, 최대 100KSPS
- 1×SPI 마스터
- 1×I2C
- 4×PWM(임의 GPIO)
- 15×GPIO(멀티플렉스)
- 2×LED, 1×리셋 + 1×BOOT 키
- USB-TTL 다운로드/디버그
- 2.4GHz PCB 안테나
실물 사진
데모 영상: https://www.bilibili.com/video/BV1MH4y1B7Df/
전체 사진
4G 노드
WiFi 노드
WiFi 연결 중:
WiFi 연결 후 MQTT·NTP 동기화:
4G 노드 데이터 표시:
온습도 변화 곡선:
IoT 플랫폼
알리바바 IoT 플랫폼 데이터:
회로도
4G 노드
WiFi 노드
PCB
4G 노드
4G 모듈 패키지가 정확하지 않습니다.
Top:
Bottom:
WiFi 노드
Top:
Bottom:
코드
코드 다운로드 방법은 공식 문서를 참고하세요.
Air700E 문서: https://doc.openluat.com/wiki/44?wiki_page_id=4730
LVGL for LuatOS 매뉴얼: https://url.zeruns.com/7z7fN
ESP32-C3 문서: https://url.zeruns.com/497AP
Lua 튜토리얼: https://url.zeruns.com/Pc4PA
4G 노드
펌웨어 다운로드: https://url.zeruns.com/2G3K7
main.lua:
-- LuaTools는 PROJECT, VERSION 정보가 필요합니다
PROJECT = "환경 모니터링 노드"
VERSION = "1.1.0"
-- 필수 라이브러리 로드
sys = require("sys")
aht10 = require "aht10"
bmx = require "bmx"
-- 하드웨어 워치독
if wdt then
wdt.init(9000) -- 9초 설정
sys.timerLoopStart(wdt.feed, 3000) -- 3초마다 감시견 피딩
end
print(_VERSION)
log.info(mobile.ipv6(true)) -- IPv6 활성화
local ProductKey = "xxxxxx"
local DeviceName = "xxxxxx"
local DeviceSecret = "xxxxxx"
local client_id, user_name, password = iotauth.aliyun(ProductKey, DeviceName, DeviceSecret)
log.info("MQTT 파라미터", client_id, user_name, password)
local softI2C = i2c.createSoft(29, 31, 2)
local aht10_data, bmx_data
local RH, Temp, Press, High, distance, BAT_Voltage, CPU_T = 0,0,0,0,0,0,0
local RH_C, Temp_C, Press_C, High_C, distance_C, BAT_Voltage_C, CPU_T_C = 0,0,0,0,0,0,0
local AHT10_flag, BMP180_flag, US100_flag, BAT_Voltage_flag, CPU_T_flag = false,false,false,false,false
all_data = {params = {CurrentVoltage = 0, CurrentTemperature = 0, CurrentHumidity = 0, Atmosphere = 0, Altitude = 0, DetectDistance = 0, CPUTemperature = 0}}
function US_100() -- US-100 초음파 거리 측정
uart.write(1, string.char(0x55))
sys.wait(50)
local hData, lData = string.byte(uart.read(1, 2), 1, 2)
uart.rxClear(1)
if hData and lData then
local Distance_mm = tonumber((hData * 256) + lData)
if Distance_mm > 4500 then Distance_mm = 4500 end
return (Distance_mm / 10)
end
end
sys.taskInit(function() -- 센서 데이터 읽기 스레드
sys.wait(500)
aht10.init(softI2C)
bmx.init(softI2C)
uart.setup(1, 9600, 8, 1, uart.NONE)
adc.open(0)
adc.open(adc.CH_CPU)
sys.wait(500)
local RH_sum, Temp_sum, Press_sum, High_sum, distance_sum, BAT_Voltage_sum, CPU_T_sum = 0,0,0,0,0,0,0
local avg_count, avg_count2, avg_count3, avg_count4, avg_count5 = 0,0,0,0,0
while 1 do
aht10_data = aht10.get_data()
bmx_data = bmx.get_data()
distance_C = US_100()
BAT_Voltage_C = ((adc.get(0) / 1000 / 1007) * 1473)
CPU_T_C = adc.get(adc.CH_CPU) / 1000
-- AHT10 평균 계산
if aht10_data.RH and aht10_data.T then
all_data.params.CurrentTemperature = aht10_data.T
all_data.params.CurrentHumidity = aht10_data.RH * 100
if avg_count < 6 then
RH_C, Temp_C = aht10_data.RH * 100, aht10_data.T
RH_sum = RH_C + RH_sum
Temp_sum = Temp_C + Temp_sum
avg_count = avg_count + 1
elseif avg_count == 6 then
RH = RH_sum / 6
Temp = Temp_sum / 6
log.info("AHT10_data.RH: "..(string.format("%.2f", RH)).." %", " AHT10_data.T: "..(string.format("%.2f", Temp)).." ℃")
AHT10_flag = true
sys.publish("MQTT_P")
avg_count, RH_sum, Temp_sum = 0,0,0
end
end
```--BMP180 기압 및 고도 평균 계산
if bmx_data.press and bmx_data.high then
all_data.params.Atmosphere = bmx_data.press
all_data.params.Altitude = bmx_data.high
if avg_count2 < 10 then -- 10 미만인지 판단하여 평균 누적
Press_C,High_C = bmx_data.press, bmx_data.high -- 현재 기압과 고도 값 읽기
Press_sum = Press_C + Press_sum
High_sum = High_C + High_sum
avg_count2 = avg_count2 + 1
elseif avg_count2 == 10 then
Press = Press_sum / 10
High = High_sum / 10
log.info("BMP180_data.press: "..(string.format("%.2f", Press)).." hPa"," BMP180_data.high: "..(string.format("%.2f", High)).." m")
BMP180_flag = true
sys.publish("MQTT_P")
avg_count2,Press_sum,High_sum=0,0,0
end
end
-- US-100 초음파 거리 측정 거리 평균 계산
if distance_C then -- 데이터를 읽었는지 판단
all_data.params.DetectDistance = distance_C
if avg_count3 < 3 then
distance_sum = distance_C + distance_sum
avg_count3 = avg_count3 + 1
elseif avg_count3 == 3 then
distance = distance_sum / 3
log.info("US-100: "..(string.format("%.1f", distance)).." cm")
US100_flag = true
sys.publish("MQTT_P")
avg_count3,distance_sum = 0,0
end
end
-- 배터리 전압
if BAT_Voltage_C then -- 데이터를 읽었는지 판단
all_data.params.CurrentVoltage = BAT_Voltage_C
if avg_count4 < 20 then
BAT_Voltage_sum = BAT_Voltage_C + BAT_Voltage_sum
avg_count4 = avg_count4 + 1
elseif avg_count4 == 20 then
BAT_Voltage = BAT_Voltage_sum / 20
log.info("BAT_Voltage: "..(string.format("%.2f", BAT_Voltage)).." V")
BAT_Voltage_flag = true
sys.publish("MQTT_P")
avg_count4,BAT_Voltage_sum = 0,0
end
end
-- CPU 온도
if CPU_T_C then -- 데이터를 읽었는지 판단
all_data.params.CPUTemperature = CPU_T_C
if avg_count5 < 20 then
CPU_T_sum = CPU_T_C + CPU_T_sum
avg_count5 = avg_count4 + 1
elseif avg_count5 == 20 then
CPU_T = CPU_T_sum / 20
log.info("CPU_T: "..(string.format("%.2f", CPU_T)).." ℃")
CPU_T_flag = true
sys.publish("MQTT_P")
avg_count5,CPU_T_sum = 0,0
end
end
sys.wait(500)
end
end)
--[[sys.taskInit(function() -- 초음파 거리 측정 작업 생성, 1.5초마다
uart.setup(1, 9600, 8, 1, uart.NONE) -- 시리얼 포트 1 초기화
sys.wait(1000)
while 1 do
distance = US_100() -- US-100 데이터 읽기
if distance then -- 데이터를 읽었는지 판단
log.info("US-100: "..(string.format("%.1f", distance)).." cm")
US100_flag = true
sys.publish("MQTT_P")
end
sys.wait(1500)
end
end)]]
sys.taskInit(function() -- MQTT 초기화 및 데이터 보고 스레드 생성
mqttc = mqtt.create(nil, "a1sJbDQiEqr.iot-as-mqtt.cn-shanghai.aliyuncs.com", 1883,true,true)
mqttc:auth(client_id, user_name, password)
mqttc:keepalive(120) -- 기본값 240s
mqttc:autoreconn(true, 3000) -- 자동 재연결 메커니즘
mqttc:on(function(mqtt_client, event, data, payload)
if event == "conack" then
sys.publish("mqtt_conack")
log.info("mqtt", "mqtt 연결됨")
mqtt_client:subscribe("/sys/"..ProductKey.."/"..DeviceName.."/thing/service/property/set")
elseif event == "recv" then
log.info("mqtt", "메시지 수신", data, payload)
local mqtt_date = json.decode(payload)
elseif event == "sent" then
log.info("mqtt", "sent", "pkgid", data)
end
end)
mqttc:connect()
while true do
sys.waitUntil("MQTT_P", 3000)
if AHT10_flag then
local json_str = json.encode({params = {CurrentTemperature = Temp, CurrentHumidity = RH}}, "2f") -- JSON 형식으로 변환, 소수점 2자리 유지
mqttc:publish("/sys/"..ProductKey.."/".. DeviceName.."/thing/event/property/post", json_str) -- MQTT 속성 보고
mqttc:publish("/"..ProductKey.."/".. DeviceName.."/user/update", json.encode(all_data,"2f")) -- MQTT 속성 보고
AHT10_flag = false
end
if BMP180_flag then
local json_str = json.encode({params = {Atmosphere = Press, Altitude = High}}, "2f") -- JSON 형식으로 변환, 소수점 2자리 유지
mqttc:publish("/sys/"..ProductKey.."/"..DeviceName.."/thing/event/property/post", json_str) -- MQTT 속성 보고
mqttc:publish("/"..ProductKey.."/".. DeviceName.."/user/update", json.encode(all_data,"2f")) -- MQTT 속성 보고
BMP180_flag = false
end
if US100_flag then
local json_str = json.encode({params = {DetectDistance = distance}}, "1f") -- JSON 형식으로 변환, 소수점 2자리 유지
mqttc:publish("/sys/"..ProductKey.."/"..DeviceName.."/thing/event/property/post", json_str) -- MQTT 속성 보고
mqttc:publish("/"..ProductKey.."/".. DeviceName.."/user/update", json.encode(all_data,"2f")) -- MQTT 속성 보고
US100_flag = false
end
if BAT_Voltage_flag then
local json_str = json.encode({params = {CurrentVoltage = BAT_Voltage}}, "2f") -- JSON 형식으로 변환, 소수점 2자리 유지
mqttc:publish("/sys/"..ProductKey.."/"..DeviceName.."/thing/event/property/post", json_str) -- MQTT 속성 보고
mqttc:publish("/"..ProductKey.."/".. DeviceName.."/user/update", json.encode(all_data,"2f")) -- MQTT 속성 보고
BAT_Voltage_flag = false
end
if CPU_T_flag then
local json_str = json.encode({params = {CPUTemperature = CPU_T}}, "2f") -- JSON 형식으로 변환
mqttc:publish("/sys/"..ProductKey.."/"..DeviceName.."/thing/event/property/post", json_str) -- MQTT 속성 보고
mqttc:publish("/"..ProductKey.."/".. DeviceName.."/user/update", json.encode(all_data,"2f")) -- MQTT 속성 보고
CPU_T_flag = false
end
end
end)
-- https://blog.zeruns.com
sys.taskInit(function()
u8g2.begin({ic = "ssd1306",direction = 0,mode="i2c_hw",i2c_id=1,i2c_speed = i2c.FAST}) -- direction 선택 가능 0 90 180 270
u8g2.ClearBuffer() -- 화면 지우기
u8g2.SetFont(u8g2.font_opposansm10) -- 글꼴 전환
u8g2.DrawUTF8("IMEI:", 0, 16)
u8g2.DrawUTF8(mobile.imei(), 0, 32)
u8g2.SendBuffer()
--ntp 시간 동기화
--socket.sntp()
socket.sntp({"ntp.aliyun.com","ntp1.aliyun.com","ntp2.aliyun.com"}) -- sntp 사용자 지정 서버 주소
--socket.sntp(nil, socket.ETH0) -- sntp 사용자 지정 어댑터 번호
sys.subscribe("NTP_UPDATE", function()
log.info("sntp", "time", os.date())
sys.publish("NTP_OK")
end)
sys.subscribe("NTP_ERROR", function()
log.info("socket", "sntp error")
socket.sntp()
end)
sys.wait(1000)
sys.waitUntil("NTP_OK", 3000)
u8g2.ClearBuffer() -- 화면 지우기
u8g2.SetFont(u8g2.font_opposansm10) -- 글꼴 전환
u8g2.DrawUTF8(os.date("%Y-%m-%d"), 0, 16) -- 시간 표시
u8g2.DrawUTF8(os.date("%H:%M:%S"), 0, 32) -- 시간 표시
local IP = socket.localIP() -- IP 주소 표시
if IP then
u8g2.DrawUTF8("IP:"..IP, 0, 63)
end
u8g2.SendBuffer()
sys.wait(2500)
while true do
u8g2.ClearBuffer() -- 화면 지우기
u8g2.SetFont(u8g2.font_sarasa_m10_ascii)
if Temp_C then
u8g2.DrawUTF8("T:"..(string.format("%.2f", Temp_C)).."°C", 0, 16)
end
if RH_C then
u8g2.DrawUTF8("RH:"..(string.format("%.2f", RH_C)).."%", 0, 32)
end
if Press_C then
u8g2.DrawUTF8("P:"..(string.format("%.2f", Press_C)).."hPa", 0, 48)
end
if distance_C then
u8g2.DrawUTF8("D:"..(string.format("%.1f", distance_C)).."cm", 0, 63)
end
if High_C then
u8g2.DrawUTF8("H:"..(string.format("%.2f", High_C)).."m", 61, 16)
end
if BAT_Voltage_C then
u8g2.DrawUTF8("B:"..(string.format("%.2f", BAT_Voltage_C)).."V", 66, 32)
end
if CPU_T_C then
u8g2.DrawUTF8("CPUT:"..(string.format("%d", CPU_T_C)).."°C", 63, 63)
end
u8g2.SendBuffer() -- 화면에 데이터 업데이트 표시
sys.wait(200)
end
end)sys.taskInit(function() --스레드 생성, 500ms마다 LED 깜빡임
gpio.setup(27, 0) -- gpio27을 출력으로 설정, 초기 레벨은 LOW, 하드웨어 기본 풀업/풀다운 사용
while true do
gpio.toggle(27) -- gpio 레벨 토글
sys.wait(500)
end
end)
--[[
지원 글꼴
["unifont_t_symbols","open_iconic_weather_6x_t","opposansm8","opposansm10","opposansm12","opposansm16","opposansm20",
"opposansm24","opposansm32","sarasa_m8_ascii","sarasa_m10_ascii","sarasa_m12_ascii","sarasa_m14_ascii",
"sarasa_m16_ascii","sarasa_m18_ascii","sarasa_m20_ascii","sarasa_m22_ascii"]
]]
-- 사용자 코드 종료---------------------------------------------
-- 항상 이 문장으로 끝남
sys.run()
-- sys.run() 이후에는 어떤 문장도 추가하지 마세요!!!!!
### WiFi 노드
펌웨어 다운로드 주소: [https://url.zeruns.com/a7eXJ](https://url.zeruns.com/a7eXJ)
**main.lua 파일:**
```lua
-- LuaTools는 PROJECT와 VERSION 정보가 필요합니다
PROJECT = "데이터 표시 노드"
VERSION = "1.0.5"
-- sys 라이브러리는 필수
_G.sys = require("sys")
require("sysplus")
-- 하드웨어 워치독 추가로 프로그램 정지 방지
wdt.init(9000)-- 워치독 초기화, 6s로 설정
wdt_timer_id = sys.timerLoopStart(function()
wdt.feed()
end, 2000) -- 2s마다 워치독 피드
local ProductKey= "xxxxxx" -- 제품 키
local DeviceName= "xxxxxx" -- 자신의 장치 이름으로 변경
local DeviceSecret = "xxxxxx" -- 자신의 장비 시크릿으로 변경
local client_id, user_name, password = iotauth.aliyun(ProductKey, DeviceName ,DeviceSecret) -- MQTT 3요소 생성
log.info("MQTT 매개변수", client_id, user_name, password)
local local_CPU_T_C = 0;
local all_data = {params = {CurrentVoltage = 0,CurrentTemperature = 0, CurrentHumidity = 0,
Atmosphere = 0, Altitude = 0,DetectDistance = 0,CPUTemperature = 0}};
local key1_flag,key2_flag = false,false
sys.taskInit(function() -- 스레드 생성
log.info("wlan", "wlan_init:", wlan.init()) -- wlan 초기화
wlan.setMode(wlan.STATION) -- wlan 모드를 STATION으로 설정
wlan.connect("Mate 40 Pro", "123456789", 1) -- wlan 네트워크 연결
local result, data = sys.waitUntil("IP_READY",6000)-- IP_READY 이벤트 대기
log.info("wlan", "IP_READY", result, data) -- IP_READY 이벤트 결과 및 데이터 출력
if result then
socket.setDNS(socket.STA, 1, "114.114.114.114")
log.info("wlan", "info", json.encode(wlan.getInfo())) -- wlan 네트워크 상세 정보 출력
sys.publish("WiFi_connected_OK",data) -- 메시지 발행, WiFi 연결 성공
--ntp 시간 동기화
--socket.sntp()
socket.sntp({"ntp.aliyun.com","time.windows.com","ntp.tencent.com","ntp2.aliyun.com"}, socket.STA) --sntp 사용자 지정 서버 주소
--socket.sntp(nil, socket.STA) --sntp 사용자 지정 어댑터 번호
-- NTP_UPDATE 이벤트 구독
sys.subscribe("NTP_UPDATE", function()
sys.publish("NTP_OK") -- 메시지 발행, NTP 시간 동기화 성공
log.info("sntp", "time", os.date()) -- 시스템 시간 출력
end)
sys.subscribe("NTP_ERROR", function()
log.info("socket", "sntp error")
socket.sntp()
end)
else
while true do
sys.wait(1000)
end
end
adc.open(adc.CH_CPU)-- ADC 채널 열기-CPU 내부 온도 채널
local CH_CPU = adc.get(adc.CH_CPU) / 1000 -- CPU 온도 읽기
if CH_CPU then -- 데이터 유효성 판단
local_CPU_T_C = CH_CPU
end
mqttc = mqtt.create(nil, "a1sJbDQiEqr.iot-as-mqtt.cn-shanghai.aliyuncs.com", 1883,true) -- MQTT 클라이언트 생성
mqttc:auth(client_id, user_name, password) -- MQTT 인증 수행
mqttc:keepalive(60) -- MQTT keepalive 시간 설정, 기본값 60초
mqttc:autoreconn(true, 3000) -- 자동 재연결 메커니즘 활성화
mqttc:on(function(mqtt_client, event, data, payload)-- MQTT 이벤트 콜백 함수 정의
if event == "conack" then -- 연결 확인 이벤트(conack) 수신 시
sys.publish("mqtt_conack") -- mqtt_conack 메시지 발행
log.info("mqtt", "mqtt 연결됨") -- 연결 성공 정보 출력
mqtt_client:subscribe("/sys/"..ProductKey.."/"..DeviceName.."/thing/service/property/set") -- 지정 토픽 구독
mqtt_client:subscribe("/"..ProductKey.."/"..DeviceName.."/user/get")
elseif event == "recv" then -- 메시지 수신 이벤트(recv) 시
if data == "/"..ProductKey.."/"..DeviceName.."/user/get" then -- 수신 토픽 판단
all_data = json.decode(payload) -- 메시지 내용을 JSON 형식으로 파싱
mqttc:publish("/sys/"..ProductKey.."/"..DeviceName.."/thing/event/property/post", payload) -- MQTT 속성 보고
else
log.info("mqtt", "메시지 수신", data, payload) -- 수신 메시지 정보 출력
local mqtt_date = json.decode(payload) -- 메시지 내용을 JSON 형식으로 파싱
end
elseif event == "sent" then -- 메시지 발송 이벤트(sent) 시
--log.info("mqtt", "sent", "pkgid", data)-- 발송 메시지 정보 출력
end
end)
mqttc:connect()
while true do
local CH_CPU = adc.get(adc.CH_CPU) / 1000 -- CPU 온도 읽기
if CH_CPU then -- 데이터 유효성 판단
CPU_T_C = CH_CPU
end
gpio.toggle(12) --gpio 레벨 토글
sys.wait(500)
end
end)
sys.taskInit(function() -- 스레드 생성
spi.setup(2, 7, 0, 0, 8, 80 * 1000 * 1000, spi.MSB, 1, 1) -- SPI 초기화
log.info("lcd.init", lcd.init("st7789",{
port = 2, -- spi 포트
-- pin_cs = 7, -- SPI 칩 선택
pin_dc = 8, -- lcd 데이터/명령 선택 핀
-- pin_pwr = 18, -- lcd 백라이트 핀 옵션, 설정 안 해도 됨
pin_rst = 6, -- lcd 리셋 핀
direction = 2, -- lcd 화면 방향 0:0° 1:180° 2:270° 3:90°
w = 320, -- lcd 수평 해상도
h = 172, -- lcd 수직 해상도
xoffset = 0, -- x 오프셋(다른 화면 ic 및 방향에 따라 다름)
yoffset = 34; -- y 오프셋(다른 화면 ic 및 방향에 따라 다름)
}))
log.info("lvgl", lvgl.init()) --- LVGL 초기화
local style_screen_label_main = lvgl.style_create() -- style_screen_label_main 이름의 스타일 객체 생성
lvgl.style_set_text_font(style_screen_label_main, lvgl.STATE_DEFAULT, lvgl.font_get("opposans_m_16")) -- 라벨 기본 글꼴 설정
```local Init_scr = lvgl.obj_create(nil, nil) -- 화면 객체 생성
lvgl.scr_load(Init_scr) -- 화면 객체 로드하여 디스플레이에 표시
local spinner = lvgl.spinner_create(Init_scr, nil) -- 회전 아이콘 객체 생성
lvgl.obj_set_size(spinner, 100, 100) -- 회전 아이콘 객체 크기 설정
lvgl.obj_align(spinner, nil, lvgl.ALIGN_CENTER, 0, -20) -- 회전 아이콘 객체 중앙 정렬
local label_WiFiConnecting = lvgl.label_create(Init_scr, nil) -- 라벨 객체 생성
lvgl.label_set_recolor(label_WiFiConnecting, true) -- 라벨 재색상 기능 활성화, 텍스트 변경 시 색상 자동 업데이트
lvgl.obj_add_style(label_WiFiConnecting, lvgl.LABEL_PART_MAIN, style_screen_label_main) -- 스타일 객체를 라벨 객체의 main 부분에 할당
lvgl.label_set_text(label_WiFiConnecting, "WiFi 연결 중...") -- 라벨 객체 텍스트 설정
lvgl.label_set_align(label_WiFiConnecting, lvgl.LABEL_ALIGN_CENTER) -- 라벨 객체 텍스트 중앙 정렬
lvgl.obj_align(label_WiFiConnecting, nil, lvgl.ALIGN_CENTER, 0, 46) -- 라벨 객체 중앙 정렬
local result, ip_data = sys.waitUntil("WiFi_connected_OK", 5000) -- WiFi 연결 성공 메시지 대기, 5초 타임아웃
if result == false then
lvgl.label_set_text(label_WiFiConnecting, "#ff0000 WiFi 연결 실패!#\\n기기를 재시작하거나 네트워크를 확인하세요") -- 라벨 객체 텍스트 설정 (WiFi 연결 실패 표시)
lvgl.label_set_align(label_WiFiConnecting, lvgl.LABEL_ALIGN_CENTER) -- 라벨 객체 텍스트 중앙 정렬
lvgl.obj_align(label_WiFiConnecting, nil, lvgl.ALIGN_CENTER, 0, 51) -- 라벨 객체 중앙 정렬
while true do
sys.wait(1000) -- 프로그램 진행 방지를 위한 무한 대기
end
end
lvgl.label_set_text(label_WiFiConnecting, "WiFi 연결 성공!") -- 라벨 객체 텍스트 설정 (WiFi 연결 성공 표시)
lvgl.label_set_align(label_WiFiConnecting, lvgl.LABEL_ALIGN_CENTER) -- 라벨 객체 텍스트 중앙 정렬
lvgl.obj_align(label_WiFiConnecting, nil, lvgl.ALIGN_CENTER, 0, 51) -- 라벨 객체 중앙 정렬
sys.wait(500) -- 500밀리초 대기
lvgl.obj_del(label_WiFiConnecting) -- 라벨 객체 삭제
lvgl.obj_align(spinner, nil, lvgl.ALIGN_CENTER, 0, 0) -- 회전 아이콘 객체 중앙 정렬
local label_Init_log = lvgl.label_create(Init_scr, nil) -- 라벨 객체 생성
lvgl.label_set_recolor(label_Init_log, true) -- 라벨 재색상 기능 활성화
lvgl.label_set_align(label_Init_log, lvgl.LABEL_ALIGN_LEFT) -- 라벨 객체 텍스트 좌측 정렬
lvgl.obj_align(label_Init_log, nil, lvgl.ALIGN_IN_TOP_LEFT, 10, 5) -- 라벨 객체 화면 좌상단에 정렬
local Init_log = "#0000ff 초기화 로그: #\\nWiFi 연결 성공!\\n" -- 초기화 로그 정보
lvgl.label_set_text(label_Init_log, Init_log) -- 라벨 객체 텍스트 설정
Init_log = Init_log.."IP: "..ip_data.."\\nMQTT 서버 연결 중...\\n" -- 로그 정보 업데이트
lvgl.label_set_text(label_Init_log, Init_log) -- 라벨 객체 텍스트 설정
if sys.waitUntil("mqtt_conack", 10000) == false then
Init_log = Init_log.."#ff0000 MQTT 서버 연결 실패!\\n기기를 재시작하세요!#\\n" -- 로그 정보 업데이트 (MQTT 연결 실패 표시)
lvgl.label_set_text(label_Init_log, Init_log) -- 라벨 객체 텍스트 설정
mqttc:disconnect() -- MQTT 연결 해제
mqttc:close() -- MQTT 연결 닫기
while true do
sys.wait(1000) -- 프로그램 진행 방지를 위한 무한 대기
end
end
Init_log = Init_log.."MQTT 서버 연결 성공!\\n" -- 로그 정보 업데이트 (MQTT 연결 성공 표시)
lvgl.label_set_text(label_Init_log, Init_log) -- 라벨 객체 텍스트 설정
Init_log = Init_log.."NTP 시간 동기화 중...\\n" -- 로그 정보 업데이트
lvgl.label_set_text(label_Init_log, Init_log) -- 라벨 객체 텍스트 설정
local result = sys.waitUntil("NTP_OK", 3500) -- NTP 시간 동기화 성공 메시지 대기, 3초 타임아웃
if result then
Init_log = Init_log.."NTP 시간 동기화 성공!\\n" -- 로그 정보 업데이트 (NTP 시간 동기화 성공 표시)
lvgl.label_set_text(label_Init_log, Init_log) -- 라벨 객체 텍스트 설정
else
Init_log = Init_log.."NTP 시간 동기화 실패!\\n" -- 로그 정보 업데이트 (NTP 시간 동기화 실패 표시)
lvgl.label_set_text(label_Init_log, Init_log) -- 라벨 객체 텍스트 설정
end
Init_log = Init_log.."현재 시간: "..(os.date("%Y-%m-%d %H:%M:%S")).."\\n" -- 로그 정보 업데이트 (현재 시간 표시)
lvgl.label_set_text(label_Init_log, Init_log) -- 라벨 객체 텍스트 설정
Init_log = Init_log.."시스템 초기화 완료!\\n" -- 로그 정보 업데이트 (시스템 초기화 완료 표시)
lvgl.label_set_text(label_Init_log, Init_log) -- 라벨 객체 텍스트 설정
sys.wait(2000)
local alldata_scr = lvgl.obj_create(nil, nil) -- 모든 데이터 표시용 화면 객체 생성, 부모 객체와 스타일 없음
lvgl.scr_load(alldata_scr) -- 화면 객체 로드하여 디스플레이에 표시
local label_alldata = lvgl.label_create(alldata_scr, nil) -- 모든 데이터 표시용 Label 객체 생성
lvgl.label_set_recolor(label_alldata, true) -- 라벨 재색상 기능 활성화
lvgl.label_set_align(label_alldata, lvgl.LABEL_ALIGN_LEFT) -- 라벨 정렬 방식을 좌측 정렬로 설정
lvgl.obj_align(label_alldata, nil, lvgl.ALIGN_IN_TOP_LEFT, 10, 5) -- 라벨을 화면 좌상단에 정렬, 좌측 여백 10픽셀, 상단 여백 5픽셀
lvgl.obj_add_style(label_alldata, lvgl.LABEL_PART_MAIN, style_screen_label_main)-- 스타일 객체를 label_alldata 라벨의 main 부분에 할당
local label_time = lvgl.label_create(alldata_scr, nil) -- 현재 시간 표시용 Label 객체 생성
lvgl.label_set_text(label_time, os.date("%Y-%m-%d").."\\n"..os.date("%H:%M:%S"))
lvgl.label_set_align(label_time, lvgl.LABEL_ALIGN_CENTER) -- 라벨 정렬 방식을 중앙 정렬로 설정
lvgl.obj_align(label_time, nil, lvgl.ALIGN_IN_TOP_RIGHT, -25, 10)-- 라벨을 화면 우상단에 정렬, 좌측 여백 10픽셀, 상단 여백 5픽셀
lvgl.obj_add_style(label_time, lvgl.LABEL_PART_MAIN, style_screen_label_main)
lvgl.obj_del(Init_scr)
local chart_scr = lvgl.obj_create(nil, nil) -- 차트 표시용 화면 객체 생성, 부모 객체와 스타일 없음
local chart = lvgl.chart_create(chart_scr, nil);
lvgl.obj_set_size(chart, 310, 150);
lvgl.obj_align(chart, nil, lvgl.ALIGN_CENTER, 0, 0);
lvgl.chart_set_type(chart, lvgl.CHART_TYPE_LINE); -- 라인과 포인트도 표시
lvgl.chart_set_point_count(chart, 20)
lvgl.chart_set_y_range(chart, lvgl.CHART_AXIS_PRIMARY_Y, 0, 100)
local ser1 = lvgl.chart_add_series(chart, lvgl.color_make(0xFF, 0x00, 0x00));
local ser2 = lvgl.chart_add_series(chart, lvgl.color_make(0x00, 0x80, 0x00));
-- 메모리 사용량 출력
log.info("mem.lua", rtos.meminfo())
log.info("mem.sys", rtos.meminfo("sys"))
while true do
lvgl.label_set_text(label_alldata, string.format([[#0000ff 환경 온도: %.2f°C#
#ff00ff 환경 습도: %.2f%%#
#ff0000 기압: %.2fhPa#
#800080 해발 고도: %.2fm#
#0000ff 초음파 거리 측정: %.2fcm#
#ff00ff 원격 노드 배터리 전압: %.2fV#
#ff0000 원격 노드 CPU 온도: %.0f°C#
#800080 로컬 노드 CPU 온도: %.0f°C#
]],all_data.params.CurrentTemperature,all_data.params.CurrentHumidity,all_data.params.Atmosphere,
all_data.params.Altitude,all_data.params.DetectDistance,all_data.params.CurrentVoltage,
all_data.params.CPUTemperature,local_CPU_T_C)); -- 라벨 텍스트 설정
lvgl.label_set_text(label_time, os.date("%Y-%m-%d").."\\n"..os.date("%H:%M:%S"))
lvgl.chart_set_next(chart, ser1, all_data.params.CurrentTemperature);
lvgl.chart_set_next(chart, ser2, all_data.params.CurrentHumidity);
lvgl.chart_refresh(chart);
if key1_flag then
lvgl.scr_load(chart_scr)
key1_flag = false
end
if key2_flag then
lvgl.scr_load(alldata_scr)
key2_flag = false
end
gpio.toggle(12) --gpio 레벨 토글
sys.wait(300)
end
end)
sys.taskInit(function() --500밀리초마다 LED 깜빡이는 스레드 생성
gpio.setup(13, 0) -- gpio13을 출력으로 설정, 초기 레벨은 낮음, 하드웨어 기본 풀업/풀다운 사용
gpio.setup(12, 0) -- gpio12를 출력으로 설정, 초기 레벨은 낮음, 하드웨어 기본 풀업/풀다운 사용
while true do
gpio.toggle(13) --gpio 레벨 토글
sys.wait(500)
end
end)
sys.taskInit(function() --키 스캔 스레드 생성
gpio.setup(18, nil, gpio.PULLUP)
gpio.setup(19, nil, gpio.PULLUP)
while true do
if gpio.get(18) == 0 then
sys.wait(20)
if gpio.get(18) == 0 then
key1_flag = true
end
end
if gpio.get(19) == 0 then
sys.wait(20)
if gpio.get(19) == 0 then
key2_flag = true
end
end
sys.wait(50)
end
end)
--[[
지원 글꼴 ["sarasa_m8_ascii","sarasa_m10_ascii","sarasa_m12_ascii",
"sarasa_m14_ascii","sarasa_m16_ascii","sarasa_m18_ascii","sarasa_m20_ascii","sarasa_m22_ascii"]
]]
-- 사용자 코드 종료---------------------------------------------
-- 항상 이 문장으로 끝남
sys.run()
-- sys.run() 이후에는 어떤 문장도 추가하지 마세요!!!!!
## 사용된 하드웨어
사용된 하드웨어 모듈 및 구매 링크:- 4G 모듈: Air700E, [https://s.click.taobao.com/gMXE14u](https://uland.taobao.com/coupon/edetail?e=LUUvClZZaoalhHvvyUNXZfh8CuWt5YH5OVuOuRD5gLJMmdsrkidbOUV9IBA4kmjLCKSz6NMEOpOk6DkEOOy39ANONOd65bn6k%2BQD1WLWk7D58pWrh7e7ViECg58T7b6E7qOXUj4MT3dyBOK%2B8KjzSuzY3MUSAX0G1TP3uC6T%2BzrKa4jyh4U%2Bo5gBVnx58RcK3x24QQZ%2BkKRI%2Bf4%2BtcDu44oLvKgaQ5D83qmGq7GPCXsH2XAjD13xyT%2FhMZgljYbZj4NAR0X%2B9c23Sv8LMk9JOkIQtV1V6tmtIciWFcjrsPzH6emLlAySAVD9ZzTfOOXe%2Bm9PGdJ%2FlaUZUAGa9XIpkqJ7%2BkHL3AEW&traceId=213d811317025749037687621e65ab&union_lens=lensId%3APUB%401702574899%40212be3f7_0d90_18c695f4255_c520%400212cIwjWn6h4JZ67isD7Et6%40eyJmbG9vcklkIjo4MDY3NCwiic3BtQiiI6Il9wb3J0YWxfdjJfcGFnZXNfcHJvbW9fZ29vZHNfaW5kZXhfaHRtIiiwiic3JjRmxvb3JJZCI6IjgwNjc0In0ie%3Bscm%3A1007.30148.329090.pub_search-item_ea9ed1dc-121c-4a26-85aa-1c27c9c4e982_)
- WiFi 모듈: ESP32-C3, [https://s.click.taobao.com/VU6E14u](https://s.click.taobao.com/t?e=m%3D2%26s%3DZlxzb7VA%2BERw4vFB6t2Z2ueEDrYVVa64YUrQeSeIhnK53hKxp7mNFhiPRfK6WZZbW%2BG7BH3F%2BVP0JlhLk0Jl4QTquP0kWxBLBDnvz6xo38xspWc9%2BCL4bTGF1ceZMhPo8mL8HhJ3EdVrH4ks4QyiY4z4rjZDGVMA7PT7P4MIjv0iDnQnCfxRCKLWMw3EOEsyJN2owMjhufwDudUsQ2T%2BdtwdcXrvJnQ7ZHuYE9Ro5OOZ8DKCp9t3JAIHG%2FUGGufvqH4FkV%2B42f2z1OkmXn0f%2BU%2FuprW1TdmBLeMqtJBmsqBWpXpRELkuYcbEo3ADJdJgcSpj5qSCmbA%3D&union_lens=lensId%3APUB%401702575245%4021334feb_0c8e_18c6964886f_3037%4002FXjqZ71jUAMAWD59wyxDr%40eyJmbG9vcklkIjo4MDY3NCwiic3BtQiiI6Il9wb3J0YWxfdjJfcGFnZXNfcHJvbW9fZ29vZHNfaW5kZXhfaHRtIiiwiic3JjRmxvb3JJZCI6IjgwNjc0In0ie%3Bscm%3A1007.30148.329090.pub_search-item_86a564e3-eb01-4328-b966-1f368fd8dd53_)
- 온습도 센서: AHT10, [https://s.click.taobao.com/0bmD14u](https://s.click.taobao.com/t?e=m%3D2%26s%3D771Jk01ERgJw4vFB6t2Z2ueEDrYVVa64g3vZOarmkFi53hKxp7mNFhiPRfK6WZZbARW0aicXof30JlhLk0Jl4QTquP0kWxBLBDnvz6xo38xspWc9%2BCL4bTGF1ceZMhPo8mL8HhJ3EdVrH4ks4QyiY4z4rjZDGVMAhscfsB2%2FyzZJq71CBMBeP%2F1SarTXhIOTsgIpc1WFZiJNubylQlnZt9wh0O3n7rEs7VSraZkgkhwlqDRRVlGxRqvyzFinE2vlF34xAtPUu%2BiG3j8B3S26WYwmLWBgEm80VKxcI130SjETn2JhMaQNtYWLhXkoGmYy4m7hkqalpkwvY%2BXqRXyCksYOae24fhW0&union_lens=lensId%3APUB%401702575301%4021055555_16ff_18c69656404_8e69%40024dxCNyvH1jSaZZpYn2bbD3%40eyJmbG9vcklkIjo4MDY3NCwiic3BtQiiI6Il9wb3J0YWxfdjJfcGFnZXNfcHJvbW9fZ29vZHNfaW5kZXhfaHRtIiiwiic3JjRmxvb3JJZCI6IjgwNjc0In0ie%3Bscm%3A1007.30148.329090.pub_search-item_e4951d39-761b-41f5-8840-673a3c0c7f1f_)
- 기압 센서: BMP180, [https://s.click.taobao.com/lj5E14u](https://s.click.taobao.com/t?e=m%3D2%26s%3DbnhyRgad73lw4vFB6t2Z2ueEDrYVVa64YUrQeSeIhnK53hKxp7mNFhiPRfK6WZZbbJVKleC4LJX0JlhLk0Jl4QTquP0kWxBLBDnvz6xo38xspWc9%2BCL4bTGF1ceZMhPo8mL8HhJ3EdVrH4ks4QyiY4z4rjZDGVMAFBcM8wkWlGmBPeR%2FUFCetKLWMw3EOEsyJN2owMjhufwDudUsQ2T%2BduXhptvf7sm0vQrr15PsJfJByQLpIiyxZXY%2Fio3PXH82JxEGSxl4yKUtXkuY7xjNZU%2FuprW1TdmBLeMqtJBmsqAZVo9hr9WaqYgTf7YQgcVJcSpj5qSCmbA%3D&union_lens=lensId%3APUB%401702575360%402106d2ff_0cdf_18c69664982_7aaf%40021C2JTg214QOPnilxsDb2w%40eyJmbG9vcklkIjo4MDY3NCwiic3BtQiiI6Il9wb3J0YWxfdjJfcGFnZXNfcHJvbW9fZ29vZHNfaW5kZXhfaHRtIiiwiic3JjRmxvb3JJZCI6IjgwNjc0In0ie%3Bscm%3A1007.30148.329090.pub_search-item_f8a710ac-0037-4ec2-bbff-896f3c1af2c5_)
- 초음파 거리 측정 모듈: US-100(직렬 통신 모드 사용), [https://s.click.taobao.com/K0o5X3u](https://s.click.taobao.com/t?e=m%3D2%26s%3DInz6n3%2B%2FZwxw4vFB6t2Z2ueEDrYVVa64YUrQeSeIhnK53hKxp7mNFhiPRfK6WZZbq%2FcxWpaeRwj0JlhLk0Jl4QTquP0kWxBLBDnvz6xo38xspWc9%2BCL4bTGF1ceZMhPo8mL8HhJ3EdVrH4ks4QyiY4z4rjZDGVMAFBcM8wkWlGmBPeR%2FUFCetKLWMw3EOEsyJN2owMjhufwDudUsQ2T%2Bdg68505k9IiwAZQz22%2FRFMA5pQILDo6IOf16Gn%2BAIx7L96W3Eb16pLNyU%2FAPg17%2FFE%2FuprW1TdmBLeMqtJBmsqB4r3mjD%2F4H9bgUNPZMnoHFcSpj5qSCmbA%3D&skuId=4276770277565&union_lens=lensId%3APUB%401702575435%40213e7f1b_0c9e_18c69676fe9_4d3a%40036cIiBD2TZI9c9YU2Vchohd%40eyJmbG9vcklkIjo2MTQyOSwiic3BtQiiI6Il9wb3J0YWxfdjJfcGFnZXNfcHJvbW9fZ29vZHNfZGV0YWlsX2h0bSIsInNyY0Zsb29ySWQiiOiiI4MDY3NCJ9%3Bscm%3A1007.30148.329090.pub_search-item_972f304d-0e03-4fbf-b740-fd750c7af1d6_)
- LCD 화면: 1.47인치 ST7789, 해상도 172*320, [https://s.click.taobao.com/qalD14u](https://s.click.taobao.com/t?e=m%3D2%26s%3DgP4fG3vZI%2FNw4vFB6t2Z2ueEDrYVVa64g3vZOarmkFi53hKxp7mNFhiPRfK6WZZbfpmjeIyJHHf0JlhLk0Jl4QTquP0kWxBLBDnvz6xo38xspWc9%2BCL4bTGF1ceZMhPo8mL8HhJ3EdVrH4ks4QyiY4z4rjZDGVMAhscfsB2%2FyzZJq71CBMBeP%2F1SarTXhIOTsgIpc1WFZiJNubylQlnZt8KAViuQdyPNc8ER84P6KktsP7OMD4hiwaj%2Fx4cHJV5ILJ9HqoY3BUsLMohkjCbsqowmLWBgEm80VKxcI130SjETn2JhMaQNtYWLhXkoGmYyruoikO2OymYJLixcAe8pyMYOae24fhW0&union_lens=lensId%3APUB%401702575502%40212c48cb_0c8f_18c69687670_23aa%40024B9sLEl2iRKmna6a9po7FA%40eyJmbG9vcklkIjo4MDY3NCwiic3BtQiiI6Il9wb3J0YWxfdjJfcGFnZXNfcHJvbW9fZ29vZHNfaW5kZXhfaHRtIiiwiic3JjRmxvb3JJZCI6IjgwNjc0In0ie%3Bscm%3A1007.30148.329090.pub_search-item_5e0d1922-0ca6-44f9-99a9-821166c9de7d_)
- OLED 화면: 0.96인치 SSD1306, I2C 인터페이스, [https://s.click.taobao.com/otWD14u](https://s.click.taobao.com/t?e=m%3D2%26s%3DKH7sw7eX%2F2Bw4vFB6t2Z2ueEDrYVVa64YUrQeSeIhnK53hKxp7mNFhiPRfK6WZZbUnl%2Fg%2F1GNuL0JlhLk0Jl4QTquP0kWxBLBDnvz6xo38xspWc9%2BCL4bTGF1ceZMhPo8mL8HhJ3EdVrH4ks4QyiY4z4rjZDGVMAc7QBxLpsf4TZIsq6%2BWiNSqLWMw3EOEsyJN2owMjhufwDudUsQ2T%2BdqwhF6wjgAjmYU48%2FUVSeeMab%2F%2BCSuws4OiHLQ4Yn8csh%2BdzzS7mHW11b5eySA3UA0%2FuprW1TdmBLeMqtJBmsqChj81ryXyWXeLqYXvNN1cOcSpj5qSCmbA%3D&union_lens=lensId%3APUB%401702575558%40213f6e5c_0cfd_18c69694f33_999c%40021vqRKMT5nzj9ALhoKTH8lx%40eyJmbG9vcklkIjo4MDY3NCwiic3BtQiiI6Il9wb3J0YWxfdjJfcGFnZXNfcHJvbW9fZ29vZHNfaW5kZXhfaHRtIiiwiic3JjRmxvb3JJZCI6IjgwNjc0In0ie%3Bscm%3A1007.30148.329090.pub_search-item_b4129703-d754-49d5-b48a-82cdfefb2b5f_)
- 배터리 충·방전 칩: IP5306-CK(CK 버전을 구매해야 함, 일반 버전은 방전 전류가 너무 작으면 자동으로 출력이 차단되어 마이크로컨트롤러에 적합하지 않음), [https://s.click.taobao.com/eu85X3u](https://s.click.taobao.com/t?e=m%3D2%26s%3DjX7JisUJSllw4vFB6t2Z2ueEDrYVVa64g3vZOarmkFi53hKxp7mNFhiPRfK6WZZbiJKehPSaPYD0JlhLk0Jl4QTquP0kWxBLBDnvz6xo38xspWc9%2BCL4bTGF1ceZMhPo8mL8HhJ3EdVrH4ks4QyiY4z4rjZDGVMAhscfsB2%2FyzZJq71CBMBeP%2F1SarTXhIOTsgIpc1WFZiJNubylQlnZt4mEKVwjSJcGFXvRQPy5FMG3%2FxXe%2BxQvKcLHPTEEdUKrO5xtKw8OA8bUMx%2BC19Mn3YwmLWBgEm80VKxcI130SjETn2JhMaQNtYWLhXkoGmYy5%2FXtHaC5QvUT2J2P4FlLNcYOae24fhW0&union_lens=lensId%3APUB%401702575629%4021055b80_0c9f_18c696a64f6_4c08%40022k2R4UBS6bcyB2aIphUK2l%40eyJmbG9vcklkIjo4MDY3NCwiic3BtQiiI6Il9wb3J0YWxfdjJfcGFnZXNfcHJvbW9fZ29vZHNfaW5kZXhfaHRtIiiwiic3JjRmxvb3JJZCI6IjgwNjc0In0ie%3Bscm%3A1007.30148.329090.pub_search-item_9fa456ea-a73f-470b-94dc-a6e6199bf4a4_)
- 배터리: 이웨이 35V-18650, 3500mAh, [https://s.click.taobao.com/uUc5X3u](https://s.click.taobao.com/t?e=m%3D2%26s%3DS952IFxDAbxw4vFB6t2Z2ueEDrYVVa64g3vZOarmkFi53hKxp7mNFhiPRfK6WZZbhQCvBpU9uKb0JlhLk0Jl4QTquP0kWxBLBDnvz6xo38xspWc9%2BCL4bTGF1ceZMhPo8mL8HhJ3EdVrH4ks4QyiY4z4rjZDGVMA2wPTjyt1VFhJDk80jsGTwv1SarTXhIOT%2FcbizUjsed%2BEr%2BInjt7kJlMJo4xVYoI6QTU2mSOmawi8xTwUuWBJq9spaWqoW5XN2MTzYpfP%2FlmjO9AJYjY8CXJ%2BwEVkOqHFdIW9JNkz7%2FgDXc3BRboPm%2FkFZVUCNgR0oMbC7PHmBq9RLBgaW5udaw%3D%3D&union_lens=lensId%3APUB%401702575711%400b8b8151_148e_18c696ba6d8_29d5%40021a7vszDH3fGcvCMrLJyErd%40eyJmbG9vcklkIjo4MDY3NCwiic3BtQiiI6Il9wb3J0YWxfdjJfcGFnZXNfcHJvbW9fZ29vZHNfaW5kZXhfaHRtIiiwiic3JjRmxvb3JJZCI6IjgwNjc0In0ie%3Bscm%3A1007.30148.329090.pub_search-item_52261151-42b3-4abc-8483-08f2c5c3cc3d_)
**부품 구매는 리창몰(立创商城) 추천, 할인 가입 링크: [https://activity.szlcsc.com/invite/D03E5B9CEAAE70A4.html](https://activity.szlcsc.com/invite/D03E5B9CEAAE70A4.html)**
**보드의 모든 부품은 리창몰에서 구매 가능하며, 오픈소스 링크의 BOM表에서 ‘즉시 리창몰로 이동해 주문하기’를 클릭하면 사용된 부품을 한 번에 장바구니로 가져올 수 있습니다.**
## IoT 플랫폼 설정 설명
먼저 알리윤 IoT 플랫폼에서 신제품을 생성하고, 노드 유형은 직접 연결 디바이스로 선택합니다.

기능 정의 설정:

이어서 디바이스 2개를 추가합니다

스크립트의 제품 키 등 매개변수를 수정한 후 펌웨어와 스크립트를 Air700E에 다운로드하여 디바이스가 정상적으로 온라인 상태가 되고 데이터를 업로드하는지 확인합니다.

메시지 전달→클라우드 제품 전달로 이동해 데이터 소스를 생성합니다:

방금 생성한 데이터 소스 오른쪽 ‘보기’를 클릭한 뒤 Topic 추가, 첫 번째는 사용자 지정, 두 번째는 생성한 제품 선택, 세 번째는 4G 노드 디바이스 선택, 네 번째는 `user/update` 선택

데이터 대상 생성, 작업 선택은 ‘다른 Topic에 게시’, 제품도 위에서 생성한 제품 선택

파서 생성 후 ‘편집하러 가기’ 클릭, 혹은 오른쪽 ‘보기’ 클릭

연결 데이터 소스에서 방금 생성한 데이터 소스 선택:

연결 데이터 대상에서 방금 생성한 데이터 대상 선택

파서 스크립트에서 `deviceName()`을 WiFi 노드 디바이스 이름으로 변경, 아래 그림 참고

편집 완료 후 ‘게시’ 클릭, 이후 시작하면 `/ProductKey/DeviceName/user/update` 주제의 데이터가 `/ProductKey/DeviceName/user/get` 주제로 자동 전달됩니다.
## 기타 오픈소스 프로젝트 추천- STM32F030C8T6 최소 시스템 보드와 물결 LED (회로도 및 PCB): [https://blog.zeruns.com/archives/715.html](https://blog.zeruns.com/archives/715.html)
- MSP430F149 최소 시스템 보드를 그려서 오픈소스로 공개했습니다: [https://blog.zeruns.com/archives/713.html](https://blog.zeruns.com/archives/713.html)
- 2007년 전자 설계 대회 전원 문제: 30~36V 가변 승압 DCDC 모듈(UC3843): [https://oshwhub.com/zeruns/36v-sheng-ya-dcdc-mo-kuai-uc3842](https://oshwhub.com/zeruns/36v-sheng-ya-dcdc-mo-kuai-uc3842)
- STC12C5A60S2 최소 시스템 보드/51 MCU 온도 표시 및 온도 제어 팬: [https://blog.zeruns.com/archives/721.html](https://blog.zeruns.com/archives/721.html)
- U8g2 그래픽 라이브러리를 이식한 STM32F407 표준 라이브러리 프로젝트 템플릿: [https://blog.zeruns.com/archives/722.html](https://blog.zeruns.com/archives/722.html)
- Qinheng CH32V307VCT6 최소 시스템 보드 오픈소스: [https://blog.zeruns.com/archives/726.html](https://blog.zeruns.com/archives/726.html)
- LM25118 자동 승압/강압 가변 DCDC 전원 모듈: [https://blog.zeruns.com/archives/727.html](https://blog.zeruns.com/archives/727.html)
- EG1164 대용량 동기 정류 승압 모듈 오픈소스, 최대 효율 97%: [https://blog.zeruns.com/archives/730.html](https://blog.zeruns.com/archives/730.html)
## 추천 글
- **높은 가성비와 저렴한 VPS/클라우드 서버 추천:** [https://blog.zeruns.com/archives/383.html](https://blog.zeruns.com/archives/383.html)
- 마인크래프트 서버 구축 튜토리얼: [https://blog.zeruns.com/tag/mc/](https://blog.zeruns.com/tag/mc/)
- 집 네트워크 랙, 홈 네트워크 장비 추천 공유: [https://blog.zeruns.com/archives/732.html](https://blog.zeruns.com/archives/732.html)
- Orange Pi 3B(RK3566) 개발 보드 개봉기 및 리뷰: [https://blog.zeruns.com/archives/729.html](https://blog.zeruns.com/archives/729.html)
- PC 업그레이드, 그래픽 카드 교체, Yeston RTX3070: [https://blog.zeruns.com/archives/746.html](https://blog.zeruns.com/archives/746.html)












