# Automatic Twitch On-Air Sign

## Overview

Warning: 

![](https://cdn-learn.adafruit.com/assets/assets/000/031/031/medium800/feather_IMG_4598.jpg?1457647226)

We're doing a lot of streaming lately, and I wanted to make a sign that would let people know when we're on air.

All this guide will do is connect to the Twitch API and determine if the user is currently streaming - if so, the Feather will turn on some NeoPixels (you can also just use LEDs if you like) to light up the sign.

**You can easily extend this to, instead of parsing for a live stream, display the stream name, number of viewers, game-being-played** or [anything else available from the Twitch API](https://github.com/justintv/Twitch-API)

I did this project as an IoT-Tuesday project and livestreamed it on Youtube, you can watch it here:

https://www.youtube.com/watch?v=LQzoixcnFXw

(It turns out the SSL failure on ESP8226 is a timeout not an encryption issue, so you can also do this project with an ESP8266!)

# Previous projects

[We did this once already with a raspberry Pi to be able to connect to YouTube or UStream's API but it really does require quite a bit of hacking](../../../../internet-streaming-on-air-sign/)

![](https://cdn-learn.adafruit.com/assets/assets/000/030/946/medium800/feather_projects_onair.jpg?1457498588)

I wanted to make something simpler, all-in-one, using a Feather ESP8266 or WINC1500. In the end, the Feather M0 ATWINC1500 & ESP8266 worked best, since you need to have an SSL connection to twitch.tv but at least you dont need any OAuth or API keys!

# Automatic Twitch On-Air Sign

## Twitch API

Lucky for us, instead of forcing us to use OAuth or API keys or sacrificing chickens, twitch makes it really easy to see what's going on with _any_ stream. Yay!

All you have to do is go to **[https://api.twitch.tv/kraken/streams/adafruit](https://api.twitch.tv/kraken/streams/twitchname)** and you'll be able to see the current status of the **adafruit** stream. Just change the last part of the url to see another stream

The data will be a json package, in ascii text. For example, if the stream is active:

![](https://cdn-learn.adafruit.com/assets/assets/000/030/939/medium800/feather_streaming.png?1457495054)

```auto
{"stream":{"_id":20082214992,"game":null,"viewers":0,"created_at":"2016-03-09T02:51:06Z","video_height":540,"average_fps":30,"delay":0,"is_playlist":false,"_links":{"self":"https://api.twitch.tv/kraken/streams/ladyada1337"},"preview":{"small":"http://static-cdn.jtvnw.net/previews-ttv/live_user_ladyada1337-80x45.jpg","medium":"http://static-cdn.jtvnw.net/previews-ttv/live_user_ladyada1337-320x180.jpg","large":"http://static-cdn.jtvnw.net/previews-ttv/live_user_ladyada1337-640x360.jpg","template":"http://static-cdn.jtvnw.net/previews-ttv/live_user_ladyada1337-{width}x{height}.jpg"},"channel":{"mature":null,"status":null,"broadcaster_language":null,"display_name":"ladyada1337","game":null,"language":"en","_id":113575809,"name":"ladyada1337","created_at":"2016-01-23T00:38:01Z","updated_at":"2016-03-09T02:15:32Z","delay":null,"logo":null,"banner":null,"video_banner":null,"background":null,"profile_banner":null,"profile_banner_background_color":null,"partner":false,"url":"http://www.twitch.tv/ladyada1337","views":11,"followers":0,"_links":{"self":"http://api.twitch.tv/kraken/channels/ladyada1337","follows":"http://api.twitch.tv/kraken/channels/ladyada1337/follows","commercial":"http://api.twitch.tv/kraken/channels/ladyada1337/commercial","stream_key":"http://api.twitch.tv/kraken/channels/ladyada1337/stream_key","chat":"http://api.twitch.tv/kraken/chat/ladyada1337","features":"http://api.twitch.tv/kraken/channels/ladyada1337/features","subscriptions":"http://api.twitch.tv/kraken/channels/ladyada1337/subscriptions","editors":"http://api.twitch.tv/kraken/channels/ladyada1337/editors","teams":"http://api.twitch.tv/kraken/channels/ladyada1337/teams","videos":"http://api.twitch.tv/kraken/channels/ladyada1337/videos"}}},"_links":{"self":"https://api.twitch.tv/kraken/streams/ladyada1337","channel":"https://api.twitch.tv/kraken/channels/ladyada1337"}}
```

And if not active...

![](https://cdn-learn.adafruit.com/assets/assets/000/030/938/medium800/feather_notstream.png?1457495005)

```auto
{"stream":null,"_links":{"self":"https://api.twitch.tv/kraken/streams/adafruit","channel":"https://api.twitch.tv/kraken/channels/adafruit"}}
```

There is a ton of details over at [https://github.com/justintv/Twitch-API](https://github.com/justintv/Twitch-API) but we're going to be lazy and just parse the data manually.

If we see the string `{"stream":{"_id"` then we know the stream is active. If we see the string `{"stream":null` then we know it is not.

One thing to note is you **must use SSL** to connect, if you try to connect without, you'll get

```auto
{"error":"Bad Request","message":"Requests must be made over SSL","status":400}
```

# Automatic Twitch On-Air Sign

## Querying API

OK now that we know we just need to connect with SSL, so open up the **Adafruit\_WINC1500-\>WiFiSSLClient** example, and change the server to **api.twitch.tv**

![](https://cdn-learn.adafruit.com/assets/assets/000/030/940/medium800/feather_twitchapi.png?1457495912)

and the actual query to grab the twitch api url (you'll need to update the path and the host)

![](https://cdn-learn.adafruit.com/assets/assets/000/030/941/medium800/feather_twitchpatch.png?1457495970)

Here's the complete edited code, you'll also need to update the network SSID & password

```auto
#include <SPI.h>
#include <Adafruit_WINC1500.h>

// Define the WINC1500 board connections below.
// If you're following the Adafruit WINC1500 board
// guide you don't need to modify these:
#define WINC_CS   8
#define WINC_IRQ  7
#define WINC_RST  4
#define WINC_EN   2     // or, tie EN to VCC and comment this out
// The SPI pins of the WINC1500 (SCK, MOSI, MISO) should be
// connected to the hardware SPI port of the Arduino.
// On an Uno or compatible these are SCK = #13, MISO = #12, MOSI = #11.
// On an Arduino Zero use the 6-pin ICSP header, see:
//   https://www.arduino.cc/en/Reference/SPI

// Setup the WINC1500 connection with the pins above and the default hardware SPI.
Adafruit_WINC1500 WiFi(WINC_CS, WINC_IRQ, WINC_RST);

// Or just use hardware SPI (SCK/MOSI/MISO) and defaults, SS -> #10, INT -> #7, RST -> #5, EN -> 3-5V
//Adafruit_WINC1500 WiFi;

char ssid[] = "networkssid"; //  your network SSID (name)
char pass[] = "password";    // your network password (use for WPA, or use as key for WEP)
int keyIndex = 0;            // your network key Index number (needed only for WEP)

int status = WL_IDLE_STATUS;
char server[] = "api.twitch.tv";    // name address for Google (using DNS)

Adafruit_WINC1500SSLClient client;

void setup() {
#ifdef WINC_EN
  pinMode(WINC_EN, OUTPUT);
  digitalWrite(WINC_EN, HIGH);
#endif

  //Initialize serial and wait for port to open:
  Serial.begin(9600);
  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 (WiFi.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:
    uint8_t timeout = 10;
    while (timeout && (WiFi.status() != WL_CONNECTED)) {
      timeout--;
      delay(1000);
    }
  }

  Serial.println("Connected to wifi");
  printWifiStatus();

  Serial.println("\nStarting connection to server...");
  // if you get a connection, report back via serial:
  if (client.connect(server, 443)) {
    Serial.println("connected to server");
    // Make a HTTP request:
    client.println("GET /kraken/streams/adafruit HTTP/1.1");
    client.println("Host: api.twitch.tv");
    client.println("Connection: close");
    client.println();
  }
}

void loop() {
  // if there are incoming bytes available
  // from the server, read them and print them:
  while (client.available()) {
    char c = client.read();
    Serial.write(c);
  }

  // if the server's disconnected, stop the client:
  if (!client.connected()) {
    Serial.println();
    Serial.println("disconnecting from server.");
    client.stop();

    // do nothing forevermore:
    while (true);
  }
}


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);

  // print the received signal strength:
  long rssi = WiFi.RSSI();
  Serial.print("signal strength (RSSI):");
  Serial.print(rssi);
  Serial.println(" dBm");
}
```

Upload to your Feather WINC and check that you can connect:

![](https://cdn-learn.adafruit.com/assets/assets/000/030/942/medium800/feather_sslconn.png?1457496132)

If you can connect to the SSID but then can't connect to twitch, you might be missing the SSL root cert for twitch (DigiCertGlobalRootCA)

![](https://cdn-learn.adafruit.com/assets/assets/000/030/943/medium800/feather_sslnope.png?1457496396)

In which case, [run the instructions from this tutorial for updating the SSL certificates](../../../../adafruit-feather-m0-wifi-atwinc1500/updating-ssl-certificates)

Before doing so, make sure that the certs directory contains the DigiCertGlobal certificate file

![](https://cdn-learn.adafruit.com/assets/assets/000/030/944/medium800/feather_thecert.png?1457496525)

Then upload the **FirmwareUploader** sketch & run the cert updater

![](https://cdn-learn.adafruit.com/assets/assets/000/030/945/medium800/feather_certs.png?1457496551)

Then re-upload the SSL connection test, make sure you can connect to twitch and get that json string

# Automatic Twitch On-Air Sign

## Final Sketch

Once that works, upload eiher of these sketches, with your SSID & network password:

- [WINC1500 Demo](https://raw.githubusercontent.com/adafruit/Twitch-API-Examples/master/WINC1500_OnAirSign/WINC1500_OnAirSign.ino)
- [ESP8266 Demo](https://raw.githubusercontent.com/adafruit/Twitch-API-Examples/master/ESP8266_OnAirSign/ESP8266_OnAirSign.ino)

# Sketch Explanation

This sketch is not much different than the SSL test sketch.

## Configuration

In the pre-setup configuration, you can set up your SSID & password. Also, set what pin has the LED connected. Define the path you want to grab, change this to your favorite twitch streamer

```auto
// Define the WINC1500 board connections below.
// If you're following the Adafruit WINC1500 board
// guide you don't need to modify these:
#define WINC_CS   8
#define WINC_IRQ  7
#define WINC_RST  4
#define WINC_EN   2     // or, tie EN to VCC and comment this out

#define LED 13

// Setup the WINC1500 connection with the pins above and the default hardware SPI.
Adafruit_WINC1500 WiFi(WINC_CS, WINC_IRQ, WINC_RST);

// Or just use hardware SPI (SCK/MOSI/MISO) and defaults, SS -> #10, INT -> #7, RST -> #5, EN -> 3-5V
//Adafruit_WINC1500 WiFi;

char ssid[] = "networkssid"; //  your network SSID (name)
char pass[] = "networkpass";    // your network password (use for WPA, or use as key for WEP)
int keyIndex = 0;            // your network key Index number (needed only for WEP)

int status = WL_IDLE_STATUS;
#define HOST "api.twitch.tv"
#define PATH "/kraken/streams/adafruit"
#define REFRESH 20  // seconds between refresh

Adafruit_WINC1500SSLClient client;
```

## &nbsp;Setup

In **setup** we just check that the WiFi module is attached, and set the pin #13 LED to an output

```auto
void setup() {
#ifdef WINC_EN
  pinMode(WINC_EN, OUTPUT);
  digitalWrite(WINC_EN, HIGH);
#endif

  pinMode(LED, OUTPUT);
  
  //Initialize serial and wait for port to open:
  Serial.begin(9600);
  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);
  }
}
```

# Loop

We start by checking if we are connected to the SSID, if not we connect

```auto
void loop() {
  // attempt to connect to Wifi network:
  if (WiFi.status() != WL_CONNECTED) {
    while (WiFi.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:
      uint8_t timeout = 10;
      while (timeout && (WiFi.status() != WL_CONNECTED)) {
        timeout--;
        delay(1000);
      }
    }
  
    Serial.println("Connected to wifi");
    printWifiStatus();
  }
```

Then we SSL connect to twitch.tv and ask for the path from the setup section

```auto
  Serial.println("\nStarting connection to twitch...");
  // if you get a connection, report back via serial:
  if (client.connect(HOST, 443)) {
    Serial.println("connected to twitch api server");
    // Make a HTTP request:
    client.println("GET " PATH " HTTP/1.1");
    client.println("Host: " HOST);
    client.println("Connection: close");
    client.println();
  }
```

We then use **find** to locate whether the magic string appears

```auto
  boolean isStreaming = false;
  while (client.connected()) {
    if (client.find("\"stream\":{\"_id\":")) {
      isStreaming = true;
    }
  }

```

if so, then **isStreaming** is set to true. Finally we print out the current status, wait a few seconds, and restart the loop

```auto
Serial.print("Streaming status: "); Serial.println(isStreaming);
  digitalWrite(LED, isStreaming);
  Serial.println("disconnecting from server.");
  client.stop();

  delay(REFRESH*1000);
}
```

# Automatic Twitch On-Air Sign

## Sign Assembly

I started with an off-the-shelf ON AIR sign, that just plugs into a 12V power supply

![feather_sign.jpg](https://cdn-learn.adafruit.com/assets/assets/000/031/033/medium640/feather_sign.jpg?1457647723)

If you open up the sign you'll see a little holder for two lamps, it's pretty basic!

![feather_signopen.jpg](https://cdn-learn.adafruit.com/assets/assets/000/031/034/medium640/feather_signopen.jpg?1457647748)

I removed the lamps

![feather_removelight.jpg](https://cdn-learn.adafruit.com/assets/assets/000/031/035/medium640/feather_removelight.jpg?1457647765)

And cut some RGBW NeoPixel strip I had handy

![feather_strip.jpg](https://cdn-learn.adafruit.com/assets/assets/000/031/036/medium640/feather_strip.jpg?1457647785)

![feather_cutstrip.jpg](https://cdn-learn.adafruit.com/assets/assets/000/031/039/medium640/feather_cutstrip.jpg?1457647856)

I decided to go with two strips of 30 LED/meter

![feather_twostrips.jpg](https://cdn-learn.adafruit.com/assets/assets/000/031/037/medium640/feather_twostrips.jpg?1457647819)

Some thin wires connect the two strips

![feather_wires.jpg](https://cdn-learn.adafruit.com/assets/assets/000/031/038/medium640/feather_wires.jpg?1457647838)

Some foam tape or packing tape can be used to keep the strips in place. Solder the strip wires to the Feather, the Power pin goes to USB, Ground to Ground, and Data to #12

![featherin.jpg](https://cdn-learn.adafruit.com/assets/assets/000/031/041/medium640/featherin.jpg?1457647885)

I plugged in a[USB wall adapter with a MicroUSB plug](https://www.adafruit.com/products/1995) to power it. You can also go with a long USB cable, that way you could plug it into a USB port and also reprogram it when necessary

![feather_usbplug.jpg](https://cdn-learn.adafruit.com/assets/assets/000/031/042/medium640/feather_usbplug.jpg?1457647910)

Plug it in and rock out!

![feather_IMG_4598.jpg](https://cdn-learn.adafruit.com/assets/assets/000/031/043/medium640/feather_IMG_4598.jpg?1457647977)

The final code will turn on the NeoPixel RGBW's dimly when powered up and bright red if the stream is detected. You may need to change the NeoPixel definition to RGB instead of RGBW if you're using plain NeoPixels


## Related Guides

- [Adafruit Feather HUZZAH ESP8266](https://learn.adafruit.com/adafruit-feather-huzzah-esp8266.md)
- [Introducing Adafruit Feather](https://learn.adafruit.com/adafruit-feather.md)
- [CircuitPython 2FA TOTP Authentication Friend](https://learn.adafruit.com/circuitpython-totp-otp-2fa-authy-authenticator-friend.md)
- [Easy Alexa (Echo) Control of your ESP8266 Huzzah](https://learn.adafruit.com/easy-alexa-or-echo-control-of-your-esp8266-huzzah.md)
- [Using Crickit and Adafruit IO together](https://learn.adafruit.com/crickit-and-adafruitio.md)
- [Adafruit IO Time Tracking Cube](https://learn.adafruit.com/time-tracking-cube.md)
- [Gmailbox](https://learn.adafruit.com/gmailbox.md)
- [Adding a WiFi Co-Processor to CircuitPython](https://learn.adafruit.com/adding-a-wifi-co-processor-to-circuitpython-esp8266-esp32.md)
- [Adafruit IO Home: Security ](https://learn.adafruit.com/adafruit-io-home-security.md)
- [Adafruit IO Environmental Monitor for Feather or Raspberry Pi](https://learn.adafruit.com/adafruit-io-air-quality-monitor.md)
- [Huzzah Weather Display](https://learn.adafruit.com/huzzah-weather-display.md)
- [Adafruit IO Home: Lights and Temperature ](https://learn.adafruit.com/adafruit-io-house-lights-and-temperature.md)
- [Feather-based Hue lighting controller](https://learn.adafruit.com/feather-hue-lighting-controller.md)
- [Adafruit IO Basics: ESP8266 + Arduino](https://learn.adafruit.com/adafruit-io-basics-esp8266-arduino.md)
- [Boomy The Boombox](https://learn.adafruit.com/boomy-the-boombox.md)
