Water Guru Integration

I basically just followed these steps. I’m running on Unraid, but ran the commands via an SSH terminal shell:

Once that’s up and running, you should be able to hit that URL in a browser on your local network and get your pool info in JSON format:

I was definitely overthinking the setup… I have a similar setup (HA on a Raspberry Pi 4).

Here’s what I did:

  1. Followed this tutorial to get myself comfortable creating a custom add-on: Tutorial: Making your first add-on | Home Assistant Developer Docs
  2. Created my own add-on by taking the Dockerfile from the project being passed around: GitHub - bdwilson/waterguru-api: WaterGuru API (I had to update the Dockerfile a bit to add my credentials for my WaterGuru).

Once I had the add-on running, I just added the sensors @sarahmva shared with the thread (much appreciated).

1 Like

If you have a Sense 2, you can expose even more in the UI: (I might add Saturation Index at some point)

image

BTW, somewhat unrelated, but good to know: Waterguru support told me today that TA, CH & CYA values are currently running on a 4 day average. So if you make a change that affects any of those, it’s going to take 4 days to see the end result. I’m hoping that will change soon.

Can you share your config and lovelace yaml?

configuration.yaml:

# Sensors
sensor:
  - platform: rest
    name: waterguru_raw
    unique_id: 'wg14839'
    scan_interval: 7200
    resource: http://192.168.1.200:53255/api/wg
    json_attributes_path: "$.waterBodies[0]"
    json_attributes:
      - waterTemp
      - status
      - pods
      - measurements
      - latestMeasureTime
      - latestMeasureTimeHuman
    value_template: '{{ value_json.status }}'

  - platform: template
    sensors:
      waterguru_water_temperature:
        friendly_name: Waterguru Water Temperature
        unique_id: 'wg195046'
        unit_of_measurement: F
        value_template: >-
          {{"%.1f"|format(state_attr('sensor.waterguru_raw','waterTemp')|float)}}
        attribute_templates:
          temp_fahrenheit: >-
            {{state_attr('sensor.waterguru_raw','waterTemp')}}

      waterguru_cl:
        friendly_name: Waterguru Free Chlorine Level
        unique_id: 'wg9284769303'
        value_template: >-
          {{(state_attr('sensor.waterguru_raw','measurements')[0].floatValue)}}
        attribute_templates:
          status: >-
            {{(state_attr('sensor.waterguru_raw','measurements')[0].status)}}
          measure_time: >-
            {{(state_attr('sensor.waterguru_raw','measurements')[0].measureTime)}}     
          measure_time_human: >-
            {{(state_attr('sensor.waterguru_raw','measurements')[0].measureTimeHuman)}}
          advice: >-
            {%if 'alerts' in (state_attr('sensor.waterguru_raw','measurements')[0])%}
              {{(state_attr('sensor.waterguru_raw','measurements')[0].alerts[0].advice.action.summary)}}
            {%else%}
              all clear
            {%endif%}

      waterguru_ph:
        friendly_name: Waterguru PH Level
        unique_id: 'wg10583983'
        value_template: >-
          {{(state_attr('sensor.waterguru_raw','measurements')[1].floatValue)}}
        attribute_templates:
          status: >-
            {{(state_attr('sensor.waterguru_raw','measurements')[1].status)}}
          measure_time: >-
              {{(state_attr('sensor.waterguru_raw','measurements')[1].measureTime)}}     
          measure_time_human: >-
              {{(state_attr('sensor.waterguru_raw','measurements')[1].measureTimeHuman)}}
          advice: >-
            {%if 'alerts' in (state_attr('sensor.waterguru_raw','measurements')[1])%}
              {{(state_attr('sensor.waterguru_raw','measurements')[1].alerts[0].advice.action.summary)}}
            {%else%}
              all clear
            {%endif%}

      waterguru_wf:
        friendly_name: Waterguru Flow
        unique_id: 'wg84568945'
        value_template: >-
          {{(state_attr('sensor.waterguru_raw','measurements')[2].intValue)}}
        attribute_templates:
          status: >-
            {{(state_attr('sensor.waterguru_raw','measurements')[2].status)}}
          measure_time: >-
              {{(state_attr('sensor.waterguru_raw','measurements')[2].measureTime)}}     
          measure_time_human: >-
              {{(state_attr('sensor.waterguru_raw','measurements')[2].measureTimeHuman)}}
          advice: >-
            {%if 'alerts' in (state_attr('sensor.waterguru_raw','measurements')[2])%}
              {{(state_attr('sensor.waterguru_raw','measurements')[2].alerts[0].advice.action.summary)}}
            {%else%}
              all clear
            {%endif%}

      waterguru_ta:
        friendly_name: Waterguru Total Alkalinity
        unique_id: 'wg856749596'
        value_template: >-
          {{(state_attr('sensor.waterguru_raw','measurements')[3].intValue)}}
        attribute_templates:
          status: >-
            {{(state_attr('sensor.waterguru_raw','measurements')[3].status)}}
          measure_time: >-
              {{(state_attr('sensor.waterguru_raw','measurements')[3].measureTime)}}     
          measure_time_human: >-
              {{(state_attr('sensor.waterguru_raw','measurements')[3].measureTimeHuman)}}
          advice: >-
            {%if 'alerts' in (state_attr('sensor.waterguru_raw','measurements')[3])%}
              {{(state_attr('sensor.waterguru_raw','measurements')[3].alerts[0].advice.action.summary)}}
            {%else%}
              all clear
            {%endif%}

      waterguru_ch:
        friendly_name: Waterguru CH Level
        unique_id: 'wg9876544'
        value_template: >-
          {{(state_attr('sensor.waterguru_raw','measurements')[4].intValue)}}
        attribute_templates:
          status: >-
            {{(state_attr('sensor.waterguru_raw','measurements')[4].status)}}
          measure_time: >-
            {{(state_attr('sensor.waterguru_raw','measurements')[4].measureTime)}}     
          measure_time_human: >-
            {{(state_attr('sensor.waterguru_raw','measurements')[4].measureTimeHuman)}}
          advice: >-
            {%if 'alerts' in (state_attr('sensor.waterguru_raw','measurements')[4])%}
              {{(state_attr('sensor.waterguru_raw','measurements')[4].alerts[0].advice.action.summary)}}
            {%else%}
              all clear
            {%endif%}

      waterguru_cya:
        friendly_name: Waterguru CYA Level
        unique_id: 'wg9876543'
        value_template: >-
          {{(state_attr('sensor.waterguru_raw','measurements')[5].intValue)}}
        attribute_templates:
          status: >-
            {{(state_attr('sensor.waterguru_raw','measurements')[5].status)}}
          measure_time: >-
            {{(state_attr('sensor.waterguru_raw','measurements')[5].measureTime)}}     
          measure_time_human: >-
            {{(state_attr('sensor.waterguru_raw','measurements')[5].measureTimeHuman)}}
          advice: >-
            {%if 'alerts' in (state_attr('sensor.waterguru_raw','measurements')[5])%}
              {{(state_attr('sensor.waterguru_raw','measurements')[5].alerts[0].advice.action.summary)}}
            {%else%}
              all clear
            {%endif%}

      waterguru_si:
        friendly_name: Waterguru Saturation Index
        unique_id: 'wg987695738'
        value_template: >-
          {{(state_attr('sensor.waterguru_raw','measurements')[10].floatValue)}}
        attribute_templates:
          status: >-
            {{(state_attr('sensor.waterguru_raw','measurements')[10].status)}}
          measure_time: >-
            {{(state_attr('sensor.waterguru_raw','measurements')[10].measureTime)}}     
          measure_time_human: >-
            {{(state_attr('sensor.waterguru_raw','measurements')[10].measureTimeHuman)}}

      waterguru_cassette:
        friendly_name: Waterguru Cassette Status
        unique_id: 'wg19004785830'
        value_template: >-
          {{(state_attr('sensor.waterguru_raw','pods')[0].refillables[0].pctLeft)}}
        attribute_templates:
          status: >-
            {{(state_attr('sensor.waterguru_raw','pods')[0].refillables[0].status)}}
          measurements_left: >-
            {{(state_attr('sensor.waterguru_raw','pods')[0].refillables[0].timeLeftText)}}

      waterguru_cassette_left:
        friendly_name: Waterguru Cassette Left
        unique_id: 'wg19004785831'
        value_template: >-
          {{(state_attr('sensor.waterguru_raw','pods')[0].refillables[0].timeLeftText)}}

      waterguru_battery:
        friendly_name: Waterguru Battery
        unique_id: 'wg025489093'
        unit_of_measurement: "%"
        device_class: battery
        value_template: >-
          {{(state_attr('sensor.waterguru_raw','pods')[0].refillables[1].pctLeft)}}
        attribute_templates:
          status: >-
            {{(state_attr('sensor.waterguru_raw','pods')[0].refillables[1].status)}}
          measurements_left: >-
            {{(state_attr('sensor.waterguru_raw','pods')[0].refillables[1].amountLeft)}}

Lovelace Raw Editor code:

type: vertical-stack
cards:
  - type: horizontal-stack
    cards:
      - entity: sensor.waterguru_ph
        max: 9
        min: 7
        severity:
          green: 7.4
          yellow: 0
          red: 7.9
        type: gauge
        name: Pool PH
        needle: true
      - entity: sensor.waterguru_cl
        min: 0
        severity:
          green: 1
          yellow: 0
          red: 4
        type: gauge
        name: Free Chlorine
        needle: true
        max: 8
      - entity: sensor.waterguru_cya
        max: 120
        min: 0
        type: gauge
        needle: true
        severity:
          green: 30
          yellow: 0
          red: 101
        name: CYA
  - type: horizontal-stack
    cards:
      - entity: sensor.waterguru_ta
        max: 180
        min: 0
        severity:
          green: 50
          yellow: 0
          red: 131
        type: gauge
        name: Total Alkalinity
        needle: true
      - entity: sensor.waterguru_ch
        max: 600
        min: 0
        severity:
          green: 200
          yellow: 0
          red: 401
        type: gauge
        name: Calcium Hardness
        needle: true
      - entity: sensor.waterguru_water_temperature
        max: 102
        min: 32
        type: gauge
        needle: true
        severity:
          green: 84
          yellow: 55
          red: 0
        name: Temperature
  - type: custom:mushroom-template-card
    primary: >-
      Last Measured:
      {{(state_attr('sensor.waterguru_ph','measure_time_human'))}}
    secondary: >-
      {{(as_timestamp(strptime(state_attr('sensor.waterguru_ph','measure_time')[:19],'%Y-%m-%dT%H:%M:%S'))|float
      -14400)|timestamp_custom('%m-%d-%Y %H:%M', local=True)}}

      {%if state_attr('sensor.waterguru_ph','advice') != 'all clear'%}PH:
      {{state_attr('sensor.waterguru_ph','advice')}}{%endif%}

      {%if state_attr('sensor.waterguru_cl','advice') != 'all clear'%}Chlorine:
      {{state_attr('sensor.waterguru_cl','advice')}}{%endif%}

      Saturation Index:  {{states('sensor.waterguru_si')}}

      Water Flow:  {{states('sensor.waterguru_wf')}} GPM

      Battery: {{states('sensor.waterguru_battery')}}%

      Cassette: {{states('sensor.waterguru_cassette')}}% -
      {{state_attr('sensor.waterguru_cassette','measurements_left')}}
    icon: mdi:pool
    badge_icon: >-
      {%if 'alerts' in (state_attr('sensor.waterguru_raw','measurements')[0]) or
      'alerts' in (state_attr('sensor.waterguru_raw','measurements')[1])%}
      mdi:alert {%else%}

      {%endif%}
    badge_color: red
    multiline_secondary: true
    icon_color: |2-
        {%if 'alerts' in (state_attr('sensor.waterguru_raw','measurements')[0]) or
        'alerts' in (state_attr('sensor.waterguru_raw','measurements')[1])%}
        yellow
        {%else%}
         green
        {%endif%}
    tap_action:
      action: more-info
    entity: sensor.waterguru_si
    card_mod:
      style: |
        ha-card {
          --card-primary-font-size: 14px;
          --card-secondary-font-size: 15px;
          --icon-size: 2em;
        }
        :host {
          --mush-icon-symbol-size: 1.7em;
        } 

NOTE: CYA and CH have flipped on me once in a blue moon, when that happens I just swap them in the UI.

1 Like

I was able to convert this into a standard custom integration that can be installed via HACS which does not require a separate addon or docker container. I’m testing this week and I’ll post it after I get all the attributes exposed properly.

3 Likes

Awesome!!! If you need any help testing it let me know.

1 Like

Alright, here it is: GitHub - dwradcliffe/home-assistant-waterguru

It seems to be working for me, although I’m sure there are some edge cases that break. Let me know and I’ll try to fix it when I have a chance.

5 Likes

Wow, this is really great!!! Thank you so much for sharing!!!

David,

Awesome work! Thanks for sharing!

1 Like

I have had a WaterGuru for several years and really like the product. I tried several other pool chemistry monitors before I found WaterGuru and they all either did not work or were unreliable. I been looking for ways to integrate with HA but have always come up short. I stumble on this thread this morning and am definitely going to move ahead with the suggestions here. Thanks everyone for your contributions1

1 Like

@dwradcliffe thank you for porting WaterGuru-API to a Home Assistant integration. I have been trying to do this for several years and can now add this to my dashboard.

Thank you again.

1 Like

@sarahmva thanks for posting this example. Great stuff.

@dwradcliffe is it possible to add the latestMeasureTime and ‘latestMeasureTimeHuman’ to you HA Integration. I think the best approach would be to add these as attributes to each of the entities.

Thank you both for your contributions. This is a huge improvement to my Smart Home!

1 Like

This is awesome.
You should add a tip jar to github repo my dude :wink: :beer: :coffee:

2 Likes

I can’t get this integration to work. Do you need a docker API setup and to update the host ?

There’s a couple solutions in this thread. The most recent does NOT need that Docker container running:

1 Like

Hi, @dwradcliffe, I’m OP. I cannot thank you enough. Wow. This is absolutely amazing! :heart_eyes:

2 Likes

@dwradcliffe The Cassette Days Remain is always showing full weeks. For example, WaterGuru shows 5 weeks and Home Assistant shows 35 days for the whole week. I have created a template helper to get a more accurate value for cassette days remaining:

{{ (states('sensor.waterguru_back_yard_cassette_remaining')  | int) / 100 * 60 | int}}

Thank you for helping me get this worked out.

Now, if the API supported resetting the counter when the cassette is replaced, I would be able to ditch the WaterGuru app all together :wink:

You could use an NFC to set off specific intervals.

@ttough66, did you get it to work? I installed following the steps on GitHub - https://github.com/dwradcliffe/home-assistant-waterguru - and everything just worked. One think I noticed on many integrations is that you username must be all lower case. I generally use Camel case for my username to make it easier to read but this does not seem to work for most home assistant integrations.

Hope this helps.