Lua - Oil Tank Monitor

From Domoticz
Jump to: navigation, search

Purpose

The purpose of this script is to allow monitoring of a heating oil tank, by use of an ultrasonic sensor which measures the distance (of air) from the top of the fuel to the top of the tank.

The script is configured with the dimensions of the tank, and calculates the fuel level both as a percentage and as a volume in litres. It can also adjust to compensate for fuel expansion/contraction with temperature, to give a stable reading.

Dependencies

You will require a distance sensor which measures the air gap at the top of the tank. This is outside the scope of this example, but there are plenty of such devices on the market and many of them actually seem to be the same design, just rehoused and rebranded.

The Beckett Rocket, Watchman Sonic, and Apollo Ultrasonic oil tank monitors, and probably others, should all work with rtl_433 using a cheap USB DVB receiver. With a little more work, it should also be possible to use an RFM01 or RFM12B FSK receiver module on a Raspberry Pi, which should require less CPU.

Note that the RFXtrx433 modules are not suitable for this, as the modulation of the 433MHz signal is FSK. See here for the full details.

Others have made their own sensors.

Most sensors will also provide a temperature reading, since the speed of sound varies significantly across the temperature range that they need to operate within. However, is this is not required — the compensation for expansion of the fuel can be disabled if no temperature sensor is available.

Domoticz Setup

Input sensors

In my case, the input sensors are virtual; I haven't yet hooked up the rtl_433 receiver software to Domoticz directly, so I'm feeding values in externally. They were created as follows:

Temperature sensor (type 80):

curl 'http://localhost:8080/json.htm?type=createvirtualsensor&idx=1&sensortype=80'

Depth sensor (type 13):

curl 'http://localhost:8080/json.htm?type=createvirtualsensor&idx=1&sensortype=13'

Output sensors

Percentage sensor (type 2):

curl 'http://localhost:8080/json.htm?type=createvirtualsensor&idx=1&sensortype=2'

Volume sensor (RFXMeter type 113, subtype 2):

curl 'http://localhost:8080/json.htm?type=createvirtualsensor&idx=1&sensortype=113'
curl 'http://localhost:8080/json.htm?type=setused&idx=5&name=Oil&switchtype=2&used=true'

The idx=5 in the above will need to be replaced with the index of the created device in your own system.

(In fact, it's not clear that this is the correct device type to use. It's the only one I could find that has a unit of litres (or m³ in some cases), but it's designed for measuring water flow' not an amount. So the graphs aren't useful. We might need to add a new sensor type of plain volume to Domoticz.)

Installation instructions

Having configured the devices as described above, all that remains is to edit the configuration in the script below, and place it into your scripts/lua directory.

Script with comments

------------------------------------------------------------------------------
--
-- Copyright © 2015 David Woodhouse <[email protected]> and released under
-- the GNU General Public License, v2 or later.
--
--
-- Domoticz lua script to convert ultrasonic tank monitor readings into
-- percentage and volume virtual sensors for fuel tanks.
--
-- Takes input from distance sensor measuring the air above the fluid, and
-- converts to percentage and volume using the dimensions of the tank as
-- configured below.
--
-- Optionally, to prevent fluctuation as the fluid expands/contracts with
-- temperature, can convert the output values to report what the percentage
-- and volume *would* be at a fixed temperature.
--
------------------------------------------------------------------------------
--
-- Input sensors don't *have* to be virtual; mine are because they're filled in
-- by an external script running rtl_433 and receiving Watchman Sonic transmissions
--
-- Add tank temperature sensor:
-- 'http://localhost:8080/json.htm?type=createvirtualsensor&idx=1&sensortype=80'
-- Add depth sensor:
-- 'http://localhost:8080/json.htm?type=createvirtualsensor&idx=1&sensortype=13'
--
------------------------------------------------------------------------------
-- Output sensors are virtual, fed solely by this script
--
-- Add percentage sensor:
-- 'http://localhost:8080/json.htm?type=createvirtualsensor&idx=1&sensortype=2'
--
-- Add tank volume:
-- 'http://localhost:8080/json.htm?type=createvirtualsensor&idx=1&sensortype=113'
-- 'http://localhost:8080/json.htm?type=setused&idx=5&name=Oil&switchtype=2&used=true'
--
------------------------------------------------------------------------------
--
-- Update depth:
-- 'http://localhost:8080/json.htm?type=command&param=udevice&idx=3&nvalue=0&svalue=59'
--
------------------------------------------------------------------------------
 
 
-- Input devices: Temperature and air gap above fluid in tank
tank_temp_sensor = 'Oil tank temp'
depth_sensor = 'Oil tank sensor'
 
-- Output devices: Percentage full, volume.
pct_sensor = 'Oil tank'
pct_sensor_id = 4
volume_sensor = 'Oil'
volume_sensor_id = 5
 
-- To adjust for fluid expansion
-- Report volume/percentage as they would be at 10°C
canon_temp = -10
-- Kerosene
expansion_coeff = 1.00099
 
-- Tank dimensions
tank_height = 120
tank_area = 60 * 181
 
-----------------------------------------------------------------------------------
commandArray = {}
 
if (devicechanged[depth_sensor] or devicechanged[tank_temp_sensor]) then
   -- Use otherdevices_svalues[] because devicechanged[foo_Utility] is not
   -- present when the value is zero
   depth = otherdevices_svalues[depth_sensor]
 
   -- Calculate percentage and volume
   pct = (tank_height - depth) / tank_height * 100
   volume = (tank_height - depth) * tank_area / 1000
 
   -- Adjust for fluid expansion
   tank_temp = otherdevices_svalues[tank_temp_sensor]
   if (tank_temp ~= nil) then
      temp_delta = tank_temp - canon_temp
      scale = math.pow(expansion_coeff, temp_delta)
      pct = pct * scale
      volume = volume * scale
   end
 
-- print(string.format("depth now %f; percentage %f %% volume %f l", depth, pct, volume))
 
   commandArray[1] = {['UpdateDevice'] = pct_sensor_id .. "|0|" .. pct}
   commandArray[2] = {['UpdateDevice'] = volume_sensor_id .. "|0|" .. volume}
end
 
return commandArray

Example of use (if relevant) i.e. output files / screen displays

Domoticz displaying oil tank levels