Adding Bristol Water quality to Home Assistant

Published in Home Automation on Jan 15, 2024

Recently, I was looking up the water quality for my area, and I noticed that it pulls the data from an API within their CMS. This makes the data perfect to pull into Home Assistant.

I've used the rest integration a lot previously, and it allows for great integration with APIs and data, without needing a full custom integration.

The API URL has a base of https://www.bristolwater.co.uk/_hcms/api/getWQHubdbDataInfo and takes a query parameter of the postcode (e.g. ?q=BS1).

The data is returned with numeric key names, so using something like a single sensor with attributes via json_attributes would be unclean, and hard to know what the attribute is.

{
    "1": "Shipton Moyne",
    "2": 403,
    "3": "Sherston, Marshfield and Pucklechurch",
    "4": "Your water supply comes primarily from groundwater (boreholes) though at times this is supplemented with surface water (river)",
    "5": "Your drinking water supply is classed as  hard.",
    "6": 91,
    "7": 9.5,
    "8": "266",
    "9": 19,
    "10": 27,
    "11": 16,
    "12": "...",
    "13": "0.41",
    "14": "209",
    "15": "255",
    "16": "41",
    "17": "13",
    "18": "1.2",
    "19": "43",
    "20": "55",
    "21": "635",
    "22": "7.52",
    "24": "...",
    "25": "..."
}

The values within the API response can be mapped to the values from the code of the water quality checker.

The mapping is as follows:

  • 4: This is a message relating to the source of the water (e.g. from ground water, boreholes, etc.)
  • 5: This is a message relating to the classification of the water (e.g. hard or soft)
  • 6: This is the level of calcium (in mg/L)
  • 7: This is the level of magnesium (in mg/L)
  • 8: This is the level of water hardness from calcium carbonate (in mg/L)
  • 13: This is the level of flouride (in mg/L)
  • 14: This is the level of water alkalinity from calcium carbonate (in mg/L)
  • 15: This is the level of water alkalinity from bicarbonate (in mg/L)
  • 16: This is the level of chloride (in mg/L)
  • 17: This is the level of nitrate (in mg/L)
  • 18: This is the level of phosphate (in mg/L)
  • 19: This is the level of sulphate (in mg/L)
  • 20: This is the level of sodium (in mg/L)

Creating the sensors

By mapping these into sensors under a REST integration, I ended up with the following YAML:

rest:
  - resource: 'https://www.bristolwater.co.uk/_hcms/api/getWQHubdbDataInfo'
    params:
      q: !secret postcode
    scan_interval: 86400

    sensor:

      - name: Water Source
        unique_id: bristol_water_source
        value_template: "{{ value_json['objects'][0]['values']['4'] }}"

      - name: Water Classification
        unique_id: bristol_water_classification
        value_template: "{{ value_json['objects'][0]['values']['5'] }}"

      - name: Water Calcium
        unique_id: bristol_water_calcium
        value_template: "{{ value_json['objects'][0]['values']['6'] }}"
        unit_of_measurement: mg/L

      - name: Water Magnesium
        unique_id: bristol_water_magnesium
        value_template: "{{ value_json['objects'][0]['values']['7'] }}"
        unit_of_measurement: mg/L

      - name: Water Hardness (CaCO3)
        unique_id: bristol_water_hardness
        value_template: "{{ value_json['objects'][0]['values']['8'] }}"
        unit_of_measurement: mg/L

      - name: Water Flouride
        unique_id: bristol_water_flouride
        value_template: "{{ value_json['objects'][0]['values']['13'] }}"
        unit_of_measurement: mg/L

      - name: Water Alkalinity (CaCO3)
        unique_id: bristol_water_alkalinity_caco3
        value_template: "{{ value_json['objects'][0]['values']['14'] }}"
        unit_of_measurement: mg/L

      - name: Water Alkalinity (HCO3)
        unique_id: bristol_water_alkalinity_hco3
        value_template: "{{ value_json['objects'][0]['values']['15'] }}"
        unit_of_measurement: mg/L

      - name: Water Chloride
        unique_id: bristol_water_chloride
        value_template: "{{ value_json['objects'][0]['values']['16'] }}"
        unit_of_measurement: mg/L

      - name: Water Nitrate
        unique_id: bristol_water_nitrate
        value_template: "{{ value_json['objects'][0]['values']['17'] }}"
        unit_of_measurement: mg/L

      - name: Water Phosphate
        unique_id: bristol_water_phosphate
        value_template: "{{ value_json['objects'][0]['values']['18'] }}"
        unit_of_measurement: mg/L

      - name: Water Sodium
        unique_id: bristol_water_sodium
        value_template: "{{ value_json['objects'][0]['values']['19'] }}"
        unit_of_measurement: mg/L

      - name: Water Sulphate
        unique_id: bristol_water_sulphate
        value_template: "{{ value_json['objects'][0]['values']['20'] }}"
        unit_of_measurement: mg/L

Displaying it on the dashboard

I then created a dashboard page using this with the following YAML:

Summary

type: markdown
title: Bristol Water
content: |-
  **Classification**
  {{ states('sensor.water_classification') }}

  **Source**
  {{ states('sensor.water_source') }}

Contents

type: vertical-stack
cards:
  - type: horizontal-stack
    cards:
      - type: custom:mushroom-entity-card
        entity: sensor.water_calcium
        icon_type: none
        name: Calcium
        layout: vertical
        fill_container: true
      - type: custom:mushroom-entity-card
        entity: sensor.water_magnesium
        icon_type: none
        name: Magnesium
        layout: vertical
        fill_container: true
      - type: custom:mushroom-entity-card
        name: Fluoride
        icon_type: none
        fill_container: true
        layout: vertical
        entity: sensor.water_flouride
  - type: horizontal-stack
    cards:
      - type: custom:mushroom-entity-card
        icon_type: none
        layout: vertical
        fill_container: true
        entity: sensor.water_chloride
        name: Chloride
      - type: custom:mushroom-entity-card
        icon_type: none
        layout: vertical
        fill_container: true
        entity: sensor.water_nitrate
        name: Nitrate
      - type: custom:mushroom-entity-card
        icon_type: none
        fill_container: true
        layout: vertical
        entity: sensor.water_phosphate
        name: Phosphate
  - type: horizontal-stack
    cards:
      - type: custom:mushroom-entity-card
        icon_type: none
        layout: vertical
        fill_container: true
        entity: sensor.water_sulphate
        name: Sulphate
      - type: custom:mushroom-entity-card
        icon_type: none
        layout: vertical
        fill_container: true
        entity: sensor.water_sodium
        name: Sodium
      - type: custom:mushroom-entity-card
        entity: sensor.water_hardness
        icon_type: none
        fill_container: true
        layout: vertical
        name: Hardness

Alkalinity

type: vertical-stack
cards:
  - type: horizontal-stack
    cards:
      - type: custom:mushroom-entity-card
        icon_type: none
        layout: vertical
        fill_container: true
        entity: sensor.water_alkalinity_caco3
        name: Alkalinity (CaCO3)
      - type: custom:mushroom-entity-card
        icon_type: none
        layout: vertical
        fill_container: true
        entity: sensor.water_alkalinity_hco3
        name: Alkalinity (HCO3)
0
0
0
0