OMG I thought this forum was perhaps one place that disproved the theory that the internet was designed solely for the purpose of disseminating cute cat pictures.
Clearly I am deluded and should just accept the inevitable: cat world domination.
OMG I thought this forum was perhaps one place that disproved the theory that the internet was designed solely for the purpose of disseminating cute cat pictures.
Clearly I am deluded and should just accept the inevitable: cat world domination.
That’s genius! Will implement myself right away.
I just wrote an AppDaemon App for my version, which is triggered by alexa for querying and resetting - PIR is on order Its a little more complex because I was picky about exactly what I wanted Alexa to say. Also loving the spreadsheet idea - I might add that next!
import appdaemon.appapi as appapi
import shelve
import datetime
import globals
import calendar
#
# App to track Jack's visits to his litter tray
#
# Args:
#
# motion - motion sensor to use
# reset_daily - whether to reset the count daily or not
# file - file to use for DB
# log - log all visits
# notify - notify all visits
# limit - number of visits before alert
# timeout - mimimum time in seconds between visits
#
#
# Release Notes
#
# Version 1.0:
# Initial Version
class JackLitter(appapi.AppDaemon):
def initialize(self):
self.litter_db = shelve.open(self.args["file"])
if self.litter_db is None:
self.litter_db = {}
if "visits" not in self.litter_db:
self.litter_db["visits"] = 0
if "last_reset" not in self.litter_db:
yesterday = self.datetime() - datetime.timedelta(days=2)
self.litter_db["last_reset"] = yesterday
if "last_visit" not in self.litter_db:
yesterday = self.datetime() - datetime.timedelta(days=2)
self.litter_db["last_visit"] = yesterday
self.log("Restarting. Visits = {}, Last Visit = {}, Last Reset = {}".format(self.litter_db["visits"], self.litter_db["last_visit"], self.litter_db["last_reset"]))
self.listen_state(self.motion, self.args["motion"])
self.run_daily(self.midnight, datetime.time(0, 0, 0))
def since(self):
if "reset_daily" in self.args and self.args["reset_daily"] == 1:
since = "today"
else:
lr = self.litter_db["last_reset"]
if lr.date() == self.date():
since = "since {} today".format(lr.time().strftime("%H:%M"))
elif lr.date() == self.date() - datetime.timedelta(days=1):
since = "since yesterday at {}".format(lr.time().strftime("%H:%M"))
elif self.date() - lr.date() >= datetime.timedelta(days=7):
self.log(self.date() - lr.date())
since = "since {} at {}".format(lr.date(), lr.time().strftime("%H:%M"))
else:
since = "since {} at {}".format(calendar.day_name[lr.weekday()], lr.time().strftime("%H:%M"))
return (since)
def motion(self, entity, attribute, old, new, kwargs):
if new == "on":
elapsed = self.datetime() - self.litter_db["last_visit"]
if elapsed.total_seconds() > self.args["timeout"]:
self.litter_db["visits"] += 1
self.litter_db["last_visit"] = self.datetime()
ordinal = lambda n: "%d%s" % (n, "tsnrhtdd"[(n / 10 % 10 != 1) * (n % 10 < 4) * n % 10::4])
self.log_notify(
"Jack is visiting his litter tray for the {} time {}".format(ordinal(self.litter_db["visits"]), self.since()))
if self.litter_db["visits"] >= self.args["limit"]:
self.log_notify("Time to clean his tray out!")
def midnight(self, kwargs):
if "reset_daily" in self.args and self.args["reset_daily"] == 1:
self.reset()
def reset(self):
self.litter_db["visits"] = 0
self.litter_db["last_reset"] = self.datetime()
n = "Jack's litter tray tracking has been reset"
self.log_notify(n)
return n
def query(self):
if self.litter_db["visits"] == 1:
times = "once"
elif self.litter_db["visits"] == 2:
times = "twice"
else:
times = "{} times".format(self.litter_db["visits"])
n = "Jack has visited his litter tray {} {}".format(times, self.since())
self.log_notify(n)
return n
def log_notify(self, message, level="INFO"):
if "log" in self.args:
self.log(message)
if "notify" in self.args:
self.notify(message, service=globals.notify, name=globals.notify)
This is great! ehehe always have been thinking in a way of makin my pets life ‘smart’
Gonna definitely gonna give it a go since we got 4 litter box.
this is Nina and Charlie on the behind, two of our 5 cats
and this is Charlie
All the cute kitties
See what you started??
The inevitable overtaking of the community by cats?
Looks like it, yes
Anacleta (Eclectus female), Dudu (Sun Conure male), Yoshi (Indian RingNeck male)
and our newest member Scarlet the Scotish fold female
Actually Scarlet isn’t our last family member!!
Almost forgot I bought yesterday a Venus flytrap (Dionaea muscipula)
Already busy making her soil moisture sensor, temperature, and lux
This is a great little project! I have two cats and decided to give this a try. I’m using a spare esp8266 and pir sensor with MQTT. I figured out a way to update the dummy sensor directly from configuration.yaml using mqtt.publish service rather than using external python scripts. It increments the count and posts a card to the Web page each time the sensor trips. I just run the reset automation to zero out the count for now. I plan to add a reset button to the esp at some point.
Posting in case anyone is interested.
- alias: Count visits to litter box
trigger:
- platform: state
entity_id: sensor.pir
to: '1'
condition:
- condition: template
value_template: >
{% if states.automation.count_visits_to_litter_box.last_triggered is not none %}
{% if as_timestamp(now()) | int - as_timestamp(states.automation.count_visits_to_litter_box.attributes.last_triggered) | int > 300 %} true {% else %} false
{% endif %}
{% else %}
false
{% endif %}
action:
- service: persistent_notification.create
data:
title: "Litter Box"
message: ' {{ now().strftime("%I:%M %p") }} Litter Box Visit! '
- service: mqtt.publish
data:
topic: "dummy/litterbox/count"
payload_template: '{{ states.sensor.litter_box_visits.state |int +1 }}'
- alias: Set Litter Box Sensor To Zero On Start
trigger:
platform: homeassistant
event: start
action:
- service: mqtt.publish
data:
topic: "dummy/litterbox/count"
payload: 0
My situation was a little bit different. We have one litter tray in our house, and want to check/empty it after every visit to minimise odour.
The tray is conveniently in the same room as my Raspberry Pi, though. So I was able to build my own sensor, with a PIR attached to an Arduino, plug it in to the Pi, and check its state with a serial sensor.
Every second, the Arduino sends a number. 0 means the tray hasn’t been visited. Greater than 0 is the time in seconds since last visit. The sensor also has a button attached - after cleaning the tray you hit the button, and the sensor is reset back to an unvisited state. This makes it a lot easier to track visits.
I have three sensors: One is just the raw readings from the serial device. One parses that reading from seconds to a friendly string. And one uses that string and a custom icon for use in the frontend.
sensor:
- platform: serial
name: raw poopmon
serial_port: /dev/ttyS3
- platform: template
sensors:
poopmon_time:
friendly_name: "Time when litter tray was last used"
value_template: >-
{% set time = states.sensor.raw_poopmon.state | int %}
{% set minutes = ((time % 3600) / 60) | int %}
{% set hours = ((time % 86400) / 3600) | int %}
{%- if time < 60 -%}
less than a minute
{%- else -%}
{%- if hours > 0 -%}
{% if hours == 1 -%}
1 hour
{%- else -%}
{{ hours }} hours
{%- endif -%}
{%- endif -%}
{%- if minutes > 0 -%}
{%- if hours > 0 -%}
{{ ', ' }}
{%- endif -%}
{%- if minutes == 1 -%}
1 minute
{%- else -%}
{{ minutes }} minutes
{%- endif -%}
{%- endif -%}
{%- endif -%}
litter_tray:
friendly_name: "Eli's litter tray"
value_template: >-
{% if states.sensor.raw_poopmon.state|int == 0 %}
Clean
{% else %}
Last used {{ states.sensor.poopmon_time.state }} ago
{% endif %}
icon_template: >-
{% if states.sensor.raw_poopmon.state|int == 0 %}
mdi:cat
{% else %}
mdi:emoticon-poop
{% endif %}
Automations are done by just looking at the raw readings:
automation:
- id: 'cat poop notification'
alias: cat poop notification
trigger:
platform: numeric_state
entity_id: sensor.raw_poopmon
above: 0
action:
service: notify.html5_notifier
data_template:
title: "\uD83D\uDCA9 alert"
message: Litter box has been visited
- id: 'clean tray notification'
alias: clean tray notification
trigger:
platform: numeric_state
entity_id: sensor.raw_poopmon
below: 1
for:
minutes: 3
action:
service: notify.html5_notifier
data_template:
title: "\uD83D\uDE3B alert"
message: Litter box has been cleaned
I haven’t checked yet, but it should be fairly easy to count visits by just looking for raw_poopmon
changing state from 0 to >0.
This needs https://home-assistant.io/components/xiaomi_aqara/ no?
Do you also need the “Xiaomi gateway” for this to work? Just asking because you didn’t mention it specifically, a bit confused.
You need the gateway if you don’t have any other way of getting the sensors in hass. For example, Homey and Smartthings can both take the Xiaomi sensors without the gateway, and I think you can also use the Conbee usb stick.
Thats Thinking out side the Litter box LOL
Like the Logic
I need this
Since we have the litterbox where people passes I’m wondering if a internal pir would do the trick? Just have to figure out how to get the electricity close enough…
Where did you all put your motion detectors?
The litter boxes are kind of hidden away, so that’s not a problem with people passing here.