ESP-NOW는 ESP32에서 지원하는 ESP32간의 통신 방식이다. WiFi 방식을 기반하고, 실제로 소스에도 WiFi Station 모드를 명시하는데 정확한 내부 로직은 더 알아봐야 할 것 같다. ESP32가 직접 AP(공유기 역할)을 할 수도 있고 공유기에 연결되어 인터넷과 ESP-NOW 통신을 병행할 수 있어서, 아마 WiFi 방식을 활용한 ESP32만의 기술이 있는 것 같다.
공유기에 연결하지 않고 ESP-NOW를 사용하는 방식과 공유기 연결 + ESP-NOW 방식을 둘 다 사용해봤을 땐, ESP-NOW만 사용하는 방식이 패킷 손실이 적고, 통신 거리가 비교적 멀리까지 되어서 이 부분은 조금 더 공부해야할 듯하다..
공유기를 함께 사용할 경우 특별히 통신할 모든 ESP32 소스에 채널을 고정해야 통신이 가능하다.
#define CHANNEL 6
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
Serial.println(WiFi.localIP());
esp_wifi_set_channel(CHANNEL, WIFI_SECOND_CHAN_NONE);
initESPNow();
server.on("/", handleRoot);
server.on("/send", HTTP_POST, handleSend);
server.begin();
}
동영상 서비스가 종료되어 해당 콘텐츠를 재생할 수 없습니다.
동영상 서비스가 종료되어 해당 콘텐츠를 재생할 수 없습니다.
WEB에서 특정 ID를 입력받으면 해당 정보를 노드에 브로드캐스팅하는 방식으로 만들었는데, WEB도 몇번 입력을 넣다보면 로딩이 걸려서 해결이 필요하다.. 우선 브로드캐스팅을 할 ESP32와 점등할 ESP32를 1m정도 거리를 두고 점등 테스트를 해보았다.
구조
서버가 되는 ESP32(공유기에 연결, WEB 호스팅)
클라이언트(몇번 노드가 점멸할지 요청)
노드 ESP32
브로드캐스팅용 소스 전문(Master)
#include <WiFi.h>
#include <esp_now.h>
#include <esp_wifi.h>
#include <WebServer.h>
const char* ssid = "와이파이명";
const char* password = "비밀번호";
#define CHANNEL 6 // 모두 동일하게 설정해야 함
WebServer server(80);
#pragma pack(push, 1)
typedef struct struct_message {
int ids[30];
int count;
char label[20];
bool ledState;
} struct_message;
#pragma pack(pop)
struct_message outgoingData;
// 브로드캐스팅용 MAC 주소 셋팅
uint8_t broadcastAddress[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};
String inputIDs = "";
void sendESPNowMessage() {
inputIDs.trim();
inputIDs.replace(" ", "");
int idIndex = 0;
int lastIndex = 0;
while (true) {
int commaIndex = inputIDs.indexOf(',', lastIndex);
String token = (commaIndex == -1) ? inputIDs.substring(lastIndex) : inputIDs.substring(lastIndex, commaIndex);
outgoingData.ids[idIndex++] = token.toInt();
if (commaIndex == -1 || idIndex >= 30) break;
lastIndex = commaIndex + 1;
}
outgoingData.count = idIndex;
strcpy(outgoingData.label, "HELLO");
outgoingData.ledState = true;
// 패킷손실을 고려해서 3번 쏘게 만듬
for (int i = 0; i < 3; i++) {
esp_err_t result = esp_now_send(broadcastAddress, (uint8_t*)&outgoingData, sizeof(outgoingData));
if (result == ESP_OK) {
Serial.printf("전송 성공\n", i + 1);
} else {
Serial.printf("전송 실패\n", i + 1);
}
delay(50);
}
inputIDs = "";
}
void handleRoot() {
String html = "<!DOCTYPE html><html><head><meta charset='utf-8'><title>ESP-NOW Sender</title></head><body>";
html += "<form action='/send' method='POST'>";
html += "<input name='ids' placeholder='예: 1,2,3,4' style='width: 300px; height: 40px; font-size: 18px;'><br><br>";
html += "<input type='submit' value='전송' style='width: 150px; height: 40px; font-size: 18px;'>";
html += "</form></body></html>";
server.send(200, "text/html", html);
}
void handleSend() {
if (server.hasArg("ids")) {
inputIDs = server.arg("ids");
Serial.print("ID List : ");
Serial.println(inputIDs);
sendESPNowMessage();
}
server.sendHeader("Location", "/");
server.send(303);
}
void initESPNow() {
if (esp_now_init() != ESP_OK) {
Serial.println("초기화 실패");
ESP.restart();
}
esp_now_peer_info_t peerInfo = {};
memcpy(peerInfo.peer_addr, broadcastAddress, 6);
peerInfo.channel = CHANNEL;
peerInfo.encrypt = false;
if (!esp_now_is_peer_exist(broadcastAddress)) {
if (esp_now_add_peer(&peerInfo) != ESP_OK) {
Serial.println("브로드캐스트 피어 등록 fail");
return;
}
}
}
#define CHANNEL 6
void setup() {
Serial.begin(115200);
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
Serial.println(WiFi.localIP());
esp_wifi_set_channel(CHANNEL, WIFI_SECOND_CHAN_NONE);
initESPNow();
server.on("/", handleRoot);
server.on("/send", HTTP_POST, handleSend);
server.begin();
}
void loop() {
server.handleClient();
}
'Logistics IoT > DAS-PJT' 카테고리의 다른 글
| [DAS-PJT-004] ESP-NOW 활용 SubMaster-Slave 노드 구조 정리 (1) | 2025.06.08 |
|---|---|
| [DAS-PJT-003]ESP32 핀맵과 용도 (0) | 2025.06.06 |
| [DAS-PJT-002]ESP32 개발 환경 셋팅 (0) | 2025.06.02 |
| [DAS-PJT-001] 노드를 활용한 물류 분류 시스템 만들기 (0) | 2025.05.18 |