Build Monitor Light Siren (using MQTT)
I've wanted to do something with a MQTT broker for a while now, and I finally had a project that would be perfect to use a little ESP8266 chip listening into a MQTT broker. I decided to make a build monitor for our source control at my current job at New River Kinematics (NRK). The main goal is to have the siren go off whenever someone checks something in that either breaks the build or fails a unit test. So I picked up some ESP8266 boards from Adafruit, and a LED-based siren light off of eBay.
The setup was pretty simple, just hooked into a free MQTT broker through Adafruits io.adafruit.com, which was a real simple setup. Adafruit always provides great tutorials, and I used their Huzzah ESP8266 chip. The Huzzah board can be flashed as if it's just an Arduino with a built in wifi-chip, which made things convinent. After setting up connection to the broker, I added a simple relay to get things going quickly since I couldn't find any FETS lying around and it provided some great audible feedback to the siren "clicking " on. Since the siren is just an LED array in a ring shape, it was nice to actually hear something click on when the siren was toggled on, but it was eventually replaced with a TIP120 that just acts a relay to open current flow to the siren light. Initially I brought a simple protoboard-circuit in for testing in the office. Shortly afterward it was suggested from someone in the office that I could put it in a "cool enclosure or something," which was a good idea but I wanted to make it a bit more compact and get all the modded circuit bits into the siren. Getting all the control bits into the siren was the most time consuming task of the entire project, because there was not much room inside the siren. The base looked like a fairly large enclosure, but in reality most the space is used by a large magnet (I guess the normal intent of the siren is to be placed on the tops of vehicles). I managed to make some space by desoldering the top bit of the circuit which connected all the vertical LED boards together. The Huzzah chip was placed in the hollow space between all the LEDs, and then wires were rain underneath to all the other components. This is where things got gross, and frustrating because I was kinda proud of how organized I kept things on the perfboard. I inevitably found myself just making a rats nest of wires and components down under the LED control board, and then I decided that the siren should have some more controls so I added a couple LED indicators and a button that I mounted to the sidewall of the siren. I used some black hot-snot to keep everything in place, and then somehow I managed to get all the wires into good locations so I could screw back down the main LED circuit board to begin to close everything up.. I wrote a simple C# program that monitors our build server, and will publish failures to the io.Adafruit.com broker. The siren's listen to published events from the broker, and will begin flashing if the server publishes "ON". The sirens got a good reception around the office, and I was asked to make another build monitor. Somehow, it wasn't any easier for the second monitor to shove all the components and wires into the base of the siren, but it does look good and compact. The magnetic base made things convenient for mounting to the wall, since they easily stick to the metal in the drywall corner bead.
|
/*************************************************** Adafruit MQTT Library ESP8266 Example Must use ESP8266 Arduino from: https://github.com/esp8266/Arduino Works great with Adafruit's Huzzah ESP board & Feather ----> https://www.adafruit.com/product/2471 ----> https://www.adafruit.com/products/2821 Adafruit invests time and resources providing this open source code, please support Adafruit and open-source hardware by purchasing products from Adafruit! Written by Tony DiCola for Adafruit Industries. MIT license, all text above must be included in any redistribution Assuming the hardware is okay and the right binary is loaded it's almost surly a power problem. 1) Make sure what ever voltage regulator you're using is rated for 200mA or more. In your case the LD1117 can source 800mA so that's good. 2) Make sure you're upstream power supply can source 200mA or more. If you're powering from a USB hub make sure the hub is powered. 3) Make sure you have some large low ESR capacitors across GND and 3.3v. Two capacitors: 10uF and 100uF worked for me (there's nothing magic about these exact values, 10-100uF should work). The ESP8266 can draw huge (relatively) amounts of current for short periods while booting or transmitting. This can cause a bad transient on the power supply, which will cause the system to reboot, which can lead to an infinite reboot cycle. ****************************************************/ #include <ESP8266WiFi.h> #include "Adafruit_MQTT.h" #include "Adafruit_MQTT_Client.h" /************************* WiFi Access Point *********************************/ #define WLAN_SSID "SSID_NAME" #define WLAN_PASS "PASSWORD" /************************* Adafruit.io Setup *********************************/ #define AIO_SERVER "io.adafruit.com" #define AIO_SERVERPORT 1883 // use 8883 for SSL #define AIO_USERNAME "USERNAME" #define AIO_KEY "KEY" /************ Global State (you don't need to change this!) ******************/ // Create an ESP8266 WiFiClient class to connect to the MQTT server. WiFiClient client; // or... use WiFiFlientSecure for SSL //WiFiClientSecure client; // Store the MQTT server, username, and password in flash memory. // This is required for using the Adafruit MQTT library. const char MQTT_SERVER[] PROGMEM = AIO_SERVER; const char MQTT_USERNAME[] PROGMEM = AIO_USERNAME; const char MQTT_PASSWORD[] PROGMEM = AIO_KEY; // Setup Relay pin int relayPin = 12; bool pinOn = false; int onPin = 4; int wifiPin = 13; int buttonPin = 15; // Variables int buttonState = 0; int lightState = 0; // Setup the MQTT client class by passing in the WiFi client and MQTT server and login details. Adafruit_MQTT_Client mqtt(&client, MQTT_SERVER, AIO_SERVERPORT, MQTT_USERNAME, MQTT_PASSWORD); /****************************** Feeds ***************************************/ // Setup a feed called 'onoff' for subscribing to changes. const char ONOFF_FEED[] PROGMEM = AIO_USERNAME "/feeds/onoff"; Adafruit_MQTT_Subscribe onoffbutton = Adafruit_MQTT_Subscribe(&mqtt, ONOFF_FEED); Adafruit_MQTT_Publish onOffPublish = Adafruit_MQTT_Publish(&mqtt, ONOFF_FEED); /*************************** Sketch Code ************************************/ // Bug workaround for Arduino 1.6.6, it seems to need a function declaration // for some reason (only affects ESP8266, likely an arduino-builder bug). void MQTT_connect(); void setup() { Serial.begin(115200); delay(10); pinMode(relayPin, OUTPUT); pinMode(onPin, OUTPUT); pinMode(wifiPin, OUTPUT); pinMode(buttonPin, INPUT); digitalWrite(onPin, HIGH); // Set pin to on right when running.. Serial.println(F("Adafruit MQTT demo")); // Connect to WiFi access point. Serial.println(); Serial.println(); Serial.print("Connecting to "); Serial.println(WLAN_SSID); WiFi.begin(WLAN_SSID, WLAN_PASS); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); // Setup MQTT subscription for onoff feed. mqtt.subscribe(&onoffbutton); } uint32_t x = 0; void loop() { // Ensure the connection to the MQTT server is alive (this will make the first // connection and automatically reconnect when disconnected). See the MQTT_connect // function definition further below. MQTT_connect(); // this is our 'wait for incoming subscription packets' busy subloop // try to spend your time here Adafruit_MQTT_Subscribe *subscription; while ((subscription = mqtt.readSubscription(5000))) { if (subscription == &onoffbutton) { char *value = (char *)onoffbutton.lastread; Serial.print(F("Got: ")); Serial.println(value); if (strcmp((char *)onoffbutton.lastread, "ON") == 0) { digitalWrite(relayPin, HIGH); buttonState = 1; } if (strcmp((char *)onoffbutton.lastread, "OFF") == 0) { digitalWrite(relayPin, LOW); buttonState = 0; } } } // Button for testing if connected to broker by publishing to FEED buttonState = digitalRead(buttonPin); if (buttonState == HIGH) { //Serial.println("Button pressed!!"); if (strcmp((char *)onoffbutton.lastread, "ON") == 0){ Serial.println("OFF!!"); onOffPublish.publish((char *) "OFF"); } if (strcmp((char *)onoffbutton.lastread, "OFF") == 0) { Serial.println("ON!!"); onOffPublish.publish((char *) "ON"); } } // ping the server to keep the mqtt connection alive // NOT required if you are publishing once every KEEPALIVE seconds /* if(! mqtt.ping()) { mqtt.disconnect(); } */ } // Function to connect and reconnect as necessary to the MQTT server. // Should be called in the loop function and it will take care if connecting. void MQTT_connect() { int8_t ret; digitalWrite(wifiPin, LOW); // Stop if already connected. if (mqtt.connected()) { digitalWrite(wifiPin, HIGH); return; } Serial.print("Connecting to MQTT... "); uint8_t retries = 3; while ((ret = mqtt.connect()) != 0) { // connect will return 0 for connected Serial.println(mqtt.connectErrorString(ret)); Serial.println("Retrying MQTT connection in 5 seconds..."); mqtt.disconnect(); delay(5000); // wait 5 seconds retries--; if (retries == 0) { // basically die and wait for WDT to reset me while (1); } } Serial.println("MQTT Connected!"); } |