A wireless Fuel Tank monitor

I saw an excellent write-up on how to monitor fuel levels in an oil tank using ultrasonic sensors over on hackaday.  In his blog, alaskanshade details how he used Arduino and an ultrasonic sensor to log the data and measure fuel levels.  I really like the idea of monitoring fuel levels using this setup, so I had to give it a try.  I also wanted to incorporate the following design goals:

  1. Perform all-wireless data acquisition
  2. Ability to see current fuel level on the internet/web-page
  3. Log all data to a sql database/web-server using deviceLogger
  4. Battery life should last a long time, at least six months without having to change batteries

Forgive my lack of drawing skills, here is a diagram of the whole system:

deviceLogger system

In a nutshell, the process works like this:

  1. The sending unit pings the tank with the ultrasonic sensor and calculates the gallons (see attached gist for code, I found some code online that I adapted for use here. I’d give credit, but I can’t remember which site(s?) I found it on anymore)
  2. The entire system shuts down using the excellent LowPower library for Arduino.  After about one minute, it wakes back up and does another measurement.  After 15 measurements/minutes we send the current running median (another great Arduino Library) of the measurements. At this point, the whole process repeats.
  3. On the receiving end, there is an Arduino with an nrf24l01 module and ethernet shield (see my previous post on getting these two to work together if needed).  The receiver publishes some text/xml to a web page.
  4. The deviceLogger reader script periodically checks this page for new data.  It then writes the data to a mySQL database.  The deviceLogger php application then serves up the graphs and current data.

I ended up using one of my protoBoard pcbs on this project, and it worked out very well.  It fit perfectly in the 2″ pvc that I used to build the sensor housing.  Here’s some images from the build:

This shows a 4-AA battery holder, but I've since swapped it out for a 3-AA holder
The complete setup, all components. I later switched to a 3-AAA holder instead.


tank reader protoboard
This is a custom PCB I call a protoBoard. It basically just maps most of the atmega328’s pins to solder pads/screw-term pads.
You can see the snoot that was added to avoid the ‘multipathing’ issues that I experienced previously. Works great!
The ultrasonic sensor at the bottom of the unit.
PVC sheet cut to shape for bottom of the sending unit (You can find this material at a sign-supply shop)
Bottom of the unit with 1/2″ PVC installed for snoot.
Everything fit inside the 2″ PVC easily.
Top cap is just a slip fitting. I suppose you could use screw-on version if you cared to.

tankReader4 tankReader2

Sending unit uses 2" PVC to connect to tank.
Sending unit installed on tank.

Sending unit installed on tank

One thing that I noticed in the course of this project was that I was getting some strange readings from time to time, and sometimes readings would just be completely off from what I knew to be the current tank depth.  I had a theory that some of the erroneous readings may have been caused by multiple echoes bouncing off of the many internal facets of the tank (multipathing).  I decided to try adding a ‘snoot’ of 1/2″ pvc pipe to the end of the ultrasonic sensor to better guide the send signal towards the surface I actually wanted to measure (the fuel sitting at rest in the tank).  This seems to work very well.  Once I placed the snoot on the sensor, I immediately began receiving good readings without error.  I do still have some bad-value rejection and median-smoothing in the Arduino sketch though.  And as you can see from the screenshots, I still get fluctuations in the ultrasonic readings that work out to about a +/- 1 gallon level of accuracy over the course of a day:

This is the summary screen on deviceLogger
This is the summary screen on deviceLogger


You can see that there is still some fluctuation in readings even when rejecting bad values and median-smoothing
You can see that there is still some fluctuation in readings even when rejecting bad values and median-smoothing. I think to expect anything more would be a little unreasonable for a sensor that cost about $1.25

I also made a few modifications to the newPing library settings that changed the amount of time delay between pings on the ping_median() method.  This was done because the aforementioned multipathing/echo issues seem to present themselves once again if you don’t wait long enough between pings.  I adjusted the time from 29ms up to 1000ms.

As mentioned above, the sketch also uses the excellent LowPower library.  I used LowPower to power down the Atmega328 for about a minute at a time between readings.    This should allow the three AAA batteries to last about one year before needing to be replaced.

If you want to use this code, but have a different sized tank, you should be able to adjust the values for variables ‘tankHeight, tankWidth, and tankLength’.  As long as your tank maintains standard ob-round dimensions/shape, it should work fine.

Here’s the sketches:

PSA: Use a heatsink on your W5100 Arduino Ethernet Shield


This past summer, I had quite a few problems with some of my ethernet shields when the temperatures got hot.  I had intermittent connectivity and sometimes the shields would need to be reset, or would only work randomly whenever ambient temperatures were up above 80 degrees F or so (I have a few in the garage).  It took me a while to figure out that the problem was with the w5100 chip on the shields.  They get hot (or at least the inexpensive eBay knock-off versions I have been buying do).

I was able to make them work in a completely reliable fashion by attaching a small heatsink directly to the w5100 chip with some thermal paste (cpu paste).  I was able to get some 11x11x5mm heatsinks from eBay for about $2.50 shipped for five of them.

Anyhow, if you have experienced unreliable results with Arduino Ethernet Shields, you might try this.  It worked perfectly for me.

How to use an nrf24l01 (rf24) with an Arduino Ethernet Shield

I have been working on a project that requires the use of both a wiznet-type w5100 Ethernet shield like this and an nrf24l01 radio at the same time.  The problem I ran into was that both of these peripherals use the SPI protocol, and I could not get them both working simultaneously (the Ethernet shield has it’s pins hardwired to the hardware SPI, of course).  After doing some reading on the SPI protocol, I found out that there seems to be some kind of issue that, according to the freetronics website, causes the w5100 chip to maintain control of the SPI bus even when another device has been selected.

After much searching, and much experimenting, I finally found a workaround that seems to be working reliably for me.  The solution was to use ‘software’ or ‘bit-banged’ SPI.  This allows the Ethernet shield to happily commandeer the hardware SPI pins, while the nrf24l01 (or any other peripheral, I suppose) to operate on a separate, emulated SPI bus.

The credit for this goes to a user on the Arduino forums, nicoverduin, who suggested using some software SPI libraries already available and modifying maniacbug’s nrf24 library to use the software spi interface.

Here is the step by step:

1.)  Download the modified maniacbug library and softSPI libraries here.
2.) Copy the libraries to your Arduino libraries folder.
3.) Configure your Arduino/Ethernet-shield/nrf24l01 like this (you can also modify the pin configuration if needed.  Instructions are in the readme file on the linked github repository):


Connect to the soft-spi designated pins
Connect to the soft-spi designated pins


If you would like to download the fritzing file, here you go:

4.) Add the library references to your code or use example code provided below.

This sketch is a companion sketch to the nrf24l01_send_string sketch I posted previously.

Once you have completed the above steps, you can upload your sketch to the Arduino and you should be able to browse to the IP of your Arduino with Ethernet shield and you will see a web page that tells you the last message received over the nrf24l01.

There is one major caveat to all of this, however.  I have found that sometimes when I am working with the softSPI version of the nrf24 library and then I switch back to the regular/hardware version (e.g. when I work on the sending device, which in this case has no ethernet shield, after I upload a sketch to the one with the ethernet shield), the hardware-based SPI nrf24l01 breaks.  This seems to be happening because the Arduino IDE is holding on to the softSPI version of the rf24 library.  I am just speculating on that, but it kind of makes sense since the internal naming is identical between the libraries.

The fix for this problem is simple, if a bit inconvenient.  I have been removing my modified version of the rf24 library from the Arduino libraries folder before working with the hardware-SPI version.  I am sure there is a smarter way of fixing this, and if someone could point it out to me, I would be glad to post the solution here.

Another NRF24L01 Sketch – string send/receive

In a previous post I described a very simple setup to send and receive data using the NRF24L01 breakouts that can be purchased (very!) inexpensively on eBay.  I wanted to show another sketch, using basically the same physical setup, to send and receive text from one arduino to another.  Forgive the mostly copy-and-paste nature of this post, if you are just looking for the code, scroll to the bottom.

You will need (hardware):
(2) nrf24L01 2.4ghz wireless transcievers
(2) Arduino Uno (or compatible)
Recommended: male-female jumpers for connecting nrf24L01 modules to Arduino

You will need (software):
Arduino IDE
RF24 libraries by maniacbug (https://github.com/maniacbug/RF24)

The image below shows the view of the nrf24L01 from the top.  Note: the pins are on the bottom-side.  The image shows the top-side.

This is what the breakout looks like from the top.
This is what the breakout looks like from the top.

For this sketch, both arduino boards will need to be setup like this:

fritzing drawing of nrf24l01 connections

fritzing drawing of nrf24l01 connections
closeup of nrf24l01 to arduino connections
closeup of nrf24l01 to arduino connections

Upload the send and receive sketches to corresponding Arduinos physically configured as above.  The sending unit will take a string and break it down into individual characters, then send each character until the end of the string is reached.  After that, it sends a ‘termination message’, in this case, the integer ‘2’.  This tells the receiving end that the message is complete.  The sending unit then powers down it’s radio for one second, then powers it back up and runs through the loop again.

You will see some comments in the code about this delay period causing some occasional lost data when sending.  I’m hoping someone with more experience with the nrf24 radios can comment on this and provide some code improvements, but this method seems to work well for the most part.  I have added an alternative receive-side sketch below that checks for a proper message length as a sort of ‘checksum’ function.

On the receiving end, the sketch begins listening for available messages.  Once it begins receiving characters, it begins appending them to the receive string.  It continues to append characters until it receives the termination character (again, the integer ‘2’ in this case, but you could set it to something else).  It then prints the complete string to serial.

There is a second version of the receive sketch (receive_string_withChecksum) that also checks the final string length against an expected message length.  If the actual received message length does not match the expected length, the string is rejected and the radio begins listening for a new message.  Obviously, this will only work if you expect a message of a certain fixed size every time.


Simple nrf24L01 with Arduino Sketch and Setup


I have been working with the 2.4Ghz nrf24L01 modules on a few projects. These modules are very inexpensive (about US $1.25 ea. when bought in quantities of 2 or more on eBay), and they seem to work well for short range, small payload data transmittal. This walk-through will show you how to wire them up, and then will demonstrate a pair of very basic sketches (one for the sender, and one for the receiver) used to verify that data is being sent wirelessly.

You will need (hardware):
(2) nrf24L01 2.4ghz wireless transcievers
(2) Arduino Uno (or compatible)
(2) LEDs: Red and Green (or whatever you have)
Recommended: male-female jumpers for connecting nrf24L01 modules to Arduino

You will need (software):
Arduino IDE
RF24 libraries by maniacbug (https://github.com/maniacbug/RF24)

The image below shows the view of the nrf24L01 from the top.  Note: the pins are on the bottom-side.  The image shows the top-side.


This drawing shows the basic connections from nrf24L01 to Arduino.  For this sketch, the only difference between the sender and the receiver will be that two LEDs will need to be added on pins 3 and 5 (or whichever you choose, really).

closeup of nrf24l01 to arduino connections
closeup of nrf24l01 to arduino connections
The send and receive Arduino setups.  Pay no attention to the LEDs without resistors.
The send and receive Arduino setups. Pay no attention to the LEDs without resistors.

Once you have the sender and receiver wired up, you will need to upload sketches to each.  All the sender sketch does is send values 0 to 255 to the receiver, repeatedly.

On the receiver side, the sketch just reads the sent data and compares it to the last value received.  If the value received is equal to the last value plus one, the green LED will light.  If it is not, the red LED will light.  This works pretty well to visually display how reliable the signal is.  If you see lots of red, you know you are dropping packets.  Note, though, that this sketch will blink the red LED once each cycle to indicate that a complete 0-255 cycle has taken place.

Again, the idea behind these two simple sketches is to get down to the most basic possible setup for use with nrf24L01.  I hope this helps someone trying out the nrf24L01 transceivers for the first time.  The video embedded below shows the behavior of the receiver when it experiences lost wireless packets.

Sketch for the sender:Sketch for the receiver:


Arduino: from prototype to product

When I first got into working with Arduino, I had a hard time finding examples of projects that made it all the way to the ‘finished product’ stage.  Hopefully this information will benefit someone looking to see what can be involved with bringing a simple prototype full circle.  The following information is for background and does not have anything to do with the prototyping process itself:

The problem: We have an ‘instant’ water heater that also runs a hydronic air handler and radiant slab in the garage.  In the winter, the system gets overloaded, and shower temps fluctuate.

The project:  Reset switch for domestic/hydronic water heater.  The device senses flow from a flow switch and intelligently shuts off power to pumps connected to the air handler after a preset amount of time.  The device also resets itself if it’s locked out for too long.

So, here’s what I started out with:

The first version of the device is big, bulky, and (relatively) expensive.  It consists of an arduino, a protoshield (which is unnecessary in this case), a breadboard, a large terminal block, and a collection of components.  As you can see, this is not portable, at least not easily.  As well, it’s got lots and lots of places where something could fall out, be pulled out, or otherwise experience a failure.

So, I decided to put it all in a box:

By moving the necessary components off of the arduino/breadboard and onto a prototyping board, I was able to condense the whole device into a more usable form factor.  I used this instructables tutorial to get all of the necessary components off the Arduino.  This intermediate step would have been fine if the goal was a one-off, but I was looking to design an easily repeatable ‘product-like’ final version.

In order to do this, it was necessary to design a printed circuit board that incorporated all of the components and circuit paths.  After some research, I found that many hobbyists use an application called Eagle PCB Design to do this.  Below, you can see what a PCB looks like in Eagle:

Eagle has a bit of a learning curve, but there are many great tutorials out there. Just do a youtube search and you’ll get quite a few examples.  It took me a few nights of working with my design to get it the way I wanted.  The next step is to find a PCB fabrication company to fabricate your boards.  I chose to go with seeedstudio, there are many others. Unfortunately (but somewhat expectedly), some errors on my first design caused my first run of boards to be unusable (Tip: make sure to be extra careful about the orientation of all parts you place into your design, top/bottom orientation can be very confusing for a newbie).  So, I made the necessary corrections and sent the board designs off again.

A few weeks later, my new boards arrived.  Below, you can see the results:

Above: Intermediate prototype next to finished product.  Quite a difference in size and complexity.

So as you can see, even someone with very little experience can go from prototype to (sort-of) final product.  I have found the design of PCBs to be one of the most enjoyable parts of this hobby.


First attempt: Controlling the LED driver brightness via PWM/arduino

This video shows an example sketch that controls the dimming on each channel (blue and white) independently.  You’ll see it go from 100% to 50% to low on each channel, and then slowly fade from 0 to 100% and then back down again, then repeat:

I now have pwm dimming set up and working on my tank via Arduino.  The whole system is operated by a regular programmable timer.  The timer turns the whole system on at 10:00 and off at 22:00.  The Arduino turns on with the timer (5v power is fed to the arduino via the Steve’s LEDs controller), and ramps from 0 to 100% on both channels over the course of six hours, and back down to 0% during the next six hours.  This, of course, is the first draft of the Arduino sketch and has one major shortcoming (outside of lack of on-the-fly programmability and user-feedback): if the power goes out, it starts back over at 0% output and begins ramping up again.  This isn’t a big deal if you rarely experience power outages, but could really mess up your tank’s usual light cycle if there are any power interruptions.

Here’s the Arduino code:

// This skectch brings LEDs from off to full brightness over a period of 6 hrs
// Then it dims down to off over a period of 6 hrs allowing for a full 12 hour
// cycle when controlled via an external timer.
int BluePin = 9; //this is the pwm output for the blue channel
int WhitePin = 10; //this is the pwm output for the white channel
void setup()
 pinMode(BluePin, OUTPUT);
 pinMode(WhitePin, OUTPUT);
void loop()
 for (int i = 0; i<255; i++)
 analogWrite(BluePin, i);
 analogWrite(WhitePin, i);
 //delay for 84.375 seconds.

 for (int i = 255; i>0; i--)
 analogWrite(BluePin, i);
 analogWrite(WhitePin, i);
 //delay for 84.375 seconds


In case you are wondering, the ‘84.375 seconds’ value in the sketch corresponds to 256 slices of six hours.  The analogWrite method accepts values from 0 to 255.


Arduino air-horn alarm

Using an Arduino to detect light, sound alarm.

Just wanted to share a very simple setup for sounding an air-horn using a servo connected to an Arduino.  I found that it can be tricky to get the mounting just right, and that  the servo (I’m using a standard issue Hitec HS-322HD) can have trouble pressing the trigger.  It takes a fair amount of effort (for a servo) to press the button and sound the horn.  You may have to play with the mounting to get it just right and take advantage of the best position for leverage.

You can see above I’ve fashioned a mount and some zip ties to fasten the servo.  I made this out of high density urethane which can be found at sign supply shops.  I’m sure results will vary depending on the brand of air horn you buy as I would guess they all have different tolerances and need more/less pressure to actuate the horn.

Above, you’ll see the Arduino with a protoshield mounted to the top along-side the airhorn.

Parts needed:

Arduino (any, I’m using a Duemilanove)
Photocell (also known as an LDR, or light-dependent resistor), Iike this one: https://www.adafruit.com/products/161
resistor (I’m using a 220 ohm,  but it will depend on the value of your Photocell)
Servo: You’ll need one that will run happily on the 40ma of current an Arduino pin will provide.

Here’s a schematic:

Here’s the Arduino code:

 //this sketch measures the light level of a room when powered up, sets a thresshold value, and waits for lights to be turned on to trigger the servo.
#define LDRpin 0
#include <Servo.h>
Servo myservo;
int AlarmHasSounded = 0;
int LDRval = 0;
int ThreshholdValue = 0;
void setup() {
 ThreshholdValue=analogRead(LDRpin); //get original light level of the room

void loop() {

 LDRval = analogRead(LDRpin);
if (LDRval > (20+ThreshholdValue) ) {
 if (AlarmHasSounded == 0) { //check to make sure alarm has not sounded yet
 delay(3000); //how long to wait from the time of lights turning on to triggering the servo
 AlarmHasSounded = 1;
 Serial.println("Alarm Triggered!");



The code above will need to be modified for your particular ambient light settings.  Depending on how much the amount of light fluctuates under normal conditions, you will need to modify the line that contains :

if (LDRval > (20+ThreshholdValue)

where the value ’20’ is a representation of the fluctuation you expect.

Additionally, you can modify the code to sense a laser beam from a laser pointer such that it acts as a trip-wire, as shown below:

Here’s a tip if you wish to do the laser tripwire thing, wrap some black electrical tape around a drinking straw and cover the photocell with it.  That way, the photocell will not be receiving much input from stray ambient light and it makes your program much easier to tune.  You could use this for the regular light-sensing alarm code posted above as well if you needed to shield the photocell from a specific light source.