11. Embedded Networking and Communications


💧 Just Vibing around

This week's assignment consisted of exploring the remote connectivity capabilities of our microcontrollers. For this, we carried out a group exercise between our boards and an individual one.

Imagen

Learning Plan:

To enable wireless communication, we will initially attempt to create an interaction via Wi-Fi, using an MQTT broker for communication.


An MQTT broker is a server that manages communication between devices using the MQTT protocol. It receives messages from clients (publishers) and routes them to the appropriate recipients (subscribers), enabling lightweight and efficient machine-to-machine communication, especially over Wi-Fi or the internet. We attempted to test its functionality, but the signal tended to drop quickly and was not reliable for long-term use, so we opted to switch to Bluetooth instead


💧 Research Objectives & Workflow

Ofelia and I had already designed and fabricated our boards during weeks 6 and 8. Therefore, for this group assignment, we chose to establish communication between them. In this part of the assignment, I will present my code and explain the testing process I followed.

Imagen

💧 Connecting Colors (Group Asignment)

1. As a first step, it is necessary to use the multimeter to properly understand what is happening electrically within our board.q

Imagen

2. To start, we needed to connect to a broker server using MQTT Broker, with each device connected to a Wi-Fi network. In my case, I used my phone's hotspot to ensure a stable connection.

Imagen

3. Button to Servo A code is designed that, in the first block, sets up the Wi-Fi service for the connection. Then, it defines the behavior of each pin for signal control, and finally, it registers the looped action that will occur when the button is pressed.

            
                #include 
#include 

// Wi-Fi
const char* ssid = "OfeliA phone";
const char* password = "xxxxxxxxxx";

// MQTT
const char* mqtt_server = "broker.hivemq.com";

WiFiClient espClient;
PubSubClient client(espClient);
const int botonPin = 3;  // button pin
bool lastButtonState = HIGH;

// to avoid repeating
String lastSent = "";

void setup() {
  Serial.begin(115200);
  pinMode(botonPin, INPUT_PULLUP); 

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("WiFi conectado");  // connected

  client.setServer(mqtt_server, 1883);
  while (!client.connected()) {
    Serial.print("Conectando a MQTT...");
    if (client.connect("ButtonClient")) {
      Serial.println("conectado");
    } else {
      Serial.print("falló, rc=");
      Serial.print(client.state());
      delay(5000);
    }
  }
}const int botonPin = 3;  // button pin
bool lastButtonState = HIGH;

// to avoid repeating
String lastSent = "";

void setup() {
  Serial.begin(115200);
  pinMode(botonPin, INPUT_PULLUP); 

  WiFi.begin(ssid, password);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println("WiFi conectado");  // connected

  client.setServer(mqtt_server, 1883);
  while (!client.connected()) {
    Serial.print("Conectando a MQTT...");
    if (client.connect("ButtonClient")) {
      Serial.println("conectado");
    } else {
      Serial.print("falló, rc=");
      Serial.print(client.state());
      delay(5000);
    }
  }
}
            
            

4. Potentiometer to Led RGB Another code is designed to connect the potentiometer to the LED. First, it initiates the Wi-Fi request, then identifies the pins used for the potentiometer, and scales its resistance value to a range from 0 to 255 to control the LED's color.

            
                #include 
#include 

// Wi-Fi
const char* ssid = "OfeliA phone";
const char* password = "xxxxxxxxxx";

// MQTT
const char* mqtt_server = "broker.hivemq.com";

WiFiClient espClient;
PubSubClient client(espClient);
        int ledRojo = 10;
int ledVerde = 9;
int ledAzul = 8;

WiFiClient espClient;       // Create a WiFi client instance
PubSubClient client(espClient);  // Create a MQTT client instance

void setup() {
  pinMode(ledRojo, OUTPUT);
  pinMode(ledVerde, OUTPUT);
  pinMode(ledAzul, OUTPUT);
  Serial.begin(115200);     // Start the serial communication
  delay(10);

  // Connect to Wi-Fi
  WiFi.begin(ssid, password);   // Connect to WiFi network
  while (WiFi.status() != WL_CONNECTED) {  // Wait for WiFi connection
    delay(500);
    Serial.print(".");
  }
  Serial.println("WiFi connected");

  // Connect to MQTT Broker
  client.setServer(mqtt_server, 1883);   // Set the MQTT broker server and port
  client.setCallback(callback);   // Set callback function to handle incoming messages
  
  while (!client.connected()) {   // Attempt to connect to MQTT broker
    Serial.print("Attempting MQTT connection...");
    if (client.connect("ESP32C3Client")) {   // Client ID for MQTT connection
      Serial.println("connected");
      client.subscribe("arduino/uno");  // Subscribe to the topic "arduino/uno"
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());   // Print connection status
      Serial.println(" try again in 5 seconds");
      delay(5000);   // Wait 5 seconds before retrying
    }
  }
}
void loop() {
  client.loop();    // Maintain MQTT connection and handle incoming messages
}

// MQTT callback function to handle incoming messages
void callback(char* topic, byte* payload, unsigned int length) {
  Serial.print("Message arrived [");
  Serial.print(topic);   // Print the topic of the incoming message
  Serial.print("] ");
  String msg;
  // Print the incoming message
  for (int i = 0; i < length; i++) {
    msg += (char)payload[i];
  }
  Serial.println(msg);
  if (msg == "A") {
  // 10 combinaciones de magenta
  analogWrite(ledRojo, 50);   // más brillante
  analogWrite(ledVerde, 255); // verde apagado
  analogWrite(ledAzul, 80);   // más brillante
  Serial.println("Magenta combo 1");
}
else if (msg == "S") {
  analogWrite(ledRojo, 70);
  analogWrite(ledVerde, 255);
  analogWrite(ledAzul, 60);
  Serial.println("Magenta combo 2");
}
else if (msg == "D") {
  analogWrite(ledRojo, 90);
  analogWrite(ledVerde, 255);
  analogWrite(ledAzul, 40);
  Serial.println("Magenta combo 3");
}
else if (msg == "F") {
  analogWrite(ledRojo, 110);
  analogWrite(ledVerde, 255);
  analogWrite(ledAzul, 30);
  Serial.println("Magenta combo 4");
}
else if (msg == "G") {
  analogWrite(ledRojo, 130);
  analogWrite(ledVerde, 255);
  analogWrite(ledAzul, 20);
  Serial.println("Magenta combo 5");
}
else if (msg == "H") {
  analogWrite(ledRojo, 150);
  analogWrite(ledVerde, 255);
  analogWrite(ledAzul, 15);
  Serial.println("Magenta combo 6");
}
else if (msg == "I") {
  analogWrite(ledRojo, 170);
  analogWrite(ledVerde, 255);
  analogWrite(ledAzul, 10);
  Serial.println("Magenta combo 7");
}
else if (msg == "J") {
  analogWrite(ledRojo, 190);
  analogWrite(ledVerde, 255);
  analogWrite(ledAzul, 5);
  Serial.println("Magenta combo 8");
}
else if (msg == "K") {
  analogWrite(ledRojo, 210);
  analogWrite(ledVerde, 255);
  analogWrite(ledAzul, 2);
  Serial.println("Magenta combo 9");
}
else if (msg == "L") {
  analogWrite(ledRojo, 230);
  analogWrite(ledVerde, 255);
  analogWrite(ledAzul, 0);
  Serial.println("Magenta combo 10");
}

  } 
            
            

5. Final visualization of both Arduinos running in parallel and exchanging information.

💧 A Remote Camera (Personal Asignment)

6. A second exercise was developed to validate the use of Bluetooth. In this case, the goal was to create a remote camera trigger using Bluetooth Low Energy between the Seeed board and my cellphone.

Imagen
Imagen

7. The first part of the code for the action will be used to call the BLE and HID libraries (to emulate a keyboard) and define the action pins..

            
                #include 
#include 
#include 
#include 
#include 

#define swPin D1  // Joystick SW button on D1

BLEHIDDevice* hid;
BLECharacteristic* input;
int lastButtonState = HIGH;  // Pull-up, button press is LOW
bool deviceConnected = false;

            
            

8. The next block defines the BLE behavior so that it can be detected and recognized by the cellphone. It also begins assigning a code to each function of the simulated HID keyboard.

            
                class MyServerCallbacks: public BLEServerCallbacks {
  void onConnect(BLEServer* pServer) { deviceConnected = true; Serial.println("Device connected"); }
  void onDisconnect(BLEServer* pServer) { deviceConnected = false; Serial.println("Device disconnected"); }
};

void setup() {
  // Empty setup
}

void loop() {
  // One-time initialization
  static bool initialized = false;
  if (!initialized) {
    Serial.begin(115200);
    BLEDevice::init("XIAO_ESP32C3");
    BLEServer* pServer = BLEDevice::createServer();
    pServer->setCallbacks(new MyServerCallbacks());
    hid = new BLEHIDDevice(pServer);
    input = hid->inputReport(1);
    hid->manufacturer()->setValue("Seeed");
    hid->pnp(0x02, 0xe502, 0xa111, 0x0210);
    hid->hidInfo(0x00, 0x01);
    hid->reportMap((uint8_t[]) {
      0x05, 0x01,        // Usage Page (Generic Desktop)
      0x09, 0x0D,        // Usage (Camera)
      0xA1, 0x01,        // Collection (Application)
      0x85, 0x01,        //   Report ID (1)
      0x05, 0x01,        //   Usage Page (Generic Desktop)
      0x09, 0x6D,        //   Usage (System Camera Shutter)
      0x15, 0x00,        //   Logical Minimum (0)
      0x25, 0x01,        //   Logical Maximum (1)
      0x75, 0x01,        //   Report Size (1)
      0x95, 0x01,        //   Report Count (1)
      0x81, 0x02,        //   Input (Data,Var,Abs)
      0x95, 0x07,        //   Report Count (7)
      0x81, 0x03,        //   Input (Const)
      0xC0               // End Collection
    }, 20);
    hid->startServices();
    BLEDevice::getAdvertising()->start();
    Serial.println("BLE HID Advertising Started");
    pinMode(swPin, INPUT_PULLUP);
    initialized = true;
  }

            
            

9. The third part is responsible for enabling constant reconnection to avoid issues with loss of control.

            
               if (!deviceConnected) {
    BLEDevice::getAdvertising()->start();
    Serial.println("Restarting advertising...");
    delay(500);
  }

            
            

10. Finally, the action block is generated to detect the joystick click and convert it into a signal interpretable by the cellphone.

            
               int buttonState = digitalRead(swPin);
  if (buttonState == LOW && lastButtonState == HIGH) {
    if (deviceConnected) {
      uint8_t report[] = {1};  // Camera shutter press
      input->setValue(report, sizeof(report));
      input->notify();
      delay(10);
      report[0] = 0;  // Release
      input->setValue(report, sizeof(report));
      input->notify();
      Serial.println("Button pressed - Camera shutter sent successfully");
    } else {
      Serial.println("Button pressed - No device connected");
    }
    delay(50);
  }
  lastButtonState = buttonState;
}
            
            

10. The final step will be to review the outcome of the experiment and identify the issues that need to be resolved.

Imagen
Imagen
Imagen

💧 Downloadable Files

Arduino Code of Group Project

Arduino Code of Personal project