element14 Community
element14 Community
    Register Log In
  • Site
  • Search
  • Log In Register
  • Community Hub
    Community Hub
    • What's New on element14
    • Feedback and Support
    • Benefits of Membership
    • Personal Blogs
    • Members Area
    • Achievement Levels
  • Learn
    Learn
    • Ask an Expert
    • eBooks
    • element14 presents
    • Learning Center
    • Tech Spotlight
    • STEM Academy
    • Webinars, Training and Events
    • Learning Groups
  • Technologies
    Technologies
    • 3D Printing
    • FPGA
    • Industrial Automation
    • Internet of Things
    • Power & Energy
    • Sensors
    • Technology Groups
  • Challenges & Projects
    Challenges & Projects
    • Design Challenges
    • element14 presents Projects
    • Project14
    • Arduino Projects
    • Raspberry Pi Projects
    • Project Groups
  • Products
    Products
    • Arduino
    • Avnet & Tria Boards Community
    • Dev Tools
    • Manufacturers
    • Multicomp Pro
    • Product Groups
    • Raspberry Pi
    • RoadTests & Reviews
  • About Us
  • Store
    Store
    • Visit Your Store
    • Choose another store...
      • Europe
      •  Austria (German)
      •  Belgium (Dutch, French)
      •  Bulgaria (Bulgarian)
      •  Czech Republic (Czech)
      •  Denmark (Danish)
      •  Estonia (Estonian)
      •  Finland (Finnish)
      •  France (French)
      •  Germany (German)
      •  Hungary (Hungarian)
      •  Ireland
      •  Israel
      •  Italy (Italian)
      •  Latvia (Latvian)
      •  
      •  Lithuania (Lithuanian)
      •  Netherlands (Dutch)
      •  Norway (Norwegian)
      •  Poland (Polish)
      •  Portugal (Portuguese)
      •  Romania (Romanian)
      •  Russia (Russian)
      •  Slovakia (Slovak)
      •  Slovenia (Slovenian)
      •  Spain (Spanish)
      •  Sweden (Swedish)
      •  Switzerland(German, French)
      •  Turkey (Turkish)
      •  United Kingdom
      • Asia Pacific
      •  Australia
      •  China
      •  Hong Kong
      •  India
      • Japan
      •  Korea (Korean)
      •  Malaysia
      •  New Zealand
      •  Philippines
      •  Singapore
      •  Taiwan
      •  Thailand (Thai)
      • Vietnam
      • Americas
      •  Brazil (Portuguese)
      •  Canada
      •  Mexico (Spanish)
      •  United States
      Can't find the country/region you're looking for? Visit our export site or find a local distributor.
  • Translate
  • Profile
  • Settings
Wearable Technology
  • Technologies
  • More
Wearable Technology
Blog Spring Hoodie 8: It's Done!
  • Blog
  • Forum
  • Documents
  • Events
  • Polls
  • Files
  • Members
  • Mentions
  • Sub-Groups
  • Tags
  • More
  • Cancel
  • New
Join Wearable Technology to participate - click to join for free!
  • Share
  • More
  • Cancel
Group Actions
  • Group RSS
  • More
  • Cancel
Engagement
  • Author Author: brenyc13
  • Date Created: 21 Apr 2015 1:33 PM Date Created
  • Views 1941 views
  • Likes 3 likes
  • Comments 4 comments
  • wearable_electronics
  • flora
  • spring_hoodie
  • wearable_technology
  • adafruit
Related
Recommended

Spring Hoodie 8: It's Done!

brenyc13
brenyc13
21 Apr 2015

The hoodie is finished!


You don't have permission to edit metadata of this video.
Edit media
x
image
Upload Preview
image


A few weeks ago, I started dreaming up this wacky project. And now I have a fun flower-covered Spring Hoodie that lights up depending on the weather forecast.


image


What's in it?

The components in the hoodie include an Adafruit Flora, a CC3000 WiFi module, and a lithium battery, all concealed inside an inner pocket. Eighteen NeoPixel LEDs are hidden inside of fake flowers covering the hood. I used two Old Navy hoodies, turning one inside out and putting it inside the other as a lining that protects and conceals all the wiring.



image


I bought the flowers at a craft store and put LEDs inside of 18 of them, wiring the lights together and connecting them to the Flora. Then I sewed or glued the rest of my flowers all over the hood.


I added a clicky button stitched into the pocket to make it easy to turn on and off without needing to pull out the main components.


image


How does it work?

When I turn on the hoodie, the WiFi module tethers to my phone, and the Flora uses it to connect to a simple PHP web page pulling 3-hour forecast data for the predicted precipitation, temperature, and wind speed from the Open Weather Map API.


When the Flora is connecting over WiFi, the lapel flower glows green to show that it’s working. Once it connects to this web page and grabs the weather information, the Flora uses it to control the color, brightness, and rate of change of the LED flowers.



image


The color changes based on amount of predicted precipitation. The more rain that’s forecasted, the more LEDs will be blue.


Intensity is dictated by temperature. The warmer it is, the brighter the lights. One thing I like about this feature is that if it’s too cold out, the hoodie will protect me by not lighting up at all. (funny story: I forgot about this feature the day after coding it. It was a cold day and I could not for the life of me figure out why the lights weren’t lighting up! After my “doh” moment, I decided to add that green lapel indicator light.)


I wanted there to always be some slight pulsing or suggestion of movement in the lights, but the speed of this movement is dictated by the predicted wind speed. The faster the wind, the faster the lights will change or flicker.



image


The Code

The vast majority of the code was written by my Hunky Assistant. He's the best!


//first version of SpringHoodie code




#include <Adafruit_NeoPixel.h>
#include <Adafruit_CC3000.h>
#include <ccspi.h>
#include <SPI.h>




// ========= CC3000 Parameters =========
// These are the interrupt and control pins
#define ADAFRUIT_CC3000_IRQ  2  // MUST be an interrupt pin!
// These can be any two pins
#define ADAFRUIT_CC3000_VBAT  9
#define ADAFRUIT_CC3000_CS    10
// Use hardware SPI for the remaining pins
// On an UNO, SCK = 13, MISO = 12, and MOSI = 11
Adafruit_CC3000 cc3000 = Adafruit_CC3000(ADAFRUIT_CC3000_CS, ADAFRUIT_CC3000_IRQ, ADAFRUIT_CC3000_VBAT,
                                        SPI_CLOCK_DIVIDER); // you can change this clock speed




#define WLAN_SSID      "NAME OF WIFI NETWORK"          // cannot be longer than 32 characters!
#define WLAN_PASS      "WIFI PASSWORD"
// Security can be WLAN_SEC_UNSEC, WLAN_SEC_WEP, WLAN_SEC_WPA or WLAN_SEC_WPA2
#define WLAN_SECURITY  WLAN_SEC_WPA2




#define IDLE_TIMEOUT_MS  10000      // Amount of time to wait (in milliseconds) with no data
                                  // received before closing the connection.  If you know the server
                                  // you're accessing is quick to respond, you can reduce this value.




// What page to grab!
#define WEBSITE      "mbah.org"
#define WEBPAGE      "/weather.php"




// =========== NEOPIXEL parameters ===========




#define INSTALLED_PIXELS 17
#define PIN 6




//The long Neopixel Strip is called "strip"
Adafruit_NeoPixel strip = Adafruit_NeoPixel(INSTALLED_PIXELS, PIN, NEO_GRB + NEO_KHZ800);




// =========== Program vars =============




bool g_initialized = false;




// Temp (degrees C)
const uint8_t g_temp_min = 13;
const uint8_t g_temp_max = 30;
uint8_t  g_temp = g_temp_min;








// Wind (km/h)
const uint8_t g_wind_min = 0;
const uint8_t g_wind_max = 60;
uint8_t g_wind = g_wind_min;




// Rain (tenths of mm in last 3 hours)
const uint8_t g_rain_min = 0;
const uint8_t g_rain_max = 25;
uint8_t g_rain = g_rain_min;




// def gohaina rain
const uint8_t colors[3][3] = {
  {0, 0, 50},  // orange
  {0, 0, 200},  // greenish
  {0, 0, 250},    // yellow
};
//
//// somewhat gohaina rain
//const uint8_t colors[3][3] = {
//  {250, 150, 0},  // orange
//  {0, 0, 200},  // blue
//  {250, 20, 0},    // yellow
//};
//
//// not gohaina rain
//const uint8_t colors[3][3] = {
//  {250, 150, 0},  // orange
//  {200, 200, 20},  // greenish
//  {250, 20, 0},    // yellow
//};




#define COLOR_POINTS 5
#define COLOR_STATES 5




struct color_state {
  uint8_t rain_amount;
  uint8_t colors[COLOR_POINTS][3];
};




const uint8_t temp_lut[] = {
  0, /* 0 */
  1, /* 1 */
  1, /* 2 */
  2, /* 3 */
  2, /* 4 */
  2, /* 5 */
  3, /* 6 */
  3, /* 7 */
  4, /* 8 */
  5, /* 9 */
  6, /* 10 */
  7, /* 11 */
  8, /* 12 */
  10, /* 13 */
  11, /* 14 */
  13, /* 15 */
};








const struct color_state cs[5] = {
  { 0, {
      { 250, 150, 0 },
      { 80, 0, 10 },
      { 250, 20, 0 },
      { 150, 0, 0 },
      { 250, 20, 0 },
    }
  },
  { 5, {
      { 250, 150, 0 },
      { 200, 200, 20 },
      { 250, 20, 0 },
      { 0, 0, 50 },
      { 0, 0, 200 },
    }
  },
  { 10, {
      { 250, 150, 0 },
      { 0, 0, 250 },
      { 250, 20, 0 },
      { 0, 0, 50 },
      { 0, 0, 200 },
    }
  },
  { 15, {
      { 20, 0, 100 },
      { 0, 0, 250 },
      { 250, 20, 0 },
      { 0, 0, 50 },
      { 0, 0, 200 },
    }
  },
  { 20, {
      { 0, 0, 100 },
      { 0, 0, 250 },
      { 20, 0, 100 },
      { 0, 0, 50 },
      { 0, 0, 200 },
    }
  },
};




int t=0;




#define INTERPOINT_DISTANCE 1000
//#define N_POINTS 3
//void get_color_on_domain(int i, uint8_t *r, uint8_t *g, uint8_t *b)
//{
//  int point0 = i / INTERPOINT_DISTANCE;
//  int point1 = (point0 + 1) % N_POINTS;
//  int interpoint = i % INTERPOINT_DISTANCE;
// 
//  *r = ((int32_t)colors[point1][0] - (int32_t)colors[point0][0]) * interpoint / INTERPOINT_DISTANCE + colors[point0][0];
//  *g = ((int32_t)colors[point1][1] - (int32_t)colors[point0][1]) * interpoint / INTERPOINT_DISTANCE + colors[point0][1];
//  *b = ((int32_t)colors[point1][2] - (int32_t)colors[point0][2]) * interpoint / INTERPOINT_DISTANCE + colors[point0][2];
//}








void get_color_on_domain2(const struct color_state *ccs, int i, uint8_t *col)
{
  int point0 = i / INTERPOINT_DISTANCE;
  int point1 = (point0 + 1) % COLOR_POINTS;
  int interpoint = i % INTERPOINT_DISTANCE;

  uint8_t j;
  for (j = 0; j < 3; j++) {
    col[j] = ((int32_t)ccs->colors[point1][j] - (int32_t)ccs->colors[point0][j]) * interpoint / INTERPOINT_DISTANCE + ccs->colors[point0][j];
  }
}




bool displayConnectionDetails(void)
{
  uint32_t ipAddress, netmask, gateway, dhcpserv, dnsserv;

  if(!cc3000.getIPAddress(&ipAddress, &netmask, &gateway, &dhcpserv, &dnsserv))
  {
    Serial.println(F("Unable to retrieve the IP Address!\r\n"));
    return false;
  }
  else
  {
    Serial.print(F("\nIP Addr: ")); cc3000.printIPdotsRev(ipAddress);
    //Serial.print(F("\nNetmask: ")); cc3000.printIPdotsRev(netmask);
    //Serial.print(F("\nGateway: ")); cc3000.printIPdotsRev(gateway);
    //Serial.print(F("\nDHCPsrv: ")); cc3000.printIPdotsRev(dhcpserv);
    //Serial.print(F("\nDNSserv: ")); cc3000.printIPdotsRev(dnsserv);
    Serial.println();
    return true;
  }
}




uint32_t ip;
void setup_cc3000(void)
{
  //Serial.println(F("Hello, CC3000!\n"));




  //Serial.print("Free RAM: "); Serial.println(getFreeRam(), DEC);

  /* Initialise the module */
  //Serial.println(F("\nInitializing cc3000..."));
  if (!cc3000.begin())
  {
    //Serial.println(F("Couldn't begin()! Check your wiring?"));
    while(1);
  }

  // Optional SSID scan
  // listSSIDResults();

  //Serial.print(F("\nAttempting to connect to ")); Serial.println(WLAN_SSID);
  if (!cc3000.connectToAP(WLAN_SSID, WLAN_PASS, WLAN_SECURITY)) {
    //Serial.println(F("Failed!"));
    while(1);
  }

  //Serial.println(F("Connected!"));

  /* Wait for DHCP to complete */
  //Serial.println(F("Request DHCP"));
  while (!cc3000.checkDHCP())
  {
    delay(100); // ToDo: Insert a DHCP timeout!
  } 




  /* Display the IP address DNS, Gateway, etc. */ 
//  while (! displayConnectionDetails()) {
//    delay(1000);
//  }




  ip = 919684817; // 54.209.70.209




  /* Try connecting to the website.
    Note: HTTP/1.1 protocol is used to keep the server from closing the connection before all data is read.
  */
  Adafruit_CC3000_Client www = cc3000.connectTCP(ip, 80);
  if (www.connected()) {
    www.fastrprint(F("GET " WEBPAGE " HTTP/1.1\r\n" "Host: " WEBSITE "\r\n" "\r\n"));
    //www.fastrprint(WEBPAGE);
    //www.fastrprint(F(" HTTP/1.1\r\n"));
    //www.fastrprint(F("Host: ")); www.fastrprint(WEBSITE); www.fastrprint(F("\r\n"));
    //www.fastrprint(F("\r\n"));
    www.println();
  } else {
    Serial.println(F("Connection failed"));   
    return;
  }




  //Serial.println(F("-------------------------------------"));

  /* Read data until either the connection is closed, or the idle timeout is reached. */
  unsigned long lastRead = millis();
  updateFromHttpReply(www);
  www.close();
  //Serial.println(F("-------------------------------------"));

  /* You need to make sure to clean up after yourself or the CC3000 can freak out */
  /* the next time your try to connect ... */
  //Serial.println(F("\n\nDisconnecting"));
  cc3000.disconnect();

}




void updateFromHttpReply(Adafruit_CC3000_Client &www)
{
  int consecutive_newlines = 0;
  bool in_payload = false;
  char payload[50];
  size_t payload_len = 0;




  unsigned long lastRead = millis();
  while (www.connected() && (millis() - lastRead < IDLE_TIMEOUT_MS)) {
    while (www.available()) {
      char c = www.read();
      //Serial.print(consecutive_newlines);
      if (c == '\n' || c == '\r') {
        consecutive_newlines++;
        if (consecutive_newlines == 4) {
          in_payload = true;
          continue;
        }
      } else {
        consecutive_newlines = 0;
      }
      if (in_payload) {
        payload[payload_len++] = c;
        if (payload_len == sizeof(payload)) {
          return;
        }
      }
      //Serial.print(c);
      lastRead = millis();
    }
  }

  payload[payload_len] = '\0';
  //Serial.print("Got payload ");
  //Serial.println(payload);

  updateFromString(payload);

  printStatus();
}




void setup()
{
  Serial.begin(9600);
  //while(!Serial);

  strip.begin();
  strip.setPixelColor(0, 0, 200, 0);
  strip.show(); // Initializes strip to 'off' + 1 pixel

  //Serial.println("Ready:");

  setup_cc3000();




}




void printStatus(void)
{
  Serial.print("Temp: ");
  Serial.println(g_temp);
  Serial.print("Wind: ");
  Serial.println(g_wind);
  Serial.print("Rain: ");
  Serial.println(g_rain);
}




void updateFromString(char *s)
{
  const char *temp_str = strtok(s, " ");
  const char *wind_str = strtok(NULL, " ");
  const char *rain_str = strtok(NULL, "\n");

  g_temp = atoi(temp_str);
  if (g_temp < g_temp_min) {
    g_temp = g_temp_min;
  } else if (g_temp > g_temp_max) {
    g_temp = g_temp_max;
  }

  g_wind = atoi(wind_str);
  if (g_wind < g_wind_min) {
    g_wind = g_wind_min;
  } else if (g_wind > g_wind_max) {
    g_wind = g_wind_max;
  }

  g_rain = atoi(rain_str);
  if (g_rain < g_rain_min) {
    g_rain = g_rain_min;
  } else if (g_rain > g_rain_max) {
    g_rain = g_rain_max;
  }
}




void updateViaSerial(void)
{
  if (!Serial.available()) {
    return;
  }
  String s = Serial.readStringUntil('\n');
  Serial.println("Got "+ s + "\n");

  updateFromString((char *) s.c_str());

  printStatus();

}




void loop() 
{
  uint8_t r, g, b;
  int i;

  updateViaSerial();

  // Rain: Determine the n main colors
  const struct color_state *ccs;
  for (i = 0; i < COLOR_STATES; i++) {
    if (g_rain >= cs[i].rain_amount) {
      ccs = &cs[i];
    }
  }




  // Temp: Determine the brightness
  uint8_t logtemp = temp_lut[g_temp - 15] + 15;
  uint8_t brightness = (uint32_t) (logtemp - g_temp_min) * 255 / (g_temp_max - g_temp_min);
  strip.setBrightness(brightness);




  uint8_t color[3];
  // Fill colors[i] with interpolated color
  for (i = 0; i < 20; i++) {
    get_color_on_domain2(ccs, (t + i * COLOR_POINTS * 1000 / 20) % (COLOR_POINTS * 1000),  color);
    strip.setPixelColor(i, color[0], color[1], color[2]);
  }

  // Wind: Determine the speed of the animation
  uint32_t animation_speed = (uint32_t) (g_wind - g_wind_min) * 70 / (g_wind_max - g_wind_min) + 5;




//  for (i = 0; i < 20; i++) {
//    get_color_on_domain((t + i * 3000 / 20) % 3000, &r, &g, &b);
//    strip.setPixelColor(i, r, g, b);
//  }

  strip.show();

  t = t + animation_speed;

  if (t >= INTERPOINT_DISTANCE * COLOR_POINTS) {
    t = 0;
  }
}


image


The Spring Hoodie is admittedly a pretty wacky piece of clothing. But after the cold wet winter we’ve had, I’m ready for flowers and color. And I like that it'll always let me know how the weather's going to be.


Hope you enjoy!


image

image

image

image

image

image

image

image


image

  • Sign in to reply
  • jw0752
    jw0752 over 10 years ago

    Hi Barbara,

    What a beautiful and well executed project. I have book marked it so I can show it to my 9 year old granddaughter. She will absolutely love it.

    John

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • doctorcdf
    doctorcdf over 10 years ago

    Bravo, Barbara!

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • brenyc13
    brenyc13 over 10 years ago in reply to DAB

    Thanks, DAB!

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
  • DAB
    DAB over 10 years ago

    Great job Barbara.

     

    I am very impressed at how quickly you have been able to take technology and embed it into fashion as a non-intrusive wearable capability.

     

    You are doing very well and I hope you encourage others to look into the possibilities of adding technology to their everyday lives.

     

    Well done.

    DAB

    • Cancel
    • Vote Up 0 Vote Down
    • Sign in to reply
    • More
    • Cancel
element14 Community

element14 is the first online community specifically for engineers. Connect with your peers and get expert answers to your questions.

  • Members
  • Learn
  • Technologies
  • Challenges & Projects
  • Products
  • Store
  • About Us
  • Feedback & Support
  • FAQs
  • Terms of Use
  • Privacy Policy
  • Legal and Copyright Notices
  • Sitemap
  • Cookies

An Avnet Company © 2026 Premier Farnell Limited. All Rights Reserved.

Premier Farnell Ltd, registered in England and Wales (no 00876412), registered office: Farnell House, Forge Lane, Leeds LS12 2NE.

ICP 备案号 10220084.

Follow element14

  • X
  • Facebook
  • linkedin
  • YouTube