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