1. เริ่มต้นใช้งาน
- สมัครสมาชิกและเข้าสู่ระบบ
- ที่แดชบอร์ดกด สร้างโปรเจกต์ใหม่ แล้วเลือกเทมเพลตที่ใกล้เคียง หรือเริ่มจากหน้าว่าง
- ในหน้าออกแบบ เปิดแท็บ บอร์ด ทางขวา เลือกรุ่นบอร์ดให้ตรงกับที่มี ขนาดจอและขาต่อจอจะถูกตั้งให้เอง
- ลากวิดเจ็ตจากแถบซ้ายมาวางบนจอ ตั้งค่าในแผงขวา แล้วกด บันทึก
- กด ▶ ทดสอบรัน เพื่อลองแตะปุ่มและเลื่อนสไลเดอร์บนจอจำลอง
- เสียบบอร์ดเข้ากับคอมพิวเตอร์ แล้วกด ⚡ เบิร์นลงบอร์ด หรือกด สร้างโค้ด ESP32 เพื่อดูและดาวน์โหลดโค้ด
2. ส่วนต่าง ๆ ของหน้าออกแบบ
- แถบซ้าย
- รายการวิดเจ็ต แบ่งเป็นกลุ่มพื้นฐาน รับค่า แสดงผล และขั้นสูง คลิกหรือลากมาวางบนจอ
- ตรงกลาง
- จอจำลองขนาดเท่าจอจริง แท็บด้านบนคือหน้าจอแต่ละหน้า กด + หน้าจอ เพื่อเพิ่ม และดับเบิลคลิกที่แท็บเพื่อเปลี่ยนชื่อ
- แผงขวา
- แท็บคุณสมบัติ (ค่าของวิดเจ็ตที่เลือก) แท็บเลเยอร์ (ลำดับการซ้อน) และแท็บบอร์ด (รุ่นบอร์ด การหมุนจอ และ Wi-Fi)
- แถบบน
- ชื่องาน ซูม กริดสำหรับจัดแนว ย้อนกลับ บันทึก ผู้ช่วย AI ทดสอบรัน และสร้างโค้ด
3. วาง ย้าย และปรับขนาด
- ลากกล่องวิดเจ็ตเพื่อย้าย ลากจุดสี่เหลี่ยมที่มุมขวาล่างเพื่อปรับขนาด หรือพิมพ์ตำแหน่งและขนาดในแผงคุณสมบัติ
- วิดเจ็ตที่ซ้อนกัน ตัวที่อยู่บนสุดในแท็บเลเยอร์จะอยู่ด้านหน้า ใช้ปุ่ม ขึ้นหน้าสุด ในแผงคุณสมบัติเพื่อนำวิดเจ็ตที่เลือกขึ้นมาด้านหน้า
| ปุ่มลัด | ทำอะไร |
|---|---|
| ← → ↑ ↓ | ขยับวิดเจ็ตที่เลือกทีละ 1 px (กด Shift ค้างไว้ = ทีละ 10 px) |
| Ctrl + D | ทำซ้ำวิดเจ็ตที่เลือก |
| Delete | ลบวิดเจ็ตที่เลือก |
| Ctrl + Z / Ctrl + Y | ย้อนกลับ / ทำซ้ำสิ่งที่ย้อน |
| Ctrl + S | บันทึกงาน |
| Esc | หยุดทดสอบรัน หรือยกเลิกการเลือก |
4. ตั้งค่าวิดเจ็ต
- ชื่อตัวแปร ใช้อ้างถึงวิดเจ็ตในโค้ด ชื่อจะถูกเติม ui_ ข้างหน้า เช่น ตั้งชื่อ LabelTemp จะได้ตัวแปร
ui_LabelTempควรตั้งเป็นภาษาอังกฤษที่บอกหน้าที่ชัดเจน - หน้าตา ปรับสี ขนาดตัวอักษร ความมน เส้นขอบ และความทึบได้ ภาพบนจอจำลองตรงกับที่จะขึ้นบนจอจริง
- ใช้ข้อความภาษาไทยได้ ระบบจะแนบฟอนต์ไทยให้เอง แต่ใช้อีโมจิและอักษรจีนหรือญี่ปุ่นไม่ได้ (ขึ้นเป็นกล่องว่าง)
- ติ๊ก ซ่อนตอนเริ่มต้น เพื่อให้วิดเจ็ตยังไม่แสดงจนกว่าโค้ดของคุณจะสั่งให้แสดง
5. ทำให้ปุ่มทำงาน
เลือกวิดเจ็ต แล้วดูหัวข้อ การทำงาน ในแผงคุณสมบัติ ช่อง เมื่อกด มีสามแบบ
- ไม่ทำอะไร
- ค่าเริ่มต้น
- ไปยังหน้าจออื่น
- เลือกหน้าปลายทางและแอนิเมชันได้ ไม่ต้องเขียนโค้ด
- เรียกฟังก์ชันของฉัน
- เขียนโค้ดเองว่าจะให้เกิดอะไรขึ้น เช่น สั่งรีเลย์ อ่านเซนเซอร์ หรือเปลี่ยนข้อความบนจอ (ดูหัวข้อถัดไป)
วิดเจ็ตที่รับค่าได้ (สวิตช์ ช่องติ๊ก สไลเดอร์ วงแหวน ดรอปดาวน์ ล้อเลือกค่า ช่องพิมพ์ข้อความ) มีช่องติ๊ก เรียกฟังก์ชันเมื่อค่าเปลี่ยน เพิ่มมาด้วย ใช้เมื่อต้องการรู้ค่าที่ผู้ใช้เลือก
6. เขียนฟังก์ชันของฉัน
- เลือกวิดเจ็ต แล้วตั้ง ชื่อตัวแปร ก่อน เช่น BtnLamp
- ในหัวข้อ การทำงาน เลือก เมื่อกด = เรียกฟังก์ชันของฉัน
- แผงจะบอกชื่อฟังก์ชันที่จะได้ เช่น
void ui_onBtnLampClicked(void) - พิมพ์โค้ดในช่อง โค้ดเมื่อกด เฉพาะคำสั่งข้างในฟังก์ชัน ไม่ต้องพิมพ์บรรทัดชื่อฟังก์ชันและวงเล็บปีกกา
- กดบันทึก โค้ดจะเก็บอยู่ในโปรเจกต์ และถูกใส่ลงไฟล์ .ino ทุกครั้งที่สร้างโค้ดหรือเบิร์น
สิ่งที่พิมพ์ในช่องจะกลายเป็นเนื้อในของฟังก์ชันในไฟล์ .ino แบบนี้
void ui_onBtnLampClicked(void)
{
// โค้ดที่คุณพิมพ์ในช่อง "โค้ดเมื่อกด"
}
ถ้าเว้นช่องว่างไว้ ระบบจะใส่โค้ดตัวอย่างที่พิมพ์ชื่อปุ่มที่ถูกกดออกทาง Serial Monitor ให้ ใช้ตรวจว่าปุ่มทำงานก่อนเขียนโค้ดจริง
ในฟังก์ชันใช้อะไรได้บ้าง
- คำสั่ง Arduino ทั้งหมด เช่น pinMode, digitalWrite, digitalRead, analogRead, millis และ Serial.println
- คำสั่ง LVGL กับวิดเจ็ตบนจอ ผ่านชื่อ ui_ชื่อตัวแปร เช่น เปลี่ยนข้อความ ซ่อนหรือแสดง หรือเปลี่ยนสี
- ฟังก์ชันของวิดเจ็ตพิเศษ เช่น ui_symbol_set_on() ของสัญลักษณ์สำเร็จรูป หรือ ui_shape_set_angle() ของรูปทรง (ดูไฟล์ HOWTO.md ที่ได้พร้อมโค้ด)
- setBacklight(0-100) ปรับความสว่างหน้าจอ
- getLocalTime() อ่านเวลาไทยจริงจาก NTP เมื่อใส่ชื่อ Wi-Fi ในแท็บบอร์ดไว้ (ดูตัวอย่างรีเลย์ตั้งเวลาตามนาฬิกา)
ฟังก์ชันเมื่อค่าเปลี่ยน
เมื่อติ๊ก "เรียกฟังก์ชันเมื่อค่าเปลี่ยน" จะได้ฟังก์ชันชื่อ ui_on ตามด้วยชื่อตัวแปร และ Changed ค่าที่ผู้ใช้เลือกส่งมาในตัวแปรตามชนิดของวิดเจ็ต
| วิดเจ็ต | ตัวแปรที่ได้รับ | ความหมาย |
|---|---|---|
| สวิตช์, ช่องติ๊ก | bool checked | true เมื่อเปิดหรือติ๊ก, false เมื่อปิด |
| สไลเดอร์, วงแหวน | int32_t value | ค่าปัจจุบัน อยู่ระหว่างค่าต่ำสุดถึงสูงสุดที่ตั้งไว้ |
| ดรอปดาวน์, ล้อเลือกค่า | uint16_t index | ลำดับตัวเลือกที่เลือก เริ่มนับจาก 0 |
| ช่องพิมพ์ข้อความ | const char * text | ข้อความทั้งหมดในช่อง |
7. ตัวอย่างโค้ด
ทุกตัวอย่างคอมไพล์ผ่านกับบอร์ด CYD 2.8" แล้ว ตั้งชื่อตัวแปรของวิดเจ็ตให้ตรงตามที่บอก แล้วคัดลอกโค้ดไปวางในช่องโค้ดได้เลย
1. ปุ่มเปิด/ปิดไฟ
วิดเจ็ตที่ต้องมี: ปุ่มกดชื่อ BtnLamp (เมื่อกด = เรียกฟังก์ชันของฉัน) และข้อความชื่อ LabelLamp
ฟังก์ชันที่ได้: void ui_onBtnLampClicked(void)
static bool on = false; // static = จำค่าไว้ระหว่างการกดแต่ละครั้ง on = !on; pinMode(22, OUTPUT); digitalWrite(22, on ? HIGH : LOW); lv_label_set_text(ui_LabelLamp, on ? "LAMP: ON" : "LAMP: OFF");
กดแต่ละครั้งสลับเปิด/ปิด ขา 22 เป็นแค่ตัวอย่าง ให้ใช้ขาที่ว่างและต่อรีเลย์หรือหลอดไฟไว้บนบอร์ดของคุณ
2. นับจำนวนครั้งที่กด
วิดเจ็ตที่ต้องมี: ปุ่มกดชื่อ BtnCount และข้อความชื่อ LabelCount
ฟังก์ชันที่ได้: void ui_onBtnCountClicked(void)
static int count = 0; count++; lv_label_set_text_fmt(ui_LabelCount, "%d", count);
lv_label_set_text_fmt ใส่ตัวเลขลงข้อความแบบเดียวกับ printf
3. สไลเดอร์ปรับความสว่างหน้าจอ
วิดเจ็ตที่ต้องมี: สไลเดอร์ชื่อ SliderLight (ต่ำสุด 0 สูงสุด 100 ติ๊ก "เรียกฟังก์ชันเมื่อค่าเปลี่ยน") และข้อความชื่อ LabelLight
ฟังก์ชันที่ได้: void ui_onSliderLightChanged(int32_t value)
setBacklight((uint8_t)value); // ปรับไฟหน้าจอ 0-100 % lv_label_set_text_fmt(ui_LabelLight, "%d%%", (int)value);
value คือค่าปัจจุบันของสไลเดอร์ ส่วน setBacklight() มีอยู่ในไฟล์ .ino ที่สร้างให้อยู่แล้ว
4. สวิตช์เปิดพัดลม และแสดง/ซ่อนวิดเจ็ต
วิดเจ็ตที่ต้องมี: สวิตช์ชื่อ SwitchFan (ติ๊ก "เรียกฟังก์ชันเมื่อค่าเปลี่ยน") และกรอบชื่อ PanelFan
ฟังก์ชันที่ได้: void ui_onSwitchFanChanged(bool checked)
pinMode(27, OUTPUT); digitalWrite(27, checked ? HIGH : LOW); if (checked) lv_obj_clear_flag(ui_PanelFan, LV_OBJ_FLAG_HIDDEN); // แสดง else lv_obj_add_flag(ui_PanelFan, LV_OBJ_FLAG_HIDDEN); // ซ่อน
checked เป็น true เมื่อเปิดสวิตช์ และ false เมื่อปิด
5. อ่านค่าแสงด้วย analogRead
วิดเจ็ตที่ต้องมี: ปุ่มกดชื่อ BtnLdr (เมื่อกด = เรียกฟังก์ชันของฉัน) และข้อความชื่อ LabelLdr
ฟังก์ชันที่ได้: void ui_onBtnLdrClicked(void)
int raw = analogRead(34); // LDR บนบอร์ด CYD ต่ออยู่ที่ขา 34 ได้ค่า 0-4095
int mv = analogReadMilliVolts(34); // หรืออ่านเป็นแรงดัน หน่วยมิลลิโวลต์
lv_label_set_text_fmt(ui_LabelLdr, "LDR: %d (%d mV)", raw, mv);
Serial.printf("LDR raw=%d mV=%d\n", raw, mv);
กดแต่ละครั้งอ่านค่าเซนเซอร์แสง (LDR) ที่มีอยู่บนบอร์ด CYD หนึ่งครั้ง analogRead ได้ค่า 0-4095 ถ้าต่อเซนเซอร์อื่นเอง บอร์ด CYD มีขา 35 ว่างให้อ่านค่า analog (ขา 22 และ 27 อ่านค่า analog ไม่ได้ขณะเปิด Wi-Fi)
6. อ่านปุ่มหรือสวิตช์ด้วย digitalRead
วิดเจ็ตที่ต้องมี: ปุ่มกดชื่อ BtnBoot (เมื่อกด = เรียกฟังก์ชันของฉัน) และข้อความชื่อ LabelBoot
ฟังก์ชันที่ได้: void ui_onBtnBootClicked(void)
pinMode(0, INPUT_PULLUP); // ปุ่ม BOOT บนบอร์ดต่ออยู่ที่ขา 0 bool pressed = (digitalRead(0) == LOW); // กดอยู่ = LOW เพราะปุ่มต่อลงกราวด์ lv_label_set_text(ui_LabelBoot, pressed ? "BOOT: PRESSED" : "BOOT: RELEASED");
กดปุ่ม BOOT บนบอร์ดค้างไว้แล้วแตะปุ่มบนจอ ข้อความจะเป็น PRESSED ถ้าต่อสวิตช์เอง ให้ต่อระหว่างขาที่ใช้กับ GND แล้วใช้ INPUT_PULLUP แบบเดียวกัน (ขา 35 ไม่มี pull-up ในตัว ต้องต่อตัวต้านทานเพิ่ม)
7. อ่านค่าต่อเนื่องอัตโนมัติ (analogRead + digitalRead)
วิดเจ็ตที่ต้องมี: สวิตช์ชื่อ SwitchLive (ติ๊ก "เรียกฟังก์ชันเมื่อค่าเปลี่ยน") และข้อความชื่อ LabelLive
ฟังก์ชันที่ได้: void ui_onSwitchLiveChanged(bool checked)
static lv_timer_t * timer = NULL; // static = จำตัวจับเวลาไว้ ไม่สร้างซ้ำ
if (checked && timer == NULL) {
pinMode(0, INPUT_PULLUP);
timer = lv_timer_create([](lv_timer_t * t) { // ทำงานซ้ำทุก 500 ms
int light = analogRead(34);
bool boot = (digitalRead(0) == LOW);
lv_label_set_text_fmt(ui_LabelLive, "LDR %d | BOOT %s", light, boot ? "ON" : "OFF");
}, 500, NULL);
} else if (!checked && timer != NULL) {
lv_timer_del(timer); // ปิดสวิตช์ = หยุดอ่าน
timer = NULL;
}
เปิดสวิตช์ = เริ่มอ่านทุก 500 ms ด้วยตัวจับเวลาของ LVGL ปิดสวิตช์ = หยุด ไม่ใช้ delay() จอจึงไม่ค้าง เปลี่ยน 500 เป็นช่วงเวลาที่ต้องการได้
8. อ่านอุณหภูมิและความชื้นจาก DHT22
วิดเจ็ตที่ต้องมี: ปุ่มกดชื่อ BtnDht (เมื่อกด = เรียกฟังก์ชันของฉัน) และข้อความชื่อ LabelTemp กับ LabelHumi
ฟังก์ชันที่ได้: void ui_onBtnDhtClicked(void)
static lv_timer_t * timer = NULL; // กดครั้งแรก = เริ่มอ่านทุก 3 วินาที (DHT22 อ่านถี่กว่า 2 วินาทีไม่ได้)
if (timer == NULL) {
timer = lv_timer_create([](lv_timer_t * t) {
const int PIN = 27; // ขา DATA ของ DHT22
uint8_t d[5] = {0, 0, 0, 0, 0};
bool ok = true;
// รอจนขาเปลี่ยนจากระดับ level - คืนเวลาที่รอ (ไมโครวินาที) หรือ -1 ถ้าเกิน limit
auto wait = [](int pin, int level, uint32_t limit) -> int32_t {
uint32_t start = micros();
while (digitalRead(pin) == level) {
if (micros() - start > limit) return -1;
}
return (int32_t)(micros() - start);
};
// สัญญาณเริ่ม: ดึงขาลง 1.2 ms แล้วปล่อย
pinMode(PIN, OUTPUT);
digitalWrite(PIN, LOW);
delayMicroseconds(1200);
pinMode(PIN, INPUT_PULLUP);
// อ่าน 40 บิต ห้ามมีงานอื่นแทรกระหว่างนี้ (ใช้เวลาราว 5 ms)
static portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
portENTER_CRITICAL(&mux);
if (wait(PIN, HIGH, 100) < 0 || wait(PIN, LOW, 100) < 0 || wait(PIN, HIGH, 100) < 0) ok = false;
for (int i = 0; ok && i < 40; i++) {
if (wait(PIN, LOW, 80) < 0) { ok = false; break; }
int32_t high = wait(PIN, HIGH, 100); // HIGH สั้น ~27 us = 0, ยาว ~70 us = 1
if (high < 0) { ok = false; break; }
d[i / 8] = (d[i / 8] << 1) | (high > 40 ? 1 : 0);
}
portEXIT_CRITICAL(&mux);
if (!ok || (uint8_t)(d[0] + d[1] + d[2] + d[3]) != d[4]) {
lv_label_set_text(ui_LabelTemp, "DHT22: ERROR");
return;
}
float humi = ((d[0] << 8) | d[1]) * 0.1f;
float temp = (((d[2] & 0x7F) << 8) | d[3]) * 0.1f;
if (d[2] & 0x80) temp = -temp;
char buf[32];
snprintf(buf, sizeof(buf), "TEMP: %.1f C", temp);
lv_label_set_text(ui_LabelTemp, buf);
snprintf(buf, sizeof(buf), "HUMI: %.1f %%", humi);
lv_label_set_text(ui_LabelHumi, buf);
Serial.printf("DHT22 %.1f C %.1f %%\n", temp, humi);
}, 3000, NULL);
lv_timer_ready(timer); // อ่านครั้งแรกทันที ไม่ต้องรอ 3 วินาที
}
ต่อ DHT22: VCC เข้า 3.3V, GND เข้า GND, DATA เข้าขา 27 (ช่อง CN1 ของบอร์ด CYD) ถ้าเป็นเซนเซอร์เปล่าไม่ใช่โมดูล ให้ต่อตัวต้านทาน 10k จาก DATA ไป 3.3V เพิ่ม โค้ดนี้อ่าน DHT22 เองโดยไม่ต้องลงไลบรารี กดปุ่มครั้งแรกแล้วจะอ่านค่าใหม่ทุก 3 วินาทีเอง ถ้าขึ้น ERROR ให้ตรวจสายและขา
9. รีเลย์ตั้งเวลาเปิดแล้วปิดเอง
วิดเจ็ตที่ต้องมี: ปุ่มกดชื่อ BtnRelay (เมื่อกด = เรียกฟังก์ชันของฉัน) และข้อความชื่อ LabelRelay
ฟังก์ชันที่ได้: void ui_onBtnRelayClicked(void)
static const int PIN = 22; // ขาที่ต่อรีเลย์
static const int RELAY_ON = HIGH, RELAY_OFF = LOW; // รีเลย์แบบ active LOW ให้สลับเป็น LOW / HIGH
static const uint32_t RUN_MS = 10UL * 60 * 1000; // เปิดนาน 10 นาที (แก้ตัวเลขได้)
static lv_timer_t * timer = NULL;
static uint32_t endAt = 0;
pinMode(PIN, OUTPUT);
if (timer != NULL) { // กดซ้ำระหว่างนับถอยหลัง = ยกเลิก ปิดรีเลย์ทันที
lv_timer_del(timer);
timer = NULL;
digitalWrite(PIN, RELAY_OFF);
lv_label_set_text(ui_LabelRelay, "RELAY: OFF");
return;
}
digitalWrite(PIN, RELAY_ON); // เปิดรีเลย์ แล้วนับถอยหลัง
endAt = millis() + RUN_MS;
timer = lv_timer_create([](lv_timer_t * t) { // ทำงานทุก 1 วินาที
int32_t left = (int32_t)(endAt - millis());
if (left <= 0) { // ครบเวลา = ปิดรีเลย์
digitalWrite(PIN, RELAY_OFF);
lv_label_set_text(ui_LabelRelay, "RELAY: OFF");
lv_timer_del(t);
timer = NULL;
return;
}
int sec = (left + 999) / 1000;
lv_label_set_text_fmt(ui_LabelRelay, "RELAY: ON %02d:%02d", sec / 60, sec % 60);
}, 1000, NULL);
lv_timer_ready(timer); // แสดงเวลาที่เหลือทันที
กดหนึ่งครั้ง = รีเลย์เปิดและนับถอยหลัง 10 นาที ครบเวลาแล้วปิดเอง กดอีกครั้งระหว่างนับ = ยกเลิกและปิดทันที แก้ระยะเวลาที่ RUN_MS ถ้ารีเลย์ทำงานกลับด้าน (โมดูลแบบ active LOW) ให้สลับค่า RELAY_ON กับ RELAY_OFF ขา 22 เป็นแค่ตัวอย่าง ให้ใช้ขาที่ต่อรีเลย์ไว้จริง
10. รีเลย์ตั้งเวลาตามนาฬิกา (NTP)
วิดเจ็ตที่ต้องมี: สวิตช์ชื่อ SwitchSchedule (ติ๊ก "เรียกฟังก์ชันเมื่อค่าเปลี่ยน") ข้อความชื่อ LabelClock และใส่ชื่อ Wi-Fi กับรหัสผ่านในแท็บบอร์ด
ฟังก์ชันที่ได้: void ui_onSwitchScheduleChanged(bool checked)
static const int PIN = 22; // ขาที่ต่อรีเลย์
static const int RELAY_ON = HIGH, RELAY_OFF = LOW; // รีเลย์แบบ active LOW ให้สลับเป็น LOW / HIGH
static const int ON_MIN = 18 * 60 + 0; // เปิดเวลา 18:00 (ชั่วโมง * 60 + นาที)
static const int OFF_MIN = 6 * 60 + 0; // ปิดเวลา 06:00
static lv_timer_t * timer = NULL;
pinMode(PIN, OUTPUT);
if (!checked) { // ปิดสวิตช์ = เลิกตั้งเวลา และปิดรีเลย์
if (timer != NULL) { lv_timer_del(timer); timer = NULL; }
digitalWrite(PIN, RELAY_OFF);
lv_label_set_text(ui_LabelClock, "SCHEDULE: OFF");
return;
}
if (timer != NULL) return;
timer = lv_timer_create([](lv_timer_t * t) { // ตรวจเวลาทุก 1 วินาที
struct tm now;
if (!getLocalTime(&now, 0)) { // ยังไม่ได้เวลาจากอินเทอร์เน็ต
lv_label_set_text(ui_LabelClock, "WAITING FOR NTP...");
return;
}
int m = now.tm_hour * 60 + now.tm_min;
bool on = (ON_MIN < OFF_MIN) ? (m >= ON_MIN && m < OFF_MIN) // ช่วงในวันเดียว เช่น 08:00-17:00
: (m >= ON_MIN || m < OFF_MIN); // ช่วงข้ามเที่ยงคืน เช่น 18:00-06:00
digitalWrite(PIN, on ? RELAY_ON : RELAY_OFF);
lv_label_set_text_fmt(ui_LabelClock, "%02d:%02d:%02d RELAY %s", now.tm_hour, now.tm_min, now.tm_sec, on ? "ON" : "OFF");
}, 1000, NULL);
lv_timer_ready(timer); // ตรวจครั้งแรกทันที
ใส่ชื่อ Wi-Fi ในแท็บบอร์ดแล้ว บอร์ดจะซิงค์เวลาไทยจากอินเทอร์เน็ตเองตอนเปิดเครื่อง เปิดสวิตช์ = รีเลย์เปิดปิดตามเวลา ON_MIN ถึง OFF_MIN ทุกวัน (ตัวอย่างนี้ 18:00 ถึง 06:00 ข้ามเที่ยงคืนได้) ปิดสวิตช์ = เลิกตั้งเวลาและปิดรีเลย์ ถ้าไฟดับหรือรีสตาร์ต ต้องเปิดสวิตช์ใหม่ ระหว่างยังไม่ได้เวลาจะขึ้น WAITING FOR NTP
11. ดรอปดาวน์เลือกโหมด
วิดเจ็ตที่ต้องมี: ดรอปดาวน์ชื่อ DropMode (ติ๊ก "เรียกฟังก์ชันเมื่อค่าเปลี่ยน")
ฟังก์ชันที่ได้: void ui_onDropModeChanged(uint16_t index)
switch (index) {
case 0: Serial.println("เลือกตัวเลือกที่ 1"); break;
case 1: Serial.println("เลือกตัวเลือกที่ 2"); break;
default: Serial.println("เลือกตัวเลือกอื่น"); break;
}
index คือลำดับของตัวเลือกที่เลือก เริ่มนับจาก 0 ตามบรรทัดในช่องตัวเลือก
12. ไปหน้าจออื่นจากโค้ด
วิดเจ็ตที่ต้องมี: ปุ่มกดชื่อ BtnSettings และหน้าจอชื่อ Settings
ฟังก์ชันที่ได้: void ui_onBtnSettingsClicked(void)
lv_scr_load_anim(ui_Settings, LV_SCR_LOAD_ANIM_MOVE_LEFT, 300, 0, false);
ถ้าแค่ต้องการเปลี่ยนหน้า ไม่ต้องเขียนโค้ด ให้เลือก "ไปยังหน้าจออื่น" แทน ใช้โค้ดเมื่อต้องการทำอย่างอื่นด้วย เช่น ตรวจเงื่อนไขก่อนไป
13. สลับสถานะปั๊ม (สัญลักษณ์สำเร็จรูป)
วิดเจ็ตที่ต้องมี: สัญลักษณ์ปั๊มชื่อ Pump1 และปุ่มกดชื่อ BtnPump
ฟังก์ชันที่ได้: void ui_onBtnPumpClicked(void)
ui_symbol_set_on(ui_Pump1, !ui_symbol_get_on(ui_Pump1));
สัญลักษณ์อื่นใช้แบบเดียวกัน ถังน้ำและแบตเตอรี่ใช้ ui_symbol_set_value() เพื่อเปลี่ยนระดับ
14. อ่านข้อความจากช่องพิมพ์
วิดเจ็ตที่ต้องมี: ช่องพิมพ์ข้อความชื่อ InputName (ติ๊ก "เรียกฟังก์ชันเมื่อค่าเปลี่ยน")
ฟังก์ชันที่ได้: void ui_onInputNameChanged(const char * text)
Serial.print("พิมพ์ว่า: ");
Serial.println(text);
ฟังก์ชันถูกเรียกทุกครั้งที่ข้อความเปลี่ยน text คือข้อความทั้งหมดในช่อง
8. ข้อควรระวัง
- อย่าใช้ delay() นาน ๆ ในฟังก์ชัน ฟังก์ชันถูกเรียกระหว่างที่จอกำลังทำงาน ถ้าหน่วงนาน จอจะค้างจนกว่าฟังก์ชันจะจบ งานที่ต้องรอเวลา ให้จดเวลาด้วย millis() แล้วตรวจทีหลังแทน
- ใช้ static เพื่อจำค่า ตัวแปรธรรมดาในฟังก์ชันจะหายเมื่อฟังก์ชันจบ ถ้าต้องจำค่าไว้ใช้ครั้งถัดไป เช่น สถานะเปิด/ปิด หรือจำนวนครั้ง ให้ใส่ static ข้างหน้า
- ข้อความไทยที่ตั้งจากโค้ด ต้องครอบด้วย ui_thai("...") และในหน้าออกแบบต้องมีข้อความไทยขนาดตัวอักษรนั้นอยู่แล้วอย่างน้อยหนึ่งที่ ไม่งั้นบอร์ดจะไม่มีฟอนต์ไทยขนาดนั้น ตัวอย่างในคู่มือนี้จึงใช้ข้อความอังกฤษบนจอ
- เปลี่ยนชื่อตัวแปรได้ ชื่อฟังก์ชันจะเปลี่ยนตาม และโค้ดที่เขียนไว้ยังอยู่ แต่ถ้าโค้ดอื่นอ้างถึงชื่อเดิม (เช่น ui_LabelLamp) ต้องแก้ตามเอง
- ทดสอบรันไม่ได้รันโค้ด C ของคุณ จอจำลองบอกว่าฟังก์ชันไหนถูกเรียก (ดูในหน้าต่างด้านล่าง) แต่ผลของโค้ดจริง เช่น รีเลย์ทำงาน จะเห็นเมื่อเบิร์นลงบอร์ดแล้วเท่านั้น
- คอมไพล์ไม่ผ่าน ข้อความในหน้าต่างคอมไพล์จะบอกชื่อไฟล์และบรรทัด ส่วนใหญ่เกิดจากลืมเครื่องหมาย ; พิมพ์ชื่อวิดเจ็ตผิด หรือใช้ชื่อวิดเจ็ตที่ถูกลบไปแล้ว
9. เบิร์นลงบอร์ด
- ⚡ เบิร์นลงบอร์ด ใช้กับ Chrome หรือ Edge บนคอมพิวเตอร์ เสียบบอร์ดด้วยสาย USB ที่ส่งข้อมูลได้ (สายชาร์จอย่างเดียวใช้ไม่ได้) แล้วเลือกพอร์ตของบอร์ด เซิร์ฟเวอร์จะคอมไพล์ให้ แล้วเบราว์เซอร์เบิร์นลงบอร์ดเอง
- สร้างโค้ด ESP32 ดูโค้ดทุกไฟล์และดาวน์โหลดเป็น .zip ไปเปิดด้วย PlatformIO ได้ ในไฟล์ HOWTO.md มีวิธีใช้และฟังก์ชันของวิดเจ็ตพิเศษที่โปรเจกต์นั้นใช้
- หลังเบิร์น หน้าต่าง Serial Monitor ในหน้าออกแบบแสดงข้อความจาก Serial.println() ของบอร์ด ใช้ดูว่าฟังก์ชันของคุณถูกเรียกหรือไม่