Freya - Networking

Made by Freya Yang

The goal of networking exercise is for the design and development of How’s the Weather project. We want to design and prototype an interactive IoT device that leverages real-time communication to create a shared emotional connection between friends. By combining tactile interaction with visual feedback, the project aimed to explore how everyday emotional check-ins can be enhanced through tangible, responsive design.

Created: December 15th, 2024

0

Intention:

The goal of the How’s the Weather networking project was to design and prototype an interactive IoT device that leverages real-time communication to create a shared emotional connection between friends. By combining tactile interaction with visual feedback, the project aimed to explore how everyday emotional check-ins can be enhanced through tangible, responsive design.

Specifically, we sought to:

  1. Enable friends to communicate emotional states (represented as weather patterns) using synchronized devices connected over a network.
  2. Demonstrate real-time interaction, where a simple physical input on one device triggers a corresponding light-based response on a paired device.
  3. Explore affordances for physical interaction—particularly through a bird-shaped touch interface—and refine how mood-based communication can be natural, expressive, and non-intrusive.
  4. Investigate how metaphors like weather can provide accessible and universal representations of human emotions, encouraging deeper reflection and connection.


0

Process

This connecting assignment is part of our prototype process. We started by connecting a basic pressure sensor to an LED light to test input-output functionality. After achieving reliable lighting control, we connected two devices via Particle Photon microcontrollers. When one user pressed the sensor on their device, the paired device lit up in real time, successfully achieving synchronized emotional communication.

During development, I ensured each light pattern for the weather states was separated into its own event. This allowed us to publish and test each event individually. However, when the same code was uploaded to the second device and tested, the devices failed to respond to each other. We suspected the issue was tied to the way events were titled and attempted to simplify the titles to numerical names for easier debugging. With assistance from our TA, we were able to successfully network the devices and ensure real-time communication. However, we encountered an additional issue with the sunny and cloudy patterns: they would only flash momentarily at the start of each event. To resolve this, we introduced millis() for timing control and added delays to simulate a longer-lasting light pattern. This approach successfully created the desired behavior for these two states, while the rain and thunderstorm effects required no further adjustment due to their existing functionality.

0
// This #include statement was automatically added by the Particle IDE.
#include <neopixel.h>

#include "Particle.h"
#include "neopixel.h"

SYSTEM_MODE(AUTOMATIC);

// Define pin and NeoPixel configuration for Photon 2
#if (PLATFORM_ID == 32)
#define NEOPIXEL_PIN SPI // Use MOSI for Photon 2
#else
#define NEOPIXEL_PIN D3 // Use D3 for other Particle devices
#endif

#define NUM_PIXELS 8     // Number of LEDs in the NeoPixel strip
#define PIXEL_TYPE WS2812B // Specify the NeoPixel type

// Pressure sensor pin
#define PRESSURE_PIN A0

// Create a NeoPixel object
Adafruit_NeoPixel strip(NUM_PIXELS, NEOPIXEL_PIN, PIXEL_TYPE);

void setup() {
    strip.begin();   // Initialize NeoPixel strip
    strip.show();    // Turn off all LEDs initially
    Serial.begin(9600); // Debugging

    // Subscribe to events from the Particle Cloud
    Particle.subscribe("weatherEvent", weatherEventHandler);
}

// Function prototypes for weather effects
void thunderEffect();
void rainEffect();
void cloudyEffect();
void sunnyEffect();

// Function to publish weather events
void publishWeatherEvent(const char* eventName) {
    String event = String("weatherEvent/") + eventName;
    Particle.publish(event);  // Publish the event with the prefix
    weatherEventHandler(event.c_str(), ""); // Call event handler immediately
}

// Particle event handler
void weatherEventHandler(const char* event, const char* data) {
    String eventString = String(event);

    if (eventString == "weatherEvent/sunny") {
        sunnyEffect(); // Call sunny effect function
    }
    else if (eventString == "weatherEvent/cloudy") {
        cloudyEffect(); // Call cloudy effect function
    }
    else if (eventString == "weatherEvent/rainy") {
        rainEffect(); // Call rainy effect function
    }
    else if (eventString == "weatherEvent/thunder") {
        thunderEffect(); // Call thunder effect function
    }
}

void loop() {
    // Read the pressure sensor value
    int pressure = analogRead(PRESSURE_PIN);
    Serial.println(pressure); // Debugging the sensor value

    // Determine weather event based on pressure level
    if (pressure > 3600) {
        publishWeatherEvent("thunder");
    } else if (pressure > 2700) {
        publishWeatherEvent("rainy");
    } else if (pressure > 1800) {
        publishWeatherEvent("cloudy");
    } else if (pressure > 900) {
        publishWeatherEvent("sunny");
    } else {
        strip.clear(); // Turn off LEDs when pressure is too low
        strip.show();
    }
}

// Thunder: Blue and yellow flash
void thunderEffect() {
    for (int i = 0; i < NUM_PIXELS; i++) {
        strip.clear();
        if (i % 2 == 0) {
            strip.setPixelColor(i, strip.Color(0, 0, 128)); // Dim blue
        } else {
            strip.setPixelColor(i, strip.Color(128, 128, 0)); // Dim yellow
        }
        strip.show();
        delay(50);
    }
    strip.clear();
    strip.show();
}

// Rain: Light dim blue light
void rainEffect() {
    for (int i = 0; i < NUM_PIXELS; i++) {
        strip.clear();
        strip.setPixelColor(i, strip.Color(0, 0, 128)); // Dim blue
        strip.show();
        delay(100);
    }
}

// Cloudy: Dim violet/lavender light
void cloudyEffect() {
    static int brightness = 0;
    static int direction = 5;

    brightness += direction;
    if (brightness >= 100 || brightness <= 0) {
        direction = -direction;
    }

    uint32_t color = strip.Color(75 + brightness, 50 + brightness, 150 + brightness); // Dim lavender/violet
    for (int i = 0; i < NUM_PIXELS; i++) {
        strip.setPixelColor(i, color);
    }
    strip.show();
    delay(50);
}

// Sunny: Warm orange light
void sunnyEffect() {
    static int brightness = 0;
    static int direction = 5;

    brightness += direction;
    if (brightness >= 255 || brightness <= 50) {
        direction = -direction;
    }

    uint32_t color = strip.Color(255, 140, 0); // Warm orange
    for (int i = 0; i < NUM_PIXELS; i++) {
        strip.setPixelColor(i, color);
    }
    strip.show();
    delay(50);
}
Click to Expand
0
#include "Particle.h"
#include "neopixel.h"

SYSTEM_MODE(AUTOMATIC);

// Define pin and NeoPixel configuration for Photon 2
#if (PLATFORM_ID == 32)
#define NEOPIXEL_PIN SPI // Use MOSI for Photon 2
#else
#define NEOPIXEL_PIN D3 // Use D3 for other Particle devices
#endif

#define NUM_PIXELS 8     // Number of LEDs in the NeoPixel strip
#define PIXEL_TYPE WS2812B // Specify the NeoPixel type

// Pressure sensor pin
#define PRESSURE_PIN A0

// This value will store the last time we published an event
long lastPublishedAt = 0;
// this is the time delay before we should publish a new event
int publishAfter = 10000;

// Create a NeoPixel object
Adafruit_NeoPixel strip(NUM_PIXELS, NEOPIXEL_PIN, PIXEL_TYPE);

void setup() {
    strip.begin();   // Initialize NeoPixel strip
    strip.show();    // Turn off all LEDs initially
    Serial.begin(9600); // Debugging

    // Subscribe to shared events
    Particle.subscribe("weatherEvent/shared", weatherEventHandler);
}

// Function prototypes for weather effects
void thunderEffect();
void rainEffect();
void cloudyEffect();
void sunnyEffect();

// Function to publish weather events
void publishWeatherEvent(const char* eventName) {
    String event = String("weatherEvent/shared/") + System.deviceID() + "/" + eventName;
    Particle.publish(event);  // Publish the shared event
    weatherEventHandler(event.c_str(), ""); // Call event handler immediately for local effect
    delay(1000);
}

// Particle event handler
void weatherEventHandler(const char* event, const char* data) {
    String eventString = String(event);
    Serial.println(eventString);
    // Ignore events originating from this device
    // if (eventString.indexOf(System.deviceID()) != -1) return;

    // Parse the event name to determine the weather condition
    if (eventString.endsWith("/sunny")) {
        sunnyEffect();
    } else if (eventString.endsWith("/cloudy")) {
        cloudyEffect();
    } else if (eventString.endsWith("/rainy")) {
        rainEffect();
    } else if (eventString.endsWith("/thunder")) {
        thunderEffect();
    }
}

void loop() {
    // Read the pressure sensor value
    int pressure = analogRead(PRESSURE_PIN);
    // Serial.println(pressure); // Debugging the sensor value

    // Determine weather event based on pressure level
    if (pressure > 3600) {
        publishWeatherEvent("thunder");
    } else if (pressure > 2700) {
        publishWeatherEvent("rainy");
    } else if (pressure > 1800) {
        publishWeatherEvent("cloudy");
    } else if (pressure > 900) {
        publishWeatherEvent("sunny");
    } else {
        strip.clear(); // Turn off LEDs when pressure is too low
        strip.show();
    }
}

// Thunder: Blue and yellow flash
void thunderEffect() {
    for (int i = 0; i < NUM_PIXELS; i++) {
        strip.clear();
        if (i % 2 == 0) {
            strip.setPixelColor(i, strip.Color(0, 0, 128)); // Dim blue
        } else {
            strip.setPixelColor(i, strip.Color(128, 128, 0)); // Dim yellow
        }
        strip.show();
        delay(50);
    }
    strip.clear();
    strip.show();
}

// Rain: Light dim blue light
void rainEffect() {
    for (int i = 0; i < NUM_PIXELS; i++) {
        strip.clear();
        strip.setPixelColor(i, strip.Color(0, 0, 128)); // Dim blue
        strip.show();
        delay(100);
    }
}

// Cloudy: Dim violet/lavender light
void cloudyEffect() {
    static int brightness = 0;
    static int direction = 5;

    brightness += direction;
    if (brightness >= 100 || brightness <= 0) {
        direction = -direction;
    }

    uint32_t color = strip.Color(75 + brightness, 50 + brightness, 150 + brightness); // Dim lavender/violet
    for (int i = 0; i < NUM_PIXELS; i++) {
        strip.setPixelColor(i, color);
    }
    strip.show();
    delay(50);
}

// Sunny: Warm orange light
void sunnyEffect() {
    static int brightness = 0;
    static int direction = 5;

    brightness += direction;
    if (brightness >= 255 || brightness <= 50) {
        direction = -direction;
    }

    uint32_t color = strip.Color(255, 140, 0); // Warm orange
    for (int i = 0; i < NUM_PIXELS; i++) {
        strip.setPixelColor(i, color);
    }
    strip.show();
    delay(50);
}
Click to Expand
0
0
0
x
Share this Project


About

The goal of networking exercise is for the design and development of How’s the Weather project. We want to design and prototype an interactive IoT device that leverages real-time communication to create a shared emotional connection between friends. By combining tactile interaction with visual feedback, the project aimed to explore how everyday emotional check-ins can be enhanced through tangible, responsive design.