Skip to content

13. Networking and communications

Group Assignment:
- [x]Send a message between two projects
- [x]Document your work to the group work page and reflect on your individual page what you learned

Individual Assignment:
- [x]Design, build and connect wired or wireless node(s) with network or bus addresses and a local interface

Group Assignment

Principle of Wirelees Communication

The comman wireless communication is using the radio signals to transmit the message and the data. Here are some common wireless communication methods.

Bluetooth

Bluetooth is a relatively new technology that is becoming increasingly common. It provides a simple way to send information over short distances, including messages and files.
Originally designed to replace physical cables, Bluetooth does have some limitations. Its maximum range is about 30 feet, which can be further reduced by walls and other solid objects.

WiFi

Wi-Fi internet is a low-powered wireless electronic network available in almost every shopping mall and cafe worldwide. A physical wired network connects to a router, creating a localized and low-power wireless network.
This allows various devices to connect to the local network. However, public Wi-Fi is often targeted by thieves and hackers, so it is crucial for both users and providers to use password protection and other security measures.

Cellular

Cellular technology is a well-known type of IoT wireless technology, especially popular in mobile phones. It provides reliable and fast communication for things like streaming videos and making phone calls.
Cellular networks are very well-established, so they offer high-speed connections. Besides regular mobile data, there are special types of cellular options like Cat-M1 and NB-IoT. These are designed to work with new low-power, wide-area network (LPWAN) technologies, which are used for connecting devices over long distances with minimal energy.

Infrared

Infrared (IR) communication is commonly used in devices like TV remote controls. Here’s how it works:
IR uses invisible light to send information. This light falls between microwaves and visible light on the electromagnetic spectrum.
For IR communication to work, you need a transmitter (like your remote) and a photoreceiver (like the sensor on your TV). The transmitter sends out an IR light beam, and the photoreceiver catches it. However, this only works if there’s nothing blocking the light. So, if you stand between the remote and the TV, it might not work because the light can’t get through.

Microwave

Microwave technologies can provide very secure communication. For short-distance transmission, you just need to set up two antennas with a clear line of sight between them. The signal can then be sent directly from one antenna to the other, without needing to connect to an outside network. This is alao the reason why i chosse the mmwave sensor for my final projects.

Networking and Communicaton Test

I will still use the Seeed XIAO ESP32 to test the wireless function. It will also used in my final projects.
Seeed Studio XIAO ESP32C3 supports WiFi connectivity with IEEE 802.11b/g/n and Bluetooth 5 (LE) connectivity.

Pairing XIAO ESP32 via Bluetooth

First, I checked Seeed’s wiki page to find the BLE reference routine. When I compiled the code, I found that errors kept popping up. It turned out to be because there were too many library files installed in my Arduino IDE, so I couldn’t load the correct library file.
1. Upload the Source code into XIAO ESP32.

#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/

#define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"


class MyCallbacks: public BLECharacteristicCallbacks {
    void onWrite(BLECharacteristic *pCharacteristic) {
      std::string value = pCharacteristic->getValue();

      if (value.length() > 0) {
        Serial.println("*********");
        Serial.print("New value: ");
        for (int i = 0; i < value.length(); i++)
          Serial.print(value[i]);

        Serial.println();
        Serial.println("*********");
      }
    }
};

void setup() {
  Serial.begin(115200);

  BLEDevice::init("MyESP32");
  BLEServer *pServer = BLEDevice::createServer();

  BLEService *pService = pServer->createService(SERVICE_UUID);

  BLECharacteristic *pCharacteristic = pService->createCharacteristic(
                                         CHARACTERISTIC_UUID,
                                         BLECharacteristic::PROPERTY_READ |
                                         BLECharacteristic::PROPERTY_WRITE
                                       );

  pCharacteristic->setCallbacks(new MyCallbacks());

  pCharacteristic->setValue("Hello World");
  pService->start();

  BLEAdvertising *pAdvertising = pServer->getAdvertising();
  pAdvertising->start();
}

void loop() {
  // put your main code here, to run repeatedly:
  delay(2000);
}
  1. Download the BLE App to my Phone and pairing the XIAO ESP32.
    Find the “My ESP32” and connect the Bluetooth.

  2. Change the data format and write the data.


  3. Review the result via Arduino IDE’s serial monito and watch the status.
    We can also check the HEX status when the BLE send the data to my XIAO ESP32.


Send the the command to controll XIAO ESP32

Here is the sample code that I use Bluetooth to control the LED to change their color on XIAO ESP32C3.
I set the different value such as“R”,”G”,”B”,”W” to control the LED to change their color and print the received result via serial monitor.


#include "Arduino.h"
#include <Adafruit_NeoPixel.h>
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>

// Define the LED pin
#define LED_PIN 9

// Create the NeoPixel strip object
Adafruit_NeoPixel strip = Adafruit_NeoPixel(24, LED_PIN, NEO_GRB + NEO_KHZ800);

// BLE UUIDs
#define SERVICE_UUID        "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define CHARACTERISTIC_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"

// Function prototypes
void colorWipe(uint32_t c, uint8_t wait);
void theaterChase(uint32_t c, uint8_t wait);
uint32_t Wheel(byte WheelPos);

class MyCallbacks: public BLECharacteristicCallbacks {
    void onWrite(BLECharacteristic *pCharacteristic) {
      std::string value = pCharacteristic->getValue();

      if (value.length() > 0) {
        Serial.println("*********");
        Serial.print("New value: ");
        for (int i = 0; i < value.length(); i++)
          Serial.print(value[i]);

        Serial.println();
        Serial.println("*********");

        // Assuming the value is a simple command like "R", "G", "B", "C" (chase), "W" (wipe)
        if (value == "R") {
          colorWipe(strip.Color(255, 0, 0), 50); // Red
        } else if (value == "G") {
          colorWipe(strip.Color(0, 255, 0), 50); // Green
        } else if (value == "B") {
          colorWipe(strip.Color(0, 0, 255), 50); // Blue
        } else if (value == "C") {
          theaterChase(strip.Color(127, 127, 127), 50); // White chase
        } else if (value == "W") {
          colorWipe(strip.Color(255, 255, 255), 50); // White wipe
        }
      }
    }
};

void setup() {
  Serial.begin(115200);

  // Initialize BLE
  BLEDevice::init("MyESP32");
  BLEServer *pServer = BLEDevice::createServer();

  BLEService *pService = pServer->createService(SERVICE_UUID);

  BLECharacteristic *pCharacteristic = pService->createCharacteristic(
                                         CHARACTERISTIC_UUID,
                                         BLECharacteristic::PROPERTY_READ |
                                         BLECharacteristic::PROPERTY_WRITE
                                       );

  pCharacteristic->setCallbacks(new MyCallbacks());

  pCharacteristic->setValue("Hello World");
  pService->start();

  BLEAdvertising *pAdvertising = pServer->getAdvertising();
  pAdvertising->start();

  // Initialize the NeoPixel strip
  strip.begin();
  strip.setBrightness(50);
  strip.show(); // Initialize all pixels to 'off'
}

void loop() {
  // put your main code here, to run repeatedly:
  delay(2000);
}

// Fill the dots one after the other with a color
void colorWipe(uint32_t c, uint8_t wait) {
  for (uint16_t i = 0; i < strip.numPixels(); i++) {
    strip.setPixelColor(i, c);
    strip.show();
    delay(wait);
  }
}

// Theatre-style crawling lights
void theaterChase(uint32_t c, uint8_t wait) {
  for (int j = 0; j < 10; j++) { // Do 10 cycles of chasing
    for (int q = 0; q < 3; q++) {
      for (uint16_t i = 0; i < strip.numPixels(); i += 3) {
        strip.setPixelColor(i + q, c); // Turn every third pixel on
      }
      strip.show();
      delay(wait);
      for (uint16_t i = 0; i < strip.numPixels(); i += 3) {
        strip.setPixelColor(i + q, 0); // Turn every third pixel off
      }
    }
  }
}

// Input a value 0 to 255 to get a color value.
// The colors are a transition r - g - b - back to r.
uint32_t Wheel(byte WheelPos) {
  WheelPos = 255 - WheelPos;
  if (WheelPos < 85) {
    return strip.Color(255 - WheelPos * 3, 0, WheelPos * 3);
  }
  if (WheelPos < 170) {
    WheelPos -= 85;
    return strip.Color(0, WheelPos * 3, 255 - WheelPos * 3);
  }
  WheelPos -= 170;
  return strip.Color(WheelPos * 3, 255 - WheelPos * 3, 0);
}

Individual Assignment

I would like to direct design this assignment in my final project.
The main work flows for my final project is I want to receiv the data remotely from the sensor. So the maincontroller have to connect with local WiFi as a server so that it can push the data to the MQTT Server.

1. Get Data via Sofware Serial

Because the PCB that I designed it not used the default USB connectors. So the first i need to do is get the data from software serial which can be a serial bus.
The fisrt thing i need to add here is define the software pin. Then the funtion will be the same as harware serial so that i can also use serial monitor at the same time.

#include <SoftwareSerial.h>
#define RX_Pin A2
#define TX_Pin A3

SoftwareSerial mySerial(RX_Pin, TX_Pin);
void setup() {
  Serial.begin(115200);
  mySerial.begin(115200);
  setup_wifi();
}

2. Connecting data then send the data via MQTT Server.

This is the very simple code for XIAO ESP32C3 WiFi function.
The main usage for this program is connecting Wifi via defarly wifi name and passward then coonect to MOTT and futher actions.

The main thing here is to repart the WiFi connection status and IP address which is very important for future actions.

#include <WiFi.h>
const char* ssid = "x.factory";       // WiFi Name
const char* password = "make0314";    // WiFi Password

void setup() {
  Serial.begin(115200);
  mySerial.begin(115200);
  setup_wifi();
}
void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();
  }
void setup_wifi() {
  delay(10);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

3. Source code and final showcase

Here is the source code for everything works.

#include <60ghzfalldetection.h>
#include <SoftwareSerial.h>
#include <WiFi.h>
#include <PubSubClient.h>
#include <Adafruit_NeoPixel.h>

// Define the pins for SoftwareSerial
#define RX_Pin A2
#define TX_Pin A3
#define LED_PIN 9

// Define the control inputs for a single motor
#define MOT_A1_PIN D0
#define MOT_A2_PIN D1

// MQTT Broker Details
const char* ssid = "x.factory";               // WiFi Name
const char* password = "make0314";    // WiFi Password
const char* mqtt_server = "mqtt.fabcloud.org"; // MQTT Broker Name
const char* mqtt_username = "fabacademy"; // MQTT Username
const char* mqtt_password = "fabacademy"; // MQTT Password
const char* mqtt_topic = "fabacademy/chaihuo/crail/sensor"; // MQTT Topic
const char* mqtt_topic1 = "fabacademy/chaihuo/crail/rawdata"; // MQTT Topic1
const char* mqtt_topic_fall = "fabacademy/chaihuo/crail/fall"; // MQTT Topic for Fall
const char* mqtt_topic_motor = "fabacademy/chaihuo/crail/motor"; // MQTT Topic for Motor Control

WiFiClient espClient;
PubSubClient client(espClient);

SoftwareSerial mySerial(RX_Pin, TX_Pin);
FallDetection_60GHz radar = FallDetection_60GHz(&mySerial);

Adafruit_NeoPixel strip = Adafruit_NeoPixel(24, LED_PIN, NEO_GRB + NEO_KHZ800);

bool motorSequenceExecuted = false;

void setup() {
  Serial.begin(115200);
  mySerial.begin(115200);
  setup_wifi();
  client.setServer(mqtt_server, 1883);
  client.setCallback(mqttCallback);
  client.subscribe(mqtt_topic_motor);

  strip.begin();
  strip.setBrightness(50);

  // Motor control setup
  pinMode(MOT_A1_PIN, OUTPUT);
  pinMode(MOT_A2_PIN, OUTPUT);

  // Turn off motor - Initial state
  digitalWrite(MOT_A1_PIN, LOW);
  digitalWrite(MOT_A2_PIN, LOW);
}

void loop() {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  radar.HumanExis_Func();
  if (radar.sensor_report != 0x00) {
    handleRadarReport(radar.sensor_report);
  }
}

void mqttCallback(char* topic, byte* payload, unsigned int length) {
  String message;
  for (unsigned int i = 0; i < length; i++) {
    message += (char)payload[i];
  }
  Serial.print("Message arrived on topic: ");
  Serial.print(topic);
  Serial.print(". Message: ");
  Serial.println(message);

  if (String(topic) == mqtt_topic_motor) {
    if (message == "ON") {
      runMotorSequence();
    } else if (message == "OFF") {
      stopMotor();
    }
  }
}

void runMotorSequence() {
  Serial.println("Running motor sequence...");

  // Ramp speed up.
  for (int i = 0; i < 6; i++) {
    spin_and_wait(25 * i, 150);
  }

  // Ramp speed into full reverse.
  for (int i = 0; i < 6 ; i++) {
    spin_and_wait(135 - 25 * i, 150);
  }

  // Stop.
  spin_and_wait(0, 100);

  Serial.println("Motor sequence completed.");
}

void stopMotor() {
  Serial.println("Stopping motor...");

  for (int i = 0; i < 6; i++) {
    spin_and_wait(-25 * i, 150);
  }

  // Ramp speed into full reverse.
  for (int i = 0; i < 6 ; i++) {
    spin_and_wait(-135 + 25 * i, 150);
  }

  Serial.println("Motor stopped.");
}

void handleRadarReport(uint8_t report) {
  String message;
  String message1;
  uint32_t color;
  switch (report) {
    case NOONE:
      message = "Nobody here.";
      color = strip.Color(0, 0, 0); // Off
      publishMQTT(mqtt_topic, message);
      break;
    case SOMEONE:
      message = "Someone is here.";
      color = strip.Color(255, 255, 255); // White
      publishMQTT(mqtt_topic, message);
      break;
    case NONEPSE:
      message = "No human activity messages.";
      color = strip.Color(0, 0, 0); // Off
      publishMQTT(mqtt_topic, message);
      break;
    case STATION:
    case MOVE:
      message = "Someone moving or stopped.";
      color = strip.Color(255, 255, 0); // Yellow
      publishMQTT(mqtt_topic, message);
      break;
    case BODYVAL:
      message1 = String(radar.bodysign_val, DEC);
      color = strip.Color(0, 255, 0); // Green
      publishMQTT(mqtt_topic1, message1);
      break;
    case FALL:
      message = "Someone fell!";
      color = strip.Color(255, 0, 0); // Red
      publishMQTT(mqtt_topic, message);
      publishMQTT(mqtt_topic_fall, message);
      break;
  }

  Serial.println(message);
  if (report == BODYVAL) {
    Serial.println(message1);
  }
  setColor(color); // Set LED color
  delay(200); // Delay for 0.2 seconds to prevent rapid flashing
}

void publishMQTT(const char* topic, String message) {
  if (!client.connected()) {
    reconnect();
  }
  client.loop();

  if (client.connected()) {
    client.publish(topic, message.c_str());
  }
}

void setup_wifi() {
  delay(10);
  Serial.println();
  Serial.print("Connecting to ");
  Serial.println(ssid);

  WiFi.mode(WIFI_STA);
  WiFi.begin(ssid, password);

  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }

  Serial.println("");
  Serial.println("WiFi connected");
  Serial.println("IP address: ");
  Serial.println(WiFi.localIP());
}

void reconnect() {
  while (!client.connected()) {
    Serial.print("Attempting MQTT connection...");
    String clientId = "XIAO-ESP32-Client-";
    clientId += String(random(0xffff), HEX);
    if (client.connect(clientId.c_str(), mqtt_username, mqtt_password)) {
      Serial.println("connected");
      client.subscribe(mqtt_topic_motor); // Subscribe to the motor control topic
    } else {
      Serial.print("failed, rc=");
      Serial.print(client.state());
      Serial.println(" try again in 5 seconds");
      delay(5000);
    }
  }
}

void setColor(uint32_t color) {
  for (uint16_t i = 0; i < strip.numPixels(); i++) {
    strip.setPixelColor(i, color);
  }
  strip.show();
}

/// Set the current on the motor using PWM and directional logic.
///
/// \param pwm    PWM duty cycle ranging from -255 full reverse to 255 full forward
/// \param IN1_PIN  pin number xIN1 for the given channel
/// \param IN2_PIN  pin number xIN2 for the given channel
void set_motor_pwm(int pwm, int IN1_PIN, int IN2_PIN) {
  if (pwm < 0) {  // reverse speeds
    analogWrite(IN1_PIN, -pwm);
    digitalWrite(IN2_PIN, LOW);
  } else { // stop or forward
    digitalWrite(IN1_PIN, LOW);
    analogWrite(IN2_PIN, pwm);
  }
}

/// Set the current on the motor.
///
/// \param pwm_A  motor A PWM, -255 to 255
void set_motor_current(int pwm_A) {
  set_motor_pwm(pwm_A, MOT_A1_PIN, MOT_A2_PIN);

  // Print a status message to the console.
  Serial.print("Set motor A PWM = ");
  Serial.println(pwm_A);
}

/// Simple primitive for the motion sequence to set a speed and wait for an interval.
///
/// \param pwm_A  motor A PWM, -255 to 255
/// \param duration delay in milliseconds
void spin_and_wait(int pwm_A, int duration) {
  set_motor_current(pwm_A);
  delay(duration);
}