WS2812B LED strips are pretty cool. They are string of individually addressable RGB LEDs. This allows control of the color and brightness of each LED.
Fireworks are also pretty cool. On the downside they can be dangerous, scare wildlife, start fires, be expensive, illegal, etc. So, until we can afford our own fleet of drones we settled on this alternative. Like many projects, we stand on the shoulders of giants mentioned in the Ardunio source code below. Our main issue with their code was the effect was never changing so we improved mainly on that aspect; a few other things as well.
----
Result:
-----
The hardware is an ESP8266 and a WS2812B LED-strip with 300 LEDs (16.5 feet). We wanted to use a Ardunio Nano (because we had one), but due to the amount of memory needed to define the arrays for the 300 LEDs we went with an ESP8266 (because we had one).
----- You are also going to need a big pole.
-----
/* * LED Fireworks Simulator * WhiskeyTangoHotel.Com * JAN 2024 * * To vary the effect experiments randomizing variables * within acceptable limits was done. Otherwise the effect * just looks to same 'shot after shot'. Other mods as well * * Leverage from https://www.Daniel-Westhof.de and * https://www.anirama.com/1000leds/1d-fireworks/ * * Hardware: * HiLetgo 1PC ESP8266 NodeMCU CP2102 ESP-12E Development Board and a * WS2812B LED-strip with 300 LEDs (16.5 feet). */
#include <FastLED.h> #define NUM_LEDS 300 #define DATA_PIN 5 // Labeled a D1 on the board. #define LED_PIN 2 // This is the BLUE LED on board #define NUM_SPARKS NUM_LEDS/2 // OG: NUM_LEDS/2
CRGB leds[NUM_LEDS]; // sets up block of memory
float sparkPos[NUM_SPARKS]; float sparkVel[NUM_SPARKS]; float sparkCol[NUM_SPARKS]; float flarePos; float gravity = -.008; // m/s/s int launch_delay; // we later randomize seconds between launches
void loop() { // Delay untill next launch. Blink BLUE on board LED Serial.println(" "); launch_delay = int(random(5,30)); // Min>=5. Randomize secs between BOOMs. //launch_delay = 5; for (int i = (launch_delay - 5); i > 0; i--) { Serial.println(String(i + 5) + " seconds to launch..."); digitalWrite(LED_PIN, LOW); // ON delay(500); digitalWrite(LED_PIN, HIGH); // OFF delay(500); }
// Slower timer done . Fast blink for ~5 seconds to warn of BOOM Serial.print("5 seconds to launch!!!"); for (int i = 50; i > 0; i--) { Serial.print("."); digitalWrite(LED_PIN, LOW); // ON delay(50); digitalWrite(LED_PIN, HIGH); // OFF delay(50); }
Serial.println("."); Serial.print("BOOM..."); digitalWrite(LED_PIN, LOW); // LED ON
// send up flare flare(); digitalWrite(LED_PIN, HIGH); // LED OFF
// explode explodeLoop(); }
void flare() { flarePos = 0; // 0 // flareVel is how hight the BOOM is. 2.2 is max height float flareVel = float(random(180, 215)) / 100; // Start: (180, 195)) / 100; trial and error to get reasonable range Serial.println(" with flare height of " + String((flareVel*100)/2.2) + "%"); // How high is the BOOM? float brightness = 5; // OG: 1
// initialize launch sparks int blast_base = random(5,20); // number of sparks at blast base. for (int i = 0; i < blast_base; i++) { // OG: int i = 0; i < 5; i++ sparkPos[i] = 0; sparkVel[i] = (float(random8()) / 255) * (flareVel / 2); // OG: (float(random8()) / 255) * (flareVel / 5); the / xx); is control value for BURST sparkCol[i] = sparkVel[i] * 1000; sparkCol[i] = constrain(sparkCol[i], 0, 255); //Serial.println(String(i) + " " + String(sparkVel[i]) + " " + String(sparkCol[i])); }
// launch while (flareVel >= -.2) { // OG: flareVel >= -.2 when to explode after peak BOOM. Bigger neg val means more fall before sparks // sparks for (int i = 0; i < blast_base; i++) { // OG: int i = 0; i < 5; i++ sparkPos[i] += sparkVel[i]; sparkPos[i] = constrain(sparkPos[i], 0, 120); sparkVel[i] += gravity; sparkCol[i] += -.8; sparkCol[i] = constrain(sparkCol[i], 0, 255); leds[int(sparkPos[i])] = HeatColor(sparkCol[i]); leds[int(sparkPos[i])] %= 50; // reduce brightness to 50/255 }
void explodeLoop() { int nSpark_var = random(2, 10); // Bigger number is less BOOM sparks int nSparks = flarePos / nSpark_var; // OG: nSparks = flarePos / 2 //Serial.println(String(nSparks));
// initialize sparks for (int i = 0; i < nSparks; i++) { sparkPos[i] = flarePos; sparkVel[i] = (float(random(0, 20000)) / 10000.0) - 1.0; // from -1 to 1 sparkCol[i] = abs(sparkVel[i]) * 500; // set colors before scaling velocity to keep them bright sparkCol[i] = constrain(sparkCol[i], 0, 255); sparkVel[i] *= flarePos / NUM_LEDS; // proportional to height } sparkCol[0] = 255; // OG: 255 This will be our known spark float dying_gravity = gravity; float c1 = random(80,130); // OG: 120 float c2 = random(1,30); // OG: 50 //Serial.println("c1 is: " + String(c1)); //Serial.println("c2 is: " + String(c2));
while(sparkCol[0] > c2/128) { // OG: (sparkCol[0] > c2/128) As long as our known spark is lit, work with all the sparks int decay_rate = (random(0,50)); // Slow to decay the blast sparks. (0,50) seems right. Bigger is slower. OG: delay(0); delay(decay_rate); //Serial.println(String(decay_rate)); FastLED.clear();
for (int i = 0; i < nSparks; i++) { sparkPos[i] += sparkVel[i]; sparkPos[i] = constrain(sparkPos[i], 0, NUM_LEDS-1); sparkVel[i] += dying_gravity; sparkCol[i] *= .975; sparkCol[i] = constrain(sparkCol[i], 0, 255); // RED cross dissolve. OG: constrain(sparkCol[i], 0, 255);
if(sparkCol[i] > c1) { // fade white to yellow leds[int(sparkPos[i])] = CRGB(random(0,255), random(200,255), (255 * (sparkCol[i] - c1)) / (255 - c1)); // OG: CRGB(255, 255, (255 * (sparkCol[i] - c1)) / (255 - c1)); } else if (sparkCol[i] < c2) { // fade from red to black leds[int(sparkPos[i])] = CRGB((random(200,255) * sparkCol[i]) / c2, 0, 0); // OG: CRGB((255 * sparkCol[i]) / c2, 0, 0); } else { // fade from yellow to red leds[int(sparkPos[i])] = CRGB(random(0,255), (random(200,255) * (sparkCol[i] - c2)) / (c1 - c2), 0); // OG: CRGB(255, (255 * (sparkCol[i] - c2)) / (c1 - c2), 0); } } dying_gravity *= .99; // OG: dying_gravity *= .99; As sparks burn out they fall slower FastLED.show(); } // end while(sparkCol)
-----
On-line shopping has changed the way goods are acquired. For most packages it is not necessary to be around for the dropoff. But... for the important stuff it is. Those packages always seem to show up right when you are in the backyard for mere seconds causing that frustrating "Personal Signature Required for Delivery" note on the door. This is our DIY effort to solve that problem.
-----
Needed:
- ESP8266 (microcontroller with WiFi)
- 1M ohm resistor
- reed switch
- IFTTT account (using the WebHook applet)
- wire and stuff
- fundamental knowledge on Arduino sketches (simple code edits).
-----
The connections are simple:
----
And the rig will look something like this:
-----
A 1M ohm resister connected from 3.3V to the A0 [ADC] input on the ESP8266 keeps the A0 reading at maximum value. The normally open reed switch is placed right on top of the coils that activate the doorbell. These coils act like that electromagnet you build in grade school to ring the doorbell and cause the reed switch to close. This drops the impedance to the 1M resistor and changes the ADC value on the A0 pin for detection of the doorbell. Then the SMS is sent to your phone and a Google Drive Sheet is updated.
-----
-----
The sketch you need to upload to the the ESP8266 looks like this:
```````````````````````````````````````````````````````````````````````````````
/*
* FEB2020
* Door Bell Monitoring
* WhiskeyTangoHotel.Com
*
* Build details at:
* http://www.whiskeytangohotel.com/2020/02/esp8266-doorbell-sends-sms-and-updates.html
*
* On Doorbell ring:
* Logs to Google Drive (as an appending spreadsheet)
* Sends SMS to cell phone
*
* ESP8266 uC
*/
// For the Wireless
#include <ESP8266WiFi.h>
// WiFi Connection Information
const char* ssid = "yourssid"; // PRIVATE: Enter your personal setup information.
const char* password = "yourwifipassword"; // PRIVATE: Enter your personal setup information.
// IFTTT Information for WebHook widget
String MAKER_SECRET_KEY = "yourIFTTTprivatekey"; // PRIVATE: Enter your personal setup information. Your IFTTT Webhook key here
String TRIGGER_NAME_google_drive = "googlebell"; // this is the Maker IFTTT trigger name for google drive spreadsheet logging
String TRIGGER_NAME_SMS = "doorbell"; // this is the Maker IFTTT trigger name to send SMS.
const char* host = "maker.ifttt.com";
String url_SMS; // url that gets built for the IFTTT Webhook sending SMS
String url_google_drive; // url that gets built for the IFTTT Webhook logging to google drive spreadsheet
String Status ="**_Starting_on:"; // Status payload for Google Sheet. We log all starts and reboots
// Define and set up some variables
int sensorValue = 0; // reading from A0. This pin detects the doorbell (ADC reading between 0-1024)
// Define pins
const int led = 2; // Blue on board LED is on PIN2. Active LOW. Blinks it between reads
const int bell = A0; // analog input for the doorbell transducer. 1MOhm on board in // with 1MOhm from the reed switch pickup
// Program control variables
int Seconds_dwell_after_detect = 8; // Prevents logging flood and debounce. Sensor reads, LED flashing, etc.
int logging = 1; // If 1 then SMS and log to cloud. Any other value (0) turns it off.
void setup(){ // This is run once.
pinMode(led, OUTPUT); // set up the onbaord LED pin as an output.
Serial.begin(115200); // turn on the serial monitor for debug
// wait until serial port opens for native USB devices
while (! Serial) {
delay(10);
}
// Is the WiFi working?
WiFi.begin(ssid, password);
Serial.println("");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
Serial.print("Trying to connect to ");
Serial.print(ssid);
Serial.print(" on ");
Serial.println(WiFi.localIP());
for (int x = 0; x < 20; x++) { //
digitalWrite(led, !digitalRead(led)); // toggle state of the on board blue LED. Shows program is trying to WiFi connect
//Serial.println("Server Start blink loop....");
delay(5); // Delay so short the LED looks like it is always on
} // endfor WiFi blink connect
}
Serial.print("Connected to ");
Serial.println(ssid);
Serial.println(WiFi.localIP());
for (int x = 0; x < 10; x++) { // 5 slow LED blinks to slow WIFI Connected.
digitalWrite(led, !digitalRead(led)); // toggle state of the on board blue LED.
Serial.println("WIFI is Connected....");
delay(500); } // endif for WIFI Connected blink
// Use WiFiClient class to create TCP connections for WiFi logging
WiFiClient client;
const int httpPort = 80;
if (!client.connect(host, httpPort)) {
Serial.println("connection failed"); // Boo!!!
return;
}
// Trigger the IFTTT Webhook Channel to update a Google sheet with the activity of the server starting/restarting
// This can help log power outs, etc. For first run we defined String Status for identify a startup condition.
// Create the request for IFTTT google drive
url_google_drive = "https://maker.ifttt.com/trigger/" + TRIGGER_NAME_google_drive + "/with/key/" + MAKER_SECRET_KEY + "?value1=" + String(Status);
Serial.println (url_google_drive);
Serial.println(" ");
// This sends the request to the IFTTT server
client.print(String("POST ") + url_google_drive + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Connection: close\r\n\r\n");
delay(500); // Delay for web traffic; maybe not required.
// Read all the lines of the reply from server and print them to Serial
while(client.available()){
String line = client.readStringUntil('\r'); }
String Status = "Payload_String_for_Google_Sheet";
}
void loop(){ // Loop forever or until the Dallas Cowboys win a Super Bowl
// Read the A0 pin and post based on the delay values set above.
// The blue onboard LED will fast blink while polling
sensorValue = analogRead(bell);
//Serial.println (sensorValue); //debug only
// Fast Blink Blue LED while waiting for doorbell press
digitalWrite(led, !digitalRead(led)); // toggle state of the on board blue LED. Shows program is running
Serial.println("Waiting for DoorBell....");
delay(50);
// Use WiFiClient class to create TCP connections for IFTT
WiFiClient client;
const int httpPort = 80;
if (!client.connect(host, httpPort)) {
Serial.println("connection failed");
return;
}
if (sensorValue < 200 || sensorValue > 300) { // A0 values between 200-300 are normal. Increases (apprx doubles) when DB is pressed
Serial.println("----------Doorbell Dectected----------");
if (logging == 1) { // is logging turned on? Non "1" is for debug... Typically would be set = 1
Serial.println("***** Logging is ON *****");
// This must be run before any IFTTT webhook
const int httpPort = 80;
if (!client.connect(host, httpPort)) {
Serial.println("connection failed");
return;
}
// Set up IFTTT Webhook Channel to update a Google sheet with the activity.
Status ="__Doorbell_on:";
url_google_drive = "https://maker.ifttt.com/trigger/" + TRIGGER_NAME_google_drive + "/with/key/" + MAKER_SECRET_KEY + "?value1=" + String(Status);
client.print(String("POST ") + url_google_drive + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Connection: close\r\n\r\n");
Serial.println(" ");
Serial.println("IFTTT url payload to Google Drive is:");
Serial.println(url_google_drive);
Serial.println(" ");
} else { // We are not sending to IFTTT. Debug mode
Serial.println("Logging is OFF.");
Serial.println(" ");
} // endif/else logging
for (int x = 0; x < Seconds_dwell_after_detect*2; x++) { // DoorBell dectected. Pause and LED flash for visual acknowledgement
digitalWrite(led, !digitalRead(led)); // toggle state of the on board blue LED
Serial.println("Doorbell dectected, Now in BLINK Loop....");
delay(500); } // endfor DoorBell Dwell loop
} // end doorbell A0 pressed
} // end of endless loop
-----
That's it and thanks for stopping by!!!
-----
Note: As presented this project requires a FCC Amateur Radio license. Amateur Radio is about experimentation. Even still you must be versed in the band plan, stay away from local repeater stations, stay in accordance to FCC
Amateur Radio rules in FCC Section 97, and probably a few other things. Even after following all those
rules, nobody likes to hear a fox 'screaming' out all the time. Be courteous, aware of your RF footprint, and keep your transmission power suitable for the cause. That said, let's continue....
In ham radio speak a fox hunt is a search for a hidden transmitter. We wanted a fox transmitter and decided to go with the "roll your own method" to fill the need.
-----
For our rig we went with things that we had available around the shack. The major components:
- Baofeng 2m/70cm HT
- this is the transmitter
- Arduino Nano
- used as a simple timer to control a relay module
- Relay Module
- when closed the mic keys and the radio transmits
- MP3 playback device capable of a continuous loop of an audio file
- this contains the fox message with must include an FCC callsign
- Some 1/4 inch phono adapters
- Alligator clip wire
-----
Since we don't need a permanent fox, we wanted to be able to break down the rig. Thus, the alligator clip wire. On low power transmit the rig's battery can easily last all day. The Arduino and MP3 player are powered by a USB jump battery.
-----
1st: Get the simple source code we list below and upload it to your Arduino.
2nd: Create a 'fox message' to transmit from the MP3 player. We typically go to LCWO and create a CW message like the example in the demonstration video at the top of this page. You must ID with a FCC callsign.
3rd: Connect it all up like this:
-----
Now you're ready to go. The metal lanyard attachment point provides a handy "GND" point for the transmit relay. Select the audio file you want to transmit to continuously loop and press PLAY. Turn the HT on and power up the Arduino.
-----
At power up the Arduino will go through a Self Test. The relay will cycle five times and then normal operation will start. The Fox will only transmit when the relay is closed. In the source code below the rig is set up to transmit for 20 seconds, then rest for 60 seconds, then repeat.
-----
Pretty simple. Good luck and enjoy hosting a fox hunt. Here is the Arduino source code:
/*
* Ham Radio Fox Transmitter Control
* Requires a ham radio license.
* See: http://www.arrl.org/getting-licensed
*
* For our Nano: CH340 drivers, Processor->ATmega328P (Old Bootloader), 57600 baud
*
* See: WhiskeyTangoHotel.Com for built details.
*
* FEB 2019
*/
// Set variables and Output pins
const int Tx_seconds = 20; // seconds that the fox call will be sent
const long Silent_seconds = 60; // seconds between fox call tx. Resting time.
const long test_chatter = 5; // turn on and off the relay for self test. This will key the mic and Tx if connected
const int relay = 2; // Relay control line. Close relay to transmit
void setup(void){ //run once
pinMode(relay, OUTPUT);
digitalWrite(relay, 0); // off power to relay (not in Tx mode)
// Self test LED and Relay
Serial.begin(57600);
Serial.println("Enter Self Test:");
for (int i=0; i < test_chatter; i++){
Serial.println("*** Self Test: " + String(i) + " ***");
Serial.println("Tx Mode ON. LED ON. Relay CLOSED.");
digitalWrite(relay, 1); // Relay CLOSED
delay(500);
-----
There are plenty of ways to irritate your XYL with an obsession of ham radio; but if you feel you need just one more then keep reading. The black box above is actually a clock. It's a cool clock if you know Morse Code (or CW), but it is worthless if you don't.
-----
The brains of the Morse Code clock is an ESP8266 with on board WiFi. At power up, the rig connects to WiFi and fetches the time from the internet (so always accurate). On first run the 'clock' sends out some Self Test tones after getting the time. These Self Test tones can be something like a callsign, but it could be anything or even nothing. The pace (or WPM) of the Morse Code is adjustable by a variable in the source code. In the example videos it is 10WPM as calculated by "The Paris Standard".
From that point on the time of day (localized to your time zone) is output to a speaker and LED tower in Morse Code (24 hour format) as HHMM. A calm quite house is filled with dit-dah tones and flashing light.
----
The build is not that difficult as shown in the schematic below. On the bench it looks something like this:
-----
A metal box found around the shack was repurposed to clean up the look. This vid shows the end result. At power up the LED tower flashes until it gets the time from the internet. Then the Self Test tones and LED flashes happen. After that, only the time is "announced" when the red button is pressed.
It all came out pretty nice.
-----
If you decide to duplicate the build here is the simple schematic:
-----
And the Arduino/ESP8266 IDE Source Code:
_______________________________________________________________
/* * NOV2018 * CW "Talking Clock" * WhiskeyTangoHotel.Com * * Get Internet time. * Upon a button press, convert the Internet time to defined local time zone. * Parse the Internet time to HHMM (24 hr format) * Convert the HHMM time to Morse Code (CW) dits and dahs * Play the Morse Code converted times over a speaker and a LED. * * Hold the button down for over a second and get a random letter or number played. * * At startup a self test sends a callsign (or user define msg) to * the speaker in CW. * * BTW, CW is fun to learn. * --... / ...-- // --... / ...-- * */
#include <time.h>
// Set up or the Wireless. We wil need this to get the internet time #include <ESP8266WiFi.h> #include <WiFiClient.h> #include <ESP8266WebServer.h>
// WiFi Connection Information const char* ssid = "Virus-2.4"; // PRIVATE: Enter your personal SSID setup information. *PRIVATE* const char* password = "zenakelsocats"; // PRIVATE: Enter your personal PASSWORD setup information. *PRIVATE* ESP8266WebServer server(80);
// Define and set up some variables int timezone = 18; // Chicago = 18 int dst = 0; // 0 or 1. 1 for DST or "Summer Adjusted Time" String Callsign = "W1AW"; // ALL CAPS!!! Used for self test 'beeps' at startup. Could be anything alphanumic you like String Time_substring; // Used for parsing String Parsedtime; // Feteched internet time boiled down to HHMM in 24 hr format. String Dit_or_Dah; // Output a dit or dah to the speaker. Used when parsing a character
int Pitch = 600; // Normally around 600Hz. This this the pitch frequency of the CW tones float WPM = 12; // How fast the letters are sent to the speaker using the "Paris Standard" in Words per Minute (8-25; depending on skill level) // Paris Standard formula: Tmsec = (1200 / WPM) WPM is the desired speed in words-per-minute. T is the dit time in mSecs float Tmsec = 1200 / WPM; float Dit = Tmsec; float intercharacter_spacing = Dit; float Dah = Tmsec * 3; float interword_spacing = Dah; int Random_CW; // Random number generated to select a random character String Random_CW_Character; // This is the random character sent to speaker/LED
// Load the CW database 'dits' and 'dahs' for each Alphanumeric. Boring.... String A = ".-";; String B = "-..."; String C = "-.-."; String D = "-.."; String E = "."; String F = "..-."; String G = "--."; String H = "...."; String I = ".."; String J = ".---"; String K = "-.-"; String L = ".-.."; String M = "--"; String N = "-."; String O = "---"; String P = ".--."; String Q = "--.-"; String R = ".-."; String S = "..."; String T = "-"; String U = "..-"; String V = "...-"; String W = ".--"; String X = "-..-"; String Y = "-.--"; String Z = "--.."; String zero = "-----"; String one = ".----"; String two = "..---"; String three = "...--"; String four = "....-"; String five = "....."; String six = "-...."; String seven = "--..."; String eight = "---.."; String nine = "----.";
// Output pins const int led = 2; // NEGATIVE Logic (LOW is ON) Blue on board LED is on PIN2 for this NoderMCU 1.0 ESP8266. const int speaker = 14; // tone outputs to the EXTERNALLY amplified speaker to pin 14 int time_buttonPin = 4; // When button pressed CW the time to the speaker. pin 4 boolean buttonState = LOW; // for the time_buttonPin status
void setup(void){ // This is run once. Serial.begin(115200); // turn on the serial monitor for debug //Serial.setDebugOutput(true); // Turn on the Serial Debugger if desired
//Define the I/O pinMode(led, OUTPUT); // set up the onboard Blue LED as an output. pinMode(time_buttonPin, INPUT); // Input for the button switch. if HIGH (pressed) play CW the time to the speaker
// Connect WiFi. Is the WiFi working? WiFi.begin(ssid, password); Serial.println(""); // Wait for connection while (WiFi.status() != WL_CONNECTED) { Serial.print("Trying to connect to "); Serial.print(ssid); Serial.print(" on "); Serial.println(WiFi.localIP()); for (int x = 0; x < 20; x++) { // digitalWrite(led, !digitalRead(led)); // toggle state of the on board blue LED. Shows program is trying to WiFi connect delay(50); } // endfor WiFi blink connect } Serial.print("Connected to "); Serial.println(ssid); Serial.println(WiFi.localIP());
//Send tones for the variable Callsign to the speaker as a self test. Serial.println("Sending " + Callsign + " as Self Test......"); int L = Callsign.length(); for (int i=0; i<L; i++) { // Start Self Test Convert the time numbers to dit and dahs Time_substring = Callsign.substring(i, i+1); if (Time_substring == "0") { Time_substring = zero; } if (Time_substring == "1") { Time_substring = one; } if (Time_substring == "2") { Time_substring = two; } if (Time_substring == "3") { Time_substring = three; } if (Time_substring == "4") { Time_substring = four; } if (Time_substring == "5") { Time_substring = five; } if (Time_substring == "6") { Time_substring = six; } if (Time_substring == "7") { Time_substring = seven; } if (Time_substring == "8") { Time_substring = eight; } if (Time_substring == "9") { Time_substring = nine; } if (Time_substring == "A") { Time_substring = A; } if (Time_substring == "B") { Time_substring = B; } if (Time_substring == "C") { Time_substring = C; } if (Time_substring == "D") { Time_substring = D; } if (Time_substring == "E") { Time_substring = E; } if (Time_substring == "F") { Time_substring = F; } if (Time_substring == "G") { Time_substring = G; } if (Time_substring == "H") { Time_substring = H; } if (Time_substring == "I") { Time_substring = I; } if (Time_substring == "J") { Time_substring = J; } if (Time_substring == "K") { Time_substring = K; } if (Time_substring == "L") { Time_substring = L; } if (Time_substring == "M") { Time_substring = M; } if (Time_substring == "N") { Time_substring = N; } if (Time_substring == "O") { Time_substring = O; } if (Time_substring == "P") { Time_substring = P; } if (Time_substring == "Q") { Time_substring = Q; } if (Time_substring == "R") { Time_substring = R; } if (Time_substring == "S") { Time_substring = S; } if (Time_substring == "T") { Time_substring = T; } if (Time_substring == "U") { Time_substring = U; } if (Time_substring == "V") { Time_substring = V; } if (Time_substring == "W") { Time_substring = W; } if (Time_substring == "X") { Time_substring = X; } if (Time_substring == "Y") { Time_substring = Y; } if (Time_substring == "Z") { Time_substring = Z; }
// Now send the dit/dahs for the Self Test Callsign Character int CW_length = Time_substring.length();
for (int j=0; j<CW_length; j++) { // Send tones and blink LED in CW digitalWrite(led , HIGH); // NEGATIVE LOGIC. Make sure the onboard LED is off Dit_or_Dah = Time_substring.substring(j, j+1); //Serial.println(Dit_or_Dah);
if (Dit_or_Dah == ".") { // process a Dit digitalWrite(led , LOW); //tone(speaker, Pitch, Dit); // Comment for LED only; no BEEPS on Self Test delay(Dit); digitalWrite(led , HIGH); } // end if process a Dit
if (Dit_or_Dah == "-") { // process a Dah digitalWrite(led , LOW); // tone(speaker, Pitch, Dah); // Comment for LED only; no BEEPS on Self Test delay(Dah); digitalWrite(led , HIGH); } // end if process a Dah
delay(intercharacter_spacing); // a delay of "1 Dit" between dit/dahs in a character } // send for loop dit/dahs for selected time number delay (interword_spacing); // done with sending character, so a longer "3 * Dit" delay" } // end for loop on the Self Test
// Do we want summertime or standard time? Default is standard time dst = 0. 1 for DST or "Summer Adjusted Time" int buttonState = digitalRead(time_buttonPin); if (buttonState == HIGH) { // if the button is pushed after the self test; then set to Summer Time; dst = 1 tone(speaker, Pitch, Dit); // Quick 'dit' to say "I'm in Summer Time mode" dst = 1; }
// Get the current time from "THE INTERNET! and adjust for timezone and dst" configTime((timezone + dst) * 3600, 0, "pool.ntp.org", "time.nist.gov"); Serial.println("\nWaiting for time"); while (!time(nullptr)) { Serial.print("."); delay(100); }
Serial.println("Self test completes!!!"); digitalWrite(led , HIGH); // turn off the LED Serial.println("");
delay(1000);
} // End void setup loop
void loop(void){ // Loop forever waiting for button push. If pushed CW the local time as HHMM in CW and go back to waiting for that button int buttonState = digitalRead(time_buttonPin); // check if the pushbutton is pressed. if (buttonState == HIGH) { // button is pressed, CW time to speaker or random character? delay(1000); int buttonState = digitalRead(time_buttonPin); // check if the pushbutton is STILL pressed. if (buttonState == HIGH) { // if the button is still pressed after the delay then rnd character, not time. digitalWrite(led , LOW); // NEGATIVE LOGIC. Blink the LED to show RND char mode entered delay(150); digitalWrite(led , HIGH); // NEGATIVE LOGIC. Make sure the LED is off delay(1000); do { Random_CW = random(48,90); //48 is 0. 57 is 9. A is 65. Z is 90 } while (Random_CW > 57 and Random_CW < 65); // if the random# did not map to a letter or number then try again. char Random_CW_Character = Random_CW; Serial.print("Random CW Character is: "); Serial.println(Random_CW_Character);
Time_substring = Random_CW_Character; if (Time_substring == "0") { Time_substring = zero; } if (Time_substring == "1") { Time_substring = one; } if (Time_substring == "2") { Time_substring = two; } if (Time_substring == "3") { Time_substring = three; } if (Time_substring == "4") { Time_substring = four; } if (Time_substring == "5") { Time_substring = five; } if (Time_substring == "6") { Time_substring = six; } if (Time_substring == "7") { Time_substring = seven; } if (Time_substring == "8") { Time_substring = eight; } if (Time_substring == "9") { Time_substring = nine; } if (Time_substring == "A") { Time_substring = A; } if (Time_substring == "B") { Time_substring = B; } if (Time_substring == "C") { Time_substring = C; } if (Time_substring == "D") { Time_substring = D; } if (Time_substring == "E") { Time_substring = E; } if (Time_substring == "F") { Time_substring = F; } if (Time_substring == "G") { Time_substring = G; } if (Time_substring == "H") { Time_substring = H; } if (Time_substring == "I") { Time_substring = I; } if (Time_substring == "J") { Time_substring = J; } if (Time_substring == "K") { Time_substring = K; } if (Time_substring == "L") { Time_substring = L; } if (Time_substring == "M") { Time_substring = M; } if (Time_substring == "N") { Time_substring = N; } if (Time_substring == "O") { Time_substring = O; } if (Time_substring == "P") { Time_substring = P; } if (Time_substring == "Q") { Time_substring = Q; } if (Time_substring == "R") { Time_substring = R; } if (Time_substring == "S") { Time_substring = S; } if (Time_substring == "T") { Time_substring = T; } if (Time_substring == "U") { Time_substring = U; } if (Time_substring == "V") { Time_substring = V; } if (Time_substring == "W") { Time_substring = W; } if (Time_substring == "X") { Time_substring = X; } if (Time_substring == "Y") { Time_substring = Y; } if (Time_substring == "Z") { Time_substring = Z; }
int CW_length = Time_substring.length();
for (int j=0; j<CW_length; j++) { // Send tones and blink LED in CW digitalWrite(led , HIGH); // NEGATIVE LOGIC. Make sure the onboard LED is off Dit_or_Dah = Time_substring.substring(j, j+1); //Serial.println(Dit_or_Dah);
if (Dit_or_Dah == ".") { // process a Dit digitalWrite(led , LOW); tone(speaker, Pitch, Dit); delay(Dit); digitalWrite(led , HIGH); } // end if process a Dit
if (Dit_or_Dah == "-") { // process a Dah digitalWrite(led , LOW); tone(speaker, Pitch, Dah); delay(Dah); digitalWrite(led , HIGH); } // end if process a Dah
delay(intercharacter_spacing); // a delay of "1 Dit" between dit/dahs in a character } // send for loop dit/dahs for selected time number
} // end of if the button is still pressed after the delay then rnd character, not time. else { // random character code above; time code below time_t now = time(nullptr); Serial.println("---------------------------------------"); Serial.print("Internet time adjusted to tone zone: "); Serial.println(ctime(&now)); Parsedtime = (ctime(&now));
// Build the Parsed time from the internet time. The time is 24 hr format and always 4 characters in HHMM Parsedtime = Parsedtime.substring(11,12) + Parsedtime.substring(12,13) + Parsedtime.substring(14,15) + Parsedtime.substring(15,16); Serial.print("Parsedtime as HHMM is: "); Serial.println(Parsedtime);
for (int i=0; i<4; i++) { // Convert the time numbers to dit and dahs. Always 4 characters in HHMM Time_substring = Parsedtime.substring(i, i+1); Serial.print("Currently sending Parsedtime character: "); Serial.println(Time_substring);
if (Time_substring == "0") { Time_substring = zero; } if (Time_substring == "1") { Time_substring = one; } if (Time_substring == "2") { Time_substring = two; } if (Time_substring == "3") { Time_substring = three; } if (Time_substring == "4") { Time_substring = four; } if (Time_substring == "5") { Time_substring = five; } if (Time_substring == "6") { Time_substring = six; } if (Time_substring == "7") { Time_substring = seven; } if (Time_substring == "8") { Time_substring = eight; } if (Time_substring == "9") { Time_substring = nine; }
// Now send the dit/dahs for the time number processed int CW_length = Time_substring.length();
for (int j=0; j<CW_length; j++) { // Send tones and blink LED in CW digitalWrite(led , HIGH); // NEGATIVE LOGIC. Make sure the onboard LED is off Dit_or_Dah = Time_substring.substring(j, j+1);
if (Dit_or_Dah == ".") { // process a Dit digitalWrite(led , LOW); tone(speaker, Pitch, Dit); delay(Dit); digitalWrite(led , HIGH); } // end if process a Dit
if (Dit_or_Dah == "-") { // process a Dah digitalWrite(led , LOW); tone(speaker, Pitch, Dah); delay(Dah); digitalWrite(led , HIGH); } // end if process a Dah
delay(intercharacter_spacing); // } // send for loop dit/dahs for selected time number delay (interword_spacing); } // end for loop Convert the HHMM time numbers to dit and dahs
Serial.println("Sending time tones completed!!!"); delay(1000); // Delay for a sec just beacause... } // If checking for long press for RND character } // End button press if } // End of Loop forever waiting for button push. ________________________________________________________
-----
Thanks for stopping by and 73!
In our modern world, high bright LEDs can be purchased cheaply to provide low current draw auxiliary lighting to any vehicle. Then it is only a simple matter of connecting the LED to 12VDC and head down the road enjoying your new found wattage. However, there is no fun in the easy way. Follow the instructions below to build your own custom high bright LED driver.
-----
OBJECTIVE: A high bright LED for installation on a Kawasaki KLR650 motorcycle with six programmable modes:
-----
To keep the project simple, an Ardunio Nano is used to control the Gate Voltage (Vgs) of a MOSFET. When Vgs is HIGH the MOSFET switches on and the high bright LED turns on. By using Pulse Width Modulation (PWM) on the Arduino the brightness of the high bright LED can be easily controlled.
-----
You will need the parts in the schematic. All are readily available from Amazon or a host of electronic parts distributors. Of course, the 12VDC power source is provided by the vehicle.
---
On the bench the rig will look and function something like this:
----
The schematic leaves out some details that could be helpful. To control the MODE selection and the STROBE effect we used a handlebar mounted switch. I also drilled a small hole to mount the STATUS LED into the handlebar switch. With coded flashes, the STATUS LED lets the rider know the current mode of the rig. Pressing the GREEN button selects the next mode. Move the turn signal switch to "R" to turn on the STROBE effect. The image below provides some real world connection details. If you get the same handlebar switch we recommend buzzing out the wires first to verify them because the unit came with no diagram and low cost manufactures often change these details.
----
After you use the Arduino IDE to download the source code provided below into your Ardunio Nano you will need to mount to high bright LED. We got a mounting bracket from eBay. In the end it came out pretty nice.
-----
Here is a video of the rig running through all the modes. The quick strobe at the beginning is a wake up self test. The high bright LED swamps out the camera light sensor and doesn't provide a good indication of the actual effect. One note: It turns out Apple has a patent on the Breathing LED pattern (well, for a sleep indicator anyway). Use the "breathing LED" portion of the code with caution or, I guess, risk a cease and desist order.
-----
Here is the Arduino source code for the rig. Good luck!
//------------------------------------------------------------------------
/*
KLR650 Aux LED Driver
July 2019
WhiskeyTangoHotel.Com
Ardunio Nano (should work with other Arduinos)
Program controls a IRF510 MOSFET to drive a High Bright LED Array
(I recommend a heat sink on the MOSFET, but it should be fine without it)
A button switch selects between modes
A switch sets the LED to fast strobe mode
*/
int Number_of_Modes = 4; // Needed for program control.
int LED_Mode = 1; // LED_Mode sets the startup condition and is changed with button pushes in the main loop.
int Status_LED = 3; // PWM output pin for the LED status light.
int FET_Drive = 5; // PWM output pin to drive the gate on the MOSFET.
int mode_buttonPin = 4; // Mode changing push button (wired to GND via 10K)
int strobe_buttonPin = 8; // Mode changing push button (wired to GND via 10K)
boolean buttonState = LOW; // for the mode_ and strobe_ detect
// Percent brightness of the 3 modes. Example: 35% = .35, 100% = 1.00
// LED_Mode = 0 is OFF
float MODE1_Bright = .20;
float MODE2_Bright = .50;
// LED_Mode = 3 is FULL Bright: digitalWrite(Status_LED, 255); // 255 turns LED FULL BRIGHT
// LED_Mode = 4 is Breath
int Breath_Rate = 15; //Higher is faster
int Breath_Max_Bright = 170;
int Breath_Min_Bright = 20;
int Flash_delay = 50; // sets delay for strobe mode and self test (50 is a good start)
void setup()
{
// Serial commands are for debugging
//Serial.begin(9600);
//Serial.print(LED_Mode);
//Serial.println();
pinMode(Status_LED, OUTPUT); // sets the digital pins as output
pinMode(FET_Drive, OUTPUT);
pinMode(mode_buttonPin, INPUT); // initialize the mode pushbutton pin as an input. If HIGH change modes
pinMode(strobe_buttonPin, INPUT); // if HIGH quick stobe/flash mode
digitalWrite(Status_LED, 0); // 0 turns the LED OFF
digitalWrite(FET_Drive, 0);
// Self test loop. Quick flash the status and high bright LED
for (int i = 0; i <= 4; i++) {
digitalWrite(Status_LED, 255); // 255 turns LED FULL BRIGHT
digitalWrite(FET_Drive, 255);
delay(Flash_delay);
digitalWrite(Status_LED, 0); // 0 turns the LED OFF
digitalWrite(FET_Drive, 0);
delay(Flash_delay);
} // endSelf Test Loop
} //end Setup
void stobe_on_button () { // strobe/flash the LED when HIGH
int buttonState = digitalRead(strobe_buttonPin); // check if the pushbutton is pressed.
if (buttonState == HIGH) { // button is pressed, strobe the LEDs
Serial.println(buttonState);
digitalWrite(Status_LED, 255); // 255 turns LED FULL BRIGHT
digitalWrite(FET_Drive, 255);
delay(Flash_delay);
digitalWrite(Status_LED, 0); // 0 turns the LED OFF
digitalWrite(FET_Drive, 0);
delay(Flash_delay);
stobe_on_button (); // check to see if strobe button is still pressed HIGH
} // endif strobe_button HIGH
} // end of strobe_button function
void mode_change_button() { // function to dectect the mode_buttonPin press to change modes (increment the state machine)
int buttonState = digitalRead(mode_buttonPin); // check if the pushbutton is pressed.
if (buttonState == HIGH) { // button is pressed, advance to next LED_Mode
digitalWrite(Status_LED, 255); // 255 turns LED FULL BRIGHT
for (int x = 0; x < 25; x++) { // Quick flash the Status LED to confirm button press.
digitalWrite(Status_LED, !digitalRead(Status_LED)); // toggle state of the on board blue LED. Shows program is running
delay(100);
} // endfor quick toogle Blue LED
if (LED_Mode >= Number_of_Modes) { // reset state machine to zer0 to recycle LED_Modes
LED_Mode = 0;
}
else {
LED_Mode = LED_Mode + 1;
}
if (digitalRead(strobe_buttonPin) == HIGH) {
LED_Mode = 0; // this is a fast cycle to OFF. The flash button AND the mode button are HIGH
}
} // endif state_mode button pressed
} // end of mode_change_button function
// LED_Mode - OFF, no lights
if (LED_Mode == 0) {
analogWrite(Status_LED, 0); // 0 turns the LED OFF
analogWrite(FET_Drive, 0); // 0 turns the MOSFET
} // endif LED_Mode = 0
// LED_Mode - Percent Brightness
if (LED_Mode == 1) {
analogWrite(FET_Drive, (255 * MODE1_Bright)); // Percent Brightness = MODE1_Bright
for (int x = 0; x < LED_Mode; x++) { // Flash rate Status LED to match mode
digitalWrite(Status_LED, 255); // 255 turns LED FULL BRIGHT
delay(100); // endfor quick toogle Blue LED
digitalWrite(Status_LED, 0); // 0 turns LED OFF
delay(100); // endfor quick toogle Blue LED
} //for match Status_LED with mode
delay(600);
} // endif LED_Mode = 1
// LED_Mode - Percent Brightness
if (LED_Mode == 2) {
analogWrite(FET_Drive, (255 * MODE2_Bright)); // Percent Brightness = MODE2_Bright
for (int x = 0; x < LED_Mode; x++) { // Flash rate Status LED to match mode
digitalWrite(Status_LED, 255); // 255 turns LED FULL BRIGHT
delay(100); // endfor quick toogle Blue LED
digitalWrite(Status_LED, 0); // 0 turns LED OFF
delay(100); // endfor quick toogle Blue LED
} //for match Status_LED with mode
delay(600);
} // endif LED_Mode = 2
// LED_Mode - Full Brightness
if (LED_Mode == 3) {
digitalWrite(FET_Drive, 255); // FULL BRIGHT
for (int x = 0; x < LED_Mode; x++) { // Flash rate Status LED to match mode
digitalWrite(Status_LED, 255); // 255 turns LED FULL BRIGHT
delay(100); // endfor quick toogle Blue LED
digitalWrite(Status_LED, 0); // 0 turns LED OFF
delay(100); // endfor quick toogle Blue LED
} //for match Status_LED with mode
delay(600);
} // endif LED_Mode = 3
// LED_Mode - LED BREATHING
if (LED_Mode == 4) {
// Ramp up the brighness of the LED
for (int i = Breath_Min_Bright; i <= Breath_Max_Bright; i++) {
analogWrite(Status_LED, i);
analogWrite(FET_Drive, i);
float Breath_Delay = (exp(sin(i/2000.0*PI*10)) - 0.36787944)*108.0;
delay(Breath_Delay/Breath_Rate);
if (buttonState == HIGH) { // check if the pushbutton is pressed.
i = Breath_Max_Bright;
}
}
mode_change_button(); // check to see if mode_change button is pressed
stobe_on_button (); // check to see if strobe_button is pressed
// Ramp down the brightness of the LED
for (int i = Breath_Max_Bright; i >= Breath_Min_Bright; i--) {
analogWrite(Status_LED, i);
analogWrite(FET_Drive, i);
float Breath_Delay = (exp(sin(i/2000.0*PI*10)) - 0.36787944)*108.0;
delay(Breath_Delay/Breath_Rate);
if (buttonState == HIGH) { // check if the pushbutton is pressed.
i = Breath_Min_Bright;
}
}
} // endif LED_Mode 4
mode_change_button(); // check to see if mode_change button is pressed
stobe_on_button (); // check to see if strobe_button is pressed
-----
We live in great times. There was once a day when the only way to determine if the cat feeder needed more kibble was to actually look at it with your own eyes like some Neanderthal. Thankfully technology and the magical world of IoT has changed all of that.
----
For this project we use a WiFi enable ESP8266 and a STMicro VL53L0X ToF Sensor mounted to a breakout board. If you don't find a need to measure feline food consumption the project still provides Arduino code that can be extremely useful for your other IoT projects:
All of the above services are free but; of course, you will need to establish an account if you do not have on.
---- What's happening?
The ESP8266 runs in Arduino mode (source code below) in an endless loop. Every hour it polls the VL53L0X ToF Sensor mounted on the lid of the cat food feeder.
-----
Since we know how many centimeters the food is from the ToF sensor at full and at empty we are able to scale those values and report/log "percent full" status. Those values are posted to a Google Drive Spreadsheet and to AT&T's M2X machine to machine servers for logging. If the food level is considered CRITICALLY LOW a SMS message goes out to our mobile device. Just to increase the geek factor, CRITICALLY LOW alerts are also displayed on our Pebble watch.
----
The Google Drive Spreadsheet looks like this:
-----
Here is the bad ass AT&T M2X machine to machine server graph (note the increase after we filled the feeder):
-----
The IFTTT SMS alerts are sent if the rig determines food levels critically low:
-----
Mount it to the cat feeder and you end up with this:
-----
Now all that is left is to copy/paste the code below into the Arduino IDE. Upload it to the ESP8266 and your cats will never go hungry again!
-----
/*
* AUG2017
* STMicro VL53L0X ToF Sensor for
* Cat Food Level Monitoring
* WhiskeyTangoHotel.Com
*
* Logs % full values to:
* Google Drive (as an appending spreadsheet)
* AT&T M2X for historical graphing
* Send SMS to cell phone if level condition is RED/CRITICAL
*
* uC setting for Ardunio IDE
* NoderMCU 1.0 (ESP-12E Module), 80MHz, 921600, 4M (3M SPIFFS)
*
*/
// For the STMicro VL53L0X ToF Sensor
// I2C SDA to ESP8266 Pin D2. SCL to ESP8266 Pin D1
#include "Adafruit_VL53L0X.h" // Thanks again ADAFRUIT!!!
Adafruit_VL53L0X lox = Adafruit_VL53L0X();
// For the Wireless
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
#include <ESP8266WebServer.h>
#include <ESP8266mDNS.h>
// WiFi Connection Information
const char* ssid = "YourNetworkHere"; // PRIVATE: Enter your personal setup information.
const char* password = "YourNetworkPasswordHere"; // PRIVATE: Enter your personal setup information.
ESP8266WebServer server(80);
// IFTTT Information for WebHook widget
String MAKER_SECRET_KEY = "YourIFTTTCodeHere"; // PRIVATE: Enter your personal setup information. Your IFTTT Webhook key here
String TRIGGER_NAME_google_drive = "Cat_Food"; // this is the Maker IFTTT trigger name for google drive spreadsheet logging
String TRIGGER_NAME_M2X = "cat_food_mx"; // this is the Maker IFTTT trigger name for M2X logging
String TRIGGER_NAME_SMS = "CriticalFoodLevel_SMS"; // this is the Maker IFTTT trigger name to send SMS if low is level is CRITICAL.
const char* host = "maker.ifttt.com";
String url_google_drive; // url that gets built for the IFTTT Webhook logging to google drive spreadsheet
String url_M2X; // url that gets built for the IFTTT Webhook logging to AT&T M2X service
String url_SMS; // url that gets built for the IFTTT Webhook sending SMS if food level is critical
// Define and set up some variables
float Range_inches; // How far the sensor is from the food at time of reading. Sensor is on roof of feeder.
float Min_level = 5.0; // Distance in inches before low food alarm level. Food is far from sensor on feeder roof
float Max_level = 0.5; // Distance in inches from sensor for full feeder level. Food is close to sensor on feeder roof
float Percent_full; // How full in xx.x% is the food based on the Min/Max_levels defined above
float Caution_alarm = 35.0; // at xx.x% food level is considered low. String Status YELLOW
float Critical_alarm = 25.0; // at xx.x% food level is considered critically low. String Status RED
String Status = "***_Starting_with_Caution_at:_" + String(Caution_alarm) + "%_and_CRITICAL_at:_" + String(Critical_alarm) + "%"; // Update to Out of Range, NORMAL, LOW, CRITICAL, etc. "spaces" will error IFTTT Webhook; use "_"
int Run_number; // how many times the sensor has been read
// Output pins
const int led = 2; // Blue on board LED is on PIN2 for this NoderMCU 1.0 ESP8266. Blink it between reads
// Program control variables
int Seconds_between_posts = 60 * 60; // how often to post the results of the sensor read. NOT EXACT due to post delays, Sensor reads, LED flashing, etc.
int logging = 1; // If 1 then log to cloud. Any other value (0) turns it off. ESP8266 "Start/Restart" message is always logged.
void setup(void){ // This is run once.
pinMode(led, OUTPUT); // set up the onbaord LED pin as an output.
Serial.begin(115200); // turn on the serial monitor for debug
// wait until serial port opens for native USB devices
while (! Serial) {
delay(1);
}
// Is the ToF sensor connecting via I2C?
Serial.println("STMicro VL53L0X test");
if (!lox.begin()) {
Serial.println(F("Failed to boot VL53L0X!!!"));
while(1);
}
// power
Serial.println(F("VL53L0X Passed... \n\n"));
// Is the WiFi working?
WiFi.begin(ssid, password);
Serial.println("");
// Wait for connection
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.print("Trying to connect to ");
Serial.print(ssid);
Serial.print(" on ");
Serial.print(WiFi.localIP());
Serial.println(".");
}
Serial.print("Connected to ");
Serial.println(ssid);
Serial.println(WiFi.localIP());
if (MDNS.begin("esp8266")) {
Serial.println("MDNS responder started");
Serial.println(" ");
}
// Use WiFiClient class to create TCP connections for WiFi logging
WiFiClient client;
const int httpPort = 80;
if (!client.connect(host, httpPort)) {
Serial.println("connection failed"); // Boo!!!
return;
}
server.begin();
Serial.println("HTTP server started"); // Woo Hoo!!!
// Write to Google Sheet via IFTTT Maker channel that the ESP8266 has started/restarted
// Trigger the IFTTT Webhook Channel to update a Google sheet with the activity of the server starting/restarting
// This can help log power outs, etc. For first run we defined String Status for identify a startup condition.
// Create the request for IFTTT google drive
url_google_drive = "https://maker.ifttt.com/trigger/" + TRIGGER_NAME_google_drive + "/with/key/" + MAKER_SECRET_KEY + "?value1=" + String(Status);
Serial.println("Status: " + Status);
Serial.println(" ");
// This sends the request to the IFTTT server
client.print(String("POST ") + url_google_drive + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Connection: close\r\n\r\n");
delay(500); // Delay for web traffic; maybe not required.
}
void loop(void){
// Loop forever. Read the sensor and post based on the delay values set above.
// The blue onboard LED will blink between ToF reads.
// Read the ToF. Distance in mm returned.
for (int x = 0; x < 10; x++) { // Quick toggle blue on board LED to show measurement being taken.
digitalWrite(led, !digitalRead(led)); // toggle state of the on board blue LED. Shows program is running
delay(100); } // endfor quick toogle Blue LED
VL53L0X_RangingMeasurementData_t measure;
Serial.println("-------------------------------------");
Serial.println("Reading a measurement... ");
lox.rangingTest(&measure, false);
// Convert to inches because the USA, for some reason, doesn't want to adopt the metric system...
Range_inches = measure.RangeMilliMeter/25.4;
Run_number = Run_number + 1;
// Scale and normalize the Min Max levels to 0% to 100%. Clip the range in case of a the Max fill limit was exceeded or a misread.
Percent_full = ((Range_inches - Min_level) / (Max_level - Min_level)) * 100.0;
if (Percent_full > 100) {
Percent_full = 100.00;
}
if (Percent_full < 0) {
Percent_full = 0.0;
}
//Serial.println(String(Range_inches)); // Debug use
// Is the ToF Sensor reading 'anything' for a distance?
if (Range_inches > 100 ) { // Something's weird. Ranging error. The ToF sensor is NOT over 100 inches fron the food. EVER!!!
Status = "Run:" + String(Run_number) + "__ERROR:_***_Out_of_Range_***";
} else { // ToF made a successful reading so log the food level
if (Percent_full >= Caution_alarm) { // above CAUTION LEVEL, All's good
Status = "Run:" + String(Run_number) + "___GREEN---GOOD";
} // endif GREEN---GOOD
if (Percent_full < Caution_alarm && Percent_full > Critical_alarm) { // CAUTION Zone, YELLOW---REFILL_SOON
Status = "Run:" + String(Run_number) + "___~~~YELLOW---REFILL_SOON~~~";
} // end if YELLOW---REFILL_SOON"
if (Percent_full <= Critical_alarm) { // CAUTION Zone, RED---REFILL_ASAP"
Status = "Run:" + String(Run_number)+ "___!!!_RED---REFILL_ASAP_!!!";
if (logging == 1) { // is logging turned on? Maninly for debug... Typically would be set = 1
// Set up IFTTT Webhook Channel to send the SMS.
// Use WiFiClient class to create TCP connections for IFTT SMS
WiFiClient client;
const int httpPort = 80;
if (!client.connect(host, httpPort)) {
Serial.println("connection failed");
return;
}
url_SMS = "https://maker.ifttt.com/trigger/" + TRIGGER_NAME_SMS + "/with/key/" + MAKER_SECRET_KEY+ "?value1=" + String(Percent_full);
Serial.println("Critical Level: Sending SMS with payload:.");
Serial.println(url_SMS);
Serial.println(" ");
client.print(String("POST ") + url_SMS + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Connection: close\r\n\r\n");
//Serial.println("GOOGLE DRIVE URL:");
//Serial.println(url_google_drive);
delay(500); // pause for webservices
}
} // endif RED---REFILL_ASAP
}
// Serial print to the monitor for debug
Serial.println(String(Range_inches) + " inches down / " + String(Percent_full) + "% full");
Serial.println("Status: " + Status);
// Create the request for IFTTT Google Drive and M2X updates
url_google_drive = "https://maker.ifttt.com/trigger/" + TRIGGER_NAME_google_drive + "/with/key/" + MAKER_SECRET_KEY + "?value1=" + String(Percent_full) + "%" + "&value2=" + Status;
url_M2X = "https://maker.ifttt.com/trigger/" + TRIGGER_NAME_M2X + "/with/key/" + MAKER_SECRET_KEY + "?value1=" + String(Percent_full);
// This sends the request to the IFTTT server.
//Serial.println("Requesting URL..."); // debug
//Serial.println(url); // debug
if (logging == 1) { // is logging turned on? Maninly for debug... Typically would be set = 1
//Serial.println("Logging is ON.");
// Set up IFTTT Webhook Channel to update a Google sheet with the activity.
// Use WiFiClient class to create TCP connections for IFTT Webhook logging
WiFiClient client;
const int httpPort = 80;
if (!client.connect(host, httpPort)) {
Serial.println("connection failed");
return;
}
client.print(String("POST ") + url_google_drive + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Connection: close\r\n\r\n");
Serial.println(" ");
Serial.println("IFTTT url payload to Google Drive:");
Serial.println(url_google_drive);
Serial.println(" ");
delay(500); // pause for webservices
// Set up IFTTT Maker Channel to update a AT&T M2X Server with the activity.
// Use WiFiClient class to create TCP connections for IFTT Webhook logging
//WiFiClient client;
//const int httpPort = 80;
if (!client.connect(host, httpPort)) {
Serial.println("connection failed");
return; }
client.print(String("POST ") + url_M2X + " HTTP/1.1\r\n" +
"Host: " + host + "\r\n" +
"Connection: close\r\n\r\n");
Serial.println("IFTTT url payload for M2X:");
Serial.println(url_M2X);
} else {
Serial.println("Logging is OFF.");
} // endif/else logging
for (int x = 0; x < Seconds_between_posts; x++) { // Delay for next measurement.
digitalWrite(led, !digitalRead(led)); // toggle state of the on board blue LED. Shows program is running
delay(1000); } // endfor delay for read measurement
}
-----
Thanks and check out our other stuff!!!