Summary
SureHA integration (link: SureHA Gitlab
The core SurePet integration doesn’t expose many sensors but the SureHA one does. It tracks the amount left in the bowl, but not daily consumption.
Apologies, the code includes some weird ’ ’ quotes that you’ll need to manually adjust to ", something about copying it
This code takes the detailed attributes from the SureHA bowl entities to track daily consumption for the cat and also set up some notifications.
Integrations
Sure Petcare has the following entities exposed. I don’t think I use any of these in the code below, but they are in the lovelace frontend code below so including them for completion
Entities exposed; (not yaml)
binary_sensor.nik
sensor.niks_bowl_battery_level
binary_sensor.niks_bowl_connectivity_2
binary_sensor.surepet_hub
SureHA integration (installed through HACS)
SureHA entities
Entities exposed: (not yaml)
Feeder Nik’s bowl
sensor.feeder_niks_bowl
Feeder Nik’s bowl Battery Level
sensor.feeder_niks_bowl_battery_level
Hub Surepet Hub
binary_sensor.hub_surepet_hub
Nik - Dry food remaining
sensor.feeder_niks_bowl_bowl_0
Nik - Wet food remaining
sensor.feeder_niks_bowl_bowl_1
Nik’s Bowl Connectivity
binary_sensor.niks_bowl_connectivity
Pet Nik
binary_sensor.pet_nik
Config entry:
sensors: !include sensors.yaml
var: !include variables.yaml
Sensors & vars
Set up the following sensors
sensors.yaml
- platform: template
sensors:
nik_daily_dry:
friendly_name: "Nik daily dry food (replicate var))"
value_template: "{{ states('var.nik_dry_since_2am') | float}}"
unit_of_measurement: "g"
nik_daily_wet:
friendly_name: "Nik daily wet food (replicate var)"
value_template: "{{ states('var.nik_wet_since_2am') | float}}"
unit_of_measurement: "g"
nik_daily_wet_and_dry:
friendly_name: "Nik daily total food (replicate var)"
value_template: "{{ states('var.nik_wet_since_2am') | float + states('var.nik_dry_since_2am') | float}}"
unit_of_measurement: "g"
nik_daily_dry_calories: #optional
friendly_name: "Nik daily dry food calorie consumption"
value_template: "{{ states('input_number.nik_dry_food_calories_per_kg') | float /1000 * (states('sensor.nik_daily_dry') | float) }}"
unit_of_measurement: "kCal"
nik_daily_wet_calories: #optional
friendly_name: "Nik daily wet food calorie consumption"
value_template: "{{ states('input_number.nik_wet_food_calories_per_kg') | float /1000 * (states('sensor.nik_daily_wet') | float) }}"
unit_of_measurement: "kCal"
nik_daily_total_calories:
friendly_name: "Nik daily total food calorie consumption"
value_template: "{{ states('sensor.nik_daily_dry_calories') | float + states('sensor.nik_daily_wet_calories') | float }}"
unit_of_measurement: "kCal"
nik_feeding_change_wet:
friendly_name: "Nik Feeding Change - Wet"
unit_of_measurement: "g"
unique_id: nik_feeding_change_wet
value_template: >-
{% set feeder_status_attr = state_attr('binary_sensor.pet_nik', 'status') %}
{{ feeder_status_attr.feeding.change.1 | float }}
nik_feeding_change_dry:
friendly_name: "Nik Feeding Change - Dry"
unit_of_measurement: "g"
unique_id: nik_feeding_change_dry
value_template: >-
{% set feeder_status_attr = state_attr('binary_sensor.pet_nik', 'status') %}
{{ feeder_status_attr.feeding.change.0 | float }}
nik_feeding_time:
friendly_name: "Nik last ate at"
unique_id: nik_feeding_time
value_template: >-
{% set feeder_status_attr = state_attr('binary_sensor.pet_nik', 'status') %}
{{ as_timestamp(feeder_status_attr.feeding.at) | timestamp_custom('%a, %I:%M %p') }}
Set up the following ‘var’. I have variables+history added in HACS - i think this is using this.
var.yaml
nik_dry_since_2am:
friendly_name: 'Nik dry food consumption since 2am'
initial_value: 0
unique_id: 'nikdryfoodconsumption'
icon: mdi:cat
unit_of_measurement: g
nik_wet_since_2am:
friendly_name: 'Nik wet food consumption since 2am'
initial_value: 0
unique_id: 'nikwetfoodconsumption'
icon: mdi:cat
unit_of_measurement: g
Optional - use utility meter to view consumption over time:
utility_meter:
nik_daily_dry_food_consumption:
name: 'Nik daily dry food meter'
source: sensor.nik_daily_dry
cycle: daily
offset:
hours: 2
net_consumption: false
delta_values: false
periodically_resetting: true
nik_daily_wet_food_consumption:
name: 'Nik daily wet food meter'
source: sensor.nik_daily_wet
cycle: daily
offset:
hours: 2
net_consumption: false
delta_values: false
periodically_resetting: true
Also make sure you’re including the above sensor and var entities in your recorder.
Some input helpers
Sorry not sure how to show these in Yaml as i set them up in the UI
(Input Numbers)
set these up with step = 1
Nik dry food Calories per kg
input_number.nik_dry_food_calories_per_kg
Nik Dry Food Last Weight
input_number.nik_dry_food_last_weight
Nik wet food Calories per kg
input_number.nik_wet_food_calories_per_kg
Nik Wet Food Last Weight
input_number.nik_wet_food_last_weight
(Input DateTime)
Nik last ate
input_datetime.nik_last_ate
Nik last fed
input_datetime.nik_last_fed
(Input boolean -toggle)
Nik_fed_breakfast
input_boolean.nik_fed_breakfast
nik_fed_dinner
input_boolean.nik_fed_dinner
Automations and scripts
This is triggered when the weight of the bowls change. It works out if it is added to (fed) or subtracted from (ate). I’ve included this as one automation as previously I had them separately and both were changing similar variables so ended up both running.
When the cat eats, it adds the recent feed to the daily consumption variables and sets the time of the feed
When the cat is fed, it sets the time that the cat was last fed (i.e. the bowls were filled by a human), updates the variables measuring how much is left in each bowl, and sets the booleans for ‘fed dinner’ or ‘fed breakfast’ based on the time
alias: Nik last fed or ate
description: Nik's bowl changes weight - action 'fed' or 'ate'
trigger:
- platform: template
value_template: >
{{(((states("sensor.feeder_niks_bowl_bowl_0") | float) !=
(states("input_number.nik_dry_food_last_weight")) | float)) or
((states("sensor.feeder_niks_bowl_bowl_1") | float) !=
(states("input_number.nik_wet_food_last_weight") | float))}}
for:
hours: 0
minutes: 0
seconds: 10
variables:
dry_from: >-
{{states('input_number.nik_dry_food_last_weight') |
float('unavailable')}}
dry_to: "{{states('sensor.feeder_niks_bowl_bowl_0') | float('unavailable')}}"
wet_from: >-
{{states('input_number.nik_wet_food_last_weight') |
float('unavailable')}}
wet_to: "{{states('sensor.feeder_niks_bowl_bowl_1') | float('unavailable')}}"
condition:
- condition: and
conditions:
- condition: template
value_template: "{{ dry_from not in ['unknown', 'unavailable'] }}"
- condition: template
value_template: "{{ dry_to not in ['unknown', 'unavailable'] }}"
- condition: template
value_template: "{{ wet_from not in ['unknown', 'unavailable'] }}"
- condition: template
value_template: "{{ wet_to not in ['unknown', 'unavailable'] }}"
- condition: template
value_template: "{{ not(wet_from == wet_to and dry_from == dry_to) }}"
action:
- variables:
dry_from: "{{states('input_number.nik_dry_food_last_weight') | float(0.0)}}"
dry_to: "{{states('sensor.feeder_niks_bowl_bowl_0') | float(0.0)}}"
wet_from: "{{states('input_number.nik_wet_food_last_weight') | float(0.0)}}"
wet_to: "{{states('sensor.feeder_niks_bowl_bowl_1') | float(0.0)}}"
what_happened: >
{% if (dry_to > dry_from ) or (wet_to > wet_from) %} added_food {% elif
(dry_to < dry_from ) or (wet_to < wet_from) %} ate_food {% else %} error
{% endif %}
- choose:
- conditions:
- condition: template
value_template: "{{ what_happened == 'added_food' }}"
sequence:
- service: input_datetime.set_datetime
data:
datetime: "{{now()}}"
target:
entity_id: input_datetime.nik_last_fed
- service: input_number.set_value
data:
value: "{{states('sensor.feeder_niks_bowl_bowl_0')}}"
target:
entity_id: input_number.nik_dry_food_last_weight
- service: input_number.set_value
data:
value: "{{states('sensor.feeder_niks_bowl_bowl_1')}}"
target:
entity_id: input_number.nik_wet_food_last_weight
- if:
- condition: time
after: "04:30:00"
before: "15:00:00"
weekday:
- sun
- mon
- tue
- wed
- thu
- fri
- sat
then:
- service: input_boolean.turn_on
data: {}
target:
entity_id: input_boolean.nik_fed_breakfast
else:
- if:
- condition: time
after: "14:59:59"
before: "01:00:00"
weekday:
- sun
- mon
- tue
- wed
- thu
- fri
- sat
then:
- service: input_boolean.turn_on
data: {}
target:
entity_id: input_boolean.nik_fed_dinner
- conditions:
- condition: template
value_template: "{{ what_happened == 'ate_food' }}"
sequence:
- service: input_datetime.set_datetime
data:
datetime: "{{now()}}"
target:
entity_id: input_datetime.nik_last_ate
- service: input_number.set_value
data:
value: "{{states('sensor.feeder_niks_bowl_bowl_0')}}"
target:
entity_id: input_number.nik_dry_food_last_weight
- service: input_number.set_value
data:
value: "{{states('sensor.feeder_niks_bowl_bowl_1')}}"
target:
entity_id: input_number.nik_wet_food_last_weight
- service: var.set
data:
entity_id: var.nik_wet_since_2am
value: >-
{{states("var.nik_wet_since_2am") | float -
states("sensor.nik_feeding_change_wet") | float}}
- service: var.set
data:
entity_id: var.nik_dry_since_2am
value: >-
{{states("var.nik_dry_since_2am") | float -
states("sensor.nik_feeding_change_dry") | float}}
default:
- stop: No trigger id
trace:
stored_traces: 10
mode: single
This next one resets the dinner and breakfast flags at 2am.
- id: '[yours here 3]'
alias: Reset Nik dinner breakfast flags
description: ''
trigger:
- platform: time
at: 02:00:00
condition: []
action:
- service: input_boolean.turn_off
data: {}
target:
entity_id:
- input_boolean.nik_fed_dinner
- input_boolean.nik_fed_breakfast
mode: single
This next one notifies me if Nik hasn’t been fed breakfast by 8.30am, and again at 10am and 11am
- id: '[yours here 4]'
alias: Nik hungry (breakfast)
description: ''
trigger:
- platform: time
at: 08:30:00
- platform: time
at: '10:00:00'
- platform: time
at: '11:00:00'
condition:
- condition: state
entity_id: input_boolean.nik_fed_breakfast
state: 'off'
action:
- service: notify.[your-mobile-app-address-here-without-brackets]
data:
message: Cat is hungry :(
title: Nik hasn't been fed breakfast yet!!
mode: single
This one does the same but for dinner - 7.30pm etc.
- id: '[yours here 5]'
alias: Nik hungry (dinner)
description: ''
trigger:
- platform: time
at: '19:30:00'
- platform: time
at: '22:00:00'
- platform: time
at: '21:00:00'
condition:
- condition: state
entity_id: input_boolean.nik_fed_dinner
state: 'off'
action:
- service: notify.[your-mobile-address-here-without-brackets]
data:
message: Cat is hungry :(
title: Nik hasn't been fed dinner yet!!
mode: single
This one tells me if its after 6pm, nik hasn’t been fed dinner, and he has come in and tried to eat (usually if i’m nearby i won’t feed him until he comes in, to make it as fresh as possible
- id: '[yours here 6]'
alias: Nik hungry (dinner and tried)
description: ''
trigger:
- platform: state
entity_id:
- input_datetime.nik_last_ate
for:
hours: 0
minutes: 0
seconds: 10
condition:
- condition: state
entity_id: input_boolean.nik_fed_dinner
state: 'off'
- condition: time
after: '18:00:00'
weekday:
- sat
- fri
- thu
- wed
- tue
- mon
- sun
before: '23:59:00'
action:
- service: notify.[your-mobile-address-here-without-brackets]
data:
message: Cat is hungry and just tried to eat :(
title: Nik hasn't been fed dinner yet and he has just tried to eat something
in his bowl!!
mode: single
Same for breakfast
- id: '[yours here 7]'
alias: Nik hungry (breakfast and tried)
description: ''
trigger:
- platform: state
entity_id:
- input_datetime.nik_last_ate
for:
hours: 0
minutes: 0
seconds: 10
condition:
- condition: state
entity_id: input_boolean.nik_fed_breakfast
state: 'off'
for:
hours: 0
minutes: 0
seconds: 10
- condition: time
after: 07:00:00
weekday:
- sat
- fri
- thu
- wed
- tue
- mon
- sun
before: '15:00:00'
action:
- service: notify.[your-mobile-address-here-without-brackets]
data:
message: Cat is hungry and just tried to eat :(
title: Nik hasn't been fed breakfast yet and he has just tried to eat something
in his bowl!!
mode: single
This one lets me know if either the dry or wet bowl has dipped below 15g
- id: '[yours here 8]'
alias: Food bowl low
description: ''
trigger:
- platform: numeric_state
entity_id: sensor.feeder_niks_bowl_bowl_0
below: 15
id: dry_low
- platform: numeric_state
entity_id: sensor.feeder_niks_bowl_bowl_1
below: 15
id: wet_low
condition:
- condition: time
after: 07:00:00
before: '21:00:00'
weekday:
- sun
- mon
- tue
- wed
- thu
- fri
- sat
action:
- service: notify.[person1]
data:
title: Cat hungry - low food
message: "{% if states('sensor.feeder_niks_bowl_bowl_0') | int <= 15 -%} \n
\ {% if states('sensor.feeder_niks_bowl_bowl_1') | int <= 15 -%}\n Both
bowls are low! \n {% else -%}\n Dry bowl is low! \n {%- endif -%}\n{%-
else -%}\n {% if states('sensor.feeder_niks_bowl_bowl_1') | int <= 15 -%}\n
\ Wet bowl is low! \n {% else -%}\n No bowl is low. \n {%- endif -%}\n{%-
endif -%}\n{{''}}\nDry: {{states('sensor.feeder_niks_bowl_bowl_0') | int }}g
\ Wet: {{states('sensor.feeder_niks_bowl_bowl_1') | int }}g\n"
data:
push:
sound:
name: default
volume: 1
group: Cats
- condition: state
entity_id: person.[person2]
state: home
- service: notify.mobile_app_[person2]
data:
title: Cat hungry - low food
message: "{% if states('sensor.feeder_niks_bowl_bowl_0') | int <= 15 -%} \n
\ {% if states('sensor.feeder_niks_bowl_bowl_1') | int <= 15 -%}\n Both
bowls are low! \n {% else -%}\n Dry bowl is low! \n {%- endif -%}\n{%-
else -%}\n {% if states('sensor.feeder_niks_bowl_bowl_1') | int <= 15 -%}\n
\ Wet bowl is low! \n {% else -%}\n No bowl is low. \n {%- endif -%}\n{%-
endif -%}\n{{''}}\nDry: {{states('sensor.feeder_niks_bowl_bowl_0') | int }}g
\ Wet: {{states('sensor.feeder_niks_bowl_bowl_1') | int }}g\n"
data:
push:
sound:
name: default
volume: 1
group: Cats
mode: single
This one resets the Nik food counter at 2am
- id: '[yours here 9]'
alias: Reset Nik food counter
description: ''
trigger:
- platform: time
at: 02:00:00
condition: []
action:
- service: var.set
data:
entity_id: var.nik_dry_since_2am
value: 0
- service: var.set
data:
entity_id: var.nik_wet_since_2am
value: 0
mode: single
Lovelace
This not very tidy, and lots of extra stuff in here you don’t need to show but I had there as i was debugging. And there’s something funny going on in my apex-cards at the crossover from June to July - the flatline data there shows up properly on my mobile app but not on web desktop for some reason.
Note: I have a few custom lovelace frontends installed through HACs - e.g. apexcharts
views:
- title: Home
cards:
- show_name: true
show_icon: true
show_state: true
type: glance
entities:
- entity: input_boolean.nik_fed_breakfast
- entity: input_boolean.nik_fed_dinner
title: Nik
- type: horizontal-stack
cards:
- type: gauge
entity: sensor.feeder_niks_bowl_bowl_0
name: Dry food in bowl
unit: g
max: 75
min: 0
needle: true
severity:
green: 30
yellow: 15
red: 0
- type: gauge
entity: sensor.feeder_niks_bowl_bowl_1
name: Wet food in bowl
unit: g
max: 75
min: 0
needle: true
severity:
green: 30
yellow: 15
red: 0
- type: custom:apexcharts-card
header:
show: true
title: Nik daily food consumption
show_states: true
colorize_states: true
graph_span: 30d
span:
end: day
offset: +0d 2 hr
update_interval: 24hr
yaxis:
- min: 0
apex_config:
chart:
stacked: true
all_series_config:
extend_to: now
float_precision: 0
series:
- entity: sensor.nik_daily_wet
type: column
name: Wet
group_by:
func: max
duration: 24 hr
- entity: sensor.nik_daily_dry
type: column
name: Dry
group_by:
func: max
duration: 24 hr
- entity: sensor.nik_daily_wet_and_dry
type: column
name: Total
group_by:
func: max
duration: 24 hr
show:
in_chart: false
in_header: true
- type: entities
entities:
- entity: var.nik_dry_since_2am
- entity: var.nik_wet_since_2am
title: Nik food since 2am
- type: entities
entities:
- entity: sensor.feeder_niks_bowl_bowl_0
- entity: sensor.feeder_niks_bowl_bowl_1
- entity: sensor.feeder_niks_bowl
- entity: binary_sensor.nik
- entity: binary_sensor.pet_nik
- entity: sensor.niks_bowl_battery_level
- entity: binary_sensor.niks_bowl_connectivity
- entity: input_datetime.nik_last_ate
- entity: input_datetime.nik_last_fed
- entity: sensor.nik_feeding_change_dry
- entity: sensor.nik_feeding_change_wet
title: Nik
- type: custom:apexcharts-card
header:
show: true
title: Nik daily calorie consumption
show_states: true
colorize_states: true
graph_span: 30d
span:
end: day
offset: +0d 2hr
update_interval: 24hr
yaxis:
- min: 0
apex_config:
chart:
stacked: true
annotations:
yaxis:
- 'y': 266
borderColor: '#00E396'
label:
borderColor: '#00E396'
style:
color: '#fff'
background: '#00E396'
text: Rec
all_series_config:
extend_to: now
float_precision: 0
series:
- entity: sensor.nik_daily_wet_calories
type: column
name: Wet
group_by:
func: max
duration: 24 hr
- entity: sensor.nik_daily_dry_calories
type: column
name: Dry
group_by:
func: max
duration: 24 hr
- entity: sensor.nik_daily_total_calories
type: column
name: Total
group_by:
func: max
duration: 24 hr
show:
in_chart: false
in_header: true
- type: history-graph
entities:
- entity: input_number.nik_wet_food_last_weight
- entity: input_number.nik_dry_food_last_weight
hours_to_show: 4
title: Last weight
- type: history-graph
entities:
- entity: sensor.feeder_niks_bowl_bowl_1
- entity: sensor.feeder_niks_bowl_bowl_0
title: Nik's food
hours_to_show: 8
- type: entities
entities:
- input_number.nik_dry_food_calories_per_kg
- input_number.nik_wet_food_calories_per_kg
- type: entities
entities:
- entity: var.nik_dry_since_2am
- entity: sensor.nik_daily_dry
- entity: input_number.nik_dry_food_last_weight
- entity: var.nik_wet_since_2am
- entity: sensor.nik_daily_wet
- entity: input_number.nik_wet_food_last_weight
- entity: sensor.nik_daily_wet_and_dry