Week 11 — Networking & Communications

Group assignment

Individual assignment

Learning outcomes


Checklist


Documentation

For this week's assignment, we need to establish communication between two devices without using an external router, which means direct communication.

So far, I have two design boards based on the ESP32 C3, and one Arduino Uno. I will try to connect these boards using several protocols:

1. UART

2. I2C

3. Bluetooth LE

4. WIFI

5. ESP-Now

First four protocols I will try just basic packages and ESP-Now. I want to explore it a little bit deeper.

Week 11 documentation image image001.webp
Week 11 documentation image image002.webp

1) UART

Use this as a one-way test: ESP32-C3 sends text, Uno receives and prints it.

For more details about the XIAO ESP32C3 board interfaces, including UART and I2C, I referred to the official Seeed Studio wiki: XIAO ESP32C3 Getting Started.

Wiring

Week 11 documentation image image003.webp

Before moving to more advanced communication tests, I first wanted to make a very simple check that UART and I2C communication between two boards was working correctly. For this step, I asked AI to generate basic test code for a XIAO ESP32-C3 and an Arduino Uno.

AI request:
write a code for testing two boards, ESP32, XIAO C3, and Arduino Uno, which can get connected by UART and I2C.

Sender: XIAO ESP32-C3

#include <Arduino.h>

#include <HardwareSerial.h>

HardwareSerial MySerial(1);

void setup() {
Serial.begin(115200);                   // USB Serial Monitor
MySerial.begin(9600, SERIAL_8N1, D7, D6); // RX, TX on XIAO C3
Serial.println("ESP32-C3 UART sender started");
}

void loop() {
static int counter = 0;
String msg = "UART hello " + String(counter++);
MySerial.println(msg);
Serial.println("Sent: " + msg);
delay(1000);
}

Receiver: Arduino Uno

#include <SoftwareSerial.h>

SoftwareSerial espSerial(10, 11); // RX, TX

void setup() {
Serial.begin(115200);   // Serial Monitor
espSerial.begin(9600);  // UART from ESP32-C3
Serial.println("UNO UART receiver started");
}

void loop() {
if (espSerial.available()) {
String msg = espSerial.readStringUntil('\n');
Serial.print("Received: ");
Serial.println(msg);
}
}

As a result, we can see the exchange of messages in the serial monitor from sender to receiver using the UART protocol.

Week 11 documentation image image004.webp

2) I2C

Use this as a one-way test: ESP32-C3 is controller/master, Uno is target/slave.

For more details about the XIAO ESP32C3 board interfaces, including UART and I2C, I referred to the official Seeed Studio wiki: XIAO ESP32C3 Getting Started.

Wiring

Week 11 documentation image image005.webp

Sender: XIAO ESP32-C3

#include <Arduino.h>

#include <Wire.h>

#define SDA_PIN D4

#define SCL_PIN D5

#define UNO_ADDR 0x08

void setup() {
Serial.begin(115200);
Wire.begin(SDA_PIN, SCL_PIN);
Serial.println("ESP32-C3 I2C sender started");
}

void loop() {
static uint8_t counter = 0;
Wire.beginTransmission(UNO_ADDR);
Wire.write(counter);
byte err = Wire.endTransmission();
Serial.print("Sent byte: ");
Serial.print(counter);
Serial.print("  I2C status: ");
Serial.println(err);
counter++;
delay(1000);
}

Receiver: Arduino Uno

#include <Wire.h>

volatile int lastByte = -1;

volatile bool newData = false;

void receiveEvent(int howMany) {
while (Wire.available()) {
lastByte = Wire.read();
newData = true;
}
}

void setup() {
Serial.begin(115200);
Wire.begin(0x08);   // I2C slave address
Wire.onReceive(receiveEvent);
Serial.println("UNO I2C receiver started");
}

void loop() {
if (newData) {
noInterrupts();
int value = lastByte;
newData = false;
interrupts();
Serial.print("Received byte: ");
Serial.println(value);
}
}

The same result here is a successful exchange of packages from sender to receiver using the I2C protocol.

Week 11 documentation image image006.webp

3) Bluetooth Low Energy

Simplest BLE arrangement:

For more details about Bluetooth usage on the XIAO ESP32C3, I referred to the official Seeed Studio wiki: XIAO ESP32C3 Bluetooth Usage.

What to do:

After exploring documentation for Bluetooth Low Energy and Wi-Fi UDP packet transfer, I decided to compose the prompt for AI on how to build similar code.

Ai request:

Based on these documentation pages for XIAO ESP32C3 for Bluetooth Low Energy and Wi-Fi:

https://wiki.seeedstudio.com/XIAO_ESP32C3_Bluetooth_Usage/

https://wiki.seeedstudio.com/XIAO_ESP32C3_WiFi_Usage/

Compose a simple code for me: how can I change packages, and how can I test this protocol between two ESP32C3 devices

Sender: ESP32-C3 BLE server

#include <Arduino.h>

#include <BLEDevice.h>

#include <BLEServer.h>

#include <BLEUtils.h>

#include <BLE2902.h>

#define SERVICE_UUID        "12345678-1234-1234-1234-1234567890ab"

#define CHARACTERISTIC_UUID "abcdefab-1234-1234-1234-abcdefabcdef"

BLECharacteristic *pCharacteristic;

bool deviceConnected = false;

class MyServerCallbacks : public BLEServerCallbacks {
void onConnect(BLEServer* pServer) override {
deviceConnected = true;
}
void onDisconnect(BLEServer* pServer) override {
deviceConnected = false;
BLEDevice::startAdvertising();
}
};

void setup() {
Serial.begin(115200);
Serial.println("Starting BLE server...");
BLEDevice::init("Yaro-C3-BLE-Server");
BLEServer *pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
BLEService *pService = pServer->createService(SERVICE_UUID);
pCharacteristic = pService->createCharacteristic(
CHARACTERISTIC_UUID,
BLECharacteristic::PROPERTY_READ | BLECharacteristic::PROPERTY_NOTIFY
);
pCharacteristic->addDescriptor(new BLE2902());
pCharacteristic->setValue("BLE hello 0");
pService->start();
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
pAdvertising->start();
Serial.println("BLE server ready, advertising...");
}

void loop() {
static int counter = 0;
String msg = "BLE hello " + String(counter++);
pCharacteristic->setValue(msg.c_str());
if (deviceConnected) {
pCharacteristic->notify();
Serial.println("Notified: " + msg);
} else {
Serial.println("Waiting for BLE client...");
}
delay(1000);
}

Receiver: ESP32-C3 BLE client

#include <Arduino.h>

#include <BLEDevice.h>

#include <BLEUtils.h>

#include <BLEClient.h>

#include <BLERemoteCharacteristic.h>

#include <BLEAdvertisedDevice.h>

#define SERVICE_UUID        "12345678-1234-1234-1234-1234567890ab"

#define CHARACTERISTIC_UUID "abcdefab-1234-1234-1234-abcdefabcdef"

static BLEAddress *serverAddress = nullptr;

static BLERemoteCharacteristic *remoteCharacteristic = nullptr;

static bool doConnect = false;

static bool connected = false;

static BLEAdvertisedDevice *myDevice = nullptr;

class MyAdvertisedDeviceCallbacks: public BLEAdvertisedDeviceCallbacks {
void onResult(BLEAdvertisedDevice advertisedDevice) override {
if (advertisedDevice.haveServiceUUID() && advertisedDevice.isAdvertisingService(BLEUUID(SERVICE_UUID))) {
Serial.print("Found BLE server: ");
Serial.println(advertisedDevice.getName().c_str());
myDevice = new BLEAdvertisedDevice(advertisedDevice);
doConnect = true;
BLEDevice::getScan()->stop();
}
}
};

void notifyCallback(

BLERemoteCharacteristic* pBLERemoteCharacteristic,

uint8_t* pData,

size_t length,

bool isNotify) {
Serial.print("BLE notify: ");
for (size_t i = 0; i < length; i++) {
Serial.print((char)pData[i]);
}
Serial.println();
}

bool connectToServer() {
BLEClient *pClient = BLEDevice::createClient();
if (!pClient->connect(myDevice)) return false;
BLERemoteService *pRemoteService = pClient->getService(SERVICE_UUID);
if (pRemoteService == nullptr) return false;
remoteCharacteristic = pRemoteService->getCharacteristic(CHARACTERISTIC_UUID);
if (remoteCharacteristic == nullptr) return false;
if (remoteCharacteristic->canNotify()) {
remoteCharacteristic->registerForNotify(notifyCallback);
}
connected = true;
return true;
}

void setup() {
Serial.begin(115200);
Serial.println("Starting BLE client...");
BLEDevice::init("");
BLEScan *pScan = BLEDevice::getScan();
pScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
pScan->setActiveScan(true);
pScan->start(5, false);
}

void loop() {
if (doConnect && !connected) {
if (connectToServer()) {
Serial.println("Connected to BLE server");
} else {
Serial.println("BLE connect failed");
}
doConnect = false;
}
if (!connected) {
BLEDevice::getScan()->start(5, false);
}
delay(1000);
}
Week 11 documentation image image007.webp

At this stage, I encounter a problem when two devices on the opposite side of the laptop can't clearly connect. Probably because of interference from the electromagnetic wave from the laptop, but when I put devices together and physically create an obstacle between the laptop and the devices with my hand, it started working.

Week 11 documentation image image008.webp
Week 11 documentation image image009.webp

4) Wi-Fi UDP

Simplest Wi-Fi method: UDP. The easiest setup is:

For more details about Wi-Fi usage on the XIAO ESP32C3, I referred to the official Seeed Studio wiki: XIAO ESP32C3 Wi-Fi Usage.

What to do

Receiver: ESP32-C3 SoftAP + UDP listener

#include <Arduino.h>

#include "Network.h"

#include "WiFi.h"

NetworkUDP udp;

const char* ssid = "YaroUDP";

const char* password = "12345678";

IPAddress local_IP(192, 168, 4, 1);

IPAddress gateway(192, 168, 4, 1);

IPAddress subnet(255, 255, 255, 0);

const uint16_t udpPort = 1234;

void setup() {
Serial.begin(115200);
delay(1000);
Network.begin();
WiFi.mode(WIFI_AP);
WiFi.softAPConfig(local_IP, gateway, subnet);
WiFi.softAP(ssid, password);
udp.begin(udpPort);
Serial.println("UDP receiver started");
Serial.print("AP IP: ");
Serial.println(WiFi.softAPIP());
}

void loop() {
int packetSize = udp.parsePacket();
if (packetSize) {
char incoming[255];
int len = udp.read(incoming, sizeof(incoming) - 1);
if (len > 0) incoming[len] = '\0';
Serial.print("Received UDP: ");
Serial.println(incoming);
}
}

At this stage I can see that a UDP server is started and in my Wi-Fi network list I saw the new Wi-Fi access point - YaroUDP

Week 11 documentation image image010.webp
Week 11 documentation image image012.webp

Sender: ESP32-C3 station + UDP sender

#include <Arduino.h>

#include "Network.h"

#include "WiFi.h"

NetworkUDP udp;

const char* ssid = "YaroUDP";

const char* password = "12345678";

IPAddress receiverIP(192, 168, 4, 1);

const uint16_t udpPort = 1234;

void setup() {
Serial.begin(115200);
delay(1000);
Network.begin();
WiFi.mode(WIFI_STA);
WiFi.begin(ssid, password);
Serial.print("Connecting to AP");
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println();
Serial.println("Connected to AP");
Serial.print("My IP: ");
Serial.println(WiFi.localIP());
}

void loop() {
static int counter = 0;
String msg = "UDP hello " + String(counter++);
udp.beginPacket(receiverIP, udpPort);
udp.print(msg);
udp.endPacket();
Serial.println("Sent UDP: " + msg);
delay(1000);
}
Week 11 documentation image image013.webp

5) ESP-NOW

I found several sources of ESP-NOW protocol examples of how to do it from Espressif system, also on GitHub, and on the Seed Studio wiki page.

https://docs.espressif.com/projects/arduino-esp32/en/latest/api/espnow.html

https://github.com/espressif/arduino-esp32/blob/master/libraries/ESP_NOW/examples/ESP_NOW_Serial/ESP_NOW_Serial.ino

https://wiki.seeedstudio.com/xiao_esp32s3_espnow

ESP-NOW is a wireless communication protocol defined by espressif that enables direct, fast, and low-power control of smart devices without the need for a router.It can coexist with Wi Fi and Bluetooth LE, supporting multiple series of SoCs such as Lexin ESP8266, ESP32, ESP32-S, and ESP32-C. ESP-NOW is widely used in fields such as smart home appliances, remote control, and sensors.

Following characteristics

According to the MAC address connection method, pairing can be done quickly without network conditions, and devices can be connected in single to many, single to single, many to single, and many to many ways

ESP-NOW is a wireless communication protocol based on the data link layer, which simplifies the five layer OSI upper layer protocol into one layer without the need to add packet headers and unpacks layer by layer. It greatly alleviates the lag and delay caused by packet loss during network congestion and has a higher response speed

Compared to Wi-Fi and Bluetooth

Wi-Fi: ESP-NOW supports point-to-point communication between devices, so it has lower power consumption and higher transmission speed, and also has a longer communication distance.

Bluetooth: ESP-NOW does not require a pairing process, making it simpler and easier to use ESP-NOW, so it has lower power consumption and higher transmission speed.

But ESP-NOW is suitable for application scenarios that require fast, reliable, low-power, and point-to-point communication, while Bluetooth and Wi Fi are more suitable for complex network environments and scenarios with a large number of devices.

What I need

At this moment, I need to identify the MAC addresses of each board and use these MAC addresses in the code. I asked AI about how to extract the MAC address:\

How to extract MAC address from each Xiao ESP32 C3 board?

Result:

#include <WiFi.h>

void setup() {
Serial.begin(115200);
delay(1000);
WiFi.mode(WIFI_STA);   // set station mode
delay(100);
Serial.print("MAC Address: ");
Serial.println(WiFi.macAddress());
}

void loop() {
}

My address is successfully extracted from the Serial Monitor:

YaroBoard 1 MAC Address (Sender): E8:F6:0A:14:67:B4
And YaroBoard 2 MAC Address (Receiver): 1C:DB:D4:EB:CB:68
Week 11 documentation image image014.webp
Week 11 documentation image image015.webp

I found official documentation that the sender device is XIAO USB S3 but I need to change it for XIAO USB C3 so I ask AI to modify the existing code to use my C3 board instead of S3.

This is a code for ESP32-C6, but I have ESP32-C3. I need to change it for my sender device as ESP32-C3. Modify it.

Result for YaroBoard 1 (SENDER):

#include <Arduino.h>

#include "WiFi.h"

#include "esp_now.h"

#define ESPNOW_WIFI_CHANNEL 0

#define MAX_ESP_NOW_MAC_LEN 6

#define BAUD 115200

#define MAX_CHARACTERS_NUMBER 20

#define NO_PMK_KEY false

typedef uint8_t XIAO;

typedef int XIAO_status;

// MAC address of the RECEIVER ESP32-C3 (YaroBoard 2)

static uint8_t Receiver_XIAOC3_MAC_Address[MAX_ESP_NOW_MAC_LEN] = {0x1C, 0xDB, 0xD4, 0xEB, 0xCB, 0x68};

esp_now_peer_info_t peerInfo;

typedef struct message_types {
char device[MAX_CHARACTERS_NUMBER];
char Trag[MAX_CHARACTERS_NUMBER];
} message_types;

message_types Personal_XIAOC3_Information;

void espnow_init();

void espnow_deinit();

void SenderXIAOC3_MACAddress_Requir();

void SenderXIAOC3_Send_Data();

void SenderXIAOC3_Send_Data_cb(const wifi_tx_info_t *tx_info, esp_now_send_status_t status);

void Association_ReceiverXIAOC3_peer();

void setup() {
Serial.begin(BAUD);
delay(1000);
SenderXIAOC3_MACAddress_Requir();
espnow_init();
esp_now_register_send_cb(SenderXIAOC3_Send_Data_cb);
Association_ReceiverXIAOC3_peer();
}

void loop() {
SenderXIAOC3_Send_Data();
delay(4000);
}

void SenderXIAOC3_Send_Data_cb(const wifi_tx_info_t *tx_info, esp_now_send_status_t status) {
char macStr[18];
Serial.print("Packet to: ");
snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
tx_info->des_addr[0], tx_info->des_addr[1], tx_info->des_addr[2],
tx_info->des_addr[3], tx_info->des_addr[4], tx_info->des_addr[5]);
Serial.println(macStr);
Serial.print("Send status: ");
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
Serial.println();
}

void Association_ReceiverXIAOC3_peer() {
Serial.println("Attempting to associate peer for XIAOC3...");
memset(&peerInfo, 0, sizeof(peerInfo));
peerInfo.channel = ESPNOW_WIFI_CHANNEL;
peerInfo.encrypt = NO_PMK_KEY;
memcpy(peerInfo.peer_addr, Receiver_XIAOC3_MAC_Address, 6);
esp_err_t addPressStatus = esp_now_add_peer(&peerInfo);
if (addPressStatus != ESP_OK) {
Serial.print("Failed to add peer: ");
Serial.println(addPressStatus);
} else {
Serial.println("Successful to add peer");
}
}

void SenderXIAOC3_Send_Data() {
strcpy(Personal_XIAOC3_Information.device, "XIAOC3");
strcpy(Personal_XIAOC3_Information.Trag, "Hello, I'm sender");
esp_err_t sendStatus = esp_now_send(
Receiver_XIAOC3_MAC_Address,
(uint8_t *)&Personal_XIAOC3_Information,
sizeof(Personal_XIAOC3_Information)
);
if (sendStatus == ESP_OK) {
Serial.println("Sent with success");
} else {
Serial.print("Error sending message: ");
Serial.println(sendStatus);
}
}

void SenderXIAOC3_MACAddress_Requir() {
WiFi.mode(WIFI_STA);
delay(100);
uint8_t mac[MAX_ESP_NOW_MAC_LEN];
WiFi.macAddress(mac);
Serial.println();
Serial.printf("const uint8_t mac_self[6] = {0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x};\n",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}

void espnow_init() {
XIAO_status espnow_sign = esp_now_init();
if (espnow_sign == ESP_OK) {
Serial.println("The ESP-NOW is successfully initialized!");
} else {
Serial.println("The ESP-NOW initialization failed");
}
}

void espnow_deinit() {
XIAO_status espnow_sign = esp_now_deinit();
if (espnow_sign == ESP_OK) {
Serial.println("The ESP-NOW is successfully deinitialized!");
} else {
Serial.println("The ESP-NOW deinitialization failed!");
}
}

Libraries used

#include "WiFi.h"

#include "esp_now.h"

The sender code uses the WiFi.h and esp_now.h libraries. WiFi.h is used to configure the ESP32-C3 board in station mode and read its MAC address.

esp_now.h is used to initialize ESP-NOW communication, add a peer device, send data, and register the callback function for delivery status.

Main idea

This project uses two XIAO ESP32-C3 boards:

The sender transmits a short message to the receiver using ESP-NOW and the receiver prints the received data in the Serial Monitor.

The Core Functions

espnow_init()

Role: Initialize the ESP-NOW function.

Return value:

espnow_deinit()

Role: De-initialize the ESP-NOW function. All information related to paired devices will be deleted.

Return value:

SenderXIAOC3_MACAddress_Requir()

Role: Set the Wi-Fi mode to STA (Station Mode) and obtain the MAC address of the sender board, then print it to the Serial Monitor.

SenderXIAOC3_Send_Data()

Role: Prepare and send a specific message from the sender XIAO ESP32-C3 to the receiver XIAO ESP32-C3.

SenderXIAOC3_Send_Data_cb()

Role: This is a callback function. When it is executed, it prints whether the message was successfully delivered and to which MAC address it was sent.

Association_ReceiverXIAOC3_peer()

Role: is the send callback. It reports whether the message delivery was successful and shows the destination MAC address.

If more receivers are needed, more peer nodes can be created and added in the code.

esp_now_register_send_cb()

Role: Register a callback function to verify whether the message has been sent to the MAC layer.

Return value:

------------------------------------------------------------------------

Default Variables

#define ESPNOW_WIFI_CHANNEL

Role: Defines the Wi-Fi channel where both sender and receiver are located.

#define MAX_ESP_NOW_MAC_LEN

Role: Defines the MAC address length.

#define MAX_CHARACTERS_NUMBER

Role: Defines the maximum number of accepted or transmitted characters.

#define BAUD 115200

Role: Sets the Serial Monitor baud rate.

static uint8_t Receiver_XIAOC3_MAC_Address[MAX_ESP_NOW_MAC_LEN]

Role: Stores the MAC address of the receiver XIAO ESP32-C3. It serves as the recipient address.

Supplement: Please note that this must be replaced with your own receiver board MAC address and cannot be copied directly from another project.

NO_PMK_KEY

Role: Chooses to pair devices without encryption.

Upload was successful but delivery failed because I didn't upload any code to my receiver board, and it is not connected as well.

Week 11 documentation image image016.webp

Also, you can see that my first board connected as usbmodem1101.

When I connected the second board and the second Arduino IDE window, I saw that it's connected with a different address (usbmodem2101). I mean two boards connected, and I can program the second board on the second window without messing with the first one.

Week 11 documentation image image018.webp

Also after connecting the receiver board, the serial monitor from the first board indicates the delivery is successful.

Week 11 documentation image image019.webp

Code for Receiver Board (YaroBoard 2 Receiver)

#include <Arduino.h>

#include "WiFi.h"

#include "esp_now.h"

#define ESPNOW_WIFI_CHANNEL 0

#define MAX_ESP_NOW_MAC_LEN 6

#define BAUD 115200

#define MAX_CHARACTERS_NUMBER 20

#define NO_PMK_KEY false

typedef uint8_t XIAO;

typedef int status;

// Put here the MAC address of the SENDER ESP32-C3

static uint8_t XIAOC3_Sender_MAC_Address[MAX_ESP_NOW_MAC_LEN] = {0xE8, 0xF6, 0x0A, 0x14, 0x67, 0xB4};

esp_now_peer_info_t peerInfo_sender;

typedef struct receiver_meesage_types {
char Reveiver_device[MAX_CHARACTERS_NUMBER];
char Reveiver_Trag[MAX_CHARACTERS_NUMBER];
} receiver_meesage_types;

receiver_meesage_types XIAOC3_RECEIVER_INFORATION;

typedef struct message_types {
char Sender_device[MAX_CHARACTERS_NUMBER];
char Sender_Trag[MAX_CHARACTERS_NUMBER];
} message_types;

message_types XIAOC3_SENDER_INFORATION;

void Receiver_MACAddress_requir();

void espnow_init();

void espnow_deinit();

void ReceiverXIAOC3_Recive_Data_cb(const esp_now_recv_info_t *info, const uint8_t *incomingData, int len);

void ReceiverXIAOC3_Send_Data();

void ReceiverXIAOC3_Send_Data_cb(const wifi_tx_info_t *tx_info, esp_now_send_status_t status);

void Association_SenderXIAOC3_peer();

void setup() {
Serial.begin(BAUD);
delay(1000);
Receiver_MACAddress_requir();
espnow_init();
esp_now_register_recv_cb(ReceiverXIAOC3_Recive_Data_cb);
esp_now_register_send_cb(ReceiverXIAOC3_Send_Data_cb);
Association_SenderXIAOC3_peer();
}

void loop() {
ReceiverXIAOC3_Send_Data();
delay(4000);
}

void espnow_init() {
status espnow_sign = esp_now_init();
if (espnow_sign == ESP_OK) {
Serial.println("The ESP-NOW is successfully initialized!");
} else {
Serial.println("The ESP-NOW initialization failed");
}
}

void espnow_deinit() {
status espnow_sign = esp_now_deinit();
if (espnow_sign == ESP_OK) {
Serial.println("The ESP-NOW is successfully deinitialized!");
} else {
Serial.println("The ESP-NOW deinitialization failed!");
}
}

void Receiver_MACAddress_requir() {
WiFi.mode(WIFI_STA);
delay(100);
uint8_t mac[MAX_ESP_NOW_MAC_LEN];
WiFi.macAddress(mac);
Serial.println();
Serial.printf("const uint8_t mac_self[6] = {0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x};\n",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}

void ReceiverXIAOC3_Recive_Data_cb(const esp_now_recv_info_t *info, const uint8_t *incomingData, int len) {
memcpy(&XIAOC3_SENDER_INFORATION, incomingData, sizeof(XIAOC3_SENDER_INFORATION));
Serial.print("Bytes received: ");
Serial.println(len);
Serial.print("Sender_device: ");
Serial.println(XIAOC3_SENDER_INFORATION.Sender_device);
Serial.print("Sender_Trag: ");
Serial.println(XIAOC3_SENDER_INFORATION.Sender_Trag);
Serial.println();
}

void ReceiverXIAOC3_Send_Data_cb(const wifi_tx_info_t *tx_info, esp_now_send_status_t status) {
char macStr[18];
Serial.print("Packet to: ");
snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
tx_info->des_addr[0], tx_info->des_addr[1], tx_info->des_addr[2],
tx_info->des_addr[3], tx_info->des_addr[4], tx_info->des_addr[5]);
Serial.println(macStr);
Serial.print("Send status: ");
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
Serial.println();
}

void ReceiverXIAOC3_Send_Data() {
strcpy(XIAOC3_RECEIVER_INFORATION.Reveiver_device, "XIAOC3");
strcpy(XIAOC3_RECEIVER_INFORATION.Reveiver_Trag, "I got it");
esp_err_t sendStatus = esp_now_send(
XIAOC3_Sender_MAC_Address,
(uint8_t *)&XIAOC3_RECEIVER_INFORATION,
sizeof(receiver_meesage_types)
);
if (sendStatus == ESP_OK) {
Serial.println("Sent with success: XIAOC3_RECEIVER_INFORATION_data1");
} else {
Serial.print("Error sending message: ");
Serial.println(sendStatus);
}
}

void Association_SenderXIAOC3_peer() {
Serial.println("Attempting to associate peer for XIAOC3...");
memset(&peerInfo_sender, 0, sizeof(peerInfo_sender));
peerInfo_sender.channel = ESPNOW_WIFI_CHANNEL;
peerInfo_sender.encrypt = NO_PMK_KEY;
memcpy(peerInfo_sender.peer_addr, XIAOC3_Sender_MAC_Address, 6);
esp_err_t addPressStatus = esp_now_add_peer(&peerInfo_sender);
if (addPressStatus != ESP_OK) {
Serial.print("Failed to add peer: ");
Serial.println(addPressStatus);
} else {
Serial.println("Successful to add peer");
}
}

**The Core Functions**

**espnow_init()**

**Role:** Initialize the ESP-NOW function.

**Return value:**

espnow_deinit()

Role: De-initialize the ESP-NOW function. All information related to paired devices will be deleted.

Return value:

Receiver_MACAddress_requir()

Role: Set the Wi-Fi mode to STA (Station Mode) and obtain the MAC address of the receiver board, then print it to the Serial Monitor.

ReceiverXIAOC3_Recive_Data_cb()

Role: This is the receive callback function. When data arrives from the sender, it copies the incoming data into a message structure and prints the received content in the Serial Monitor.

ReceiverXIAOC3_Send_Data()

Role: Prepare and send a reply message from the receiver XIAO ESP32-C3 back to the sender XIAO ESP32-C3.

This function is only needed if two-way communication is used.

ReceiverXIAOC3_Send_Data_cb()

Role: This is a callback function. When it is executed, it prints whether the reply message was successfully delivered and to which MAC address it was sent.

Association_SenderXIAOC3_peer()

Role: Add the sender node as a peer device.

This is needed if the receiver also sends data back to the sender.

esp_now_register_recv_cb()

Role: Register a callback function to process incoming data when a message is received.

esp_now_register_send_cb()

Role: Register a callback function to verify whether the reply message has been sent to the MAC layer.

Return value:

Default Variables

#define ESPNOW_WIFI_CHANNEL

Role: Defines the Wi-Fi channel where both sender and receiver are located.

#define MAX_ESP_NOW_MAC_LEN

Role: Defines the MAC address length.

#define MAX_CHARACTERS_NUMBER

Role: Defines the maximum number of accepted or transmitted characters.

#define BAUD 115200

Role: Sets the Serial Monitor baud rate.

static uint8_t XIAOC3_Sender_MAC_Address[MAX_ESP_NOW_MAC_LEN]

Role: Stores the MAC address of the sender XIAO ESP32-C3. It serves as the destination address when the receiver sends a reply.

Supplement: This must be replaced with your own sender board MAC address and cannot be copied directly from another project.

NO_PMK_KEY

Role: Chooses to pair devices without encryption.

As a result, in the Serial Monitor I can see that the receiver initiated and it's able to receive packages from the sender.

Week 11 documentation image image020.webp

Button LED Control

Next step, I want to send a signal from the receiver when the button is clicked, and this signal can control the LED on the receiver board.

Changes in the code will be follow:

On the sender

Add a button pin, read its state, and send "ON" or "OFF".

1. Add a button pin near the top

#define BUTTON_PIN D7

2. In setup(), set the button as input

pinMode(BUTTON_PIN, INPUT_PULLUP);

3. Replace current SenderXIAOC3_Send_Data() with this

void SenderXIAOC3_Send_Data() {
strcpy(Personal_XIAOC3_Information.device, "XIAOC3_YaroBoard1");
if (digitalRead(BUTTON_PIN) == LOW) {
strcpy(Personal_XIAOC3_Information.Trag, "ON");
} else {
strcpy(Personal_XIAOC3_Information.Trag, "OFF");
}
esp_err_t sendStatus = esp_now_send(
Receiver_XIAOC3_MAC_Address,
(uint8_t *)&Personal_XIAOC3_Information,
sizeof(Personal_XIAOC3_Information)
);
if (sendStatus == ESP_OK) {
Serial.print("Sent: ");
Serial.println(Personal_XIAOC3_Information.Trag);
} else {
Serial.print("Error sending message: ");
Serial.println(sendStatus);
}
}

4. Make the loop faster

Replace:

delay(4000);

with:

delay(100);

On the receiver

Stop sending reply messages and control an LED instead.

1. Add an LED pin near the top

#define LED_PIN D6

2. In setup(), set the LED as output

pinMode(LED_PIN, OUTPUT);

digitalWrite(LED_PIN, LOW);

3. In the receiver, remove these parts completely

4. Replace the receiver callback with this

void ReceiverXIAOC3_Recive_Data_cb(const esp_now_recv_info_t *info, const uint8_t *incomingData, int len) {
memcpy(&XIAOC3_SENDER_INFORATION, incomingData, sizeof(XIAOC3_SENDER_INFORATION));
Serial.print("Sender_device: ");
Serial.println(XIAOC3_SENDER_INFORATION.Sender_device);
Serial.print("Sender_Trag: ");
Serial.println(XIAOC3_SENDER_INFORATION.Sender_Trag);
if (strcmp(XIAOC3_SENDER_INFORATION.Sender_Trag, "ON") == 0) {
digitalWrite(LED_PIN, HIGH);
} else if (strcmp(XIAOC3_SENDER_INFORATION.Sender_Trag, "OFF") == 0) {
digitalWrite(LED_PIN, LOW);
}
Serial.println();
}

5. Empty the receiver loop

void loop() {
}

Then the full code for SENDER:\

#include <Arduino.h>

#include "WiFi.h"

#include "esp_now.h"

#define ESPNOW_WIFI_CHANNEL 0

#define MAX_ESP_NOW_MAC_LEN 6

#define BAUD 115200

#define MAX_CHARACTERS_NUMBER 20

#define NO_PMK_KEY false

#define BUTTON_PIN D7

typedef uint8_t XIAO;

typedef int XIAO_status;

// Receiver ESP32-C3 MAC address

static uint8_t Receiver_XIAOC3_MAC_Address[MAX_ESP_NOW_MAC_LEN] = {0x1C, 0xDB, 0xD4, 0xEB, 0xCB, 0x68};

esp_now_peer_info_t peerInfo;

typedef struct message_types {
char device[MAX_CHARACTERS_NUMBER];
char Trag[MAX_CHARACTERS_NUMBER];
} message_types;

message_types Personal_XIAOC3_Information;

void espnow_init();

void SenderXIAOC3_MACAddress_Requir();

void SenderXIAOC3_Send_Data();

void SenderXIAOC3_Send_Data_cb(const wifi_tx_info_t *tx_info, esp_now_send_status_t status);

void Association_ReceiverXIAOC3_peer();

void setup() {
Serial.begin(BAUD);
delay(1000);
pinMode(BUTTON_PIN, INPUT_PULLUP);
SenderXIAOC3_MACAddress_Requir();
espnow_init();
esp_now_register_send_cb(SenderXIAOC3_Send_Data_cb);
Association_ReceiverXIAOC3_peer();
}

void loop() {
SenderXIAOC3_Send_Data();
delay(100);
}

void SenderXIAOC3_Send_Data_cb(const wifi_tx_info_t *tx_info, esp_now_send_status_t status) {
char macStr[18];
Serial.print("Packet to: ");
snprintf(macStr, sizeof(macStr), "%02x:%02x:%02x:%02x:%02x:%02x",
tx_info->des_addr[0], tx_info->des_addr[1], tx_info->des_addr[2],
tx_info->des_addr[3], tx_info->des_addr[4], tx_info->des_addr[5]);
Serial.println(macStr);
Serial.print("Send status: ");
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
Serial.println();
}

void Association_ReceiverXIAOC3_peer() {
Serial.println("Attempting to associate peer for XIAOC3...");
memset(&peerInfo, 0, sizeof(peerInfo));
peerInfo.channel = ESPNOW_WIFI_CHANNEL;
peerInfo.encrypt = NO_PMK_KEY;
memcpy(peerInfo.peer_addr, Receiver_XIAOC3_MAC_Address, 6);
esp_err_t addPressStatus = esp_now_add_peer(&peerInfo);
if (addPressStatus != ESP_OK) {
Serial.print("Failed to add peer: ");
Serial.println(addPressStatus);
} else {
Serial.println("Successful to add peer");
}
}

void SenderXIAOC3_Send_Data() {
strcpy(Personal_XIAOC3_Information.device, "XIAOC3_YaroBoard1");
if (digitalRead(BUTTON_PIN) == LOW) {
strcpy(Personal_XIAOC3_Information.Trag, "ON");
} else {
strcpy(Personal_XIAOC3_Information.Trag, "OFF");
}
esp_err_t sendStatus = esp_now_send(
Receiver_XIAOC3_MAC_Address,
(uint8_t *)&Personal_XIAOC3_Information,
sizeof(Personal_XIAOC3_Information)
);
if (sendStatus == ESP_OK) {
Serial.print("Sent: ");
Serial.println(Personal_XIAOC3_Information.Trag);
} else {
Serial.print("Error sending message: ");
Serial.println(sendStatus);
}
}

void SenderXIAOC3_MACAddress_Requir() {
WiFi.mode(WIFI_STA);
delay(100);
uint8_t mac[MAX_ESP_NOW_MAC_LEN];
WiFi.macAddress(mac);
Serial.println();
Serial.printf("const uint8_t mac_self[6] = {0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x};\n",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}

void espnow_init() {
XIAO_status espnow_sign = esp_now_init();
if (espnow_sign == ESP_OK) {
Serial.println("The ESP-NOW is successfully initialized!");
} else {
Serial.println("The ESP-NOW initialization failed");
}
}

And for RECEIVER:\
\
#include <Arduino.h>

#include "WiFi.h"

#include "esp_now.h"

#define ESPNOW_WIFI_CHANNEL 0

#define MAX_ESP_NOW_MAC_LEN 6

#define BAUD 115200

#define MAX_CHARACTERS_NUMBER 20

#define LED_PIN D6

typedef int XIAO_status;

typedef struct message_types {
char device[MAX_CHARACTERS_NUMBER];
char Trag[MAX_CHARACTERS_NUMBER];
} message_types;

message_types XIAOC3_SENDER_INFORATION;

void Receiver_MACAddress_requir();

void espnow_init();

void ReceiverXIAOC3_Recive_Data_cb(const esp_now_recv_info_t *info, const uint8_t *incomingData, int len);

void setup() {
Serial.begin(BAUD);
delay(1000);
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
Receiver_MACAddress_requir();
espnow_init();
esp_now_register_recv_cb(ReceiverXIAOC3_Recive_Data_cb);
}

void loop() {
}

void ReceiverXIAOC3_Recive_Data_cb(const esp_now_recv_info_t *info, const uint8_t *incomingData, int len) {
memcpy(&XIAOC3_SENDER_INFORATION, incomingData, sizeof(XIAOC3_SENDER_INFORATION));
Serial.print("Sender_device: ");
Serial.println(XIAOC3_SENDER_INFORATION.device);
Serial.print("Sender_Trag: ");
Serial.println(XIAOC3_SENDER_INFORATION.Trag);
if (strcmp(XIAOC3_SENDER_INFORATION.Trag, "ON") == 0) {
digitalWrite(LED_PIN, HIGH);
Serial.println("LED ON");
} else if (strcmp(XIAOC3_SENDER_INFORATION.Trag, "OFF") == 0) {
digitalWrite(LED_PIN, LOW);
Serial.println("LED OFF");
}
Serial.println();
}

void Receiver_MACAddress_requir() {
WiFi.mode(WIFI_STA);
delay(100);
uint8_t mac[MAX_ESP_NOW_MAC_LEN];
WiFi.macAddress(mac);
Serial.println();
Serial.printf("const uint8_t mac_self[6] = {0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x};\n",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}

void espnow_init() {
XIAO_status espnow_sign = esp_now_init();
if (espnow_sign == ESP_OK) {
Serial.println("The ESP-NOW is successfully initialized!");
} else {
Serial.println("The ESP-NOW initialization failed");
}
}

As a result I can control the receiver board LED by pressing the button on the sender board.

Week 11 documentation image image021.webp
Video. IMG_7262.mov

In the serial monitor of the sender, I can see that the message is sent as a packet message. In the receiver, I can see that the LED is on and off when I trigger the button.

Heart Rate Pulse Oximeter Sensor

Week 11 documentation image image022.webp

Recently I received a MAX30102 heartbeat sensor. This sensor just needs to be connected to the finger tip and then it can measure the heart beat. It is an infrared sensor.

Give me a simple code on how can I test the MAX30102 heartbeat sensor.

The output contains several code blocks. To check the board and the sensor. On this stage, I need to check the board first: is it connected well or not?

#include <Wire.h>

#define SDA_PIN D4

#define SCL_PIN D5

void setup() {
Serial.begin(115200);
delay(1000);
Wire.begin(SDA_PIN, SCL_PIN);
Serial.println("I2C scanner started...");
}

void loop() {
byte error, address;
int count = 0;
Serial.println("Scanning...");
for (address = 1; address < 127; address++) {
Wire.beginTransmission(address);
error = Wire.endTransmission();
if (error == 0) {
Serial.print("I2C device found at address 0x");
if (address < 16) Serial.print("0");
Serial.println(address, HEX);
count++;
}
}
if (count == 0) {
Serial.println("No I2C devices found.");
} else {
Serial.println("Scan complete.");
}
Serial.println();
delay(2000);
}

As a result, in the serial monitor, I can see the I2C connection is established, and the device is found.

Week 11 documentation image image023.webp

For checking the sensor I need to install the library MAX3010x

Week 11 documentation image image024.webp

Code for checking the MAX30102 sensor

#include <Wire.h>

#include "MAX30105.h"

MAX30105 sensor;

#define SDA_PIN D4

#define SCL_PIN D5

void setup() {
Serial.begin(115200);
delay(1000);
Wire.begin(SDA_PIN, SCL_PIN);
if (!sensor.begin(Wire, I2C_SPEED_STANDARD)) {
Serial.println("Sensor not found. Check wiring.");
while (1);
}
sensor.setup();
sensor.setPulseAmplitudeRed(0x1F);
sensor.setPulseAmplitudeIR(0x1F);
sensor.setPulseAmplitudeGreen(0);
Serial.println("Place your finger on the sensor.");
}

void loop() {
long irValue = sensor.getIR();
Serial.print("IR value: ");
Serial.println(irValue);
delay(100);
}

This sensor can sense a disturbance in the air when there is nothing in front but when I use my finger tip and touch it, it starts demonstrating a different value

Week 11 documentation image image025.webp
Week 11 documentation image image026.webp
Video. IMG_7266.MOV

Next, I want to try to synchronize my heartbeat with the embedded LED on the board so I ask AI about different requests.

I need to convert this value to a blinking LED. I want the embedded LED to blink the same as my heartbeat, based on information from the sensor.
Now I want to transmit my data bit from one sender to the receiver, the same as I did before. You need to change the sender code and receiver code to blink an LED based on the data heart bit signal. The LED must blink on two boards together.

Code Sender

#include <Arduino.h>

#include "WiFi.h"

#include "esp_now.h"

#include <Wire.h>

#include "MAX30105.h"

#include "heartRate.h"

#define ESPNOW_WIFI_CHANNEL 0

#define MAX_ESP_NOW_MAC_LEN 6

#define BAUD 115200

#define MAX_CHARACTERS_NUMBER 20

#define NO_PMK_KEY false

#define SDA_PIN D4

#define SCL_PIN D5

#define LED_PIN D6

typedef uint8_t XIAO;

typedef int XIAO_status;

// Receiver ESP32-C3 MAC address

static uint8_t Receiver_XIAOC3_MAC_Address[MAX_ESP_NOW_MAC_LEN] = {0x1C, 0xDB, 0xD4, 0xEB, 0xCB, 0x68};

esp_now_peer_info_t peerInfo;

MAX30105 sensor;

typedef struct message_types {
char device[MAX_CHARACTERS_NUMBER];
char Trag[MAX_CHARACTERS_NUMBER];
} message_types;

message_types Personal_XIAOC3_Information;

long lastBeat = 0;

float beatsPerMinute = 0;

unsigned long ledOffTime = 0;

void espnow_init();

void SenderXIAOC3_MACAddress_Requir();

void SenderXIAOC3_Send_Data(const char *msg);

void SenderXIAOC3_Send_Data_cb(const wifi_tx_info_t *tx_info, esp_now_send_status_t status);

void Association_ReceiverXIAOC3_peer();

void setup() {
Serial.begin(BAUD);
delay(1000);
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
Wire.begin(SDA_PIN, SCL_PIN);
if (!sensor.begin(Wire, I2C_SPEED_STANDARD)) {
Serial.println("Sensor not found. Check wiring.");
while (1);
}
sensor.setup();
sensor.setPulseAmplitudeRed(0x1F);
sensor.setPulseAmplitudeIR(0x1F);
sensor.setPulseAmplitudeGreen(0);
SenderXIAOC3_MACAddress_Requir();
espnow_init();
esp_now_register_send_cb(SenderXIAOC3_Send_Data_cb);
Association_ReceiverXIAOC3_peer();
Serial.println("Place your fingertip on the sensor.");
}

void loop() {
long irValue = sensor.getIR();
if (millis() > ledOffTime) {
digitalWrite(LED_PIN, LOW);
}
if (irValue > 5000) {
if (checkForBeat(irValue)) {
long delta = millis() - lastBeat;
lastBeat = millis();
beatsPerMinute = 60.0 / (delta / 1000.0);
Serial.print("Beat detected! BPM: ");
Serial.println(beatsPerMinute);
digitalWrite(LED_PIN, HIGH);
ledOffTime = millis() + 80;
SenderXIAOC3_Send_Data("BEAT");
}
} else {
Serial.println("No finger detected");
digitalWrite(LED_PIN, LOW);
}
delay(20);
}

void SenderXIAOC3_Send_Data_cb(const wifi_tx_info_t *tx_info, esp_now_send_status_t status) {
Serial.print("Send status: ");
Serial.println(status == ESP_NOW_SEND_SUCCESS ? "Delivery Success" : "Delivery Fail");
}

void Association_ReceiverXIAOC3_peer() {
Serial.println("Attempting to associate peer for XIAOC3...");
memset(&peerInfo, 0, sizeof(peerInfo));
peerInfo.channel = ESPNOW_WIFI_CHANNEL;
peerInfo.encrypt = NO_PMK_KEY;
memcpy(peerInfo.peer_addr, Receiver_XIAOC3_MAC_Address, 6);
esp_err_t addPressStatus = esp_now_add_peer(&peerInfo);
if (addPressStatus != ESP_OK) {
Serial.print("Failed to add peer: ");
Serial.println(addPressStatus);
} else {
Serial.println("Successful to add peer");
}
}

void SenderXIAOC3_Send_Data(const char *msg) {
strcpy(Personal_XIAOC3_Information.device, "XIAOC3_YaroBoard1");
strncpy(Personal_XIAOC3_Information.Trag, msg, MAX_CHARACTERS_NUMBER - 1);
Personal_XIAOC3_Information.Trag[MAX_CHARACTERS_NUMBER - 1] = '\0';
esp_err_t sendStatus = esp_now_send(
Receiver_XIAOC3_MAC_Address,
(uint8_t *)&Personal_XIAOC3_Information,
sizeof(Personal_XIAOC3_Information)
);
if (sendStatus == ESP_OK) {
Serial.print("Sent: ");
Serial.println(Personal_XIAOC3_Information.Trag);
} else {
Serial.print("Error sending message: ");
Serial.println(sendStatus);
}
}

void SenderXIAOC3_MACAddress_Requir() {
WiFi.mode(WIFI_STA);
delay(100);
uint8_t mac[MAX_ESP_NOW_MAC_LEN];
WiFi.macAddress(mac);
Serial.println();
Serial.printf("const uint8_t mac_self[6] = {0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x};\n",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}

void espnow_init() {
XIAO_status espnow_sign = esp_now_init();
if (espnow_sign == ESP_OK) {
Serial.println("The ESP-NOW is successfully initialized!");
} else {
Serial.println("The ESP-NOW initialization failed");
}
}

Code Receiver

#include <Arduino.h>

#include "WiFi.h"

#include "esp_now.h"

#define ESPNOW_WIFI_CHANNEL 0

#define BAUD 115200

#define MAX_CHARACTERS_NUMBER 20

#define LED_PIN D6

typedef int XIAO_status;

typedef struct message_types {
char device[MAX_CHARACTERS_NUMBER];
char Trag[MAX_CHARACTERS_NUMBER];
} message_types;

message_types XIAOC3_SENDER_INFORATION;

unsigned long ledOffTime = 0;

void Receiver_MACAddress_requir();

void espnow_init();

void ReceiverXIAOC3_Recive_Data_cb(const esp_now_recv_info_t *info, const uint8_t *incomingData, int len);

void setup() {
Serial.begin(BAUD);
delay(1000);
pinMode(LED_PIN, OUTPUT);
digitalWrite(LED_PIN, LOW);
Receiver_MACAddress_requir();
espnow_init();
esp_now_register_recv_cb(ReceiverXIAOC3_Recive_Data_cb);
}

void loop() {
if (millis() > ledOffTime) {
digitalWrite(LED_PIN, LOW);
}
}

void ReceiverXIAOC3_Recive_Data_cb(const esp_now_recv_info_t *info, const uint8_t *incomingData, int len) {
memcpy(&XIAOC3_SENDER_INFORATION, incomingData, sizeof(XIAOC3_SENDER_INFORATION));
Serial.print("Sender_device: ");
Serial.println(XIAOC3_SENDER_INFORATION.device);
Serial.print("Sender_Trag: ");
Serial.println(XIAOC3_SENDER_INFORATION.Trag);
if (strcmp(XIAOC3_SENDER_INFORATION.Trag, "BEAT") == 0) {
digitalWrite(LED_PIN, HIGH);
ledOffTime = millis() + 80;
Serial.println("Heartbeat blink");
}
Serial.println();
}

void Receiver_MACAddress_requir() {
WiFi.mode(WIFI_STA);
delay(100);
uint8_t mac[6];
WiFi.macAddress(mac);
Serial.println();
Serial.printf("const uint8_t mac_self[6] = {0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x, 0x%02x};\n",
mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
}

void espnow_init() {
XIAO_status espnow_sign = esp_now_init();
if (espnow_sign == ESP_OK) {
Serial.println("The ESP-NOW is successfully initialized!");
} else {
Serial.println("The ESP-NOW initialization failed");
}
}

I'm very excited about the result because it's actually working. I can see the serial monitor sending packages, and I can see the LED indication. The most interesting thing is that I am touching my heart with my right hand, and I'm using my left hand with a sensor. I can see that I can feel and see my heart beating and the LED blinking simultaneously

Week 11 documentation image image027.webp
Video. IMG_7268.MOV

Reflection

I tried to explore several protocols.

Wire protocols are very simple; they just need two or three wires. The code is also very simple to understand and to repeat.

Wireless communication is a bit more complex, and it requires its up some node's name or address, his name, and then some procedure for how to establish this connection and initialize the port, the mode, and the speed.

Also, for fast prototyping, I'm asking AI to generate code and explain to me what exactly is happening inside. Later on, I will dive deeper, but at this stage, I just need to make everything work.

Reference

Download the source files used in this assignment: