Introduction: Paixsphere
How music and light work as a therapeutic resource
Effection of Nervous System:
Music influences brainwaves, heart rate, and hormone levels. Slow rhythms can relax the body and upbeat music can energize it. Light affects the brain’s production of melatonin (sleep hormone) and serotonin (mood regulator), helping balance sleep, energy, and emotional stability.
Triggering Emotions:
Music can bring out deep emotions, memories, or even physical reactions, like tears. Light, especially color and brightness, can shape the emotional tone of a space
Create a Safe Sensory Environment
When used together, music and light create a controlled, immersive environment where people can relax, reflect, or express themselves without any interventions; a powerful tool in therapy.
Inspiration/Main Approach:
In the current status quo, 1 out of 8 people have a psychological disorder. In 2019, there were about 970 million people around the world living with mental disorders. However, from the covid pandemic in 2020, the rate has increased up to 28%. Although effective preventions and treatments exist, most people do not have access to effective care. Music therapy is known to be effective and is often underestimated. The sessions require focus and coordination, which normally could distract thoughts from mental disorders. Nevertheless, the standard cost of music therapies are $180 per hour. It may not be affordable for some people due to its price. Additionally, As the change in family structure centered on single-person households continues, their social isolation and disconnection are also deepening. The product can help alleviate this issue. As mentioned before, it could work as a therapy tool. The product works similarly to music therapy, but more affordable. This would be helpful for people in the future that are socially isolated as well. For instance, single-person households help handle the main issue. From this, I got an inspiration to create a product that helps alleviate mental disorders, but at the same time effective and affordable.
Supplies
MCU _ ESP32 DevkitC V4
Heart Beat Sensor _ Arduino heartbeat sensor electromyography SZH-SSBH-035
Bluetooth Module _ MH-M38 Module
Speaker _ 3inch 4Ohm 15W
LED _ Neopixel LED Strip
Battery Charger _ TP4056 5V 1A
Battery _ 18650 350mAh with Protect Shield
Battery holder for 18650 Battery
DC-DC Step Up Module _ XL6009 4A DC Converter
Kexcelled PLA Matte _ Black, Tech Grey, White
Jumper Cables
Step 1: Planning
- Thumbnail Sketch: Sketched ideas to visualize the concept of the final product
- The sketches were originally mimicking the exterior aspects of a VR headset or a headphone. The design has changed significantly from the initial visualizations compared to the final outcome
- Choosing Project Name:
- Combined with the french word for peace/pax, Paix, and the word atmosphere; means a peaceful atmosphere.
- Project Key Color:
- Chosen Colors:
- PQ-11-4001TCX, Brilliant White
- 11-4001 TPG
- 11-1001 TPG
- Purpose: Choose pastel colors in order to evoke soft, gentle, and calming emotions. Low in saturation and high in lightness, pastel colors are often used in Romantic or dreamy themes, Springtime or baby-related designs, or Mental health/wellness visuals.
- Change from initial plan
- Initially planned outcome was a headphone with a screen on top of as if it was a VR headset. However, it wasn’t clear if it suits the purpose because it would be only working as a musical device. Therefore, the product changed to a speaker incorporating ambient light. This alternative could meet the approach more adequately.
- Design references:
- Design Ideas:
- Final product model:
- Why?
- Unique shape with plausible design to create and has the general form of a sphere, which also suits name
Step 2: Survey
Created a survey to discern test subjects for the prototype
Questions:
- What is the stress level you are experiencing these days? Write a number between 1-10(1 - none, 10 - innumerable).
- Do you have any psychiatric illnesses?
- If yes, what kind do you have?
- If you have a psychiatric illness, how do you take care of it?
- What therapy do you take?
- If not, do you have any type of phobia?
- Do you attend therapy sessions, or ever been to one?
- Do you enjoy listening to music?
- What kind?(Pop, Classical, Jazz, Rock, Other)
- What color do you like?(Write specific colors or color schemes. ex: blue, warm colors)
- What color makes you feel comfortable?(Write specific colors or color schemes. ex: blue, warm colors)
- Do you listen to music while sleeping?
- If you do, what kind?(Instrumental, Nature sounds, Classical, Hiphop, etc.)
- What color do you think generally makes people feel comfortable?
- Would you like to participate in the Paixsphere prototype test?
Paixsphere survey results
Step 3: 3D Modeling
As shown previously, the first model was made with tinkercad. In order to make the model more detailed and prepared for 3D modeling, the design was made in Fusion 360. It could make simulations of the model, which allowed better preparation than tinkercad.
Step 4: 3D Printing - Test Print, Final Prototype Print
Test print - We printed the dummy model of the product in two sizes – one with a smaller size than original and the other one with actual size – and saw how it felt like to hold it with our hands. This helped to adjust the placement of the on/off button and the heart sensor based on the position of the hands.
Final prototype print - Using the information got by the dummy model, we made holes in advance during printing and assembled them together. While printing, in order to get a strong structure of the product, we slanted the model by 30 degrees in order to increase the merged area of the layers. The fuzzy skin technique allowed me to express a cozier sense.
Step 5: Physical Computing - LED, Heartbeat Sensor, Control
Using the ESP32 Dev Kit V4 with the MH38 board, we connected the speaker to bluetooth. We used one battery or the USB 5V 2A to do the power of the entire product. It is expected that the model will work 2 hours with the full charged battery. Therefore, it is recommended to use the product with the charging cable for increased time of use.
While using the SZH SSBH 035 sensor, it is necessary to block the light passing the back of the sensor with a black object in order to get accurate results.
Below are the boards, power button, and sensor connection used.
- Sensor: S(signal)
- ESP32 board pin: GPIO 34
- Role: Analog Input
- description: Pin for reading the analog signal from the heart rate sensor.
- + (VCC)
- ESP32 board pin: 3.3V
- Role: Power source
- Description: Pin that supplies power to the sensor.
- – (GND)
- ESP32 board pin: GND
- Role: Ground
- Description: Ground pin of the sensor.
- NeoPixel LED 스트립
- Data
- ESP32 board pin: GPIO 13
- Role: Digital output
- Description: Pin for sending data signals to the NeoPixel strip.
- 5V
- ESP32 board pin: External 5V Power
- Role: Power source
- Description: Supplies power to the LED strip (The board’s 5V pin may not supply enough current, so an external power source is recommended)
- GND
- ESP32 board pi: GND
- Role: Ground
- Description: Ground pin of the LED strip, Must be connected in common with the ESP32 board’s GND
## 2. Firmware (ESP32 C++ Code)
This code runs on the Geekble Mini (ESP32). It sets up the BLE server, handles LED color/brightness commands, and streams heart rate sensor data.
File: paixspheare_firmware.ino
/*
* PAIXSPHEARE BLE FIRMWARE (ESP32)
* Functions: LED Control (Write) + Heart Rate Monitoring (Notify)
* ⚠️ Ensure Heart Rate Sensor is connected to an ADC1 pin (e.g., GPIO 36).
*/
#include <BLEDevice.h>
#include <BLEUtils.h>
#include <BLEServer.h>
#include <Adafruit_NeoPixel.h>
#include <BLE2902.h>
// --- Hardware Pin Configuration ---
#define LED_PIN 7 // NeoPixel LED Pin (GPIO 7)
#define HEARTBEAT_PIN 36 // Heart Rate Sensor Pin (Example: GPIO 36 / A0)
#define NUM_LEDS 33 // Number of NeoPixel LEDs
Adafruit_NeoPixel pixels(NUM_LEDS, LED_PIN, NEO_GRB + NEO_KHZ800);
// --- BLE UUID Configuration (MUST match the HTML/JS code) ---
#define SERVICE_UUID "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
#define COLOR_CHAR_UUID "beb5483e-36e1-4688-b7f5-ea07361b26a8"
#define BRIGHTNESS_CHAR_UUID "c83059f0-0051-4091-a12b-a8108e860d5b"
#define HEARTBEAT_CHAR_UUID "a1b2c3d4-e5f6-a7b8-c9d0-e1f2a3b4c5d6"
// --- Global Variables ---
BLECharacteristic *pHeartbeatCharacteristic;
bool deviceConnected = false;
// --- BLE Callbacks ---
// 1. LED Color Control Callback
class ColorCharacteristicCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
String value = pCharacteristic->getValue(); // Use Arduino String
if (value.length() == 3) {
uint8_t r = value[0];
uint8_t g = value[1];
uint8_t b = value[2];
Serial.printf("Setting color: R=%d, G=%d, B=%d\n", r, g, b);
for (int i = 0; i < NUM_LEDS; i++) {
pixels.setPixelColor(i, pixels.Color(r, g, b));
}
pixels.show();
}
}
};
// 2. LED Brightness Control Callback
class BrightnessCharacteristicCallbacks: public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic *pCharacteristic) {
String value = pCharacteristic->getValue(); // Use Arduino String
if (value.length() == 1) {
uint8_t brightness = value[0];
Serial.printf("Setting brightness: %d\n", brightness);
pixels.setBrightness(brightness);
pixels.show();
}
}
};
// 3. Server Connection/Disconnection Callback
class MyServerCallbacks: public BLEServerCallbacks {
void onConnect(BLEServer* pServer) {
deviceConnected = true;
Serial.println("Client Connected");
}
void onDisconnect(BLEServer* pServer) {
deviceConnected = false;
Serial.println("Client Disconnected");
BLEDevice::startAdvertising();
}
};
// --- Setup ---
void setup() {
Serial.begin(115200);
Serial.println("Starting PAIXSPHEARE BLE Server...");
pinMode(HEARTBEAT_PIN, INPUT);
pixels.begin();
pixels.setBrightness(128);
pixels.show();
// Initialize BLE Device
BLEDevice::init("PAIXSPHEARE_Controller"); // New Device Name
BLEServer *pServer = BLEDevice::createServer();
pServer->setCallbacks(new MyServerCallbacks());
BLEService *pService = pServer->createService(SERVICE_UUID);
// 1. Color Characteristic (Write)
BLECharacteristic *pColorCharacteristic = pService->createCharacteristic(
COLOR_CHAR_UUID,
BLECharacteristic::PROPERTY_WRITE
);
pColorCharacteristic->setCallbacks(new ColorCharacteristicCallbacks());
// 2. Brightness Characteristic (Write)
BLECharacteristic *pBrightnessCharacteristic = pService->createCharacteristic(
BRIGHTNESS_CHAR_UUID,
BLECharacteristic::PROPERTY_WRITE
);
pBrightnessCharacteristic->setCallbacks(new BrightnessCharacteristicCallbacks());
// 3. Heartbeat Characteristic (Notify)
pHeartbeatCharacteristic = pService->createCharacteristic(
HEARTBEAT_CHAR_UUID,
BLECharacteristic::PROPERTY_NOTIFY |
BLECharacteristic::PROPERTY_READ
);
pHeartbeatCharacteristic->addDescriptor(new BLE2902());
pService->start();
// Start Advertising
BLEAdvertising *pAdvertising = BLEDevice::getAdvertising();
pAdvertising->addServiceUUID(SERVICE_UUID);
BLEDevice::startAdvertising();
Serial.println("BLE Advertising started.");
}
// --- Loop ---
void loop() {
if (deviceConnected) {
// Read raw analog value from sensor
int sensorValue = analogRead(HEARTBEAT_PIN);
// Convert 12-bit (0-4095) value to 2 bytes (Uint16)
uint8_t data[2];
data[0] = sensorValue & 0xFF; // Low byte
data[1] = (sensorValue >> 8) & 0xFF; // High byte
// Set value and send notification
pHeartbeatCharacteristic->setValue(data, 2);
pHeartbeatCharacteristic->notify();
// Serial.printf("Sent HR Sensor Value: %d\n", sensorValue);
}
delay(100); // Send data every 100ms
Attachments
Step 6: Control Interface
## 3. Control Interface (Web Bluetooth HTML)
This HTML file uses JavaScript to connect to the ESP32 via Bluetooth and provide the user interface. Save this as index.html in VSCode.
File: index.html
<!DOCTYPE html>
<html>
<head>
<title>PAIXSPHEARE BLE Control</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body { font-family: Arial, sans-serif; text-align: center; margin-top: 30px; background-color: #f0f0f0; }
.controller { max-width: 400px; margin: 0 auto; padding: 20px; background-color: white; border-radius: 10px; box-shadow: 0 4px 10px rgba(0,0,0,0.1); }
button { background-color: #007BFF; color: white; padding: 12px 20px; border: none; border-radius: 5px; font-size: 16px; cursor: pointer; margin-bottom: 20px; }
button:hover { background-color: #0056b3; }
button:disabled { background-color: #ccc; }
input[type="color"] { width: 150px; height: 150px; border: none; padding: 0; cursor: pointer; display: block; margin: 15px auto; }
input[type="range"] { width: 90%; margin-top: 10px; }
#heartRateDisplay { font-size: 28px; color: #d9534f; font-weight: bold; margin-top: 20px; background-color: #f9f9f9; padding: 15px; border-radius: 5px; }
#status { font-style: italic; color: #777; }
</style>
</head>
<body>
<h1>PAIXSPHEARE Control Panel</h1>
<div class="controller">
<button id="connectButton">1. Connect via Bluetooth</button>
<p id="status">Waiting for connection...</p>
<hr>
<h2>❤️ Heart Rate Sensor Value</h2>
<div id="heartRateDisplay">---</div>
<p style="font-size: 12px; color: #777;">(Raw 12-bit Analog Value)</p>
<hr>
<h2>🎨 LED Color</h2>
<input type="color" id="colorPicker" value="#000000" disabled>
<h2>💡 LED Brightness</h2>
<input type="range" id="brightnessSlider" min="0" max="255" value="128" disabled>
<span id="brightnessValue">128</span>
</div>
<script>
// --- UUIDs MUST match the C++ code ---
const SERVICE_UUID = "4fafc201-1fb5-459e-8fcc-c5c9c331914b";
const COLOR_CHAR_UUID = "beb5483e-36e1-4688-b7f5-ea07361b26a8";
const BRIGHTNESS_CHAR_UUID = "c83059f0-0051-4091-a12b-a8108e860d5b";
const HEARTBEAT_CHAR_UUID = "a1b2c3d4-e5f6-a7b8-c9d0-e1f2a3b4c5d6";
let colorCharacteristic;
let brightnessCharacteristic;
let heartbeatCharacteristic;
// --- UI Elements ---
const connectButton = document.getElementById('connectButton');
const statusDisplay = document.getElementById('status');
const colorPicker = document.getElementById('colorPicker');
const brightnessSlider = document.getElementById('brightnessSlider');
const brightnessValue = document.getElementById('brightnessValue');
const heartRateDisplay = document.getElementById('heartRateDisplay');
// --- Event Listeners ---
connectButton.onclick = connectToBLE;
colorPicker.oninput = writeColor;
brightnessSlider.oninput = writeBrightness;
brightnessSlider.onchange = writeBrightness; // Ensure change event also fires
brightnessSlider.onmousemove = updateBrightnessDisplay; // Update display continuously
function updateBrightnessDisplay() {
brightnessValue.innerText = brightnessSlider.value;
}
// 1. Connect to BLE Device
async function connectToBLE() {
try {
statusDisplay.innerText = "Attempting to connect...";
// Request device based on Service UUID
const bleDevice = await navigator.bluetooth.requestDevice({
filters: [{ name: "PAIXSPHEARE_Controller" }], // Filter by name for clarity
optionalServices: [SERVICE_UUID]
});
statusDisplay.innerText = "Connecting to GATT server...";
const server = await bleDevice.gatt.connect();
statusDisplay.innerText = "Discovering services and characteristics...";
const service = await server.getPrimaryService(SERVICE_UUID);
// Get Characteristics
colorCharacteristic = await service.getCharacteristic(COLOR_CHAR_UUID);
brightnessCharacteristic = await service.getCharacteristic(BRIGHTNESS_CHAR_UUID);
heartbeatCharacteristic = await service.getCharacteristic(HEARTBEAT_CHAR_UUID);
statusDisplay.innerText = "Subscribing to Heart Rate Notifications...";
// Subscribe to Heartbeat Notifications
await heartbeatCharacteristic.startNotifications();
heartbeatCharacteristic.addEventListener('characteristicvaluechanged', handleHeartbeat);
statusDisplay.innerText = "Connection successful! PAIXSPHEARE is ready.";
connectButton.disabled = true;
colorPicker.disabled = false;
brightnessSlider.disabled = false;
} catch (error) {
console.error("BLE Connection Error:", error);
statusDisplay.innerText = `Connection Failed: ${error.message}`;
}
}
// 2. Handle Heart Rate Data (Notify)
function handleHeartbeat(event) {
const value = event.target.value; // DataView object
// Read 2-byte (Uint16) value sent from ESP32
// 'true' indicates Little Endian format
const sensorValue = value.getUint16(0, true);
heartRateDisplay.innerText = sensorValue;
}
// 3. Send Color Value (Write)
function writeColor() {
if (!colorCharacteristic) return;
let hex = colorPicker.value.substring(1);
let r = parseInt(hex.substring(0, 2), 16);
let g = parseInt(hex.substring(2, 4), 16);
let b = parseInt(hex.substring(4, 6), 16);
// Send 3-byte data
const data = new Uint8Array([r, g, b]);
colorCharacteristic.writeValue(data)
.catch(err => console.error("Color Write Failed:", err));
}
// 4. Send Brightness Value (Write)
function writeBrightness() {
if (!brightnessCharacteristic) return;
let brightness = parseInt(brightnessSlider.value);
brightnessValue.innerText = brightness;
// Send 1-byte data
const data = new Uint8Array([brightness]);
brightnessCharacteristic.writeValue(data)
.catch(err => console.error("Brightness Write Failed:", err));
}
</script>
</body>
</html>
Step 7: Test
Recognized errors:
- Needed to change the IP address every single time when the product started working, therefore the music wasn't able to connect properly .
Attachments
Step 8: Finalization
Improvements made from the test:
- Made the dynamic IP into a static IP
- Changed Wi-Fi to Bluetooth
- Added multiple small speakers to produce stereo sound from mono; and develop everything on a single board.
Attachments
Step 9: Future Plan
The images above are screenshots of what the application showcases. It requires to type in:
- Name
- Age
- Gender
- Job
- Stress rate(1-10)
- Music title(what you want to listen to)
- Singer
After that, it shows bluetooth connection, BPM rate, and LED light controller. This is made so that the users could easily access the object.
This application was created for potential paixsphere users in the future, but needed some improvements.
One of the main problem was that due to the phones' strict privacy policy, the bluetooth would not connect easily. This was also happening because the application would only open on google chrome. Therefore, the next step might be actually launching an application for the paixsphere if it becomes an actual product.







