Monitoring blinkenlights with a Particle Photon

One of the e-mails I've been pending to work on for (gasp!) a year now
is from Karanbir; we discussed a simple, cloudless, and inexpensive
solution to driving a few lights for monitoring purposes, and I think
I've found a solution which fits the bill, even if this can probably
be done less expensively.

The Particle Photon [1]I wrote about recently, can be hooked up to a
strip of LEDs. I chose to use an [2]Adafruit Dotstar digital LED strip
which has 30 RGB LEDs on it.

monitoring strip

Instead of using the Particle cloud functions, I decided to drive the
LEDs using [3]MQTT, which makes things easy in my environment. The
code on the Photon sets up the dotstar strip and expects an MQTT
payload with the LED number (0 through 29) and the state (0 == OK,
etc.).
/*
* warner.ino (C) December 2015 by Jan-Piet Mens <[email protected]>
* Subscribe to an MQTT topic and read a string with two integers from
* each message. The first integer specifies an LED to set (0 -- NUMPI
XELS)
* on a Dotstar strip, whereas the second integer is a Nagios-type
* number from Unknown (-1) through ERROR (2).
*
* To set LED 7 to OK:      mosquitto_pub -t led -m "7 0"
* To set LED 9 to WARNING: mosquitto_pub -t led -m "9 1"
*
*
* The Dotstar is Adafruit's https://www.adafruit.com/products/2238
*
*                            +-----+
*                 +----------| USB |----------+
*                 |          +-----+       *  |
*                 | [ ] VIN           3V3 [ ] |
*                 | [ ] GND           RST [ ] |
*                 | [ ] TX           VBAT [ ] |
*                 | [ ] RX  [S]   [R] GND [ ] |
*                 | [ ] WKP            D7 [ ] |
*                 | [ ] DAC +-------+  D6 [ ] |
* Dotstar CLCK -->| [*] A5  |   *   |  D5 [ ] |
*                 | [ ] A4  |Photon |  D4 [ ] |
* Dotstar DATA -->| [*] A3  |       |  D3 [ ] |
*                 | [ ] A2  +-------+  D2 [ ] |
*                 | [ ] A1             D1 [ ] |
*                 | [ ] A0             D0 [ ] |
*                 |                           |
*                  \    []         [______]  /
*                   \_______________________/
*
*
*/

#include "MQTT/MQTT.h"
#include "dotstar/dotstar.h"
#include <stdlib.h>


#define NUMPIXELS   30 // Number of LEDs in strip
#define SUBTOPIC    "led"
#define PUBTOPIC    "led/status"

//-------------------------------------------------------------------
// Here's how to control the LEDs from any two pins (Software SPI):
//-------------------------------------------------------------------
// #define DATAPIN   D4
// #define CLOCKPIN  D5
// Adafruit_DotStar strip = Adafruit_DotStar(NUMPIXELS, DATAPIN, CLOCK
PIN /* JPM */, DOTSTAR_GBR);

// Hardware SPI
Adafruit_DotStar strip = Adafruit_DotStar(NUMPIXELS, A5, A3);

// char *host = "mqtt.example.org"
byte host[] = { 192, 168, 1, 130 };
MQTT client(host, 1888, callback);

static int colors[] = { 0x000000,   // Off    Unknown (-1)
                       0x00000B,   // Green  OK (0)
                       0x040004,   // Yello  WARNING (1)
                       0x0B0000 }; // Red    ERROR (2)

void ledon(int led, int status) {
   char payload[128];

   if (status >= -1 && status <= 2) {
       if (led >= 0 && led <= NUMPIXELS) {
           strip.setPixelColor(led, colors[status + 1]);
           strip.show();

           snprintf(payload, sizeof(payload), "LED %d set to %d at %l
d", led, status, Time.now());
           client.publish(PUBTOPIC, payload);
       }
   }
}

void callback(char* topic, byte* payload, unsigned int length) {
   char p[length + 1];
   memcpy(p, payload, length);
   p[length] = 0;
   int led, status;

   if (sscanf(p, "%d %d", &led, &status) == 2) {
       ledon(led, status);
   } else {
       client.publish(PUBTOPIC, "can't parse two integers from payloa
d");
   }
}

void mqtt_connect() {

   client.connect("photon-warner", PUBTOPIC, MQTT::QOS2, 0, "Oops: wa
rner going down!");

   if (client.isConnected()) {
       client.publish(PUBTOPIC, "online");
       client.subscribe(SUBTOPIC);
   }
}

void setup() {
   strip.begin(); // Initialize pins for output
   strip.show();  // Turn all LEDs off ASAP

   mqtt_connect();
}

void loop() {
   if (client.isConnected()) {
       client.loop();
   } else {
       client.disconnect();
       mqtt_connect();
   }
}

For EUR 40.00 and a bit of LEGO which my Assistant In Charge Of LEGO
Enclosures provided, I have a blinkenlights thing which shows me the
state of 30 services. Add a few labels to the LEDs, and Bob's your
uncle.

References

  1. https://jpmens.net/2015/12/15/discovering-a-particle-photon/
  2. https://www.adafruit.com/products/2238
  3. http://jpmens.net/2013/02/25/lots-of-messages-mqtt-pub-sub-and-the-mosquitto-broker/