Final Project: Reimagining the LoveBox

Made by Tyler White, Sarah Kuzniewski, Bennett Goeke and Tobi Aina · UNLISTED (SHOWN IN POOLS)

Use calm technology to improve the everyday digital messaging experience.

Created: December 18th, 2023

0

Intention

Our group found the reading on calm technology very interesting and persuasive. When brainstorming ideas we all talked about our dislike of notifications that basically yell at you to pay attention to them and how the different ways that can negatively affect you – jarring sound if you’re not expecting it, a clear disruption from your focus on something else. So one of our main areas for a potential use case was how can we use calm technology to improve on some current design and/or notification system.

From there we settled on coming up with a less intrusive way to message other people. We all preferred texting over phone calls, but the fact you have to use your phone to receive / look at messages when you get them opens you up to a whole slew of other distractions when you’re checking the message. It also requires you to keep your phone nearby, which puts you at risk of being distracted by notifications for other apps as well.

We considers other options as well, but several of the other ideas took us in directions that we thought would be too complex for our level of understanding and the time available to create the project. We talked about smart blinds, smart glasses, and even how to design a google home / Alexa that would incorporate more light options for notifications instead of just sound notifications. 

0

Historical Case

We selected the LoveBox because it was an example of an IoT device that implemented SMS messaging while also being ambient. It serves as a great alternative to the other connected devices that users need to be consistently engaged with to be effect, like normal sms. The LoveBox provides an example of calm technology influencing communication apps, but still allowing for meaningful and timely communication in the future of ubiquitous computing. Users still have all the connectedness of a regular phone, but carry much less propensity for distraction and/or disruption. We believe this increases the emotional or sentimental value that is attached to messages by refocusing all the emphasis on the actual message instead of it being split across several different potential distraction points.


0

Approach

The approach involved studying the Lovebox's design, functionality, and user experience. We aimed to replicate its core features while incorporating our own twist. We didn’t divert too much from the original design of the box. Only making alterations that would get us to a proof of concept sooner. We removed the lid and added a button, as we thought this would make the development of the box much simpler. We’d seen buttons on other similar devices that we’d researched, and they seemed to be a positive addition to the overall concept that created a simple but meaningful way for users to engage with the device and notify the sender they’d received the message.

We tried to revive the device's essential features. We mainly focused on the integration of the LCD screen as well as the unique feature of the spinning heart, which acts as the notification signal that a message has been received. We thought it created a delightful and engaging experience for the user and was one of the most important aspects of the device. 

0

Process

The journey began with a detailed analysis of Lovebox mechanics. We then sketched out our prototype, iterated on design, and implemented the chosen features. We went through a few different ideas on how to incorporate the main parts, if we’d be able to figure out the screen, what the size of the box would be, and how we’d create the box. But overall our initial ideas were what we followed through on.

Experimentation involved moments of success, such as achieving the spinning heart effect, as well as challenges, such as fine-tuning the mechanism for optimal performance. It was tough at first to get the screen to work and we needed some support with figuring out the right code for it. We also were unsure of which motor would be the best to use. We chose to use a DC motor but eventually were told other options would likely have been better because they’d have provided a more options when programming.

Initial plans underwent adjustments, particularly in the choice of materials for the spinning heart mechanism, based on real-world testing. At first we weren’t sure how to design the heart or how to attach it, but after a few trials we figured out what we thought would work best for the prototype.

0

Prototype

Regarding code, the first thing worked on was the screen. Getting images to display accurately was the first real test. Then the work shifted to adding the motor and button that triggered the images onto the display. Regarding the design, the first thing worked on was measuring out the box the device would be housed in and then deciding what material would be used and how to cut it. From there the box was cut, stained and pieced together.

The biggest challenge was the wiring of all the components because they needed to be packaged in a tight box. This meant that wires would often come out slightly and it would be very hard to diagnose where the problem wires were. On the design side of the physical space we didn’t run into many problems. We were unsure however about how the motor would stay in place to spin properly but we were able to resolve that when designing the box itself.

If we were doing this again we would try to work on a better way of packaging the device and find a better way to cleanly connect components to the breadboard with less jump cables. How we went about it worked, but it was very congested. We’d also work to create a better experience regarding interacting with the device to inform it the message has been received. The button we were using turned out to be cumbersome and placed in an inconvenient location.

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


// This #include statement was automatically added by the Particle IDE.
#include "Adafruit_ST77xx.h"

// This #include statement was automatically added by the Particle IDE.
#include "Adafruit_ST7789.h"

// This #include statement was automatically added by the Particle IDE.
// #include "Adafruit_ST7735.h"


//#include "Adafruit_ST7789.h"
#include "SPI.h"
//#include "Adafruit_GFX.h"

// You can't really have two of these on the same pins, but this is just to make sure it compiles
// It's not a working example.
// I've removed the examples because it's not possible to have dependencies for individual examples
// and the necessary libraries won't be included and the build will fail. Since other boards like
// the miniTFTWing have their own examples, you should just test this library with those examples.

Adafruit_ST7789 st7789(&SPI1, D2, D3, D4);

int buttonPin = D3;
int solPin = D2;
bool displaySmile = false;

bool displaySad = false;
bool displayHeart = false;
bool displayCry = false;
bool displayUnsat = false;

#if defined(ARDUINO_FEATHER_ESP32) // Feather Huzzah32
  #define TFT_CS         14
  #define TFT_RST        15
  #define TFT_DC         32

#elif defined(ESP8266)
  #define TFT_CS         4
  #define TFT_RST        16
  #define TFT_DC         5

#else
  // For the breakout board, you can use any 2 or 3 pins.
  // These pins will also work for the 1.8" TFT shield.
  #define TFT_CS        A5
  #define TFT_RST        -1 // Or set to -1 and connect to Arduino RESET pin
  #define TFT_DC         D8
#endif

// OPTION 1 (recommended) is to use the HARDWARE SPI pins, which are unique
// to each board and not reassignable. For Arduino Uno: MOSI = pin 11 and
// SCLK = pin 13. This is the fastest mode of operation and is required if
// using the breakout board's microSD card.

//Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_RST);

// OPTION 2 lets you interface the display using ANY TWO or THREE PINS,
// tradeoff being that performance is not as fast as hardware SPI above.
#define TFT_MOSI 11  // Data out
#define TFT_SCLK 13  // Clock out

Adafruit_ST7789 tft = Adafruit_ST7789(TFT_CS, TFT_DC, TFT_MOSI, TFT_SCLK, TFT_RST);


float p = 3.1415926;

void setup(void) {
  Serial.begin(9600);
  tft.fillScreen(ST77XX_BLACK);

  // Use this initializer (uncomment) if using a 1.3" or 1.54" 240x240 TFT:
  //tft.init(240, 240);           // Init ST7789 240x240

  // OR use this initializer (uncomment) if using a 1.69" 280x240 TFT:
  //tft.init(240, 280);           // Init ST7789 280x240

  // OR use this initializer (uncomment) if using a 2.0" 320x240 TFT:
  //tft.init(240, 320);           // Init ST7789 320x240

  // OR use this initializer (uncomment) if using a 1.14" 240x135 TFT:
  //tft.init(135, 240);           // Init ST7789 240x135
  
  
  // OR use this initializer (uncomment) if using a 1.47" 172x320 TFT:
  tft.init(200, 240);           // Init ST7789 172x320
//   tft.init(320, 320);       //clears screen


  // OR use this initializer (uncomment) if using a 1.9" 170x320 TFT:
  //tft.init(170, 320);           // Init ST7789 170x320

  // SPI speed defaults to SPI_DEFAULT_FREQ defined in the library, you can override it here
  // Note that speed allowable depends on chip and quality of wiring, if you go too fast, you
  // may end up with a black screen some times, or all the time.
  //tft.setSPISpeed(40000000);
  

  // a single pixel
//   tft.drawPixel(tft.width()/2, tft.height()/2, ST77XX_GREEN);
//   delay(500);


    pinMode(buttonPin, INPUT_PULLUP);
  
    Particle.function( "emojiSmile", activateSolenoid );
    Particle.function( "emojiSad", activateSad );
    Particle.function( "emojiHeart", activateHeart );
    Particle.function( "emojiCry", activateCry );
    Particle.function( "emojiUnsat", activateUnsat );
    pinMode(solPin, OUTPUT);
    
}

void loop() {
    
    
    
    if( displaySmile ){
        doSmile(  );
        displaySmile = false;
        
    }
    
    if( displaySad ){
        doSad(  );
        displaySad = false;
    }
    
    if( displayHeart ){
        doHeart(  );
        displayHeart = false;
    }
    
    if( displayCry ){
        doCry(  );
        displayCry = false;
    }
    
    if( displayUnsat ){
        doUnsat(  );
        displayUnsat = false;
    }
}

void doSmile() {
    // digitalWrite(solPin, HIGH);
    tft.fillScreen(ST77XX_BLACK);

    for (int i = 0; i < 2; i++) {
        digitalWrite(solPin, HIGH);
        delay(100);
        digitalWrite(solPin, LOW);
        delay(1000);
    }

    // Wait for the button to be pressed
    while (digitalRead(buttonPin) != LOW) {
        // You can add optional delay here to avoid busy-waiting
        // delay(100);
    }

    // Button is pressed, proceed to displaySmiley
    displaySmiley();
    
}

void doSad(){
    
tft.fillScreen(ST77XX_BLACK);

    for (int i = 0; i < 2; i++) {
        digitalWrite(solPin, HIGH);
        delay(100);
        digitalWrite(solPin, LOW);
        delay(1000);
    }

    // Wait for the button to be pressed
    while (digitalRead(buttonPin) != LOW) {
        // You can add optional delay here to avoid busy-waiting
        // delay(100);
    }

    // Button is pressed, proceed to displaySmiley
    displaySady();
    
}

void doHeart(){
    
tft.fillScreen(ST77XX_BLACK);

    for (int i = 0; i < 2; i++) {
        digitalWrite(solPin, HIGH);
        delay(100);
        digitalWrite(solPin, LOW);
        delay(1000);
    }

    // Wait for the button to be pressed
    while (digitalRead(buttonPin) != LOW) {
        // You can add optional delay here to avoid busy-waiting
        // delay(100);
    }

    // Button is pressed, proceed to displaySmiley
    displayHearty();
    
}

void doCry(){
    
tft.fillScreen(ST77XX_BLACK);

    for (int i = 0; i < 2; i++) {
        digitalWrite(solPin, HIGH);
        delay(100);
        digitalWrite(solPin, LOW);
        delay(1000);
    }

    // Wait for the button to be pressed
    while (digitalRead(buttonPin) != LOW) {
        // You can add optional delay here to avoid busy-waiting
        // delay(100);
    }

    // Button is pressed, proceed to displaySmiley
    displayCryFace();
    
}

void doUnsat(){
    
tft.fillScreen(ST77XX_BLACK);

    for (int i = 0; i < 2; i++) {
        digitalWrite(solPin, HIGH);
        delay(100);
        digitalWrite(solPin, LOW);
        delay(1000);
    }

    // Wait for the button to be pressed
    while (digitalRead(buttonPin) != LOW) {
        // You can add optional delay here to avoid busy-waiting
        // delay(100);
    }

    // Button is pressed, proceed to displaySmiley
    displayUnsatFace();
    
}

int activateCry( String command ){
    displayCry = true;
    return 1;
    
}

int activateUnsat( String command ){
    displayUnsat = true;
    return 1;
    
}

int activateHeart( String command ){
    displayHeart = true;
    return 1;
    
}

int activateSolenoid( String command ){
    displaySmile = true;
    return 1;
    
}
    
int activateSad( String command ){
    displaySad = true;
    return 1;

}

void displayCryFace() {
  // draw face
  tft.fillScreen(ST77XX_BLACK);
  tft.fillCircle(120, 120, 50, ST77XX_YELLOW);
  
  //draw mouth
  tft.fillCircle(145, 120, 18, ST77XX_BLACK);

  // draw left eye

  tft.fillCircle(110, 145, 15, ST77XX_BLACK);  // Swap X and Y coordinates and adjust
  tft.fillCircle(110, 145, 5, ST77XX_YELLOW);  // Swap X and Y coordinates and adjust
  tft.fillRect(110, 120, 22.5, 41, ST77XX_YELLOW);  // Swap X and Y coordinates and adjust
  
  // draw right eye
  tft.fillCircle(110, 105, 15, ST77XX_BLACK);  // Swap X and Y coordinates and adjust
  tft.fillCircle(110, 105, 5, ST77XX_YELLOW);  // Swap X and Y coordinates and adjust
  tft.fillRect(110, 80, 22.5, 41, ST77XX_YELLOW);  // Swap X and Y coordinates and adjust
  
  tft.fillRect(105, 145, 120, 10, ST77XX_BLUE);  // Swap X and Y coordinates
  tft.fillRect(105, 95, 120, 10, ST77XX_BLUE);  // Swap X and Y coordinates

}

void displayUnsatFace() {
  // draw face
  tft.fillScreen(ST77XX_BLACK);
  tft.fillCircle(120, 120, 50, ST77XX_YELLOW);

  // draw mouth (unsatisfied)
  tft.fillRect(140, 100, 12.5, 45, ST77XX_BLACK);  // Adjust Y coordinate and size for unsatisfied mouth

  for (int i = 0; i < 5; ++i) {
  // draw eyes (horizontal rectangles for unsatisfied eyes)
  tft.fillRect(100, 95, 20, 10, ST77XX_BLACK);   // Adjust X, Y coordinates, and size for left eye
  tft.fillRect(100, 135, 20, 10, ST77XX_BLACK);  // Adjust X, Y coordinates, and size for right eye
  
  delay(300);
  
  tft.fillRect(100, 95, 20, 10, ST77XX_YELLOW);   // Adjust X, Y coordinates, and size for left eye
  tft.fillRect(100, 135, 20, 10, ST77XX_YELLOW);  // Adjust X, Y coordinates, and size for right eye  
  
  delay(100);
  
  tft.fillRect(110, 90, 10, 20, ST77XX_BLACK);   // Adjust X, Y coordinates, and size for right eye
  tft.fillRect(110, 140, 10, 20, ST77XX_BLACK);  // Adjust X, Y coordinates, and size for left eye
  
  delay(1000);
  
  tft.fillRect(110, 90, 10, 20, ST77XX_YELLOW);   // Adjust X, Y coordinates, and size for right eye
  tft.fillRect(110, 140, 10, 20, ST77XX_YELLOW);  // Adjust X, Y coordinates, and size for left eye
  
  delay(150);
  
  }
  
  tft.fillRect(110, 90, 10, 20, ST77XX_BLACK);   // Adjust X, Y coordinates, and size for right eye
  tft.fillRect(110, 140, 10, 20, ST77XX_BLACK);  // Adjust X, Y coordinates, and size for left eye
  
}

void displaySmiley() {
  // draw face
  tft.fillScreen(ST77XX_BLACK);
  tft.fillCircle(120, 120, 50, ST77XX_YELLOW);

  // draw mouth
  tft.fillCircle(130, 120, 30, ST77XX_BLACK);  // Swap X and Y coordinates and adjust
  tft.fillRect(85, 90, 45, 65, ST77XX_YELLOW);  // Swap X and Y coordinates and adjust

  // loop for blinking eyes
  for (int i = 0; i < 5; ++i) {
    // draw eyes
    tft.fillCircle(110, 100, 10, ST77XX_BLACK);  // Swap X and Y coordinates
    tft.fillCircle(110, 140, 10, ST77XX_BLACK);  // Swap X and Y coordinates and adjust

    delay(500); // adjust the delay time to control the blinking speed

    // clear eyes
    tft.fillCircle(110, 100, 10, ST77XX_YELLOW);  // Swap X and Y coordinates
    tft.fillCircle(110, 140, 10, ST77XX_YELLOW);  // Swap X and Y coordinates and adjust

    delay(500); // adjust the delay time to control the blinking speed
  }
  
  tft.fillCircle(110, 100, 10, ST77XX_BLACK);  // Swap X and Y coordinates
  tft.fillCircle(110, 140, 10, ST77XX_BLACK);  // Swap X and Y coordinates and adjust
  
}

void displaySady() {
  // draw face
  tft.fillScreen(ST77XX_BLACK);
  tft.fillCircle(120, 120, 50, ST77XX_YELLOW);

  // draw mouth
  tft.fillCircle(145, 120, 20, ST77XX_BLACK);  // Swap X and Y coordinates and adjust
  tft.fillCircle(145, 120, 10, ST77XX_YELLOW);  // Swap X and Y coordinates and adjust
  tft.fillRect(145, 100, 22.5, 41, ST77XX_YELLOW);  // Swap X and Y coordinates and adjust



  // loop for blinking eyes
  for (int i = 0; i < 5; ++i) {
    // draw eyes
    tft.fillCircle(110, 100, 10, ST77XX_BLACK);  // Swap X and Y coordinates
    tft.fillCircle(110, 140, 10, ST77XX_BLACK);  // Swap X and Y coordinates and adjust

    delay(500); // adjust the delay time to control the blinking speed

    // clear eyes
    tft.fillCircle(110, 100, 10, ST77XX_YELLOW);  // Swap X and Y coordinates
    tft.fillCircle(110, 140, 10, ST77XX_YELLOW);  // Swap X and Y coordinates and adjust

    delay(500); // adjust the delay time to control the blinking speed
  }
  
  tft.fillCircle(110, 100, 10, ST77XX_BLACK);  // Swap X and Y coordinates
  tft.fillCircle(110, 140, 10, ST77XX_BLACK);  // Swap X and Y coordinates and adjust
  
}

void displayHearty() {
  // draw heart
  tft.fillScreen(ST77XX_BLACK);

  // draw triangle for the top part of the heart
  tft.fillTriangle(170, 120, 110, 70, 110, 170, ST77XX_RED);

  // draw left half of heart using a circle
  tft.fillCircle(100, 100, 30, ST77XX_RED);

  // draw right half of heart using a circle
  tft.fillCircle(100, 140, 30, ST77XX_RED);
  
  for (int i = 0; i < 3; ++i) {
      tft.fillTriangle(170, 120, 110, 70, 110, 170, ST77XX_BLACK);

      // draw left half of heart using a circle
      tft.fillCircle(100, 100, 30, ST77XX_BLACK);
    
      // draw right half of heart using a circle
      tft.fillCircle(100, 140, 30, ST77XX_BLACK);
    
        delay(50); // adjust the delay time to control the blinking speed
    
      tft.fillTriangle(170, 120, 110, 70, 110, 170, ST77XX_RED);

      // draw left half of heart using a circle
      tft.fillCircle(100, 100, 30, ST77XX_RED);
    
      // draw right half of heart using a circle
      tft.fillCircle(100, 140, 30, ST77XX_RED);
      
        delay(50); // adjust the delay time to control the blinking speed
      }

  // draw left half of heart using a circle
  tft.fillCircle(100, 100, 30, ST77XX_RED);  
  
  // draw triangle for the bottom part of the heart
  tft.fillTriangle(170, 120, 110, 70, 110, 170, ST77XX_RED);

  // draw right half of heart using a circle
  tft.fillCircle(100, 140, 30, ST77XX_RED);
  
}
Click to Expand
0
Final Project Demo
Tyler White - https://youtube.com/shorts/x2l1nAUjU10?feature=share
0

Reflection and Critique:

Our team acquired knowledge in mechanical design, microcontroller programming, user experience considerations in IoT, and what goes into designing an meaningful and effective physical space for a product. The professors who engaged with us on pitch day also provided lots of tips on how to improve on our design that most of us had not thought of before. 

Future steps may involve enhancing connectivity, exploring mobile app integration, and refining the design for a market-ready product. Other things would be to consider different ways of interacting with the box other than through the button. We got some good comments about touched based interactions as well as knocking interactions. This would make interacting with the box more intimate than using a button.

0

Acknowledgements:

Professor Byrne provided us with libraries to use to get the screen up and running. 

Zhenfang helped us make the initial steps with the tft screen and allow us to start designing the emojis for the project.

x
Share this Project

This project is only listed in this pool. Be considerate and think twice before sharing.


Courses

48-675 Designing for the Internet of Things

· 11 members

A hands-on introductory course exploring the Internet of Things and connected product experiences.


About

Use calm technology to improve the everyday digital messaging experience.