Black Lives Matter - Action and Equality. ... Adafruit joins the Stop Hate for Profit campaign.
0

Color picker, Feather M0 WiFi, keep getting same values repe
Moderators: adafruit_support_bill, adafruit

Forum rules
If you're posting code, please make sure your code does not include your Adafruit IO Active Key or WiFi network credentials.
Please be positive and constructive with your questions and comments.

Color picker, Feather M0 WiFi, keep getting same values repe

by hukuzatuna on Fri Apr 15, 2016 6:41 am

So I have a color picker running at https://io.adafruit.com/hukuzatuna/controlneopixels (it's public). I have a Feather M0 WiFi (WINC1500) with a NeoPixel FeatherWing and OLED FeatherWing on a Feather Doubler. When a visitor picks a color and hits save, the color value is published. The sketch on the Feather subscribes to the MQTT feed and reads the value. It then displays the value on the OLED, along with the current (no pun intended) battery voltage, and randomly selects a NeoPixel and turns it on to the color that the visitor sent. This all works beautifully (if only I could get my FONA version working as well!)

Here's the problem. If I send one color (presently 180213) and then wait, the same color shows up the next time I check the feed. And again, and again. Do I need to explicitly delete the value from the MQTT queue? If so, could you give me a pointer to how to do that?

Code follows... (Sorry about the tab stops. And if you decide to run the code you'll need to change feed names, user name, AIO secret key, SSID, and WiFi key)

Cheers,
Phil

P.S. I'm the Global Security Architect for the largest consulting company in the world, and in two weeks I'm co-teaching a virtual class on the security of IoT. We usually get about 400 people in these classes.... I'm going to use this device as an IoT demonstrator, along with a Raspberry Pi "security camera" that I built and programmed. At the end of the class I'm giving away the Azure Feather M0 WiFi Internet of Things Starter Pack as a door prize of sorts. Somebody in my company is going to be really happy, and Adafruit is going to get a ton of free advertising. :-)

Code: Select all | TOGGLE FULL SIZE
//###############################################################################
// DeloitteIoTNeoPixelDemo - Allow the colorPicker at io.adafruit.com to send
// colors, which will then be displayed on the NeoPixel Featherwing on a randomly-
// selected LED. We can't allow them to pick the LED or they'll write rude things
// on the display.
//
// Credit: This is based heavily on the work by Limor Fried and Tony DiCola from
// Adafruit. Suggest (strongly) you go to adafruit.com and buy some product from
// them. WINC1500 code modified from example code provided by Michael Margolis and
// Tom Igoe.
//
// Philip R. Moyer
//
// This source code is in the public domain and is released under the BSD license.
// Any further redistribution must include this header.
//
//###############################################################################

//###############################################################################
// Includes and defines
//###############################################################################

#include <Adafruit_NeoPixel.h>
#ifdef __AVR__
  #include <avr/power.h>
#endif

#include <SPI.h>                                    // SPI interface API
#include <Adafruit_WINC1500.h>                        // WINC1500 wireless header
#include <Adafruit_NeoPixel.h>                        // NeoPixel control library
#include "Adafruit_MQTT.h"                              // MQTT library
#include "Adafruit_MQTT_Client.h"                     // MQTT client library
#include <Wire.h>                             // Wire support library
#include <Adafruit_GFX.h>                     // Adafruit graphics library
#include <Adafruit_SSD1306.h>                 // Adafruit OLED display library
 
#define OLED_RESET 3                          // Reset pin for the display
Adafruit_SSD1306 display(OLED_RESET);
 
#define LOGO16_GLCD_HEIGHT 16                 // Adafruit logo height
#define LOGO16_GLCD_WIDTH  16                 // Adafruit logo width
static const unsigned char PROGMEM logo16_glcd_bmp[] =
{ B00000000, B11000000,
  B00000001, B11000000,
  B00000001, B11000000,
  B00000011, B11100000,
  B11110011, B11100000,
  B11111110, B11111000,
  B01111110, B11111111,
  B00110011, B10011111,
  B00011111, B11111100,
  B00001101, B01110000,
  B00011011, B10100000,
  B00111111, B11100000,
  B00111111, B11110000,
  B01111100, B11110000,
  B01110000, B01110000,
  B00000000, B00110000 };

#if (SSD1306_LCDHEIGHT != 32)
#error("Height incorrect, please fix Adafruit_SSD1306.h!");
#endif
 
#define PIN           6                                    // The pin on the device that drives the NeoPixels
#define NUMPIXELS     32                                 // Number of NeoPixels in the array

#define AIO_SERVER      "io.adafruit.com"         // Cloud Service Provider
#define AIO_SERVERPORT  1883                           // CSP TCP port
#define AIO_USERNAME    "hukuzatuna"               // CSP service login
#define AIO_KEY         "SecretKey"   // Secret key

// Note: this section will need to be removed/altered to support the FONA eventually. -prm
#define WINC_CS            8                           // WINC1500 Chip Select
#define WINC_IRQ         7                           // WINC1500 interrupt request line
#define WINC_RST         4                           // WINC1500 reset line
#define WINC_EN            2                           // WINC1500 enable

#define VBATPIN       9                       // Pin to read battery voltage
   

//###############################################################################
// Globals
//###############################################################################

// When we setup the NeoPixel library, we tell it how many pixels, and which pin to use to send signals.
Adafruit_NeoPixel pixels = Adafruit_NeoPixel(NUMPIXELS, PIN, NEO_GRB + NEO_KHZ800);

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

int status = WL_IDLE_STATUS;   // WINC1500 chip status
char ssid[] = "ssid";               // WiFi network SSID
char pass[] = "wifipwd";      // WiFi password (NOTE: redact before doing a git push!!!)

int delayval = 2000;               // delay for two seconds
int cPixel;                              // The current pixel
int pixelson[32];                     // An array that tracks whether a given pixel is on (0 = off)
int maxBright = 70;                  // Maximum pixel brightness. 0-255, but anything over 100 is blinding.

const char MQTT_SERVER[] PROGMEM    = AIO_SERVER;                     // Server memory allocation
const char MQTT_CLIENTID[] PROGMEM  = __TIME__ AIO_USERNAME;   // User ID memory allocation
const char MQTT_USERNAME[] PROGMEM  = AIO_USERNAME;                  // User name memory allocation
const char MQTT_PASSWORD[] PROGMEM  = AIO_KEY;                        // Secret key memory allocation

// Set up an MQTT client session
Adafruit_WINC1500Client client;
Adafruit_MQTT_Client mqtt(&client, MQTT_SERVER, AIO_SERVERPORT, MQTT_CLIENTID, MQTT_USERNAME, MQTT_PASSWORD);

// Set up a feed called 'onoff' for subscribing to changes.
const char ONOFF_FEED[] PROGMEM = AIO_USERNAME "/feeds/onbutton";
Adafruit_MQTT_Subscribe onoffbutton = Adafruit_MQTT_Subscribe(&mqtt, ONOFF_FEED);


//###############################################################################
// Functions
//###############################################################################

// This function sets a random pixel to a random color. It takes no arguments
// and returns no value. Its only purpose is to make pretty colors on the
// NeoPixel device (usually a FeatherWing).

void setRandomPixel() {
  // pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
    cPixel = random(32);                        // Pick a random pixel
    if (1 == pixelson[cPixel]) {            // If the pixel is on
      pixels.setPixelColor(cPixel, pixels.Color(0,0,0));   // Turn it off
      pixelson[cPixel] = 0;                     // Track that it's off
    }
    else {                                       // The pixel is already off
      // Set pixel to random color. They're very bright, so max it out at well below 255.
      pixels.setPixelColor(cPixel, pixels.Color(random(maxBright),random(maxBright),random(maxBright)));
      pixelson[cPixel] = 1;                     // Track that pixel is on
    }

    // This sends the updated pixel color to the hardware.
    pixels.show();
}


// This function sets a random pixel to a color that is selected by the caller.
// This is connected to io.adafruit.com's color picker, so people can
// anonymously send pixels to the device. It takes a standard Internet hex
// color specification (e.g., 0xFFFFFF) as input.

void setRandomPixelColor(char *hexstring) {

   // Convert the hex color string to usable integers.
   long number = strtol( &hexstring[1], NULL, 16);
  long r = number >> 16;                  // Red value, using bit shift
  long g = number >> 8 & 0xFF;         // Green value, using bit shift and logical operator
  long b = number & 0xFF;                  // Blue value, using logical operator

  // pixels.Color takes RGB values, from 0,0,0 up to 255,255,255
    cPixel = random(32);                  // Pick a random pixel
    if (1 == pixelson[cPixel]) {      // If the pixel is on
      pixels.setPixelColor(cPixel, pixels.Color(0,0,0));   // Turn it off
      pixelson[cPixel] = 0;               // Track that it's off
    }
    else {                                       // The pixel is already off
      // Set pixel to assigned color.
      pixels.setPixelColor(cPixel, pixels.Color(r, g, b));
      pixelson[cPixel] = 1;               // Track that pixel is on
    }

    // This sends the updated pixel color to the hardware.
    pixels.show();
}

// This function, resetPixels, turns off all the currently on pixels in the
// NeoPixel board.

void resetPixels() {
   for (int i = 0; i < NUMPIXELS; i++) {                     // For each LED
      pixelson[i] = 0;                              // Set tracker to "off"
      pixels.setPixelColor(i, pixels.Color(0,0,0));      // Set LED to off
      pixels.show();                                 // Send to hardware
   }
}

// This function, printWiFiStatus, just displays info about the current
// WiFi connection. This will not be needed for the FONA version.

void printWiFiStatus() {
  IPAddress ip = WiFi.localIP();                           // print your WiFi shield's IP address:
  long rssi = WiFi.RSSI();                                 // print the received signal strength:
}

// This function, MQTT_connect, connects and reconnects as necessary to the MQTT server.
// Should be called in the loop function and it will take care of connecting.

void MQTT_connect() {
  int8_t ret;                                       // Return value

  // attempt to connect to Wifi network:
  while (WiFi.status() != WL_CONNECTED) {         // While we're not connected...
    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);              // Initialize hardware for WiFi with SSID/Pass

    // wait 10 seconds for connection:
    uint8_t timeout = 10;
    while (timeout && (WiFi.status() != WL_CONNECTED)) {  // Still not connected
      timeout--;                                  // Decrement the number of times we'll try
      delay(1000);                                // Chill for a bit
    }
  }

  // Stop if already connected.
  if (mqtt.connected()) {                         // Are we connected to MQTT?
    return;                                       // If we are, bail here
  }

  // Ok, we're not connected to MQTT, but we have a network...
  while ((ret = mqtt.connect()) != 0) {                 // connect will return 0 for connected
       mqtt.disconnect();                         // Disconnect() to reset MQTT state
       delay(5000);                               // wait 5 seconds
  }
}


//###############################################################################
// Setup - main
//###############################################################################

// This is one of the two standard functions for every Arduino program, with the
// other being loop(). This one runs once at the beginning of the program execution
// and is ordinarily used to initialize hardware and variables.

void setup() {
#ifdef WINC_EN                                    // If the WINC1500 enable pin is connected...
  pinMode(WINC_EN, OUTPUT);                       // The pin is output
  digitalWrite(WINC_EN, HIGH);                    // Set HIGH to enable WiFi
#endif

   Serial.begin(115200);                                 // Start the serial console

  pixels.begin();                                    // This initializes the NeoPixel library.
   resetPixels();                                    // Turn off the pixels, if on

   // Make sure we have WiFi hardware, or there's no point continuing.
   if (WiFi.status() == WL_NO_SHIELD) {
    Serial.println(F("No WiFi hardware. Bailing out...."));
      while (true);                                 // Spin loop
   }

  // Take a moment to initialize the OLED display and put up the Adafruit splash screen
  // by default, we'll generate the high voltage from the 3.3v line internally! (neat!)
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);  // initialize with the I2C addr 0x3C (for the 128x32)
 
  // Show image buffer on the display hardware.
  // Since the buffer is intialized with an Adafruit splashscreen
  // internally, this will display the splashscreen.
  display.display();
  delay(2000);
 
  // Clear the buffer.
  display.clearDisplay();

  // Ok, back to the startup routine. -prm

   // Attempt to conect to the WiFi network.
   Serial.println("Connecting to WiFi netowrk.");
   while (WiFi.status() != WL_CONNECTED) {
      status = WiFi.begin(ssid, pass);                     // Connect to WPA2 network
      uint8_t timeout = 10;                              // Set a timeout variable
      while (timeout && (WiFi.status() != WL_CONNECTED)) {
         timeout--;                              // Decrement timeout
         delay(1000);                              // Delay for one second
      }
   }

   Serial.println("Connected to network.");
   printWiFiStatus();                                 // Display WiFi status data

  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(0,0);
  display.print("Connected to ");
  display.println(ssid);
  display.setCursor(0,16);
  display.print("IP address: ");
  display.println(WiFi.localIP());
  display.display();
  delay(2000);

   mqtt.subscribe(&onoffbutton);                              // Subscribe to MQTT feed
}

//###############################################################################
// Loop - main
//###############################################################################

// This is one of the two standard functions for every Arduino program, with the
// other being setup(). This one runs continuously, forever, and executes the
// Arduino program code.

void loop() {
   MQTT_connect();                                    // Connect to CSP
   Adafruit_MQTT_Subscribe *subscription;               // Create a subscription object
  char *lastValue;                                // Pointer to last value from subscription

   while ((subscription = mqtt.readSubscription(5000))) {  // Read the subscription
    if (subscription == &onoffbutton) {           // Is it for the feed we want?
      lastValue = (char *)onoffbutton.lastread;   // Save the value since we need it twice
      // setRandomPixelColor((char *)onoffbutton.lastread);  // Set a random pixel to the color sent
      setRandomPixelColor(lastValue);
      display.clearDisplay();
      display.setCursor(0,0);
      display.print("Rcvd: ");
      display.println(lastValue);
      display.display();
    }
  }

  // Display the battery level - this will eventually be displayed on the OLED -prm
  float measuredvbat = analogRead(VBATPIN);
  measuredvbat *= 2;    // we divided by 2, so multiply back
  measuredvbat *= 3.3;  // Multiply by 3.3V, our reference voltage
  measuredvbat /= 1024; // convert to voltage
  Serial.print("VBat: " ); Serial.println(measuredvbat);
  display.setCursor(0,16);
  display.print("VBat: ");
  display.println(measuredvbat);
  display.display();
}

hukuzatuna
 
Posts: 113
Joined: Wed Aug 14, 2013 11:40 pm

Please be positive and constructive with your questions and comments.