author

Abhijit Borah

3
Inbox View Profile
1Instructables28,156Views44CommentsMokokchung, Nagaland
Recovering Physicist.

Achievements

10K+ Views Earned a bronze medal
  • Arduino Rain Gauge Calibration

    Difficult to guess without having a look at the code. I could not duplicate your situation. Can it be a typo some where? Anyway I have send the code to your email.

    View Instructable »
  • Arduino Rain Gauge Calibration

    Hi, the RTClib is available at https://github.com/adafruit/RTClib and with the newer versions you can use the first method mentioned here. https://thestempedia.com/tutorials/arduino-ide-libraries/ I have included screenshots of the steps below. Let me know if you face further problems. Regards

    View Instructable »
  • Arduino Rain Gauge Calibration

    "I would like to input this into . . " - Thank you, thank you. Please go ahead!

    View Instructable »
  • Arduino Rain Gauge Calibration

    Awesome to see your solar powered weather station and thank you for your kind words. Your 0.0119 inches of rain per tip/click is correct. Yet it is different from my 0.0161 inches/click. We are differing by about 26%. This has come from the fact you got 6 tips for 10 ml while I got 4 tips for 9 ml. Not same. So I have to make sure that my 4 tips for 9 ml is correct or not. Sadly, I do not have the rain collector anymore. However all this has pointed that we need to repeat our calibration observations with great great care. One way would be to use more liquid and observe for more bucket tips. Your query has made me a wiser person, thank you.

    View Instructable »
  • Arduino Rain Gauge Calibration

    "Also what is the 5v used for as mine works with just a ground and pin 2?" - When the magnetic switch is connected, it is "sure to read" 5 volts.(https://www.instructables.com/How-to-use-a-Push...)Below is the code to watch the rain in 10 minute intervals (Not tested, only compiled).---------------------------------------------------------------------------------------------------------------/*description: Basic Rain Gauge with arduino with serial monitoring Reports the daily-rain and rain-in-last-1o-minutes in inchesacknowledgement: part of the code copied and modified from https://www.instructables.com/Arduino-Weather-S...liscence: GNU GPL. https://www.gnu.org/licenses/gpl.html*/#include "RTClib.h"#include <Wire.h>#define RainPin 2 // The Rain …

    see more »

    "Also what is the 5v used for as mine works with just a ground and pin 2?" - When the magnetic switch is connected, it is "sure to read" 5 volts.(https://www.instructables.com/How-to-use-a-Push...)Below is the code to watch the rain in 10 minute intervals (Not tested, only compiled).---------------------------------------------------------------------------------------------------------------/*description: Basic Rain Gauge with arduino with serial monitoring Reports the daily-rain and rain-in-last-1o-minutes in inchesacknowledgement: part of the code copied and modified from https://www.instructables.com/Arduino-Weather-S...liscence: GNU GPL. https://www.gnu.org/licenses/gpl.html*/#include "RTClib.h"#include <Wire.h>#define RainPin 2 // The Rain input is connected to digital pin 2 on the arduinobool bucketPositionA = false; // one of the two positions of tipping-bucket const double bucketAmount = 0.01610595; // inches equivalent of ml to trip tipping-bucketdouble dailyRain = 0.0; // rain accumulated for the daydouble rain_Last_10_mins = 0.0; double dailyRain_till_Last_10_mins = 0.0; RTC_Millis rtc; // software RTC timevoid setup(void) { Serial.begin(9600); // start the serial port at 9600 bauds rtc.begin(DateTime(__DATE__, __TIME__)); // start the RTC pinMode(RainPin, INPUT); // set the Rain Pin as input. delay(4000); // i'm slow in starting the seiral monitor (not necessary) Serial.println("Ready!!!"); // not necessary too}void loop(void){ DateTime now = rtc.now(); // ++++++++++++++++++++++++ Count the bucket tips ++++++++++++++++++++++++++++++++ if ((bucketPositionA==false)&&(digitalRead(RainPin)==HIGH)){ bucketPositionA=true; dailyRain+=bucketAmount; // update the daily rain } if ((bucketPositionA==true)&&(digitalRead(RainPin)==LOW)){ bucketPositionA=false; } // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ if(now.second()== 0 && now.minute()%10==0){ // execute only in 10 minute intervals rain_Last_10_mins = dailyRain - dailyRain_till_Last_10_mins; // calculate the last 10 minutes rain dailyRain_till_Last_10_mins = dailyRain; // record the last 10 minutes rain for next calculation // fancy display for humans to comprehend Serial.println(); Serial.print(now.hour()); Serial.print(":"); Serial.print(now.minute()); Serial.print(": Total Rain for the day = "); Serial.print(dailyRain,8); // the '8' ensures the required accuracy Serial.println(" inches"); Serial.println(); Serial.print(" : Rain in last 10 minutes = "); Serial.print(rain_Last_10_mins,8); Serial.println(" inches"); Serial.println(); } if(now.hour()== 0) { dailyRain = 0.0; // clear daily-rain at midnight rain_Last_10_mins = 0.0; // we do not want negative rain at 00:10 } } // end of loop

    View Instructable »
  • Floating World Backlit Moss Map With Arduino Fiber Optic LED Cities

    Watching the project proceed to a completion was a pleasant journey in itself.

    View Instructable »
  • Fishermen Border Alert System

    Congratulations for creating a well documented project. I hope the few shortcomings will not deter you from thinking and implementing new solutions to problems. Hoping more from you in future. Goodluck.

    View Instructable »
  • Abhijit Borah followed Clocks, Laser Cutting, Robots, Audio and 39 others channel
  • Abhijit Borah commented on indoorgeek's instructable FM Radio

    Simplicity is the best, and you have nailed it.

    View Instructable »
  • Abhijit Borah commented on Trevor_DIY's instructable Betta Fish Feeder

    In fact, my purchased automatic fish feeder got clogged (the outlet) somewhere in-between my three weeks absence. Some tiny fishes went missing from the aquarium by the time I came back.

    View Instructable »
  • Der Teil des Codes -if (now.minute () == 0 && first == true) {---- -------- -------- ----}sendet die Ausgabe nur am Ende jeder Minute an den seriellen Monitor. Wir sollten mindestens eine Minute oder länger auf die Ergebnisse warten.

    View Instructable »
  • If there are no complication errors, then (just a guess), I hope you set the baud rate in your serial monitor at 9600bps. . .

    View Instructable »
  • Abhijit Borah commented on Troubah's instructable Making a Water Drum

    Loved the sounds! Shall build it one day "for use".

    View Instructable »
  • to calumniate, or not to calumniate, is now, the question

    View Instructable »
  • First: Sorry for the long, long delay ....... .......Ans 1. The line rtc.begin(DateTime(__DATE__, __TIME__)); in the setup part of the sketch sets the soft-RTC time to the same as that of the PC at the time of compilation. Consequently, if we start the arduino later, it should start with the same time as that at the time of compilation. I did not emphasize this earlier, my mistake. For logging purposes, this would a serious issue, and we would need a hardware based RTC like DS1703, etc. But for calibration purposes this should do (but not right still).Ans 2. For using such a rain gauge and logging rain data, both will do (again do not wrongly assume me to be an expert). EEPROM has limited writes (100,000 times) and of course of finite capacity. But if you plan to use it to monitor rain,…

    see more »

    First: Sorry for the long, long delay ....... .......Ans 1. The line rtc.begin(DateTime(__DATE__, __TIME__)); in the setup part of the sketch sets the soft-RTC time to the same as that of the PC at the time of compilation. Consequently, if we start the arduino later, it should start with the same time as that at the time of compilation. I did not emphasize this earlier, my mistake. For logging purposes, this would a serious issue, and we would need a hardware based RTC like DS1703, etc. But for calibration purposes this should do (but not right still).Ans 2. For using such a rain gauge and logging rain data, both will do (again do not wrongly assume me to be an expert). EEPROM has limited writes (100,000 times) and of course of finite capacity. But if you plan to use it to monitor rain, keeping your PC on "all the time" and nearby a the rain gauge is not a good idea. Specially so, if your rain gauge happen to be remotely located.Lastly, thank you for your first question, it has showed me that I should improve on this code and make a proper rain logger in future.

    Hi,I had used my old weather station's spare parts together with DHT22, BMP180 and UVM30A to upload weather data to weather underground via a Ethernet shield. The code is below, but a few things to note first:1. The code was copies from here, there and everywhere, form the internet.2. A soft RTC updated via NTP was used and modified for my time zone (GMT+5.5).3. The code is sloppy & dirty (and very old).4. Calibrating the wind gauge is slightly tricky. At that time I did not have a hand held anemometer and so I had to go around my town with the anemometer outside my car saving data to a micro sdcard and do regression analysis later :)----------------------------------------------------------------------------------------------------------------//**************************************…

    see more »

    Hi,I had used my old weather station's spare parts together with DHT22, BMP180 and UVM30A to upload weather data to weather underground via a Ethernet shield. The code is below, but a few things to note first:1. The code was copies from here, there and everywhere, form the internet.2. A soft RTC updated via NTP was used and modified for my time zone (GMT+5.5).3. The code is sloppy & dirty (and very old).4. Calibrating the wind gauge is slightly tricky. At that time I did not have a hand held anemometer and so I had to go around my town with the anemometer outside my car saving data to a micro sdcard and do regression analysis later :)----------------------------------------------------------------------------------------------------------------//*******************************************************************************************// Minimum Code to check the ethernet shield, arduino and connection to weather underground// Arduino Uno Version 3, Ethernet Sheild, DHT22, NTP, Rain Gauge, UVM30A// Working as on 27th May 2017//*******************************************************************************************#include <Wire.h> // Library for I2C (A4 = SDA, A5 = SCL)#include "RTClib.h" // Library for realtime clock#include <DHT.h> // DHT11 & DHT22 Library#include <SFE_BMP180.h> // Including BMP180 library#include <elapsedMillis.h> // Elapsed Millisecond library#include <SPI.h> // SPI interface used by ethernet sheild#include <Ethernet.h> // Library for the Ethernet Sheild#include <EthernetUdp.h> // New from IDE 1.0#include <SD.h>byte mac[] = { 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF }; // setting mac address#define RainPin 5 // The Rain input is connected to digital pin D5// time servers for ntpchar timeServer[] = "time.nist.gov"; // time.nist.gov NTP serverconst int NTP_PACKET_SIZE= 48; // NTP time stamp is in the first 48 bytes of the messagebyte pb[NTP_PACKET_SIZE]; // buffer to hold incoming and outgoing packetsbyte packetBuffer[NTP_PACKET_SIZE]; // buffer to hold incoming and outgoing packets// Weather Underground servers and account//char SERVER[] = "weatherstation.wunderground.com"; // name address of WUchar SERVER[] = "rtupdate.wunderground.com"; // Realtime update serverchar WEBPAGE[] = "GET /weatherstation/updateweatherstation.php?";char ID[] = "Your Station ID";char PASSWORD[] ="Your Password";IPAddress ip(192, 168, 0, 11);EthernetClient client; // Initialize the Ethernet client libraryconst unsigned long IDLE_TIMEOUT_MS = 1000; // Time to wait for the WunderGround server to respondEthernetUDP Udp; // UDP for the time serverDHT dht(2, DHT22); // Initialize DHT22 sensor at Pin D2SFE_BMP180 pressure; // Initialize an object for BMP180RTC_Millis rtc; // Initialize an object for RTC// ********************** VARIABLES **************************************************************float Humidity, Temp_C1, Temp_F, dp_F; // variables for temperature, pressure of DHT22double Temp_C2, P; // variables for temperature, pressure of BMP180// Rain Variablesbool bucketPositionA = false; // one of the two positions of tipping-bucket const double bucketAmount = 0.010246; // inches equivalent of ml to trip tipping-bucketdouble dailyRain = 0;; // rain accumulated for the daydouble hourlyRain = 0;; // rain accumulated for one hourdouble dailyRain_till_LastHour = 0; // rain accumulated for the day till the last hour bool rainToggle; // as we want readings of the (MHz) loops only at the 0th momentbool actionToggle; // to upload data at stipulated times only// UV Indexint UVindex;void setup() { Serial.begin(9600); delay(4000); Serial.print("Weather Station, 4th May 2017\n\n"); delay(60000); rtc.begin(DateTime(__DATE__, __TIME__)); // Start the RTC Ethernet.begin(mac, ip); // Start the Ethernet Shield delay(4000); // Wait for Ethernet Shield Udp.begin(8888); // Local Port is 8888 delay(2000); // Give some time rtc.adjust(DateTime(ntp()+19800-2208988800UL)); // to IST (extra 19800 secs) - seventy years DateTime now = rtc.now(); // Get the date & time DateTimeNow(); // ***** Start the Sensors **************************************************************** dht.begin(); // Start the DHT22 sensor if (pressure.begin())Serial.println("BMP180 init success"); // Start the BMP180 sensor else { Serial.println("BMP180 init fail\n\n"); while(1); // Pause forever if error. }}//******************************************************************************void loop() { DateTime now = rtc.now(); // Get the date & time // adjust time every day at 00:00 if(now.hour() == 0 && now.minute() == 0)rtc.adjust(DateTime(ntp()+19800-2208988800UL)); // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // +++++++++++++++ Rain Gauge ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ // ++++++++++++++++++++++++ Count the bucket tips ++++++++++++++++++++++++++++++++ if ((bucketPositionA==false)&&(digitalRead(RainPin)==HIGH)){ bucketPositionA=true; dailyRain+=bucketAmount; // update the daily rain } if ((bucketPositionA==true)&&(digitalRead(RainPin)==LOW)){ bucketPositionA=false; } // +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ hourlyRain = dailyRain - dailyRain_till_LastHour; // calculate the last hour's rain if(now.minute() != 0) rainToggle = true; // after the first minute is over, be ready for next read if(now.minute() == 0 && rainToggle == true){ dailyRain_till_LastHour = dailyRain; // update the rain till last hour for next calculation rainToggle = false; // execute calculations only once per hour } if(now.hour()== 0) { dailyRain = 0.0; // clear daily-rain at midnight dailyRain_till_LastHour = 0.0; // we do not want negative rain at 01:00 }// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ if(now.minute()%15 != 0) actionToggle = true; // After the actionToggle minute is over, be ready for next read if(now.minute()%15 == 0 && actionToggle == true){ // Read other sensors and upload //******** readings from DHT22 with debug ************************************* Humidity = dht.readHumidity(); // Temp_C1 = dht.readTemperature(); // Temp_F = dht.readTemperature(true); // if (isnan(Humidity) || isnan(Temp_C1) || isnan(Temp_F)) { // Serial.println("Failed to read from DHT sensor!"); // return; // } // //***************************************************************************** dp_F = dewPointFast(Temp_C1,Humidity); // Calculation of dew point //******** UV Index *********************************************************** UVindex = GetUVIndex(analogRead(0)); // Get the UVIndex at A0 //********* Upload data ************************************************** if (client.connect(SERVER,80)) { Serial.println("\n\nSending DATA "); //************************************************************************* client.print(WEBPAGE); client.print("ID="); client.print(ID); client.print("&PASSWORD="); client.print(PASSWORD); client.print("&softwaretype=Arduino%20UNO%20Version%203"); //client.print("&action=updateraw"); // Standard update client.print("&action=updateraw&realtime=1&rtfreq=2.5"); //Rapid Fire client.print("&dateutc="); client.print(now.year()); client.print("-"); client.print(now.month()); client.print("-"); client.print(now.day()); client.print("+"); client.print(now.hour()); client.print("%3A"); client.print(now.minute()); client.print("%3A"); client.print(now.second()+5); client.print("&humidity="); client.print(Humidity); client.print("&tempf="); client.print(Temp_F); client.print("&dewptf="); client.print(dp_F); client.print("&rainin="); client.print(hourlyRain); client.print("&dailyrainin="); client.print(dailyRain); client.print("&UV="); client.print(UVindex); // Gsens UVM30A uv sensor client.print("&baromin="); client.print(P/33.864); client.print("&winddir="); client.print(windDirection); client.print("&windspeedmph="); client.print(windspdmph_avg2m); client.print("&windgustmph="); client.print(maxwndspdmph); //client.print("&windgustmph_10m="); //client.print(windgustmph); // [mph past 10 minutes wind gust mph ] //client.print("&solarradiation="); // TSL2561 luminosity sensor //client.print(Wm2); client.print(" HTTP/1.0\r\n"); client.print("Accept: text/html\r\n"); client.print("Host: "); client.print(SERVER); client.print("\r\n\r\n"); //************************************************************************* } else { Serial.println(F("Connection Failed")); delay(2000); return; } while (client.connected()) { if (client.available()) { char c = client.read(); Serial.print(c); } } client.stop(); // Stop/disconnect the ethernet Client PrintSerial(); // Display reading onver the serial port actionToggle = false; } // end of action toggle delay(10);}// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// +++++++++++++++ End of Void Loop +++++++++++++++++++++++++++++++++++++++++++++++++++++// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// ++++++++++++++++ NTP Function ++++++++++++++++++++++++++++++++++++++++++++++++++++++// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++unsigned long ntp(){ unsigned long secsSince1900; sendNTPpacket(timeServer); // send an NTP packet to a time server // wait to see if a reply is available delay(1000); if (Udp.parsePacket()){ // We've received a packet, read the data from it Udp.read(packetBuffer, NTP_PACKET_SIZE); // read the packet into the buffer // the timestamp starts at byte 40 of the received packet and is four bytes, // or two words, long. First, extract the two words: unsigned long highWord = word(packetBuffer[40], packetBuffer[41]); unsigned long lowWord = word(packetBuffer[42], packetBuffer[43]); // combine the four bytes (two words) into a long integer // this is NTP time (seconds since Jan 1 1900): unsigned long secsSince1900 = highWord << 16 | lowWord; return secsSince1900; }}//-------------------------------------------------------------// send an NTP request to the time server at the given addressvoid sendNTPpacket(char* address) { // set all bytes in the buffer to 0 memset(packetBuffer, 0, NTP_PACKET_SIZE); // Initialize values needed to form NTP request // (see URL above for details on the packets) packetBuffer[0] = 0b11100011; // LI, Version, Mode packetBuffer[1] = 0; // Stratum, or type of clock packetBuffer[2] = 6; // Polling Interval packetBuffer[3] = 0xEC; // Peer Clock Precision // 8 bytes of zero for Root Delay & Root Dispersion packetBuffer[12] = 49; packetBuffer[13] = 0x4E; packetBuffer[14] = 49; packetBuffer[15] = 52; // all NTP fields have been given values, now // you can send a packet requesting a timestamp: Udp.beginPacket(address, 123); //NTP requests are to port 123 Udp.write(packetBuffer, NTP_PACKET_SIZE); Udp.endPacket();}// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// ++++++++++++ Date Time display +++++++++++++++++++++++++++++++++++++++++++++++++// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++void DateTimeNow(){ DateTime now = rtc.now(); // Get the date and time if(now.hour() < 10)Serial.print("0"); Serial.print(now.hour()); Serial.print(":"); if(now.minute() < 10)Serial.print("0"); Serial.print(now.minute()); Serial.print(":"); if(now.second() < 10)Serial.print("0"); Serial.println(now.second());}// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// ++++++++++++++++ Dew Point Calculations in Fahrenheit ++++++++++++++++++++++++++++++++++++++// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// delta max = 0.6544 wrt dewPoint()// 6.9 x faster than dewPoint()// reference: http://en.wikipedia.org/wiki/Dew_pointdouble dewPointFast(double celsius, double humidity){ double a = 17.271; double b = 237.7; double temp = (a * celsius) / (b + celsius) + log(humidity*0.01); double Td = 32 + 1.8*(b * temp) / (a - temp); return Td;}// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// ++++++++++++ Serial Monitor Display ++++++++++++++++++++++++++++++++++++++++++++// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++void PrintSerial(){ Serial.print("\n\nTime :\t"); DateTimeNow(); Serial.print("\nHumidity: "); Serial.print(Humidity); Serial.print(" %,\t"); Serial.print("Dew Point: "); Serial.print(dp_F); Serial.print(" F,\t"); Serial.print("Temperature: "); Serial.print(Temp_C1); Serial.print(" C, "); Serial.print(Temp_F); Serial.println(" F\n"); Serial.print("Total Rain for the day:\t"); Serial.print(dailyRain,8); // the '8' ensures the required accuracy Serial.print(" inches\t"); Serial.print("Rain during last hour: "); Serial.print(hourlyRain,8); Serial.println(" inches"); Serial.println(); Serial.print("UV Index: "); Serial.print(UVindex); Serial.println();}// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// ++++++++++++ UV Index ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++// +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++int GetUVIndex(int uvVoltage){ int UVIndex = 0; int voltage = (uvVoltage * (5.0 / 1023.0))*1000; //Voltage in miliVolts if(voltage<50) { UVIndex = 0; }else if (voltage>50 && voltage<=227) { UVIndex = 0; }else if (voltage>227 && voltage<=318) { UVIndex = 1; } else if (voltage>318 && voltage<=408) { UVIndex = 2; }else if (voltage>408 && voltage<=503) { UVIndex = 3; } else if (voltage>503 && voltage<=606) { UVIndex = 4; }else if (voltage>606 && voltage<=696) { UVIndex = 5; }else if (voltage>696 && voltage<=795) { UVIndex = 6; }else if (voltage>795 && voltage<=881) { UVIndex = 7; } else if (voltage>881 && voltage<=976) { UVIndex = 8; } else if (voltage>976 && voltage<=1079) { UVIndex = 9; } else if (voltage>1079 && voltage<=1170) { UVIndex = 10; }else if (voltage>1170) { UVIndex = 11; } return UVIndex; }

    View Instructable »
  • Please may I have a link to the 'wireless charging part'. Thank you.

    View Instructable »
  • In fact this project was created as I wanted to repurpose a weather station rain and wind sensors with an Arduino. It worked fine, uploading data after every 15 minutes (to weather underground) untill a hailstorm totalled them.

    Such Arduino codes are available all over the internet ( and I shall be glad to share mine too).

    View Instructable »
  • Two points from my side:1. Thank you for spotting the error. I have corrected it.2. Please accept my apologies too. I cant figure out, or explain, how on earth I put in the strange number "0.394" instead of the 0.0161 which you have suggested.“If you make a mistake and do not correct it, this is called a mistake.”— ConfuciusThank you again.

    View Instructable »
  • Abhijit Borah commented on SilkeC2's instructable Happiness on Demand

    A needed gift stemmed from a wonderful idea. Congratulations.

    View Instructable »
  • NodeMCU Breadboard Tweak

    Destructive, yet with the small footprint, arguably the one of the best modifications. Thanks for sharing.

    View Instructable »
  • The game should be a rite of passage for every graduating astronaut.

    Should be included in every astronaut's graduate course.

    View Instructable »
  • Nice design, it will appeal to young people. Great project too. The Respeaker seems to be available only in Kickstarter.

    View Instructable »
  • One of my favourites. Thanks for sharing. In our side we use raw mustard oil instead of butter. Give a good sting. Only downside is the lingering smell.

    View Instructable »