I had been looking for a STL of a stoplight to print for about a year now. I wanted to use the colors of the stoplight to signal to my younger kids when it was ok to wake up in the morning, and when it was time to go back to sleep. My ideal was that I could use Node-Red running on the home server via MQTT to regulate when the stoplight changed colors. Thingiverse’s search is horrible and you could spend days there and not actually get what you are looking for so I never found one that would work. The other day I was searching for some reference STLs of something and accidentally came across a STL for a stoplight. Not one, but three (two remixed from the other).
The first one looked great, good size and decent design. Except it was designed for LEDs and an ATTiny to drive its sequence. The second was a remix of the first. The third was another remix that extended the back casing. The remixes made things easier to print but still relied on LEDs and an ATTiny of sorts. This was a great starting point for me. I have no problems modifying STLs for my purposes. I like to use Tinkercad, not very good with Fusion 360. I downloaded the files and started my own remix. I took elements from all three versions of the stoplight.
I modified the back case to allow a Lolin v3 to be able to mount to it. Then I had to create a cover for the Lolin. I took the front from the original thing, I preferred its one piece to the remixes four piece but I filled in the slot for the little switch. I used the LED panes/covers from the original, unmodified. This was great, I had a front and back a cover, LED panes and the inlay to hold the LEDs. So I printed it all out and went to work. First things first, I tested the LEDs. Like I thought, the LEDs I have are not the super bright ones and running off of the Lolins 3v they just didn’t have enough brightness to shine through very well. No super bright LEDs but I do have some WS2812 neopixels. I hooked one up to test and yes they were perfect. So I modified the LED inlay to hold three neopixels.
I wanted to be able to control the stoplight via MQTT from my server running Node-Red. I used the neopixel example from Adafruit and the default Pubsubclient example for an ESP8266. Mashed the two together and I was able to change the colors on the fly with no problems. I showed off the stoplight to a friend of mine and he loved it. He wanted one for himself, but he doesn’t have a server or anything that runs MQTT. No problem, the Lolin can handle web GUIs. A quick google for a web server on an ESP turned up a nice little tutorial on how to turn on and off GPIO pins from a web GUI. BAM! I took that code and mashed it up with the neopixel code I already had an I was able to get a nice little web page displayed to change the colors of the stoplight. This is awesome.
So behold! Two versions of a “smart” IoT stoplight, haha! One uses MQTT to change the colors. The other allows you to connect to a nice web page to change the colors of the light.
These are the devices I used
Stoplight Remix STL
I also uploaded the STL to Thingiverse if you wanna head over there and grab em.
Neopixel Stoplight (Web GUI version) Code
This will host a web page to allow you to connect and change the lights. Connects to your WiFi.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 |
/* * neopixel mqtt stop light, D5 as signal for three (3) ws2812s * stop light changes states via MQTT commands * * commands sent via MQTT topic * default state = off * 0 = off * 1 = red * 2 = yellow * 3 = green * */ #include <ESP8266WiFi.h> #include <PubSubClient.h> #include <Adafruit_NeoPixel.h> #define PIN D5 // neopixel // update these values for your network const char* ssid = "your_ssid"; const char* password = "your_passwd"; const char* mqtt_server = "your_server"; const char* subTopic = "stoplight/"; // topic to subscribe to // Parameter 1 = number of pixels in strip // Parameter 2 = pin number (most are valid) // Parameter 3 = pixel type flags, add together as needed: // NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs) // NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers) // NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products) // NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2) Adafruit_NeoPixel strip = Adafruit_NeoPixel(3, PIN, NEO_RGB + NEO_KHZ800); // define the color codes by name to make it easier to call later on uint32_t green = strip.Color(255, 0, 0); uint32_t red = strip.Color(0, 255, 0); uint32_t yellow = strip.Color(255, 100, 0); WiFiClient espClient; PubSubClient client(espClient); long lastMsg = 0; char msg[50]; int value = 0; void setup_wifi() { delay(100); // we start by connecting to a WiFi network Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } randomSeed(micros()); Serial.println(""); Serial.println("WiFi connected"); Serial.println("IP address: "); Serial.println(WiFi.localIP()); } void callback(char* topic, byte* payload, unsigned int length) { Serial.print("Command from MQTT broker is : ["); Serial.print(topic); int p =(char)payload[0]-'0'; switch (p) { case 0: Serial.println("turn off"); strip.clear(); strip.show(); break; case 1: Serial.println("red"); strip.clear(); strip.setPixelColor(0, red); strip.show(); break; case 2: Serial.println("yellow"); strip.clear(); strip.setPixelColor(1, yellow); strip.show(); break; case 3: Serial.println("green"); strip.clear(); strip.setPixelColor(2, green); strip.show(); break; default: Serial.println("off"); strip.clear(); strip.show(); } Serial.println(); } // end callback void reconnect() { // loop until we're reconnected while (!client.connected()) { Serial.print("Attempting MQTT connection..."); // create a random client ID String clientId = "ESP8266Client-"; clientId += String(random(0xffff), HEX); // attempt to connect // if you MQTT broker has clientID, username and password // please change following line to "if (client.connect(clientId,userName,passWord))" if (client.connect(clientId.c_str())) { Serial.println("connected"); // once connected to MQTT broker, subscribe command if any client.subscribe(subTopic); } else { Serial.print("failed, rc="); Serial.print(client.state()); Serial.println(" try again in 5 seconds"); // wait 6 seconds before retrying delay(6000); } } } // end reconnect() void setup() { Serial.begin(115200); strip.begin(); strip.show(); // initialize all pixels to 'off' setup_wifi(); client.setServer(mqtt_server, 1883); client.setCallback(callback); } void loop() { if (!client.connected()) { reconnect(); } client.loop(); } |
Neopixel Stoplight (MQTT version) Code
This will connect to a MQTT server and subscribe to a topic to listen for incoming messages.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 |
/* * neopixel web gui stop light, D5 as signal for three (3) ws2812s * stop light changes states via commands from a webpage gui * * Code adapted from: * Rui Santos * Complete project details at https://randomnerdtutorials.com * */ // Load Wi-Fi library #include <ESP8266WiFi.h> #include <Adafruit_NeoPixel.h> // Replace with your network credentials const char* ssid = "your_ssid"; const char* password = "your_passwd"; #define PIN D5 // neopixel // Parameter 1 = number of pixels in strip // Parameter 2 = pin number (most are valid) // Parameter 3 = pixel type flags, add together as needed: // NEO_KHZ800 800 KHz bitstream (most NeoPixel products w/WS2812 LEDs) // NEO_KHZ400 400 KHz (classic 'v1' (not v2) FLORA pixels, WS2811 drivers) // NEO_GRB Pixels are wired for GRB bitstream (most NeoPixel products) // NEO_RGB Pixels are wired for RGB bitstream (v1 FLORA pixels, not v2) Adafruit_NeoPixel strip = Adafruit_NeoPixel(3, PIN, NEO_RGB + NEO_KHZ800); // define the color codes by name to make it easier to call later on uint32_t green = strip.Color(255, 0, 0); uint32_t red = strip.Color(0, 255, 0); uint32_t yellow = strip.Color(255, 100, 0); // Set web server port number to 80 WiFiServer server(80); // Variable to store the HTTP request String header; // Auxiliar variables to store the current output state String redState = "off"; String yellowState = "off"; String greenState = "off"; // Current time unsigned long currentTime = millis(); // Previous time unsigned long previousTime = 0; // Define timeout time in milliseconds (example: 2000ms = 2s) const long timeoutTime = 2000; void setup() { Serial.begin(115200); strip.begin(); strip.show(); // initialize all pixels to 'off' // Connect to Wi-Fi network with SSID and password Serial.print("Connecting to "); Serial.println(ssid); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } // Print local IP address and start web server Serial.println(""); Serial.println("WiFi connected."); Serial.println("IP address: "); Serial.println(WiFi.localIP()); server.begin(); } void loop(){ WiFiClient client = server.available(); // Listen for incoming clients if (client) { // If a new client connects, Serial.println("New Client."); // print a message out in the serial port String currentLine = ""; // make a String to hold incoming data from the client currentTime = millis(); previousTime = currentTime; while (client.connected() && currentTime - previousTime <= timeoutTime) { // loop while the client's connected currentTime = millis(); if (client.available()) { // if there's bytes to read from the client, char c = client.read(); // read a byte, then Serial.write(c); // print it out the serial monitor header += c; if (c == '\n') { // if the byte is a newline character // if the current line is blank, you got two newline characters in a row. // that's the end of the client HTTP request, so send a response: if (currentLine.length() == 0) { // HTTP headers always start with a response code (e.g. HTTP/1.1 200 OK) // and a content-type so the client knows what's coming, then a blank line: client.println("HTTP/1.1 200 OK"); client.println("Content-type:text/html"); client.println("Connection: close"); client.println(); // turns the neopixels on and off if (header.indexOf("GET /red/on") >= 0) { Serial.println("Red on"); redState = "on"; yellowState = "off"; greenState = "off"; strip.clear(); strip.setPixelColor(0, red); strip.show(); } else if (header.indexOf("GET /red/off") >= 0) { Serial.println("Red off"); redState = "off"; yellowState = "off"; greenState = "off"; strip.clear(); strip.show(); } else if (header.indexOf("GET /yellow/on") >= 0) { Serial.println("Yellow on"); yellowState = "on"; redState = "off"; greenState = "off"; strip.clear(); strip.setPixelColor(1, yellow); strip.show(); } else if (header.indexOf("GET /yellow/off") >= 0) { Serial.println("Yellow off"); yellowState = "off"; redState = "off"; greenState = "off"; strip.clear(); strip.show(); } else if (header.indexOf("GET /green/on") >= 0) { Serial.println("Green on"); greenState = "on"; redState = "off"; yellowState = "off"; strip.clear(); strip.setPixelColor(2, green); strip.show(); } else if (header.indexOf("GET /green/off") >= 0) { Serial.println("Green off"); greenState = "off"; redState = "off"; yellowState = "off"; strip.clear(); strip.show(); } // Display the HTML web page client.println("<!DOCTYPE html><html>"); client.println("<head><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">"); client.println("<link rel=\"icon\" href=\"data:,\">"); // CSS to style the on/off buttons // Feel free to change the background-color and font-size attributes to fit your preferences client.println("<style>html { font-family: Helvetica; display: inline-block; margin: 0px auto; text-align: center;}"); client.println(".button { background-color: #195B6A; border: none; color: white; padding: 16px 40px;"); client.println("text-decoration: none; font-size: 30px; margin: 2px; cursor: pointer;}"); client.println(".button2 {background-color: #77878A;}</style></head>"); // Web Page Heading client.println("<body><h1>Stoplight Server</h1>"); // Display current state, and ON/OFF buttons for Red client.println("<p>Red: " + redState + "</p>"); // If the redState is off, it displays the ON button if (redState=="off") { client.println("<p><a href=\"/red/on\"><button class=\"button\">ON</button></a></p>"); } else { client.println("<p><a href=\"/red/off\"><button class=\"button button2\">OFF</button></a></p>"); } // Display current state, and ON/OFF buttons for Yellow client.println("<p>Yellow: " + yellowState + "</p>"); // If the yellowState is off, it displays the ON button if (yellowState=="off") { client.println("<p><a href=\"/yellow/on\"><button class=\"button\">ON</button></a></p>"); } else { client.println("<p><a href=\"/yellow/off\"><button class=\"button button2\">OFF</button></a></p>"); } // Display current state, and ON/OFF buttons for Green client.println("<p>Green: " + greenState + "</p>"); // If the greenState is off, it displays the ON button if (greenState=="off") { client.println("<p><a href=\"/green/on\"><button class=\"button\">ON</button></a></p>"); } else { client.println("<p><a href=\"/green/off\"><button class=\"button button2\">OFF</button></a></p>"); } client.println("</body></html>"); // The HTTP response ends with another blank line client.println(); // Break out of the while loop break; } else { // if you got a newline, then clear currentLine currentLine = ""; } } else if (c != '\r') { // if you got anything else but a carriage return character, currentLine += c; // add it to the end of the currentLine } } } // Clear the header variable header = ""; // Close the connection client.stop(); Serial.println("Client disconnected."); Serial.println(""); } } |
Where I found the web server code, over at Random Nerd Tutorials
Some good info I found on MQTT
https://learn.adafruit.com/adafruit-neopixel-uberguide/arduino-library-use
Discover more from Its_All.Lost
Subscribe to get the latest posts sent to your email.