Project tutorial
The Ugliest Sweater

The Ugliest Sweater

In the maker world, only boredom is truly ugly. Prevent boredom with horrible, smart flashy lights!!!

  • 757 views
  • 0 comments
  • 2 respects

Components and supplies

Abx00004 iso both
Arduino MKR1000
×1
LED string lights (battery-powered)
×1
Fairchild semiconductor pn2222abu. image
General Purpose Transistor NPN
I used the PN2222A (bought from Adafruit).
×1
5V USB Battery Pack
×1

About this project

This sweater likes to have stuff going on around it! Right now, anyone can give it a "poke" – and if it hasn't heard anything in a while, it starts flashing its red LEDs around the "BORED" text, faster and faster.

I bought this sweater two years ago as a potential victim for my first holiday hack. I saw the BORED sign and thought: This truly is the ugliest sweater of all. This year, it's back with a vengeance. And we're going to banish boredom!

The Circuit

This is based on a MKR1000, the small, WiFi-enabled Arduino.

The sweater uses a PNP transistor to toggle power to a string of cheap, generic red LEDs. I mounted them on the outside because it's supposed to be ugly, right? Plus, I wanted the lights as bright as possible :) Since the wires are insulated, I safety-pinned them to the shirt, which will also enable me to remove them on laundry day.

The LEDs run on a pair of CR2032 coin cells, with a power switch spliced into the ground wire (the power wire runs directly to the LEDs). I soldered the transistor's Collector and Emitter legs to the same two pins that are connected when the switch is on. So, you can still turn the lights on with the switch, or toggle them by closing the same connection with the transistor. The Base leg is wired to pin 13 on my MKR1000, and the Emitter is also routed to the Arduino's GND pin.

The Code

For the Arduino, I started with Vincent Wong's MKR1000 + REST API project and adapted it with my own janky blinker code. I did what I had to do so that it flashes once, then delays for 60 seconds, then divides the delay by 3 and loops back around. Eventually, it pretty much stays on. When it receives the poke, it resets the delay back to 60 seconds.

Note that Vincent was using version 2.1.1 of the Arduino aREST library, which you can download here: https://github.com/marcoschwartz/aREST/releases

I found a simple web page with an AJAX button on StackOverflow and modified it to "poke" the sweater. It's simply a button that sends a command to the Arduino's REST API. You do have to be on the same network as the sweater. First, though, I built a simple test page with "on" and "off" buttons.

I opted to download jquery-2.1.1.js and place it in the same directory as the HTML files – which is probably bad practice, but I have a problem with coming back to old software projects and having them die on me. :) So I'm a little paranoid, and this way it should work even if only your LAN is up.

Check out the Code section for the .ino and .html files!

Next Steps

There are a few ways I could take this; right now, I'm planning to use it with the Hackster API to prevent boredom. It will (hopefully) flash and post a link whenever a new Hackster project appears!

I'd like to rebuild this on a MKR1000 that doesn't have headers; this one had them soldered on from a meetup, but they come with the headers unattached. That will make it smaller, less spiky, more durable, and easier to insulate: I'll probably just smother all the pins in hot glue.

Troubleshooting

I had this working perfectly one night; and the next day, it completely failed to connect to the same office WiFi network. I think it's because of the load on the network from my colleagues. I managed to get it working just fine by tethering to my phone instead – of course, this means you have to have your computer with the browser on the same network, and it will probably be inaccessible to that phone.

Code

Arduino sketchC/C++
Adapted from Vincent Wong's project: https://www.hackster.io/wesee/control-your-mkr1000-with-arest-framework-ba6619
// Import required libraries
#include <SPI.h>
#include <WiFi101.h>

#define DEBUG_MODE 0

#include <aREST.h>

// Create aREST instance
aREST rest = aREST();

char ssid[] = "YOURSSID";      // your network SSID (name)
char pass[] = "YOURPASS";   // your network password
int keyIndex = 0;                 // your network key Index number (needed only for WEP)

int status = WL_IDLE_STATUS;

WiFiServer restServer(80);

const int ledPin = 13;
int between = 60000;

void setup(void)
{
  // Function to be exposed
  rest.function("led",ledControl);

  // Give name and ID to device
  rest.set_id("007");
  rest.set_name("bored_cat");

  // Start Serial
  Serial.begin(115200);

  while (!Serial) {
    ; // wait for serial port to connect. Needed for native USB port only

  }

  // check for the presence of the shield:
  if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println("WiFi shield not present");
    // don't continue:
    while (true);
  }

  // attempt to connect to Wifi network:
  while ( status != WL_CONNECTED) {
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);

    // wait 10 seconds for connection:
    delay(10000);
  }

  Serial.println();

  // you're connected now, so print out the status:
  printWifiStatus();

  // Start server
  restServer.begin();
  Serial.println(F("Listening for connections..."));

  pinMode(ledPin, OUTPUT);

  // Enable watchdog
  //wdt_enable(WDTO_4S);
}

void loop() {

  // Handle REST calls
  WiFiClient client = restServer.available();
  rest.handle(client);

  // flash to start
  digitalWrite(ledPin, 1);
  delay(1000);
  digitalWrite(ledPin,0);

  // pause for the delay; flash for a second; divide delay by 3; end loop
  delay(between);
  digitalWrite(ledPin, 1);
  delay(1000);
  digitalWrite(ledPin, 0);
  between = between/3;
}


// Custom function accessible by the API
int ledControl(String command) {

  Serial.println(command);
  
  // Get state from command
  int state = command.toInt();

  // reset delay length; quick double-flash to acknowledge
  between = 60000;
  digitalWrite(ledPin, 0);
  delay(100);
  digitalWrite(ledPin, 1);
  delay(100);
  digitalWrite(ledPin, 0);
  delay(100);
  digitalWrite(ledPin, 1);
  delay(100);
  digitalWrite(ledPin, 0);
  return 1;
}

void printWifiStatus() {
  // print the SSID of the network you're attached to:
  Serial.print("SSID: ");
  Serial.println(WiFi.SSID());

  // print your WiFi shield's IP address:
  IPAddress ip = WiFi.localIP();
  Serial.print("IP Address: ");
  Serial.println(ip);

  IPAddress subnet = WiFi.subnetMask();
  Serial.print("Netmask: ");
  Serial.println(subnet);

  IPAddress gateway = WiFi.gatewayIP();
  Serial.print("Gateway: ");
  Serial.println(gateway);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}
Test page with On and Off buttonsHTML
Simply toggles digital pin 13 on and off.
<!DOCTYPE html>
<html>
<head>
    <script src="jquery-2.1.1.js"></script>
    <script>
        //Usually, you put script-tags into the head
        function pokeOn() {
            //This performs a POST-Request.
            //Use "$.get();" in order to perform a GET-Request (you have to take a look in the rest-API-documentation, if you're unsure what you need)
            //The Browser downloads the webpage from the given url, and returns the data. Update with your own Arduino's IP
            $.post( "http://192.168.1.252/digital/13/1", function( data ) {
                 //As soon as the browser finished downloading, this function is called.
                 $('#demo').html(data);
            });
        }
		
        function pokeOff() {
            //This performs a POST-Request.
            //Use "$.get();" in order to perform a GET-Request (you have to take a look in the rest-API-documentation, if you're unsure what you need)
            //The Browser downloads the webpage from the given url, and returns the data.
            $.post( "http://192.168.1.252/digital/13/0", function( data ) {
                 //As soon as the browser finished downloading, this function is called.
                 $('#demo').html(data);
            });
        }
    </script>
</head>
<body>

    <p>Click the button to trigger a function.</p>

    <button onclick="pokeOn()">On</button>
    <button onclick="pokeOff()">Off</button>

    <p id="demo"></p>    
</body>
</html>
"Poke" web pageHTML
You'll have to update this with the actual IP address that your Arduino shows in the serial monitor.
<!DOCTYPE html>
<html>
<head>
    <script src="jquery-2.1.1.js"></script>
    <script>
        //Usually, you put script-tags into the head
        function pokeFunction() {
            //This performs a POST-Request.
            //Use "$.get();" in order to perform a GET-Request (you have to take a look in the rest-API-documentation, if you're unsure what you need)
            //The Browser downloads the webpage from the given url, and returns the data. Update with your own Arduino's IP
            $.post( "http://192.168.1.252/led?params=0", function( data ) {
                 //As soon as the browser finished downloading, this function is called.
                 $('#demo').html(data);
            });
        }
    </script>
</head>
<body>

    <p>Poke.</p>

    <button onclick="pokeFunction()">Poke</button>

    <p id="demo"></p>    
</body>
</html>

Schematics

Sweater circuit
Iys4jpekqsftbvfcadju

Comments

Similar projects you might like

Arduino Bluetooth Basic Tutorial

by Mayoogh Girish

  • 455,743 views
  • 42 comments
  • 242 respects

Home Automation Using Raspberry Pi 2 And Windows 10 IoT

Project tutorial by Anurag S. Vasanwala

  • 285,647 views
  • 95 comments
  • 672 respects

Security Access Using RFID Reader

by Aritro Mukherjee

  • 229,949 views
  • 38 comments
  • 239 respects

OpenCat

Project in progress by Team Petoi

  • 198,222 views
  • 154 comments
  • 1,379 respects
Add projectSign up / Login