• Elsewhere_IoT Project

An ambient reminder in the office that you're about to be late for your happy hour date!



Our intent is to provide an ambient reminder to an office-dweller that they have somewhere else to be in the next 15 minutes, perhaps a happy hour date.  We created an artistic light near the office door that intensifies as an appointment approaches, eventually creating red sharp arrows surrounding the office door. There are various power dynamics in place in an office that make wrapping up a meeting or sneaking out early difficult.  Our target user would not want a boss to know that mental energy is being spent unproductively.  The user could also feel awkward if co-workers knew that the light was a signal for this particular event, or that the light was a reminder for the user to ask others to bring their visit to a close.  At the same time, the user does not want to forget about an event, and does not want any record on a computer that could be monitored by the company's IT staff.



Our inspiration for this project was James Turell, a contemporary artist whose ethereal light displays convey an otherworldly sense of being at once very present and in another location.  Turell's pieces displace the viewer by daring him or her to slow down and examine their surroundings, while second guessing the nature of the place around them.   We wanted our users to be impacted by this ambient device as if they were viewing a Turell piece; at once very present in their current surroundings and also increasingly aware that there was a world outside of their office that was beckoning. 



There are a number of use cases for an ambient device that can react to an event in a calendar.  These can range in sensitivity depending on the particular event, but the hardware and display can remain the same.  This device is intended to be used in a personal office and is synced to an individual's private calendar. 



We started our project with the  goal of focusing on time management problems.  After a few hours of brainstorming, we knew that we wanted to create a device that could intensify to indicate to the user that an important event was approaching.  We turned to the office space, since it is an interesting joining of public and private; we need to maintain personal schedules in the office in tandem with the schedules of our coworkers and shared meetings.  We also hoped that our device could explore power dynamics that come into play as schedules are navigated.  We turned to a favorite artist, James Turell, for inspiration about intensification with time and needing to be elsewhere.   We saw a challenge that we wanted to try to tackle in harnessing his powerful imagery to convey meaning through data abstraction.

We ran into some challenges with material availability as we completed this project.  The iii studio is not stocked with an appropriate range of structural objects, and we found ourselves improvising to hack together an appropriate motor platform to convey our idea.  

We are very happy with the outcome of our effort, but would like to continue iterating by making a device that would work in a full scale office.  



We created a system for projecting light through a screen.  When the event is 15 minutes away, the LED ring turns on, creating an image around the door that cycles through various colors.  As the event nears, a conveyor controlled by two servo motors brings the LED ring closer to the screen, enlarging the image, and the rate at which the colors change increases as well.  The conveyor can be reset to respond to the next event.   Code, schematics, and additional documentation can be found below.


Bill of Materials

Qty.Part TypeNotes
2Basic Servo
1 2.1mm Barrel Jack with Terminal Block connected to 5-volt external power source
1Photon Particle Photon
1 16 NeoPixel Ring Adafruit
1 1kΩ Resistor tolerance ±5% 


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

#define PIXEL_COUNT 16   // dot count in the strip
#define PIXEL_PIN D0        // pin
#define PIXEL_TYPE WS2812

Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE);

int Color_Hue = 0;
int Color_Br = 0;
int FlagBreathe = 1;

int comingEvent = 0;
int pushEvent(String sEvent);

int effector1 = 0;
int effector2 = 0;
int effector3 = 3;

 int servoPinDig = D3;
 int servoPin2nd = D1;
 int servoPos = 0;
// int t=0; // millis counter
// int ledPin = D0;
 Servo myServo;
 Servo my2ndServo;

unsigned long tNextEvent = 0;
unsigned long tCurrent = 0;
long tRemain = 0;

struct RGB
	unsigned char R;
	unsigned char G;
	unsigned char B;

struct HSV
	double H;
	double S;
	double V;

struct RGB HSVToRGB(struct HSV hsv) {
	double r = 0, g = 0, b = 0;

	if (hsv.S == 0)
		r = hsv.V;
		g = hsv.V;
		b = hsv.V;
		int i;
		double f, p, q, t;

		if (hsv.H == 360)
			hsv.H = 0;
			hsv.H = hsv.H / 60;

		i = (int)trunc(hsv.H);
		f = hsv.H - i;

		p = hsv.V * (1.0 - hsv.S);
		q = hsv.V * (1.0 - (hsv.S * f));
		t = hsv.V * (1.0 - (hsv.S * (1.0 - f)));

		switch (i)
		case 0:
			r = hsv.V;
			g = t;
			b = p;

		case 1:
			r = q;
			g = hsv.V;
			b = p;

		case 2:
			r = p;
			g = hsv.V;
			b = t;

		case 3:
			r = p;
			g = q;
			b = hsv.V;

		case 4:
			r = t;
			g = p;
			b = hsv.V;

			r = hsv.V;
			g = p;
			b = q;


	struct RGB rgb;
	rgb.R = r * 255;
	rgb.G = g * 255;
	rgb.B = b * 255;

	return rgb;

int movemotor(String pos){
    int ipos = pos.toInt();
    return 1;

int cancelthis(String command){
    tNextEvent = 0;
    return 1;

void setup() {
    myServo.attach( servoPinDig );
  my2ndServo.attach( servoPin2nd );

    Particle.function("pushEvent", pushEvent);
    Particle.function("movemotor", movemotor);
    Particle.function("cancelthis", cancelthis);
    Particle.variable("comingEvent", &comingEvent, INT);
    Particle.variable("tNextEvent", &tNextEvent, INT);
    Particle.variable("effector1", &effector1, INT);
    Particle.variable("effector2", &effector2, INT);
    Particle.publish("COUNT_EVENT_UPDATE","Current Time: "+String(Time.now()));
    tCurrent = Time.now(); 

void lightdot(int extent, int Br = 255, int stColor = 240, int edColor = 0){
    int Color_H = constrain(map(extent,0,254,stColor,edColor),0,240);
    Br = constrain(Br,-1,255);
      struct HSV C_HColor = { Color_H, 1, 1 };  //0-360, 0-1
    struct RGB C_RColor = HSVToRGB(C_HColor);
    for (int i=0;i<PIXEL_COUNT;i=i+2){   //only use a half of dots, no enough power for all
        strip.setPixelColor(i, C_RColor.R,C_RColor.G , C_RColor.B);
    if (Br < 0){
    if (Color_Br <= 10) {
        Color_Br = 10;
        FlagBreathe = FlagBreathe * -1;
    if (Color_Br >= 255) {
        Color_Br = 255;
        FlagBreathe = FlagBreathe * -1;
        Color_Br += FlagBreathe * effector3;
    } else {


void loop() {
    tCurrent = Time.now();
    tRemain = tNextEvent - tCurrent;
    if (tRemain > (-1*3*60) && (tRemain) < (15*60)){
        effector1 = React(tRemain,15,3,0,255);   // effector act from 15 min remain and gradully go to max value at 5 min remain;
        effector2 = React(tRemain,15,3,5,175);    // effector act from 7 min remain and gradully go to max value at 0 min remain;
        effector3 = React(tRemain,7,0,3,15);
        Particle.publish("COUNT_EVENT_UPDATE","Time Remain: "+String(tRemain)+"; EF1: "+String(effector1)+"; EF2: "+String(effector2));


int React(int cT, int sMin, int mMin, int sOut, int mOut){
    int sMsec = sMin * 60;
    int mMsec = mMin * 60;
    return constrain(map(cT,mMsec,sMsec,mOut,sOut),sOut,mOut);

void individualServo(int distance){  
  distance = constrain(distance,3,179);


int pushEvent(String sEvent){     ///IFTTT PUSH EVENT
//    Particle.publish("IFTTT_PUSH",sEvent);
    if ((tNextEvent - Time.now()) > (-1*3*60) && (sEvent != "force")) {  // new push wont overwrite a in progress, un-expired notificition
        return -1;

    tNextEvent = Time.now() + (15 * 60);
    Particle.publish("IFTTT_PUSH","Event: "+sEvent+"; Time: "+String(tNextEvent));
    return 1;
Click to Expand

IFTTT Configure



This project incorporated mechanical, electrical, software, and design elements.  While each of us presented ideas and separated the project into parts based on our strengths, the project really came together when we helped each other design and implement the parts together.

There were a number of items that would be changed in a more refined product.  Mechanically, the components would be sized appropriately, screwed into surfaces or glued on instead of being taped.  We could not obtain a rack and pinion, and we did not have enough pulleys and rollers to make a high-quality conveyor belt.  Even with one servo motor, it was difficult to find an adequate pulley that fit over an available axle; we simulated a conveyor belt using two servos rotating in the same direction.  We experimented with continuous servos but found that the inconsistencies between them combined with our mechanical imprecision made open-loop coding with time delays too unreliable.

From a software perspective, it is inconvenient to test the code with mechanical components using a 15-minute timer.  We adjusted the code to have both servos rotate on a much shorter time scale to show proof of concept.  Ideally, the overall product would be externally wireless.  Perhaps multiple reminders can be incorporated into one device using different colors with patterns whose meanings are known only to the user.

Share this Project


49713 Designing for the Internet of Things

· 25 members

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

Focused on

An ambient reminder in the office that you're about to be late for your happy hour date!


February 7th, 2018