Cheerlights client using WiFiDIPCortex and WS2801 RGB LED strip
Dependencies: Adafruit_WS2801 HTTPClient cc3000_hostdriver_mbedsocket mbed
main.cpp
- Committer:
- SomeRandomBloke
- Date:
- 2014-11-26
- Revision:
- 3:7410e3231e7a
- Parent:
- 1:40027344b249
File content as of revision 3:7410e3231e7a:
/** WiFiDIPCortex Cheerlights
*
* @author Andrew Lindsay
*
* @section LICENSE
*
* Copyright (c) 2012 Andrew Lindsay (andrew [at] thiseldo [dot] co [dot] uk)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
* @section DESCRIPTION
*
* This is a basic cheerlights client, http://www.cheerlights.com/ It uses the
* API url http://api.thingspeak.com/channels/1417/field/1/last.txt to read the last
* colour selected.
*
* The hardware is the WiFiDIPCortex from SolderSplash Labs http://www.soldersplash.co.uk/products/wifi-dipcortex/
* This is a small, yet powerful LPC1347 Cortex M3 dev board with built in CC3000 WiFi module.
* The CC3000 uses the TI SmartConfig to setup the WiFi connection without having to update any code.
*
* The WiFiDIPCortex requires 2 pushbuttons connected between:
* Reset: Pin 1 (Reset) and GND, plus 10K resistor between Pin 1 and 3.3V, Pin 11
* Config: Pin 6 (P1_31) and GND, plus 10K resistor between Pin 1 and 3.3V, Pin 11
*
* The LED strip used in this example is based on the WS2801 chips and requires a CLK and DATA to use it.
* Pin 27 (P0_7) LED strip Data
* Pin 28 (P1_28) LED strip Clk.
* Ideally strip should be powered from a external 3.3V source and the GNDs connected between Power supply and
* WiFiDIPCortex.
*
* Debug output is sent to UART connected to pins 19 and 20.
*
* To use SmartConfig you'll need either the Android or iOS app from http://www.ti.com/tool/SmartConfig.
* The Java version hasnt worked so far, but could also be used.
* To enter SmartConfig mode, hold down the Config button, then press and release Reset, release Config.
* You then use the SmartConfig app to set your network parameters, when you get the notification that
* it was successful the WiFiDIPCortex is configured. The settings are saved and available next time it is powered up.
*
* If SmartConfig fails, try again.
*
* After starting the WiFiDIPCortex will connect to cheerlights.com and retrieve the latest colour and
* set the lights to the colour.
* Every minute the colour is retrieved and if its different to the last one the new colour is shown.
*
* The basic framework can be changed to use different LEDs to suit your available hardware.
*
*/
#include "mbed.h"
#include "cc3000.h"
#include "HTTPClient.h"
// Library to drive the LED strip
#include "Adafruit_WS2801.h"
// Some local defines
#define SERIAL_BAUD_RATE 115200
#define NUM_PIXELS 50
#define NUM_COL_HISTORY 5
#define WIGO 1
#define WIFI_DIPCORTEX 2
#define UNDEFINED 3
#define MY_BOARD WIFI_DIPCORTEX
using namespace mbed_cc3000;
// LED to indicate SmartConfig is running
DigitalOut LedSC(P0_1);
// Button to hold down during reset to enter SmartConfig mode
DigitalIn SCButton(P1_31);
// For Bit-Banging SPI use Pins 40 and 39
PinName dataPin(p40); // PIN 40 - Yellow wire on Adafruit Pixels
PinName clockPin(p39); // PIN 39 - Green wire on Adafruit Pixels
// For hardware SPI use Pin 16 for Data and pin 13 for Clk
/* cc3000 module declaration specific for user's board. Check also init() */
#if (MY_BOARD == WIGO)
cc3000 wifi(PTA16, PTA13, PTD0, SPI(PTD2, PTD3, PTC5), PORTA_IRQn);
Serial uart(USBTX,USBRX);
#elif (MY_BOARD == WIFI_DIPCORTEX)
cc3000 wifi(p28, p27, p30, SPI(p21, p14, p37));
Serial uart(p19, p20);
#else
#endif
#ifndef CC3000_UNENCRYPTED_SMART_CONFIG
//const uint8_t smartconfigkey[] = {0x73,0x6d,0x61,0x72,0x74,0x63,0x6f,0x6e,0x66,0x69,0x67,0x41,0x45,0x53,0x31,0x36};
#else
//const uint8_t smartconfigkey = 0;
#endif
tNetappIpconfigRetArgs ipinfo;
extern char tmpBuffer[512];
bool Connected = false;
bool UsingSmartConfig = false;
char _deviceName[] = "CC3000";
HTTPClient http;
// Set the first variable to the number of rows, the second to number of pixels. 32 = 32 pixels in a row
Adafruit_WS2801 strip = Adafruit_WS2801(NUM_PIXELS, dataPin, clockPin);
// Setup the colour table and mappings
#define NUM_COLOURS 13
struct ColourTable {
char name[12];
uint32_t value;
} colTable[NUM_COLOURS] = {
{ "red", 0xff0000 },
{ "green", 0x008000 },
{ "blue", 0x0000ff },
{ "cyan", 0x00ffff },
{ "white", 0xffffff },
{ "warmwhite", 0xfdf5e6 },
{ "purple", 0x800080 },
{ "magenta", 0xff00ff },
{ "yellow", 0xffff00 },
{ "orange", 0xffa500 },
{ "pink", 0xff69b4 },
{ "oldlace", 0xfd5e56 },
{ "black", 0x000000 }
};
/** Get status of WiFi connection
* displays and returns value
*/
int32_t getWiFiStatus(void)
{
int32_t status = 0;
const char * WIFI_STATUS[] = {"Disconnected", "Scanning", "Connecting", "Connected"};
status = wifi._wlan.ioctl_statusget();
if (( status > -1 ) && ( status < 4 )) {
uart.printf(" Wifi Status : %s\r\n", WIFI_STATUS[status]);
} else {
uart.printf(" Wifi Status : %d\r\n", status);
}
return status;
}
/** Print info from CC3000
*
*/
void print_cc3000_info()
{
uint8_t myMAC[8];
uint8_t buffer[2];
tNetappIpconfigRetArgs ipinfo2;
tUserFS cc_user_info;
wifi.get_user_file_info((uint8_t *)&cc_user_info, sizeof(cc_user_info));
wifi.get_mac_address(myMAC);
uart.printf(" MAC address : %02x:%02x:%02x:%02x:%02x:%02x\r\n", myMAC[0], myMAC[1], myMAC[2], myMAC[3], myMAC[4], myMAC[5]);
if (! wifi._nvmem.read_sp_version( (unsigned char*)&buffer ) ) {
uart.printf(" CC3000 Firmware Version : %u.%u \r\n", buffer[0], buffer[1]);
} else {
uart.printf(" CC3000 Read nvmem failed!");
}
getWiFiStatus();
if ( wifi.is_dhcp_configured() ) {
wifi.get_ip_config(&ipinfo2);
uart.printf(" Connected to : %s \r\n", ipinfo2.uaSSID);
uart.printf(" IP : %d.%d.%d.%d \r\n", ipinfo2.aucIP[3], ipinfo2.aucIP[2], ipinfo2.aucIP[1], ipinfo2.aucIP[0]);
uart.printf(" Gateway : %d.%d.%d.%d \r\n", ipinfo2.aucDefaultGateway[3], ipinfo2.aucDefaultGateway[2], ipinfo2.aucDefaultGateway[1], ipinfo2.aucDefaultGateway[0]);
uart.printf(" Subnet : %d.%d.%d.%d \r\n", ipinfo2.aucSubnetMask[3], ipinfo2.aucSubnetMask[2], ipinfo2.aucSubnetMask[1], ipinfo2.aucSubnetMask[0]);
uart.printf(" DNS : %d.%d.%d.%d \r\n", ipinfo2.aucDNSServer[3], ipinfo2.aucDNSServer[2], ipinfo2.aucDNSServer[1], ipinfo2.aucDNSServer[0]);
uart.printf(" Cached IP : %s \r\n", wifi.getIPAddress());
uart.printf(" Cached Gateway : %s \r\n", wifi.getGateway());
uart.printf(" Cached Subnet : %s \r\n", wifi.getNetworkMask());
} else {
uart.printf(" Not connected \r\n");
}
}
/** Convert name to colour and set it on LEDs. With colour history, strip will be
* changing colour for every new colour detected producing an almost random effect
* @param colNum Number of the received colour, starts 0 to NUM_COL_HISTORY with highest being latest colour
* @param colStr Received colour name
*/
void setColour( int colNum, char *colStr )
{
// uart.printf("received %s\r\n",colStr);
for( int i=0; i < NUM_COLOURS; i++ ) {
if( strncmp( colTable[i].name, colStr, strlen(colTable[i].name) ) == 0 ) {
for (int n=colNum; n < strip.numPixels()+NUM_COL_HISTORY; n += NUM_COL_HISTORY) {
strip.setPixelColor(n, colTable[i].value);
}
// Update strip after colour has been set
strip.show();
// Slight pause
wait_ms(250);
return;
}
}
uart.printf("No colour found\r\n");
}
#define CL_BUFFSIZE 1024
/** Read Cheerlights colour
* Use http call to get last Cheerlights colour
*/
void readCheerlight( void )
{
char responseStr[CL_BUFFSIZE];
//GET data
uart.printf("\r\nTrying to fetch page...\r\n");
int ret = http.get("http://api.thingspeak.com/channels/1417/feed.csv?results=5", responseStr, CL_BUFFSIZE);
if (!ret) {
uart.printf("Page fetched successfully - read %d characters\r\n", strlen(responseStr));
//uart.printf("Result: %s\r\n", responseStr);
// Parse CSV and set colours
// Get a line
char *ptr = responseStr;
// Skip header line
while(*ptr++ != 0x0a ); // Header
// 5 colours
for( int i=0; i<5; i++ ) {
while(*ptr++ != ','); // Column 1 - Date, Skip
while(*ptr++ != ','); // Column 2 - ID, Skip
char col[10];
char *cPtr = col;
while( *ptr != 0x0a ) { // Column 3 - colour
*cPtr++ = *ptr++;
}
*cPtr = '\0';
uart.printf("%d %s\r\n",i,col);
setColour( i, col );
}
} else {
uart.printf("Error - ret = %d - HTTP return code = %d\r\n", ret, http.getHTTPResponseCode());
}
uart.printf("End of readCheerlights\n\r");
}
/** Initialisations
* Hardware initialisations and any other setup needed
*/
void init()
{
LedSC = 0;
SCButton.mode(PullUp);
NVIC_SetPriority(SSP1_IRQn, 0x0);
NVIC_SetPriority(PIN_INT0_IRQn, 0x1);
// SysTick set to lower priority than Wi-Fi SPI bus interrupt
NVIC_SetPriority(SysTick_IRQn, 0x2);
// Enable RAM1
LPC_SYSCON->SYSAHBCLKCTRL |= (0x1 << 26);
uart.baud(SERIAL_BAUD_RATE);
strip.updatePins(); // Switch to Hardware SPI
strip.begin();
// Update LED contents, to start they are all 'off'
strip.show();
}
/** Main loop, handle WiFi connection, check for button press to start SmartConfig process
*
*/
int main( void )
{
// Initalise the WiFi Module
init();
uart.printf("WiFiDIPCortex Smartconfig Cheerlights\r\n");
wifi.start(0);
// Check if button pressed during startup, if so then go into SmartConfig mode
// otherwise just start wifi
if(!SCButton) {
uart.printf("Smartconfig button pressed\r\n");
//SmartConfig();
uart.printf("\r\nStarting Smart config, waiting for message from smartphone app ....\r\n");
LedSC = 1;
// We dont want to auto reconnect to an access point
wifi._wlan.ioctl_set_connection_policy(0, 0, 0);
// start smart config will disconnect, set the prefix
// wait for a message via a SmartConfig app, store it to the profile list
// finally it will reenable auto connection, triggering the module to connect to the new access point
wifi.start_smart_config(0);
LedSC = 0;
UsingSmartConfig = true;
uart.printf("Back from SmartConfig\r\n");
wait(2); // for dhcp to configure
// TODO: Add this into start_smart_config
if ( wifi.is_dhcp_configured() ) {
if (!Connected) {
// We have just connected
Connected = true;
// This might need calling for mdsn advertiser to work.
// uint32_t ip_addr[4] = {0,0,0,0};
// wifi._socket.gethostbyname((uint8_t *)_deviceName, strlen(_deviceName), uint32_t *ip_addr);
// Start the mdns service, this tells any smart config apps listening we have succeeded
wifi._socket.mdns_advertiser(1, (uint8_t *)_deviceName, strlen(_deviceName));
UsingSmartConfig = false;
}
} else {
Connected = false;
}
} else {
uart.printf("Normal startup\r\n");
}
wait_ms(750);
LedSC = 0;
print_cc3000_info();
// Check if we're connected to WiFi and have an IP address, if not then just flash LED until reset
uint32_t status = getWiFiStatus();
if( status != 3 || !wifi.is_dhcp_configured() ) {
while( 1 ) {
LedSC = !LedSC;
wait_ms(500);
}
}
while (1) {
if( getWiFiStatus() == 0 ) {
// Not connected, attempt reconnect
;
}
readCheerlight();
// Pause for a minute before checking again
wait(60);
}
}