Skip to content

Week 11 - Networking and Communications

Assignments of the Week

Group Assignment

  • Send a message between two projects

Individual Assignment

  • Design, build, and connect wired or wireless node(s) with network or bus addresses and local input &/or output device(s)

Individual Assignment

Arduino Cloud Platform Configuration

1. Account Registration and Login

  1. Visit Arduino Cloud official website and register an account (I chose GitHub OAuth registration)

2. Device Registration

  1. Go to Devices interface and select "Add Device"

  2. After clicking "Add Device", select the board type (I chose "Third Party Device" for XIAO ESP32 C3)

  3. Select XIAO ESP32 C3

  4. Configure basic device information, device name: Tiertza

  5. Save the Device ID and Secret Key:

3. Thing Object Creation

  1. Go to Thing page

  2. Define Cloud Variables:

    VariableTypePermissionDescription
    distanceintRead-onlyUltrasonic distance data (cm)
    temperaturefloatRead-onlyAmbient temperature (℃)
    humidityfloatRead-onlyAmbient humidity (%RH)
  • First create distance variable (read-only)
  • Similarly create temperature and humidity variables (float type)
  1. Variable binding configuration - associate with registered physical device

4. Network Configuration

  1. Click Network, enter WiFi credentials and device secret key

1. Development Environment Setup

  1. Install Arduino Cloud Agent
  • Follow installation prompts

Code Implementation

  1. Enter the Sketch interface, and four files will be automatically generated
  2. Below is a brief introduction to the functionality of each file:
  • thingProperties.h

    • Declare variables and initialize cloud properties
    • Contains variables created in Arduino Cloud including their types and sync modes (Read/Write)
    cpp
    // Code generated by Arduino IoT Cloud, DO NOT EDIT.
    
    #include <ArduinoIoTCloud.h>
    #include <Arduino_ConnectionHandler.h>
    
    const char DEVICE_LOGIN_NAME[]  = "0fa1ab03-c0e7-4124-a682-2fadb81c765a";
    
    const char SSID[]               = SECRET_SSID;    // Network SSID (name)
    const char PASS[]               = SECRET_OPTIONAL_PASS;    // Network password (use for WPA, or use as key for WEP)
    const char DEVICE_KEY[]  = SECRET_DEVICE_KEY;    // Secret device password
    
    
    float humidity;
    float temperature;
    int distance;
    
    void initProperties(){
    
    ArduinoCloud.setBoardId(DEVICE_LOGIN_NAME);
    ArduinoCloud.setSecretDeviceKey(DEVICE_KEY);
    ArduinoCloud.addProperty(humidity, READ, ON_CHANGE, NULL);
    ArduinoCloud.addProperty(temperature, READ, ON_CHANGE, NULL);
    ArduinoCloud.addProperty(distance, READ, ON_CHANGE, NULL);
    
    }
    
    WiFiConnectionHandler ArduinoIoTPreferredConnection(SSID, PASS);
  • demo_apr08a.ino

    • Main program file for control logic
    cpp
    #include <ArduinoIoTCloud.h>
    #include "thingProperties.h"
    #include "DHT.h"
    
    #define DHT_PIN  D1    
    #define TRIG_PIN D8   
    #define ECHO_PIN D9    
    #define LED1 D4   
    #define LED2 D5   
    
    #define DHT_TYPE DHT11
    DHT dht(DHT_PIN, DHT_TYPE);
    
    void setup() {
    Serial.begin(9600);
    delay(1500);
    
    dht.begin();
    pinMode(TRIG_PIN, OUTPUT);  
    pinMode(ECHO_PIN, INPUT); 
    
    initProperties();
    ArduinoCloud.begin(ArduinoIoTPreferredConnection);
    
    setDebugMessageLevel(2);
    ArduinoCloud.printDebugInfo();
    }
    
    void loop() {
    ArduinoCloud.update();
    
    
    long dist = getDistance();
    distance = (int)dist;
    
    
    if (distance < 200 && distance > 0) {
        digitalWrite(LED1, HIGH);
        digitalWrite(LED2, LOW);
    } else {
        digitalWrite(LED1, LOW);
        digitalWrite(LED2, HIGH);
    }
    
    
    temperature = dht.readTemperature();
    humidity = dht.readHumidity();
    
    delay(1000); 
    }
    
    long getDistance() {
    digitalWrite(TRIG_PIN, LOW);
    delayMicroseconds(2);
    digitalWrite(TRIG_PIN, HIGH);
    delayMicroseconds(10);
    digitalWrite(TRIG_PIN, LOW);
    
    long duration = pulseIn(ECHO_PIN, HIGH, 30000); 
    return (duration * 0.034) / 2; 
    }
  • Sketch Secrets

    • Stores WiFi and device credential information (SSID, password, Device ID and Secret)
  • README Document

    • This ReadMe.adoc file is a project documentation for installation, circuit assembly, code upload, and component list. Written in AsciiDoc format, suitable for Arduino hardware projects.
    txt
    :Author: xusun_fab
    :Email:
    :Date: 08/04/2025
    :Revision: version#
    :License: Public Domain
    
    = Project: {Project}
    
    Describe your project
    
    == Step 1: Installation
    Please describe the steps to install this project.
    
    For example:
    
    1. Open this file
    2. Edit as you like
    3. Release to the World!
    
    == Step 2: Assemble the circuit
    
    Assemble the circuit following the diagram layout.png attached to the sketch
    
    == Step 3: Load the code
    
    Upload the code contained in this sketch on to your board
    
    === Folder structure
    
    ....
    sketch123                => Arduino sketch folder
    ├── sketch123.ino       => main Arduino file
    ├── schematics.png      => (optional) an image of the required schematics
    ├── layout.png          => (optional) an image of the layout
    └── ReadMe.adoc         => this file
    ....
    
    === License
    This project is released under a {License} License.
    
    === Contributing
    To contribute to this project please contact: 
    
    === BOM
    Add the bill of the materials you need for this project.
    
    |===
    | ID | Part name      | Part number | Quantity
    | R1 | 10k Resistor   | 1234-abcd   | 10       
    | L1 | Red LED        | 2345-asdf   | 5        
    | A1 | Arduino Zero   | ABX00066    | 1        
    |===
    
    
    === Help
    This document is written in the _AsciiDoc_ format, a markup language to describe documents. 
    If you need help you can search the http://www.methods.co.nz/asciidoc[AsciiDoc homepage]
    or consult the http://powerman.name/doc/asciidoc[AsciiDoc cheatsheet]
  1. Add necessary library dependencies:

    • ArduinoIoTCloud (v1.x)
    • DHT sensor library
  2. After completing the code editing, there are two ways to upload it to the development board:

  • Upload via the web interface, but this method is prone to upload failures

    • Upload completed

    • Open serial monitor to view connection status

  • Upload code via Arduino IDE: log in to cloud account and pull cloud code

    • Open Arduino IDE and log in to cloud account
    • Pull cloud code:
    • Can be edited locally and uploaded to the development board, locally written code can also be pushed to the cloud for saving

Data Visualization

  1. Create Dashboard monitoring panel
  2. Add Widget components
  • Value display: Real-time temperature
  • Link variables

Group Assignment

I plan to establish communication between two XIAO ESP32 C3 boards:

Peripheral Device: The ESP32 connects to a DHT11 sensor to read real-time temperature and humidity data, then periodically transmits this data via BLE (Bluetooth Low Energy) to connected central devices (such as smartphones or another ESP32).

Central Device: Another ESP32 acts as a BLE central device that scans for and connects to the target peripheral device. After successful connection, it continuously receives the temperature/humidity data from the peripheral and displays it via serial output, achieving wireless data acquisition functionality.

Code Implementation

  • Peripheral
cpp
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>
#include <DHT.h>

#define DHTPIN A1          
#define DHTTYPE DHT11     
DHT dht(DHTPIN, DHTTYPE);

#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;
    Serial.println("Device connected!");
  }

  void onDisconnect(BLEServer* pServer) override {
    deviceConnected = false;
    Serial.println("Device disconnected!");
    pServer->getAdvertising()->start();  // Restart advertising after disconnection
  }
};

void setup() {
  Serial.begin(115200);
  dht.begin();
  delay(1000);

  BLEDevice::init("ESP32-BLE-Peripheral");
  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());

  pService->start();
  pServer->getAdvertising()->start();
  Serial.println("BLE peripheral started, waiting for central device to connect...");
}

void loop() {
  float h = dht.readHumidity();
  float t = dht.readTemperature();

  if (isnan(h) || isnan(t)) {
    Serial.println("Failed to read temperature and humidity!");
    return;
  }

  char buffer[30];
  snprintf(buffer, sizeof(buffer), "T:%.2fC H:%.2f%%", t, h);  // Keep it within 20 bytes
  Serial.print("Sending data: ");
  Serial.println(buffer);

  if (deviceConnected) {
    pCharacteristic->setValue((uint8_t*)buffer, strlen(buffer));
    pCharacteristic->notify();
  }

  delay(3000);  // Send every 3 seconds
}
  • Central
cpp
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEClient.h>
#include <BLEScan.h>
#include <BLEAdvertisedDevice.h>

// Define the UUIDs for the target BLE service and characteristic
#define SERVICE_UUID        "12345678-1234-1234-1234-1234567890ab"
#define CHARACTERISTIC_UUID "abcdefab-1234-1234-1234-abcdefabcdef"

// Global pointers and state flags
BLEAdvertisedDevice* myDevice;
BLERemoteCharacteristic* pRemoteCharacteristic;
BLEClient* pClient;
bool doConnect = false;
bool connected = false;
bool waitingPrinted = false;

// Callback for when a BLE device is discovered during scanning
class MyAdvertisedDeviceCallbacks : public BLEAdvertisedDeviceCallbacks {
  void onResult(BLEAdvertisedDevice advertisedDevice) {
    Serial.print("Discovered device: ");
    Serial.println(advertisedDevice.toString().c_str());
    Serial.print("Device address: ");
    Serial.println(advertisedDevice.getAddress().toString().c_str());

    // Check if the device contains the target service UUID
    if (advertisedDevice.haveServiceUUID() &&
        advertisedDevice.getServiceUUID().equals(BLEUUID(SERVICE_UUID))) {
      Serial.println("Target device found!");
      myDevice = new BLEAdvertisedDevice(advertisedDevice);
      doConnect = true;  // Flag to initiate connection in loop()
    }
  }
};

// Callback function for when notification data is received from the peripheral
static void notifyCallback(
  BLERemoteCharacteristic* pBLERemoteCharacteristic,
  uint8_t* pData, size_t length, bool isNotify) {
  Serial.print("Received data: ");
  Serial.println((char*)pData);  // Print data as string (assumes it's null-terminated)
}

// Function to connect to the BLE peripheral and subscribe to notifications
bool connectToServer() {
  // Replace with your peripheral device's MAC address
  BLEAddress targetAddress("40:4C:CA:F4:CF:DA");
  
  pClient = BLEDevice::createClient();  // Create BLE client
  if (pClient->connect(targetAddress)) {
    Serial.println("Connected to peripheral!");

    // Get the remote service by UUID
    BLERemoteService* pRemoteService = pClient->getService(SERVICE_UUID);
    if (pRemoteService == nullptr) {
      Serial.println("Failed to find the service");
      return false;
    }

    // Get the remote characteristic by UUID
    pRemoteCharacteristic = pRemoteService->getCharacteristic(CHARACTERISTIC_UUID);
    if (pRemoteCharacteristic == nullptr) {
      Serial.println("Failed to find the characteristic");
      return false;
    }

    // Register for notification if supported
    if (pRemoteCharacteristic->canNotify()) {
      pRemoteCharacteristic->registerForNotify(notifyCallback);
    }

    return true;
  } else {
    Serial.println("Connection failed!");
    return false;
  }
}

// Initialization
void setup() {
  Serial.begin(115200);
  BLEDevice::init("ESP32-BLE-Central");  // Set BLE device name

  // Start BLE scan with custom callback
  BLEScan* pBLEScan = BLEDevice::getScan();
  pBLEScan->setAdvertisedDeviceCallbacks(new MyAdvertisedDeviceCallbacks());
  pBLEScan->setActiveScan(true);       // Enable active scanning (more data)
  pBLEScan->start(30, false);          // Scan for 30 seconds
}

// Main loop
void loop() {
  // Try to connect if device was found and not yet connected
  if (doConnect && !connected) {
    if (connectToServer()) {
      Serial.println("Successfully connected to peripheral!");
      connected = true;
    } else {
      Serial.println("Failed to connect to peripheral.");
    }
    doConnect = false;
    waitingPrinted = false;
  }

  // Print waiting message once if idle
  if (!connected && !doConnect && !waitingPrinted) {
    Serial.println("Not connected to any device, waiting...");
    waitingPrinted = true;
  }

  delay(1000);  // Main loop delay
}