DIY water sensor
As I could not suppress my deep desire to measure my water consumption and I have the believe that I am some kind of DIY hero, I had to build a water meter myself. Actually I did not build a water meter, but merely a device that can read out (in real time) the water consumption.
My house is equipped with a Sensus 620 water meter, see Figure 1. The meter has a spinning disc, which is halve metal, halve non-metal, marked in green in Figure 1.
Figure 1: Sensus 620 water flow meter. Spinning disc highlighted in green
So I thought that by counting the number of times the metal is passing by, I could get an idea of the water consumption. This brilliant idea is not “mine” and others have illustrated it online already. So why this piece of text?
Well, because the internet is a magical place to dump information. And I learned in life that one of the best ways to learn, is by trying to explain to another what you did. So embrace yourselfs, I will explain how I build my “sensor”.
Proximity sensor
As with most things in life, I will warn you, I have little clue of what I am doing. So I bought a proximity sensor from one of my favorite websites. This one: LJ12A3-4-Z/BX. This sensor detects metal and works like this: “Inductive Proximity Sensors detect magnetic loss due to eddy currents that are generated on a conductive surface by an external magnetic field.”. In more simple turns; the output signal changes when the metallic part of the spinning disc passes by.
The sensor operates between 6 and 36 VDC according to the supplier. But I am stubborn and tried 5V. The reason is that a typical arduino board can provide power supply of 5V. It didnt work out. I then tried a 9V battery and upon contact between the sensor and a piece of metal, the build in LED turned on. The sensor worked!
The sensor is equipped with a brown, black and blue (neutral) wire. There is a blueprint of the proximity sensor, but i decided to pimp my electronics knowledge and start from scratch. I considered the sensor as a black box (i.e. no clue what is in there). I then used a multimeter and found that there is a potential difference of 9V between brown and blue wire, but also between black and blue in case the proximity sensor was not close to a metal (i.e. “OFF”), see Figure 2.
Figure 2: Schematic representation of sensor when turned "OFF" (i.e. when not in close proximity of metal)
I then performed the same measurements but now in close proximity of a metallic object (the internal LED turned on). You can see the results in Figure 3 below. The potential drop of ~0.7 V is typical for a silicon based transistor, which is expected as the proximity sensor is a NPN (transistor) based sensor.
Figure 3: Schematic representation of sensor when turned "ON" (i.e. when in close proximity of metal)
So when the metal disc is passing by we will measure a change in potential between the black and blue (ground) wire. It will change from the scenario depicted in Figure 2 to the scenario in Figure 3 and vice versa. By registering the potential change between black and blue (ground) wires we can count half a revolution of the disc. Performing this measurment by an Arduino would allow me to accurately count these changes as function of time (i.e. the water consumption).
Voltage divider
However, 9 V would fry my Arduino. So, I had to come up with a trick. This problem can be solved by applying a “Voltage divider”. I first put one resistor (R1 = 10 kOhm) between the black and blue (ground) wire, as displayed in Figure 4. I did expect the same scenario as Figure 2, a potential drop of 9 V, but to my surprise I measured a difference of only 4.5 V.
Figure 4: Schematic representation of sensor including resistor (R1 = 10 kOhm) when turned "OFF" (i.e. when not in close proximity of metal)
This made me suspicious, so I picked a different resistor with a different resistance (68 kOhm). And I measured a greater potential drop over the resistor, namely 7.85V, see Figure 4.
Figure 5: Schematic representation of sensor including resistor (R1 = 68 kOhm) when turned "OFF" (i.e. when not in close proximity of metal)
This suggested me that the sensor has an internal resistance, as illustrated in Figure 6.
Figure 6: Schematic representation of electric circuit. I = 0.116 mA.
The current is constant for every element of a series circuit. We can therefore extent Ohm’s law to:
\[V_1 + V_2 + ... + V_n = I \cdot (R_1+R_2 +... + R_n)\]In our scheme we are interested in the value of R2, so we rearrange the equation to:
\[R_2 = \frac{V_1+V_2}{I} - R_1\]In this scheme I measured a current of 0.116 mA. Filling in the equation gives:
\[R_2 = \frac{7.85+1.15}{0.116 \cdot 10^{-3}} - 68 \cdot 10^3 = \left( \frac{9}{0.116} -68 \right) \cdot 10^3 = 9.6 \ kOhm\]Then things became more clear! Let’s go back to the situation displayed in Figure 4, but now considering the fact that the sensor contains an internal resistor (R2) of ~ 10 kOhm, see Figure 7.
Figure 7: Schematic representation of electric circuit. I = 0.452 mA.
To confirm I repeated the same experiment but with a resistor (R1) of 68 kOhm , see Figure 8 (previously shown in Figure 5). I measured a current of 0.452 mA.
Plugging these numbers in the equation gives:
\[R_2 = \frac{4.56+4.47}{0.452 \cdot 10^{-3}} - 10 \cdot 10^3 = \left( \frac{9}{0.452} - 10 \right) \cdot 10^3 = 9.98 \ kOhm\]And thereby confirm that the internal resistor is indeed ~ 10 kOhm. Note that the ratio of the potentials are proportional to the ratio of the resistances for these examples, because we are here dealing with a voltage divider:
- 10 kOhm / 10 kOhm = 1 and 4.5 V / 4.5 V = 1 (Figure 7)
- 68 kOhm / 10 kOhm = 6.8 and 7.85 V / 1.15 V = 6.8 (Figure 6)
So now let’s go back to the scenario where the sensor is in close proximity of a ferrous metal. I measured a current over the circuit of 3 mA, but when turned off only 0.95 mA. The latter can be easily explained by the electrical circuit displayed in Figure 8 “OFF”. A potential of 9V is applied and the circuit contains a ~ 10 kOhm resistor, according to Ohm’s law the current should then be ~ 0.9 mA, which is similar to the measurement (0.95 mA) see the equation below. Obviously, no current flows between the brown and black wire as this is not a closed circuit.
\[I = \frac{U}{R} = \frac{9}{10 \cdot 10^3} = 0.9 \cdot 10^{-3} A = 0.9 \ mA\]Transistor
The higher current in the ON state suggests that the resistor (R2) is (partially) bypassed. I previously noted that there is a potential drop of ~ 0.7 V when the sensor is in the “ON” state, this is typical for a silicon based transistor. Moreover, the sensor is known to contain a NPN type transistor. The potential drop of 0.7 V is between the base and the emitter, which means that base is connected to the black wire and the emitter to the blue (ground). Consequently the collector is connected to the brown wire (the supply). The circuit is displayed in Figure 8.
Figure 8: Schematic representation of electric circuit in ON and OFF state.
The switch is turned on or off based on the presence of a ferrous object. Note that the sensor internals are much more complicated than drawn here, but the schematic here explains all the observations. Now we have an idea on how the sensor works, still the output potential (black wire) would fry my Arduino. So, as discussed before, we will create a “Voltage divider” and register the positive potential on the black wire compared to the ground which was previously discussed in the section Voltage divider, see Figure 9. Note that the transistor and resistor 1 (R1) form a parralel circuit, for which holds that the potential drop is equal.
Figure 9: Schematic representation of electric circuit in ON and OFF state.
I use this Wemos type of Arduino which I believe runs on 3V, but I could be wrong. Nevertheless, I needed to lower the potential further. So I added another resistor of 10 kOhm (R3), see Figure 10.
Figure 10: Schematic representation of electric circuit in ON and OFF state.
Resistor 1 and 3 form a parralel circuit, which means that the following holds for their combined resistance:
\[\frac{1}{R_{1+3}} = \frac{1}{R_1} + \frac{1}{R_3} = \frac{1}{10} + \frac{1}{10} = \frac{2}{10}\]Reorganizing the equation gives:
\[R_{1+3} = \frac{10}{2} = 5 \ kOhm\]R2 and R1+3 form a series circuit. The current is constant for every element of a series circuit. We can therefore extent Ohm’s law to:
\[V_2 + V_{1+3} + ... + V_n = I \cdot (R_2+R_{1+3} +... + R_n)\]In our scheme we are interested in the value of V1+3, but first we calculate the current (I).
\[I = \frac{V_2+V_{1+3}}{R_2 +R_{1+3}} = \frac{9}{15 \cdot 10^3} = 0.6 \ mA\]Now we calculate the potential drop over the combined resistors 1 and 3 (R1+3), which turns out to be 3 V, see the equation below. Both the calculated current and calculated potential match the measured values.
\[U = I \cdot R = 0.6 \cdot 10^{-3} \cdot 5 \cdot 10^3 = 5 \cdot 0.6 = 3 V\]Connecting the Arduino
Connect the Arduino to a power supply (likely 5V) and connect the blue wire to the ground (GND) and the black wire to an analog pin for example A0, see Figure 11. In close proximity of a ferrous object (“ON”) the potential difference read by the Arduino is ~ 0.7 V.
Figure 11: Schematic representation of electric circuit with Arduino
In absence of the metallic object (“OFF”) the potential difference read by the Arduino is ~ 3 V, see Figure 12.
Figure 12: Schematic representation of electric circuit with Arduino
Coding the Arduino
So now we need a piece of code to log the potential change when the metallic part of the disk is passing by the inductive sensor. I started with a very basic script. If you are familiar with Arduino’s you will recognize the layout. The “void setup()” is run once and “void loop()” is repeated infinitely. The “void loop()” function calls the function “SensorRead()”, which actually performes the hard work. The code kind of speaks for itself. Test the setup by moving the inductive sensor over a metallic object to see if the potential reading changes.
void setup() {
// put your setup code here, to run once:
Serial.begin(9600); // Opens the serial connection with a specified baud rate
}
void loop() {
// put your main code here, to run repeatedly:
SensorRead(); // Call the function SensorRead
}
//-----------------------------------------------------
//--Sensor-Read-Out------------------------------------
//-----------------------------------------------------
// Define Variables
float MaxV = 3.3; // [V], Maximum operating voltage, which depends on the Arduino type
int anPin = A0; // Analog pin
float Val;
float Potential;
void SensorRead(){
Val = analogRead(anPin); // Retrieve the value from the analog pin
Potential = Val*MaxV/1024;
Serial.print("Potential [V] = "); // Print text "Potential [V] = "
Serial.println(Potential); // Print the actual Potential reading
delay(100); // Delay the next iteration with 100 ms (1 s)
}
Now this code is very basic and only logs the potential. We actually want to measure the water consumption. To do so, we need to register the moment that the potential flips from ~ 3 V to ~ 0.7 V or the other way around. In other words, the absolute difference in potential in the current iteration (n) compared to the previous iteration (n-1) should be around 2.3 V (abs(3-0.7)=2.3). I played it safe, and defined this moment was greater than 2 as a “Pulse”. In such event, the spinning disc would have passed half a revolution, which in my case is equal to half a liter. See the extended “SensorRead()” function below.
//-----------------------------------------------------
//--Sensor-Read-Out------------------------------------
//-----------------------------------------------------
// Define Variables
float MaxV = 3.3; // [V], Maximum operating voltage, which depends on the Arduino type
int anPin = A0; // Analog pin
int Val;
float Potential; // [V]
float PrevPotential; // [V]
float Delta; // Difference
float Puls_to_L = 0.5; // Water liters per puls
float WaterL = 0; // [L], Water consumption
void SensorRead(){
Val = analogRead(anPin); // Retrieve the value from the analog pin
Potential = Val*MaxV/1024; // [V], calculate the potential reading
Delta = abs(Potential-PrevPotential); // Difference between the current potential reading and the reading from the previous iteration
PrevPotential = Potential; // [V], previously read (previous iteration) potential
if (Delta > 2) {
Serial.print("Potential [V] = "); // Print text "Potential [V] = "
Serial.println(Potential); // Print the actual Potential reading
Serial.print("Delta = ");
Serial.println(Delta);
WaterL = WaterL + Puls_to_L; // [L] Actual water consumption
Serial.print("Water consumption [L] = ");
Serial.println(WaterL);
}
delay(100); // (arbitrarly set) Delay the next iteration with 100 ms (1 s)
}
So the script above logs the water consumption. Still it is quite basic, but it does what need to do. I use the Wemos wifi connectivity to upload the sensor reading to a central database. As of now, I will not discuss that here, but others have written tutorials on it.
Installation
Now it is time to install the sensor on the water meter. I used the two “upstanding pins” marked in green in Figure 13 below.
Figure 13: Sensor mounting points marked in green
I drilled a wooden piece as such that it would fit on the two pins, see Figure 14.
Sensor mount | Installed sensor |
---|---|
Figure 14: Sensor installation
First result
So now it is time to test the sensor! I flushed my toilet and saw the following, see Figure 15. The consumption is quite linear and around 8 L which in line with my expectations. I have used this sensor to study my water consumption in more detail (press this link).
Figure 15: First reading! (Toilet flush)