CK Cooper
Published © MIT

Smart Grounding Sculpture

This smart sculpture helps calm and reduce anxiety by guiding people through a grounding exercise which engages the senses..

IntermediateFull instructions providedOver 3 days81
Smart Grounding Sculpture

Things used in this project

Hardware components

Photon
Particle Photon
×1
Flora RGB Neopixel LEDs- Pack of 4
Adafruit Flora RGB Neopixel LEDs- Pack of 4
×10
SG90 Micro-servo motor
SG90 Micro-servo motor
×1
Breadboard (generic)
Breadboard (generic)
×1
Solderless Breadboard Half Size
Solderless Breadboard Half Size
×1
Gravity:Digital Push Button (Yellow)
DFRobot Gravity:Digital Push Button (Yellow)
×2

Software apps and online services

Adafruit web feed
Zapier

Hand tools and fabrication machines

Wire Stripper & Cutter, 18-10 AWG / 0.75-4mm² Capacity Wires
Wire Stripper & Cutter, 18-10 AWG / 0.75-4mm² Capacity Wires
wire feed welder
silicone mold

Story

Read more

Custom parts and enclosures

Smart Grounding sculpture Scent box

Smart Grounding sculpture Scent box lid

Smart Grounding sculpture, scent box lid

Smart Grounding sculpture, scent box top

Smart Grounding sculpture, Sign standoff

Schematics

Smart Grounding sculpture

Smart Grounding sculpture, breadboard

Code

Smart Grounding sculpture

C/C++
/* 
 * Project Capstone
 * Author: CKCooper
 * Date: 11/28/2023
 * For comprehensive documentation and examples, please visit:
 * https://docs.particle.io/firmware/best-practices/firmware-template/
 */

// Include Particle Device OS APIs
#include "Particle.h"
#include <neopixel.h>
#include "Colors.h"
#include <Adafruit_MQTT.h>
#include "Adafruit_MQTT/Adafruit_MQTT_SPARK.h"
#include "Adafruit_MQTT/Adafruit_MQTT.h"
#include "IoTTimer.h"
#include "Button.h"
#include "credentials.h"


TCPClient TheClient; 
IoTTimer pixelTimer;
Servo myServo;
IoTTimer scentTimer;
Button startButton(D5);
Button scentButton(D6);
Adafruit_NeoPixel pixel(10, SPI1, WS2812B);

// Setup the MQTT client class by passing in the WiFi client and MQTT server and login details. 
Adafruit_MQTT_SPARK mqtt(&TheClient,AIO_SERVER,AIO_SERVERPORT,AIO_USERNAME,AIO_KEY); 

/****************************** Feeds ***************************************/ 
// Setup Feeds to publish or subscribe 
// Notice MQTT paths for AIO follow the form: <username>/feeds/<feedname> 
Adafruit_MQTT_Subscribe buttonFeed = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/buttononoff"); 
Adafruit_MQTT_Subscribe scentFeed = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/scentbutton"); 
// Let Device OS manage the connection to the Particle Cloud

//variables
const int SERVPIN = D13;
const int COUNT=5;
int counter;
int scentCounter;
int subValue,subValue1;
//functions
int randomPixel();
void MQTT_connect();
bool MQTT_ping();


SYSTEM_MODE(SEMI_AUTOMATIC);

// Run the application and system concurrently in separate threads
SYSTEM_THREAD(ENABLED);

// Show system, cloud connectivity, and application logs over USB
// View logs with CLI using 'particle serial monitor --follow'
SerialLogHandler logHandler(LOG_LEVEL_INFO);

void setup() {
  Serial.begin(9600);
  waitFor(Serial.isConnected,10000);

  pixel.begin();
  pixel.setBrightness(255);
  pixel.show();

  pixelTimer.startTimer(1000);
  scentTimer.startTimer(1000);
  counter=COUNT;
  scentCounter=COUNT;

  WiFi.on();
  WiFi.connect();
  while(WiFi.connecting()) {
    Serial.printf(".");
  }
  Serial.printf("\n\n");

  mqtt.subscribe(&buttonFeed);
  mqtt.subscribe(&scentFeed);

  myServo.attach(SERVPIN);

}

void loop() {
  MQTT_connect();
  MQTT_ping();

//buttons to manually start the lights and open the scent box
  if(startButton.isClicked()){
  Serial.printf("pixel button is clicked\n");
    counter = 0;
  }
//counter
  if(counter<COUNT){
    counter=counter+randomPixel();
  }
  else{
    if(pixelTimer.isTimerReady()){
      pixel.clear();
      pixel.show();
  }
  }

if(scentButton.isClicked()){
  Serial.printf("scent button is clicked\n");
  scentCounter=0;
  scentTimer.startTimer(1);
}

// switch case for servo to move the opening to one side of the box, then the other side of the box and then close
if(scentTimer.isTimerReady()) {
     switch (scentCounter){
      case 0:
          Serial.printf("Scent Counter %i\n",scentCounter);
          myServo.write(125);
          scentCounter++;
          scentTimer.startTimer(5000);
          break;
      case 1:
          Serial.printf("Scent Counter %i\n",scentCounter);
          myServo.write(10);
          scentCounter++;
          scentTimer.startTimer(5000);
          break;
      case 2:
          Serial.printf("Scent Counter %i\n",scentCounter);
          myServo.write(75);
          scentCounter++;
          scentTimer.startTimer(5000);
          break;
      }
}

Adafruit_MQTT_Subscribe *subscription;
  while ((subscription = mqtt.readSubscription(1000))) {
    if (subscription == &buttonFeed) {
      subValue = atoi((char *)buttonFeed.lastread);
      Serial.printf("Button Subscription %i \n", subValue);
    
    if(subValue==1){
      counter=0;
    }
    }
    if (subscription == &scentFeed) {
      subValue1 = atoi((char *)scentFeed.lastread);
      Serial.printf("scent Subscription %i \n", subValue1);
    
    if(subValue1==2){
      scentCounter=0;
      scentTimer.startTimer(1);
    }
    }
}
}
// Function to connect and reconnect as necessary to the MQTT server.
// Should be called in the loop function and it will take care if connecting.
void MQTT_connect() {
  int8_t ret;
 
  // Return if already connected.
  if (mqtt.connected()) {
    return;
  }
 
  Serial.print("Connecting to MQTT... ");
 
  while ((ret = mqtt.connect()) != 0) { // connect will return 0 for connected
       Serial.printf("Error Code %s\n",mqtt.connectErrorString(ret));
       Serial.printf("Retrying MQTT connection in 5 seconds...\n");
       mqtt.disconnect();
       delay(5000);  // wait 5 seconds and try again
  }
  Serial.printf("MQTT Connected!\n");
}

bool MQTT_ping() {
  static unsigned int last;
  bool pingStatus;

  if ((millis()-last)>120000) {//this lets adafruit know we're still here
      Serial.printf("Pinging MQTT \n");
      pingStatus = mqtt.ping();
      if(!pingStatus) {
        Serial.printf("Disconnecting \n");
        mqtt.disconnect();
      }
      last = millis();
  }
  return pingStatus;
}
// function to return a random color on a random pixel on a timer
int randomPixel(){
  int whichPix;
  int randColor;
  int value;

  value=0;
  if(pixelTimer.isTimerReady()){
      pixel.clear();
      whichPix=random(10);
      randColor=random(7);
      Serial.printf("Pixel %i and Color %i \n", whichPix, randColor);
      pixel.setPixelColor(whichPix, rainbow[randColor]);
      pixel.show();
      pixelTimer.startTimer(5000);
      value=1;
  } 

  return value;
}

Credits

CK Cooper
3 projects • 2 followers
I am a sculptor building smart technology into my work to make it more interactive and fun.
Contact

Comments

Please log in or sign up to comment.