49713 Designing for the Internet of Things
· 18 members
A hands-on introductory course exploring the Internet of Things and connected product experiences.
Found in Diot 2019: Social Objects - Part 3
Our project is an interactive installation that investigates what viral messages would look like in analog form, in public places where social interactions rarely occur anymore. Can we re-analog-ize viral information and nudge social interactions at bus stops?
Social media has quickly turned social information sharing into such a fast form that the term ‘viral’ was added to our daily vernacular. Instead of exploring how we can place social interactions on the web and create digital interactions, we wish to turn what the world has been focusing on for the last few decades and create social interactions that stem from the digital web to our daily ‘analog’ lives. More specifically, how might we ‘re-analog-ize’ the virality of social information sharing?
We were inspired by interactive public art installations Lightswarm and Mesa Musical Shadows, that use IoT to enable interactive experiences for the public. Lightswarm, created by the Future Cities Lab’s Jason Kelly Johnson, Nataly Gattegno, and Ripon DeLeon, uses vibration sensors on glass panels to detect viewer’s movements that turn the Yerba Buena Center for the Arts into a beautiful reactive art installation. Similarly, Mouna Andraos’ Mesa Musical Shadows is an interactive installation that uses speaker in pavement of a public space to create music using the shadows of passersby to play different singing voices.
Furthermore, we were inspired by the different bus installations the bus stop on the corner of Forbes and Craig have every couple of months. The bus stop is next to the Carnegie Museum of Art’s entrance, and so different artists have used the bus stop as a medium for their installations. For example, Busnegie Museum of Art was started by arts activist, Suzanne Weder, who bought out the ad space of that bus stop and replaces it with works by local artists. “Weder came up with the idea to use shelders - what she calls “the most egalitarian spaces that exist in Pittsburgh”- to promote public art and, potentially, as a way to boost the careers of local arts by exposing them to art professionals visiting the Carnegie International” (Walts for the PGH City Paper).
Inspired by Busnegie and the interactive public art installation, we decided to design an ambient experience that would turn a bus stop into a reactive space that responds to controversial tweets and spreads that experience based on the reactions of the people at that stop. We chose to have President Donald Trump’s Tweets on foreign policy as the feed for this project as it is a wildly popular and heavily viral content that many people retweet and share in the digital world. However, we wanted our installation to provoke people to react and share their feelings about these topics in the real world.
Commuters would see and hear an output that would indicate a certain topic of controversy being tweeted about online - in our case, @realDonalTrump's tweets on US foreign policy topics, more specifically when he tweets about policies affecting other countries around the world (i.e. China, Russia, Syria, Venezuela and Mexico). Based on how much audio response the users give to the experience at the first bus stop (i.e. conversations amongst the other commuters or in conversations on the phone reacting to the subject audibly) the sound of those conversations triggers the experience can be initialized at another bus stop in their field of view or within earshot. Based on the reaction at this bus stop another will be triggered to the bus stop across the street or down the street and so on and so forth. Creating an audiovisual indication of the controversy going viral in public spaces through people’s conversations, not just the virtual world.
I. Research: Whilst brainstorming ideas, our group first decided to list out what were the themes that we wanted our project to tackle. We ended up with the following words, “provocation”, “public space”, “interactive and social” and “no phones”. As mentioned earlier we were inspired by Mouna Andraos’s Mesa Musical Shadows and Future Cities Lab’s Lightswarm interactive public art installations as well as the Forbes and Craig bust stop that has different art installations. We initially had an idea to have social bus stops in different cities that would react when someone in a different city pushes a button, however, after our first feedback session with the class, we realized it was too complicated and does not really have a clear objective. Brainstorming again, we came up with the Viral Bus Stop idea.
II. Proposal: Use IoT sensors to outfit multiple bus stops that would react to tweets from President Donald Trump’s twitter account. When the President tweets about foreign policy issues concerning other countries (we’ve focused on the most tweeted about currently: Mexico, Venezuela, China, Russia, and Syria), the first bus stop plays the most popular music from that country and lights up the country’s flag colors. If there are people in the bus stop at that moment that are reacting (moving, talking to each other), then that reaction activates the same music and light output in the closest bus stop. This enables the first bus stop to ‘see and hear’ the viral information spreading. This theoretically could continue for multiple bus stops.
III. Creating and Iterating:
A. Component Selection:
Step 1: Light Output Write code and wire circuit to ensure that the output works for each given input (5 countries = different flag colors on the Neopixel).
Step 2: Connectivity: Linked the output code with the input event being triggered by a contextual tweet through IFTTT. We could not use @realDonuldTrump’s real account as we needed more control over the input and so linked it to Lama’s twitter account @lamaalfulaij. We tested it multiple times and adjusted code to ensure that it would output different light patterns based on the tweet’s content.
Step 3: Sensors: Hook up PIR sensor and Sparkfun sound detector to trigger the next event at the next bus stop. We struggled with the sound detector as the music output as well as the general noise level of bus stops would be too difficult to calibrate. We decided to just stick to the PIR sensor.
Step 4: Music output: We really struggled with the music output. We initially planned to pull from Spotify’s top 50 most played song of each country’s but did not find a good way of doing so, so we turned to the DFPlayer Mini. After multiple tries and help from Dylan and Daragh, we still could not figure out why two different players were still not working.
Step 5: Putting it all together: Once we ensured each component was working separately, we drew out an ideal circuitry for both bus stops and assembled all the components together to ensure all the parts of the experience were working the right way. We then started to think about how this whole idea would come together in real life and be translated into a mockup of a street corner.
C. Code:
See Execution I- Code for actual code.
See Execution II- Circuitry for fritzing diagrams.
E. Creating Form: As this is would be a large installation, we decided to create a mockup of the street corner where two of the bus stops would be located. We started by creating a foam core mock-up of the street and two bus stops to test how the assembly of the components would look like and to adjust our dimensions. We measured out how far each component needed to be so we could solder the right about of wiring.
See Form core mock up with assembled parts picture
The code was composed of 3 main pieces of functionality needed for the concept to work:
Each piece of the code was used to define a part of the interaction process. A set of tools and structures were used to create the flow of events.
We set the code for each bus stop up with the necessary pin variables, a standard speed at which the flag colors function should change each pixel in the strip and a boolean to denote whether or not there is movement being sensed by the PIR (for bus stop 1 only).
// This #include statement was automatically added by the Particle IDE.
#include <neopixel.h>
//initialize the boolean variable for movement to false.
bool motion = false;
//set the speed of the lights to cycle through one
int lightSpeed = 100;
//define pin for the PIR sensor
int PIRpin = D2;
//define neopixel ring
#define PIXEL_PIN D3
#define PIXEL_COUNT 28 //bus stop #2 has 14 pixels
#define PIXEL_TYPE WS2812
Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE);
//RGBW and CYMK colors as global variables
uint32_t w = strip.Color(255, 255, 255);// white (all on)
uint32_t r = strip.Color(255, 0, 0); // red
uint32_t y = strip.Color(255, 255, 0); // yellow
uint32_t g = strip.Color(0, 255, 0); // green
uint32_t c = strip.Color(0, 255, 255); // cyan
uint32_t b = strip.Color(0, 0, 255); // blue
uint32_t m = strip.Color(255, 0, 255); // magenta (pink/purple)
uint32_t k = strip.Color(0, 0, 0); // black (all off)
void setup()
{
/*Subscribe to a set of events published when an IFTTT widget is triggered by
a tweeting. The first one is connected to the account of a teammate for demo
purposes, the second one is connected to donaldTrump's twitter acound and the
last one is independent of a username so any other account can be used.*/
Particle.subscribe("ChenMutiatLama/2019/Group4/LamaAlFulaij", action );
Particle.subscribe("ChenMutiatLama/2019/Group4/realDonaldTrump", action );
Particle.subscribe("ChenMutiatLama/2019/Group4/tweet", action );
Particle.variable ("Motion",motion);
//PIR is readable
pinMode (PIRpin, INPUT_PULLDOWN);
//Initialize all pixels to 'off'
strip.begin();
strip.show();
}
Click to Expand
IFTTT
Using IFTTT and the action function, the first bus stop will act based upon a tweet. If This Then That or IFTTT was applied to publish a public particle event starting with the string "ChenMutiatLama/2019/Group4" if @LamaAlFulaji or @realDonaldTrump sent a tweet. The event would denote the username in the event name and publish the tweet as the data.
Particle IDE
Then in our code, the action function was used as an event handler. The data is used to determine if a country whose flag is accounted for is mentioned in the tweet. To account for tweets that mention nationality (Chinese for China or Israeli for Israel) some of the strings seem concatenated but are the prefix for the country name and the name of its people. After determining the correct action to take the function initializes the process that checks the reaction and concludes the action by turning off the neopixels.
void setup()
{
/*Subscribe to a set of events published when an IFTTT widget is triggered by
a tweeting. The first one is connected to the account of a teammate for demo
purposes, the second one is connected to donaldTrump's twitter acound and the
last one is independent of a username so any other account can be used.*/
Particle.subscribe("ChenMutiatLama/2019/Group4/LamaAlFulaij", action );
Particle.subscribe("ChenMutiatLama/2019/Group4/realDonaldTrump", action );
Particle.subscribe("ChenMutiatLama/2019/Group4/tweet", action );
Particle.variable ("Motion",motion);
//PIR is readable
pinMode (PIRpin, INPUT_PULLDOWN);
//Initialize all pixels to 'off'
strip.begin();
strip.show();
}
// Our event handler requires two bits of information
// This gives us:
// A character array that consists of the event name
// A character array that contains the data published in the event
// we're responding to.
void action(const char *event, const char *data){
//Particle.publish("acting");
String m = strstr(data, "mexic" );
String mCaps = strstr(data, "Mexic" );
String r = strstr(data, "russia" );
String rCaps = strstr(data, "Russia" );
String s = strstr(data, "syria" );
String sCaps = strstr(data, "Syria" );
String i = strstr(data, "israel" );
String iCaps = strstr(data, "Israel" );
String v = strstr(data, "venezuela" );
String vCaps = strstr(data, "Venezuela" );
String c = strstr(data, "chin" );
String cCaps = strstr(data, "Chin" );
String country = "no";
if(m!=NULL|| mCaps!=NULL){
mexicanFlag();
}
else if(r!=NULL|| rCaps!=NULL){
russianFlag();
}
else if(s!=NULL|| sCaps!=NULL){
syrianFlag();
}
else if(i!=NULL|| iCaps!=NULL){
israeliFlag();
}
else if(v!=NULL|| vCaps!=NULL){
venezuelanFlag();
}
else if(c!=NULL|| cCaps!=NULL){
chineseFlag();
}
else{
rainbow();
}
//check for a reaction
checkReaction(data);
turnoff();
}
Click to Expand
Based on a set of conditional statements, a countries flag colors are shown in sequence on the neopixel strip based on a list of colors specified in a predefined function for that country. If no country or nationality is recognized the neopixel cycles through the rainbow. It pulses and ultimately turns off while it checks the motion sensor.
The flagColors function takes a list of unsigned 32-bit integers, which is the datatype for neopixel colors, and cycles through the colors of each pixel one by one in sequence. Because of the way the language handles unsigned 32-bit integers when compiled it does not allow for the size of the list to be recognized as more than 4. So, all color lists must have four color objects regardless of the actual amount of colors on the flag. This is why many of the countries functions use black (the color that sets of all pixels to off) as a terminating variable.
The function turnoff is flagColors with a list of only the color black. The function rainbow uses its own for loop hardcoded to use all 8 colors defined to eliminate the delay that would occur in the middle of the list. The function pulse is meant to provide a subtle breath which is initialized during the reaction checking process. It changes all the pixels simultaneously unlike whenever the flagColors, which shows each pixel with a slight delay between each light's change.
// Call the flag colors function for the country or people
// from the following countries. Using predefinied lists of colors
//mexico
void mexicanFlag(){
delay(100);
uint32_t flag[] = {r,w,g,k};
flagColors(flag);
}
//syria
void syrianFlag(){
delay(100);
uint32_t flagA[] = {r,w,g,w};
uint32_t flagB[] = {g,w,k,k};
flagColors(flagA);
flagColors(flagB);
}
//russia
void russianFlag(){
delay(100);
uint32_t flag[] = {w,b,r,k};
flagColors(flag);
}
//israel
void israeliFlag(){
delay(100);
uint32_t flag[] = {b,w,b,k};
flagColors(flag);
}
//venezuela
void venezuelanFlag(){
delay(100);
uint32_t flag[] = {y,b,r,k};
flagColors(flag);
}
//china
void chineseFlag(){
delay(100);
uint32_t flag[] = {r,r,y,r};
flagColors(flag);
}
//Shows a rainbow
void rainbow(){
uint32_t rainbow[] = {w,r,y,g,c,b,m,k};
for(int c=0; c<8; c++) {
for(uint16_t p=0; p< strip.numPixels(); p++) {
//change the color
strip.setPixelColor(p, rainbow[c] );
//show the color
strip.show();
delay( lightSpeed );
}
}
}
//Flashes neopixel leaving all the lights off
void turnoff(){
//run through flag colors with all colors set to off
uint32_t onoff[] = {k,k,k,k};
flagColors(onoff);
}
//makes every neopixel breath once
void pulse(){
//ascending from 0 to 225
for (int i=0; i < 225 ; i++) {
//cycle through every pixel
for(int j=0; j<strip.numPixels(); j++) {
//ascending through shades of white
strip.setPixelColor(j, strip.Color(i,i,i));
}
//show the change
strip.show();
//wait a bit
delay(10);
}
//descending from 225 to 0
for (int i = 225; i > 0; i--) {
//cycle through every pixel
for(int j=0; j<strip.numPixels(); j++) {
//descending through shades of white
strip.setPixelColor(j, strip.Color(i,i,i));
}
//show the change
strip.show();
//wait a bit
delay(10);
}
}
//Takes a list of up to four colors and shows them on the neopixels
void flagColors(uint32_t colors[]){
for(int c=0; c< sizeof(colors); c++) {
for(uint16_t p=0; p< strip.numPixels(); p++) {
//change the color
strip.setPixelColor(p, colors[c] );
//show the color
strip.show();
delay( lightSpeed );
}
}
}
Click to Expand
Particle IDE
The first bus stop determines if there's a reaction by checking the value of the "motion" variable which is updated in the loop. The motion variable is updated based on the PIR's value and sending the next decision to the second bus stop. While this is happening the bus stop will pulse once.
Particle Cloud
If the value of the PIR is HIGH there is motion if it is LOW there is no motion. If there is motion the first bus stop will publish an event "Reaction" to evoke a new action at the next bus stop. The data argument is published as the event data and based on the event's data the second bus stop will act cycling through similar flag colors.
void loop()
{
//Stores the value output by the PIR based on whether or not
//It detects motion by reading the PIR pin.
int currentMotion = digitalRead (PIRpin);
//If there is motion the global variable motion is set to true
if (currentMotion==HIGH){
motion = true;
}
//Otherwise set the global variable motion is set to false
else{
motion = false;
}
//wait a little
delay(100);
}
/*...*/
void checkReaction(String data){
delay(3000);
if(motion==true){
//Publish an event to indicate that there was a motion
//based reaction and the first bus stop. The tweet data
//is published as the data, while "reaction" is the
//event name
publishEvent("Reaction", data);
}
else{
//Publish an event to indicate that there was not a
//motion based reaction and the first bus stop and there
//is no data in the event
publishEvent("NoReaction", "");
}
//pulse the lights onece
pulse();
//take a pause
delay(1000);
//publish the motion variable
//this is more so to allow the developer or commissioned
//entity to know when the stop is triggered and if there was a reaction.
publishEvent("Motion", (String)motion);
}
Click to Expand
The main differences between the first bus stop and the second stop are that the first stop is the initializer and the second stop is the terminator. The first bus stop has output and the sensor to check for reactions but it is also the initializer of physical virality. The second bus stop is where the buck stops for our implementation, but in concept, it is the last reachable actor in the spread of the information at the first stop. The interaction in addition to pulling patrons attention into the physical space should create a sense of recognition between commuters waiting at the opposite bus stop. For a moment in time, they are waiting for the same thing to happen, but hoping to gain access to opposite sides of the same path.
// This #include statement was automatically added by the Particle IDE.
#include <neopixel.h>
//initialize the boolean variable for movement to false.
bool motion = false;
//set the speed of the lights to cycle through one
int lightSpeed = 100;
//define pin for the PIR sensor
int PIRpin = D2;
//define neopixel ring
#define PIXEL_PIN D3
#define PIXEL_COUNT 28 //bus stop #2 has 14 pixels
#define PIXEL_TYPE WS2812
Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE);
//RGBW and CYMK colors as global variables
uint32_t w = strip.Color(255, 255, 255);// white (all on)
uint32_t r = strip.Color(255, 0, 0); // red
uint32_t y = strip.Color(255, 255, 0); // yellow
uint32_t g = strip.Color(0, 255, 0); // green
uint32_t c = strip.Color(0, 255, 255); // cyan
uint32_t b = strip.Color(0, 0, 255); // blue
uint32_t m = strip.Color(255, 0, 255); // magenta (pink/purple)
uint32_t k = strip.Color(0, 0, 0); // black (all off)
void setup()
{
/*Subscribe to a set of events published when an IFTTT widget is triggered by
a tweeting. The first one is connected to the account of a teammate for demo
purposes, the second one is connected to donaldTrump's twitter acound and the
last one is independent of a username so any other account can be used.*/
Particle.subscribe("ChenMutiatLama/2019/Group4/LamaAlFulaij", action );
Particle.subscribe("ChenMutiatLama/2019/Group4/realDonaldTrump", action );
Particle.subscribe("ChenMutiatLama/2019/Group4/tweet", action );
Particle.variable ("Motion",motion);
//PIR is readable
pinMode (PIRpin, INPUT_PULLDOWN);
//Initialize all pixels to 'off'
strip.begin();
strip.show();
}
Click to Expand
The circuit for the viral bus stop includes 2 main components managed by a Particle ARGON microcontroller. The PIR output is wired to digital pin D2 and the NEOPixel input is wired to digital pin D3 and the power is being drawn from the ARGON's USB pin for both. The first and second bus stops have similar circuitry the main difference being that the second stop's circuit has no PIR.
Bill of Materials
Amount | Label | Part Type | Properties |
2 | NEOPIXEL | Neopixel Strip -- White WS2812 | color white |
2 | ParticleArgon | Particle Argon | variant variant 1s; part # Adafruit #3405 |
1 | PIR | LHi958 | variant pyroelectric infrared-detectors; package to-39 |
2 | Breadboard | Half Breadboard | 2.2" x 3.4" (5.5 cm x 8.5 cm); a set of power rails on each side. |
Execution III - Form:
Our final form came together after many iterations using the foam core mockup we initially did. It was useful for us to learn through the foam core mockup to see how things would measure and influence our final form, including the addition of the PIR box and the backing of the bus stop to hide the wiring as well as an elevated surface of the ground of the mock-up to hide the circuit boards. We used white acrylic to create the form by laser cutting and bending the acrylic. We also added signage to the bus stop to have something in the bus stop that the people can turn to explain what’s going on (see Bus Signage A) and participate (see Bus Signage B), react by moving, in this experience. It was important for us to have this information up and easily accessible to the users.
See Execution II Form for final videos and form pictures.
1363.391 KB · Download / View
1363.076 KB · Download / View
Viral Bus Stop from Lama al fulaij on Vimeo.
After pitching the project to professors and guests, the large question of what this bus stop's goal is came up again. Was it a political art statement piece, or was it a tool to drive and provoke conversation? As a team, we were not ready to take a political stance and make this an art piece around President Trump. The conversations helped us think through a different context that would make more sense, "Know Your Neighbors Bus Stop".
This would be a bus stop that people in the bus stop could tweet to about where they are from and music and flag colors of that country would play instantaneously signalling to other waiting commuters a little glimpse into that person's culture. They can then choose to interact socially with fellow commuters and share a bit more about their culture. Allowing people that probably travel the same commuting route everyday to finally break the ice and talk to one another. It would be a more playful, interactive installation that any town can use. Every town in the US today has a diverse population that should be celebrated more often.
Similarly to our idea, this idea would also require us to apply for a grant from the city or other public art supporters and buy out the ad space at a busy bus stop. We would then fit out the bus stop with the lights and speakers. Set up a dedicated twitter account that would connect to these devices and include signage to explain this idea and ask people to tweet and participate.
// This #include statement was automatically added by the Particle IDE.
#include <neopixel.h>
//initialize the boolean variable for movement to false.
bool motion = false;
//set the speed of the lights to cycle through one
int lightSpeed = 100;
//define pin for the PIR sensor
int PIRpin = D2;
//define neopixel ring
#define PIXEL_PIN D3
#define PIXEL_COUNT 29
#define PIXEL_TYPE WS2812
Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE);
//RGBW and CYMK colors as global variables
uint32_t w = strip.Color(255, 255, 255);// white (all on)
uint32_t r = strip.Color(255, 0, 0); // red
uint32_t y = strip.Color(255, 255, 0); // yellow
uint32_t g = strip.Color(0, 255, 0); // green
uint32_t c = strip.Color(0, 255, 255); // cyan
uint32_t b = strip.Color(0, 0, 255); // blue
uint32_t m = strip.Color(255, 0, 255); // magenta (pink/purple)
uint32_t k = strip.Color(0, 0, 0); // black (all off)
void setup()
{
/*Subscribe to a set of events published when an IFTTT widget is triggered by
a tweeting. The first one is connected to the account of a teammate for demo
purposes, the second one is connected to donaldTrump's twitter acound and the
last one is independent of a username so any other account can be used.*/
Particle.subscribe("ChenMutiatLama/2019/Group4/LamaAlFulaij", action );
Particle.subscribe("ChenMutiatLama/2019/Group4/realDonaldTrump", action );
Particle.subscribe("ChenMutiatLama/2019/Group4/tweet", action );
Particle.variable ("Motion",motion);
//PIR is readable
pinMode (PIRpin, INPUT_PULLDOWN);
//Initialize all pixels to 'off'
strip.begin();
strip.show();
}
void loop()
{
//Stores the value output by the PIR based on whether or not
//It detects motion by reading the PIR pin.
int currentMotion = digitalRead (PIRpin);
//If there is motion the global variable motion is set to true
if (currentMotion==HIGH){
motion = true;
}
//Otherwise set the global variable motion is set to false
else{
motion = false;
}
//wait a little
delay(100);
}
void publishEvent(String eventID, String data)
{
/* Remember our subscribe is matching "ChenMutiatLama/2019/Group4/"
We'll append the device id to get more specific about where the
event came from and an event ID to specify what the event is
supposed to trigger.
System.deviceID() provides an easy way to extract the device ID of
your device. It returns a String object of the device ID, which is
used to identify your device.*/
String eventName = "ChenMutiatLama/2019/Group4/"+ eventID + "/" + System.deviceID();
// now we have something like "diot/2019/paired/0123456789abcdef"
// and that corresponds to this devices info
// then we publish it
Particle.publish( eventName, data );
}
// Our event handler requires two bits of information
// This gives us:
// A character array that consists of the event name
// A character array that contains the data published in the event
// we're responding to.
void action(const char *event, const char *data){
//Particle.publish("acting");
String m = strstr(data, "mexic" );
String mCaps = strstr(data, "Mexic" );
String r = strstr(data, "russia" );
String rCaps = strstr(data, "Russia" );
String s = strstr(data, "syria" );
String sCaps = strstr(data, "Syria" );
String i = strstr(data, "israel" );
String iCaps = strstr(data, "Israel" );
String v = strstr(data, "venezuela" );
String vCaps = strstr(data, "Venezuela" );
String c = strstr(data, "chin" );
String cCaps = strstr(data, "Chin" );
String country = "no";
if(m!=NULL|| mCaps!=NULL){
mexicanFlag();
}
else if(r!=NULL|| rCaps!=NULL){
russianFlag();
}
else if(s!=NULL|| sCaps!=NULL){
syrianFlag();
}
else if(i!=NULL|| iCaps!=NULL){
israeliFlag();
}
else if(v!=NULL|| vCaps!=NULL){
venezuelanFlag();
}
else if(c!=NULL|| cCaps!=NULL){
chineseFlag();
}
else{
rainbow();
}
checkReaction(data);
turnoff();
}
// Call the flag colors function for the country or people
// from the following countries. Using predefinied lists of colors
//mexico
void mexicanFlag(){
delay(100);
uint32_t flag[] = {r,w,g,k};
flagColors(flag);
}
//syria
void syrianFlag(){
delay(100);
uint32_t flagA[] = {r,w,g,w};
uint32_t flagB[] = {g,w,k,k};
flagColors(flagA);
flagColors(flagB);
}
//russia
void russianFlag(){
delay(100);
uint32_t flag[] = {w,b,r,k};
flagColors(flag);
}
//israel
void israeliFlag(){
delay(100);
uint32_t flag[] = {b,w,b,k};
flagColors(flag);
}
//venezuela
void venezuelanFlag(){
delay(100);
uint32_t flag[] = {y,b,r,k};
flagColors(flag);
}
//china
void chineseFlag(){
delay(100);
uint32_t flag[] = {r,r,y,r};
flagColors(flag);
}
//Shows a rainbow
void rainbow(){
uint32_t rainbow[] = {w,r,y,g,c,b,m,k};
for(int c=0; c<8; c++) {
for(uint16_t p=0; p< strip.numPixels(); p++) {
//change the color
strip.setPixelColor(p, rainbow[c] );
//show the color
strip.show();
delay( lightSpeed );
}
}
}
//Flashes neopixel leaving all the lights off
void turnoff(){
//run through flag colors with all colors set to off
uint32_t onoff[] = {k,k,k,k};
flagColors(onoff);
}
//makes every neopixel breath once
void pulse(){
//ascending from 0 to 225
for (int i=0; i < 225 ; i++) {
//cycle through every pixel
for(int j=0; j<strip.numPixels(); j++) {
//ascending through shades of white
strip.setPixelColor(j, strip.Color(i,i,i));
}
//show the change
strip.show();
//wait a bit
delay(10);
}
//descending from 225 to 0
for (int i = 225; i > 0; i--) {
//cycle through every pixel
for(int j=0; j<strip.numPixels(); j++) {
//descending through shades of white
strip.setPixelColor(j, strip.Color(i,i,i));
}
//show the change
strip.show();
//wait a bit
delay(10);
}
}
//Takes a list of up to four colors and shows them on the neopixels
void flagColors(uint32_t colors[]){
for(int c=0; c< sizeof(colors); c++) {
for(uint16_t p=0; p< strip.numPixels(); p++) {
//change the color
strip.setPixelColor(p, colors[c] );
//show the color
strip.show();
delay( lightSpeed );
}
}
}
void checkReaction(String data){
delay(3000);
if(motion==true){
//Publish an event to indicate that there was a motion
//based reaction and the first bus stop. The tweet data
//is published as the data, while "reaction" is the
//event name
publishEvent("Reaction", data);
}
else{
//Publish an event to indicate that there was not a
//motion based reaction and the first bus stop and there
//is no data in the event
publishEvent("NoReaction", "");
}
//pulse the lights onece
pulse();
//take a pause
delay(1000);
//publish the motion variable
//this is more so to allow the developer or commissioned
//entity to know when the stop is triggered and if there was a reaction.
publishEvent("Motion", (String)motion);
}
Click to Expand
// This #include statement was automatically added by the Particle IDE.
#include <neopixel.h>
//initialize the boolean variable for movement to false.
bool motion = false;
//set the speed of the lights to cycle through one
int lightSpeed = 100;
//define pin for the PIR sensor
int PIRpin = D2;
//define neopixel ring
#define PIXEL_PIN D3
#define PIXEL_COUNT 14
#define PIXEL_TYPE WS2812
Adafruit_NeoPixel strip = Adafruit_NeoPixel(PIXEL_COUNT, PIXEL_PIN, PIXEL_TYPE);
//RGBW and CYMK colors as global variables
uint32_t w = strip.Color(255, 255, 255);// white (all on)
uint32_t r = strip.Color(255, 0, 0); // red
uint32_t y = strip.Color(255, 255, 0); // yellow
uint32_t g = strip.Color(0, 255, 0); // green
uint32_t c = strip.Color(0, 255, 255); // cyan
uint32_t b = strip.Color(0, 0, 255); // blue
uint32_t m = strip.Color(255, 0, 255); // magenta (pink/purple)
uint32_t k = strip.Color(0, 0, 0); // black (all off)
void setup()
{
/*Subscribe to an event that is only published if there is a reaction
at another bus stop.*/
Particle.subscribe( "ChenMutiatLama/2019/Group4/Reaction", action );
//Initialize all pixels to 'off'
strip.begin();
strip.show();
}
void loop()
{
}
void publishEvent(String eventID, String data)
{
/* Remember our subscribe is matching "ChenMutiatLama/2019/Group4/"
We'll append the device id to get more specific about where the
event came from and an event ID to specify what the event is
supposed to trigger.
System.deviceID() provides an easy way to extract the device ID of
your device. It returns a String object of the device ID, which is
used to identify your device.*/
String eventName = "ChenMutiatLama/2019/Group4/"+ eventID + "/" + System.deviceID();
// now we have something like "diot/2019/paired/0123456789abcdef"
// and that corresponds to this devices info
// then we publish it
Particle.publish( eventName, data );
}
// Our event handler requires two bits of information
// This gives us:
// A character array that consists of the event name
// A character array that contains the data published in the event
// we're responding to.
void action(const char *event, const char *data){
//Particle.publish("acting");
String m = strstr(data, "mexic" );
String mCaps = strstr(data, "Mexic" );
String r = strstr(data, "russia" );
String rCaps = strstr(data, "Russia" );
String s = strstr(data, "syria" );
String sCaps = strstr(data, "Syria" );
String i = strstr(data, "israel" );
String iCaps = strstr(data, "Israel" );
String v = strstr(data, "venezuela" );
String vCaps = strstr(data, "Venezuela" );
String c = strstr(data, "chin" );
String cCaps = strstr(data, "Chin" );
String country = "no";
if(m!=NULL|| mCaps!=NULL){
mexicanFlag();
}
else if(r!=NULL|| rCaps!=NULL){
russianFlag();
}
else if(s!=NULL|| sCaps!=NULL){
syrianFlag();
}
else if(i!=NULL|| iCaps!=NULL){
israeliFlag();
}
else if(v!=NULL|| vCaps!=NULL){
venezuelanFlag();
}
else if(c!=NULL|| cCaps!=NULL){
chineseFlag();
}
else{
rainbow();
}
turnoff();
}
// Call the flag colors function for the country or people
// from the following countries. Using predefinied lists of colors
//mexico
void mexicanFlag(){
delay(100);
uint32_t flag[] = {r,w,g,k};
flagColors(flag);
}
//syria
void syrianFlag(){
delay(100);
uint32_t flagA[] = {r,w,g,w};
uint32_t flagB[] = {g,w,k,k};
flagColors(flagA);
flagColors(flagB);
}
//russia
void russianFlag(){
delay(100);
uint32_t flag[] = {w,b,r,k};
flagColors(flag);
}
//israel
void israeliFlag(){
delay(100);
uint32_t flag[] = {b,w,b,k};
flagColors(flag);
}
//venezuela
void venezuelanFlag(){
delay(100);
uint32_t flag[] = {y,b,r,k};
flagColors(flag);
}
//china
void chineseFlag(){
delay(100);
uint32_t flag[] = {r,r,y,r};
flagColors(flag);
}
//Shows a rainbow
void rainbow(){
uint32_t rainbow[] = {w,r,y,g,c,b,m,k};
for(int c=0; c<8; c++) {
for(uint16_t p=0; p< strip.numPixels(); p++) {
//change the color
strip.setPixelColor(p, rainbow[c] );
//show the color
strip.show();
delay( lightSpeed );
}
}
}
//Flashes neopixel leaving all the lights off
void turnoff(){
//run through flag colors with all colors set to off
uint32_t onoff[] = {k,k,k,k};
flagColors(onoff);
}
//Takes a list of up to four colors and shows them on the neopixels
void flagColors(uint32_t colors[]){
for(int c=0; c< sizeof(colors); c++) {
for(uint16_t p=0; p< strip.numPixels(); p++) {
//change the color
strip.setPixelColor(p, colors[c] );
//show the color
strip.show();
delay( lightSpeed );
}
}
}
Click to Expand
A hands-on introductory course exploring the Internet of Things and connected product experiences.
Our project is an interactive installation that investigates what viral messages would look like in analog form, in public places where social interactions rarely occur anymore. Can we re-analog-ize viral information and nudge social interactions at bus stops?
February 17th, 2019