Skip to content
Open
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
.DS_Store
117 changes: 117 additions & 0 deletions Atom-matrix
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
#include <M5Atom.h>
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>
#include <esp_now.h>
#include <WiFi.h>
#include <esp_wifi.h>

// --- ตั้งค่าระยะที่ต้องการ ---
const int RSSI_THRESHOLD = -45;

// หน่วงเวลาห้ามส่งซ้ำ (2000ms = 2 วินาที)
const int COOLDOWN_TIME = 5000;

BLEUUID targetUUID = BLEUUID("1234");

// MAC Address ของ Echo
uint8_t echoAddress[] = {0x90, 0x15, 0x06, 0xFD, 0xF2, 0xF8};

// ✅
int checkIcon[] = {
15, // หางสั้น (ซ้ายล่าง)
21, // จุดกลับตัว (ล่างสุด)
17, // เส้นเฉียงขึ้น
13, // เส้นเฉียงขึ้น
9 // ปลายหางยาว (ขวาบน)
};

BLEScan* pBLEScan;
unsigned long lastTriggerTime = 0;

void setup() {
M5.begin(true, false, true);
delay(10);

WiFi.mode(WIFI_STA);
if (esp_now_init() != ESP_OK) {
Serial.println("Error initializing ESP-NOW");
return;
}

esp_now_peer_info_t peerInfo;
memset(&peerInfo, 0, sizeof(peerInfo));
for (int i = 0; i < 6; i++) {
peerInfo.peer_addr[i] = echoAddress[i];
}
peerInfo.channel = 0;
peerInfo.encrypt = false;

if (esp_now_add_peer(&peerInfo) != ESP_OK){
Serial.println("Failed to add peer");
return;
}

BLEDevice::init("");
pBLEScan = BLEDevice::getScan();
pBLEScan->setActiveScan(true);
pBLEScan->setInterval(100);
pBLEScan->setWindow(99);

Serial.println("System Ready: Scanning...");
M5.dis.fillpix(0x0000FF); // เริ่มต้น: สีน้ำเงิน
}

void loop() {
M5.update();

//แก้: ใช้ Pointer (*) เพื่อแก้ Error เก่า
BLEScanResults *foundDevices = pBLEScan->start(1, false);

bool foundTarget = false;
int targetRSSI = -999;

for (int i = 0; i < foundDevices->getCount(); i++) {
BLEAdvertisedDevice device = foundDevices->getDevice(i);

// เช็ค UUID
if (device.haveServiceUUID() && device.isAdvertisingService(targetUUID)) {
targetRSSI = device.getRSSI();
Serial.printf("Target Found! RSSI: %d\n", targetRSSI);

if (targetRSSI > RSSI_THRESHOLD) {
foundTarget = true;
}
}
}

// --- ตัดสินใจ ---
if (foundTarget) {

// ---ติ๊กถูก (Checkmark) ---
M5.dis.clear(); // ล้างสีเดิมก่อน
for (int i = 0; i < 5; i++) {
M5.dis.drawpix(checkIcon[i], 0x00FF00); // วาดจุดสีเขียวตามแบบแปลน
}
// -------------------------------------------

// เช็ค Cooldown ก่อนส่งคำสั่ง
if (millis() - lastTriggerTime > COOLDOWN_TIME) {

Serial.println(">>> UNLOCK! Sending to Echo <<<");

uint8_t data = 1;
esp_now_send(echoAddress, &data, sizeof(data));

lastTriggerTime = millis();
}

} else {
// ไม่เจอ -> สีน้ำเงิน 🔵
M5.dis.fillpix(0x0000ff);
Serial.println("Searching...");
}

pBLEScan->clearResults();
}
115 changes: 115 additions & 0 deletions Atom_echo/Atom_echo.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#include <M5Atom.h>
#include <esp_now.h>
#include <WiFi.h>
#include <driver/i2s.h>
#include <esp_wifi.h> // เพิ่มเพื่อบังคับ Channel

#define CONFIG_I2S_BCK_PIN 19
#define CONFIG_I2S_LRCK_PIN 33
#define CONFIG_I2S_DATA_PIN 22
#define CONFIG_I2S_DATA_IN_PIN 23

// ตั้งค่า I2S
void InitI2S() {
i2s_config_t i2s_config = {
.mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_TX),
.sample_rate = 44100,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT,
.communication_format = I2S_COMM_FORMAT_I2S_MSB, // ใช้ MSB เสียงจะดีกว่า
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = 8,
.dma_buf_len = 64
};
i2s_pin_config_t pin_config = {
.bck_io_num = CONFIG_I2S_BCK_PIN,
.ws_io_num = CONFIG_I2S_LRCK_PIN,
.data_out_num = CONFIG_I2S_DATA_PIN,
.data_in_num = CONFIG_I2S_DATA_IN_PIN
};
i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
i2s_set_pin(I2S_NUM_0, &pin_config);
i2s_set_clk(I2S_NUM_0, 44100, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO);
}

// สร้างเสียง Beep
void PlayBeep(int freq, int duration_ms) {
size_t bytes_written;
int samples = 44100 * duration_ms / 1000;
int16_t *buffer = (int16_t *)malloc(samples * 2);
if (!buffer) return;

int period = 44100 / freq;
int volume = 2000;

for (int i = 0; i < samples; i++) {
if ((i % period) < (period / 2)) buffer[i] = volume;
else buffer[i] = -volume;
}

i2s_write(I2S_NUM_0, buffer, samples * 2, &bytes_written, portMAX_DELAY);
free(buffer);

// ล้างท่อเสียง
int16_t silence[1024] = {0};
for (int k = 0; k < 3; k++) {
i2s_write(I2S_NUM_0, silence, sizeof(silence), &bytes_written, portMAX_DELAY);
}
}

bool triggerSound = false;

// Callback รับข้อมูล
void OnDataRecv(const uint8_t * mac, const uint8_t *incomingData, int len) {
if (len > 0 && *incomingData == 1) {
triggerSound = true;
}
}

void setup() {
M5.begin(true, false, true);
InitI2S();
Serial.begin(115200);

// 1. โชว์ MAC Address ครั้งเดียวพอ (ดูใน Serial Monitor)
WiFi.mode(WIFI_STA);
Serial.println("\n--------------------------------");
Serial.print("MY MAC ADDRESS: ");
Serial.println(WiFi.macAddress());
Serial.println("--------------------------------");

// 2. ⚠️ บังคับ Channel 1 (เพื่อให้ตรงกับ Matrix) ⚠️
esp_wifi_set_channel(1, WIFI_SECOND_CHAN_NONE);

// 3. Test Sound
Serial.println("System Start: Testing Beep...");
M5.dis.drawpix(0, 0xFFFFFF);
PlayBeep(2000, 100);
M5.dis.drawpix(0, 0x0000FF);

if (esp_now_init() != ESP_OK) return;
esp_now_register_recv_cb(OnDataRecv);
}

void loop() {
M5.update();

// ปุ่มกดเทสเสียง
if (M5.Btn.wasPressed()) {
Serial.println("Button Clicked!");
triggerSound = true;
}

// เมื่อได้รับคำสั่งจาก Matrix
if (triggerSound) {
M5.dis.drawpix(0, 0x00FF00); // สีเขียว

Serial.println("Matrix Command -> Beep!");
PlayBeep(1500, 100);
delay(50);
PlayBeep(2500, 200);

triggerSound = false;
M5.dis.drawpix(0, 0x0000FF); // กลับเป็นน้ำเงิน
}
}
114 changes: 114 additions & 0 deletions M5Paper/M5Paper.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#include <M5EPD.h>

// สร้าง Canvas 2 ใบ (ใบใหญ่=เมนู, ใบเล็ก=Status)
M5EPD_Canvas canvas(&M5.EPD);
M5EPD_Canvas status_canvas(&M5.EPD);

int selectedChoice = 0;

void drawMenu() {
canvas.createCanvas(540, 960);

// Header
canvas.setTextSize(4);
canvas.drawString("What did you do?", 30, 50);

canvas.setTextSize(3);


// ข้อ 1
canvas.drawRect(0, 130, 540, 80, 15);
canvas.drawString("1. Walk 1000 steps", 30, 155);
canvas.drawString(" --> 10 CCoin", 30, 185);

// ข้อ 2
canvas.drawRect(0, 230, 540, 80, 15);
canvas.drawString("2. Recycle bottle", 30, 255);
canvas.drawString(" --> 5 CCoin", 30, 285);

// ข้อ 3
canvas.drawRect(0, 330, 540, 80, 15);
canvas.drawString("3. Bike 1 km", 30, 355);
canvas.drawString(" --> 20 CCoin", 30, 385);

// ข้อ 4
canvas.drawRect(0, 430, 540, 80, 15);
canvas.drawString("4. Reuse cup", 30, 455);
canvas.drawString(" --> 5 CCoin", 30, 485);

canvas.fillRect(120, 550, 300, 100, 15);
canvas.setTextColor(0, 15);
canvas.setTextSize(4);
canvas.drawString("Submit", 200, 585);

canvas.setTextColor(15, 0);

canvas.pushCanvas(0, 0, UPDATE_MODE_GC16);
}

void updateStatus(String msg) {
status_canvas.createCanvas(540, 100);
status_canvas.fillCanvas(0);
status_canvas.setTextSize(3);
status_canvas.drawString("Status: " + msg, 20, 20);

status_canvas.pushCanvas(0, 700, UPDATE_MODE_DU4);

Serial.print("Status: ");
Serial.println(msg);
}

void setup() {
M5.begin();

Serial.begin(115200);

M5.EPD.SetRotation(90);
M5.EPD.Clear(true);
M5.TP.SetRotation(0); // หมุนระบบสัมผัสให้ตรงกัน

drawMenu();
}

void loop() {
if (M5.TP.available()) {
if (!M5.TP.isFingerUp()) {
M5.TP.update();

// อ่านค่า X (0-540) และ Y (0-960)
int x = M5.TP.readFingerX(0);
int y = M5.TP.readFingerY(0);

Serial.printf("X: %d, Y: %d\n", x, y);

if (x >= 130 && x <= 229) {
selectedChoice = 1;
updateStatus("Selected: Walk");
}
else if (x >= 230 && x <= 329) {
selectedChoice = 2;
updateStatus("Selected: Recycle");
}
else if (x >= 330 && x <= 410) {
selectedChoice = 3;
updateStatus("Selected: Bike");
}
else if (x >= 430 && x <= 510) {
selectedChoice = 4;
updateStatus("Selected: Reuse Cup");
}
// ปุ่ม Submit (เช็ค X ให้อยู่ในกรอบ 120-420)
else if (x >= 550 && x <= 650 && y >= 120 && y <= 420) {
if (selectedChoice == 0) {
updateStatus("Please select first!");
} else {
updateStatus("Submitting...");
delay(1000);
updateStatus("Sent Successfully!");
selectedChoice = 0;
}
}
delay(100);
}
}
}
37 changes: 37 additions & 0 deletions Station2-Core2/include/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@

This directory is intended for project header files.

A header file is a file containing C declarations and macro definitions
to be shared between several project source files. You request the use of a
header file in your project source file (C, C++, etc) located in `src` folder
by including it, with the C preprocessing directive `#include'.

```src/main.c

#include "header.h"

int main (void)
{
...
}
```

Including a header file produces the same results as copying the header file
into each source file that needs it. Such copying would be time-consuming
and error-prone. With a header file, the related declarations appear
in only one place. If they need to be changed, they can be changed in one
place, and programs that include the header file will automatically use the
new version when next recompiled. The header file eliminates the labor of
finding and changing all the copies as well as the risk that a failure to
find one copy will result in inconsistencies within a program.

In C, the convention is to give header files names that end with `.h'.

Read more about using header files in official GCC documentation:

* Include Syntax
* Include Operation
* Once-Only Headers
* Computed Includes

https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html
Loading