Smart Water Metering

This article describes the setup of digitally measuring water usage, using a tessel.io microcontroller, storing data in influxdb, and integration with Grafana and Home Assistant.

Choosing the correct water meter

You are not allowed to install a water meter yourself. In dialog with the waterworks, ro replace or install a water meter you need to ask for a water meter that can support digital readings.

In Trondheim, Norway, Øwre-Johnsen as delivers the water meters allowed to be installed.

In dialoge with Øwre-Johnsen as, I ended up installing Elster V200 (KVM-T). In addition I ordered and installed the Falcon PR6 pulse module. This one you can install your self.

Reading the pulse

I chose to use a tessel.io microcontroller, because it has both analog and digital gpio ports that is very easy to interact with using javascript.

The Falcon PR6 contains a battery and gives a digital impulse every liter user detected. Connect the black wire to GND and the yellow to one of the numbered PINs.

And when/if you order a Tessel 2, remember to also order a set of jumper wires that fits.

Here is a class to read the pulse indicating one liter used.

const  
  EventEmitter = require('events'),
  tessel = require('tessel')

const pin = tessel.port.A.pin[4]

class PulseReader extends EventEmitter {  
  constructor() {
    super()
    this.previous = false
    setInterval(() => {
      this.read()
    }, 50) // Read impulse every 50 ms
  }

  // Give a short blue LED blink to signal that an pulse is detected.
  blink() {
    blue.on()
    setTimeout(function () {
      blue.off()
    }, 100);
  }

  read() {
    pin.read((error, value) => {
      if (error) {
        console.error("Error reading analog input: " + error)
        return
      }
      let val = (value === 0)

      // Emit a value event every time a digital pulse is detected
      // Will discard all subsequent readins from the same pulse
      if (val && val !== this.previous) {
        this.emit('value', true)
        this.blink()
      }
      this.previous = val
    })
  }
}

module.exports = PulseReader

It can be used like this:

let d = new Database()  
let p = new PulseReader()

p.on('value', (value) => {  
  d.post(1)
})

where the database object posts 1 liter used each time a pulse is detected.

Storing time serie data

Choose a storage backend you are confortable with, or have already access to. You can use in example Mysql.

I chose to use InfluxDB. I have it installed in a Kubernetes cluster using Google Container Engine. It is very easy to deploy InfluxDB using Docker.

Posting data to InfluxDB from any programming language is easy.

const url = 'http://influx.yourserver.com:30369/write?db=water&precision=ms'

class Database {  
  post(value) {
    let str = 'water value=1 ' + (new Date).getTime()
    request(url, {
      'auth': {
        'user': 'water',
        'pass': 'PASSWORD',
        'sendImmediately': true
      },
      'method': 'POST',
      'headers': {
        "content-type": "text/plain"
      },
      'body': str
    }, function (error, response, body) {
      if (error) {
        console.error("Error writing to database: " + error)
      }
    })
  }
}

Presenting data using Grafana

Grafana and InfluxDB is a perfect match.

It should be more or less straight forward to setup panels. I prefer to use single stat panels with sparklines in the background and using background colors.

In the screenshot above I have three single stats.

  1. Current water usage. Number of liters per minute averaged over the the last 2 minutes.
  2. Liters used in the previous 24 hours.
  3. Liters used in the previous 7 days.

Integration with Home Assistant

Home assistant has built in support for fetching data from InfluxDB, with the InfluxDB Sensor.

Here is my current configuration:

  - platform: influxdb
    host: influx.yourserver.com
    port: 30369
    username: water
    password: !secret influxdb
    queries:
      - name: 'Water 1w'
        group_function: sum
        where: 'time > now() - 7d'
        field: value
        measurement: '"water"'
        unit_of_measurement: 'Liters'
        database: water
      - name: 'Water 24h'
        group_function: sum
        where: 'time > now() - 24h'
        field: value
        measurement: '"water"'
        unit_of_measurement: 'Liters'
        database: water
      - name: 'Water now'
        group_function: sum
        where: 'time > now() - 1m'
        field: value
        measurement: '"water"'
        unit_of_measurement: 'Liters'
        database: water

Here is two of the sensors in a Lovelace glance panel:

I'm not done yet with the configuration. I'm missing:

  • Custom icons
  • The water_now sensor get state Unknown when there is no reported water usage, instead of 0 which would be correct. Ideas welcome.

Cover photo credits Pulpolux@flickr