Skip to content

Commit

Permalink
[ntfy] Improve example/tutorial about Frigate event notifications
Browse files Browse the repository at this point in the history
  • Loading branch information
amotl committed Apr 20, 2023
1 parent 79ea76a commit 2d4f487
Show file tree
Hide file tree
Showing 8 changed files with 199 additions and 87 deletions.
1 change: 1 addition & 0 deletions CHANGES.rst
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ in progress
- [ux] Rename subcommand ``mqttwarn make-samplefuncs`` to ``mqttwarn make-udf``,
and adjust naming.
- [ntfy] Add dedicated service plugin ``ntfy``
- [ntfy] Improve example/tutorial about Frigate event notifications


2023-04-11 0.33.0
Expand Down
116 changes: 93 additions & 23 deletions examples/frigate/README.rst
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
.. _processing-frigate-events:

##############################################
Frigate » Forward events and snapshots to Ntfy
Frigate » Forward events and snapshots to ntfy
##############################################


Expand All @@ -11,34 +11,50 @@ About

The specific scenario is to setup a notification pipeline which looks like::

Frigate -> Mosquitto -> mqttwarn -> Apprise -> Ntfy
Frigate -> Mosquitto -> mqttwarn -> ntfy

`Frigate`_ (`Frigate on GitHub`_) is a network video recorder (NVR) with
realtime local object detection for IP cameras. It uses MQTT to publish
`events in JSON format`_ and `camera pictures in JPEG format`_.

`Apprise`_ is a polyglot notification library that allows you to send
notifications to almost all of the most popular notification services
available today. It has an adapter for `Ntfy`_.

`Ntfy`_ (`Ntfy on GitHub`_) is a simple HTTP-based pub-sub notification
`ntfy`_ (`ntfy on GitHub`_) is a simple HTTP-based pub-sub notification
service, allowing you to send notifications to your phone or desktop from
any computer, entirely without signup, cost or setup.


*******
Details
*******
********
Synopsis
********

1. Subscribe to ntfy topic by visiting http://localhost:5555/frigate-test.

2. Publish Frigate sample events.

.. code-block:: bash
cat assets/frigate-event-new-good.json | jq -c | mosquitto_pub -t 'frigate/events' -l
mosquitto_pub -f goat.png -t 'frigate/cam-testdrive/goat/snapshot'
3. Enjoy the outcome.

.. figure:: https://user-images.githubusercontent.com/453543/233172276-6a59cefa-6461-48bc-80f2-c355b6acc496.png

We are investigating how to `Send message body or attachment to Apprise/Ntfy`_,
and if it is feasible to make mqttwarn process JPEG content, see `Non-UTF-8
encoding causes error`_.


*****
Usage
*****


Configuration
=============

Please inspect the `frigate.ini`_ mqttwarn configuration file and adjust it to
your needs before running mqttwarn on it. If you also want to inspect the
corresponding user-defined functions, you are most welcome. They are stored
within `frigate.py`_.


In a box
========

Expand All @@ -47,10 +63,14 @@ Start the Mosquitto MQTT broker::
docker run --name=mosquitto --rm -it --publish=1883:1883 \
eclipse-mosquitto:2.0.15 mosquitto -c /mosquitto-no-auth.conf

Start the Ntfy API service::
Start the ntfy API service::

docker run --name=ntfy --rm -it --publish=5555:80 \
binwiederhier/ntfy serve
docker run --name=ntfy --rm -it --publish=5555:80 binwiederhier/ntfy \
serve \
--base-url="http://localhost:5555" \
--cache-file="/tmp/ntfy-cache.db" \
--attachment-cache-dir="/tmp/ntfy-attachments" \
--attachment-expiry-duration="168h"

Run mqttwarn::

Expand All @@ -73,17 +93,67 @@ Publish a few example events individually::
Publish an example image::

wget -O goat.png https://user-images.githubusercontent.com/453543/231550862-5a64ac7c-bdfa-4509-86b8-b1a770899647.png
convert goat.png goat.jpg
mosquitto_pub -f goat.jpg -t 'frigate/cam-testdrive/goat/snapshot'
open /tmp/mqttwarn-frigate-cam-testdrive-goat.jpg
mosquitto_pub -f goat.png -t 'frigate/cam-testdrive/goat/snapshot'
open /tmp/mqttwarn-frigate-cam-testdrive-goat.png


***********
Development
***********

We are investigating how to `Receiving and processing MQTT messages from Frigate NVR`_,
and if it is feasible to make mqttwarn process JPEG content, see `Non-UTF-8
encoding causes error`_.

The `test_frigate.py`_ file covers different code paths by running a few Frigate event
message samples through the machinery, and inspecting their outcomes. You can invoke
the test cases either as part of the complete test suite, or by running them from this
directory::

pytest --no-cov -k frigate
pytest --no-cov test_frigate.py


************
Attributions
************

Acknowledgements
================
- `Sev`_ for coming up with the idea of using mqttwarn to connect Frigate with ntfy
- `Blake Blackshear`_ for `Frigate`_
- `Philipp C. Heckel`_ for `ntfy`_

Content
=======
The copyright of data, particular images, and pictograms, are held by their
respective owners, unless otherwise noted.

Example snapshot image
----------------------

- **Description**: A picture of a `Changthangi`_ goat
- **Date**: April 7, 2023
- **Source**: Own work via Unsplash
- **Author**: `Jaromír Kalina`_
- **License**: `Unsplash License`_
- **URL**: https://unsplash.com/photos/spdQ1dVuIHw


.. _Apprise: https://github.com/caronc/apprise
.. _Blake Blackshear: https://github.com/blakeblackshear
.. _camera pictures in JPEG format: https://docs.frigate.video/integrations/mqtt/#frigatecamera_nameobject_namesnapshot
.. _Changthangi: https://en.wikipedia.org/wiki/Changthangi
.. _events in JSON format: https://docs.frigate.video/integrations/mqtt/#frigateevents
.. _Frigate: https://frigate.video/
.. _Frigate on GitHub: https://github.com/blakeblackshear/frigate
.. _frigate.ini: https://github.com/jpmens/mqttwarn/blob/main/examples/frigate/frigate.ini
.. _frigate.py: https://github.com/jpmens/mqttwarn/blob/main/examples/frigate/frigate.py
.. _Jaromír Kalina: https://unsplash.com/@jkalinaofficial
.. _Non-UTF-8 encoding causes error: https://github.com/jpmens/mqttwarn/issues/634
.. _Ntfy: https://ntfy.sh/
.. _Ntfy on GitHub: https://github.com/binwiederhier/ntfy
.. _Send message body or attachment to Apprise/Ntfy: https://github.com/jpmens/mqttwarn/issues/632
.. _ntfy: https://ntfy.sh/
.. _ntfy on GitHub: https://github.com/binwiederhier/ntfy
.. _Philipp C. Heckel: https://github.com/binwiederhier
.. _Receiving and processing MQTT messages from Frigate NVR: https://github.com/jpmens/mqttwarn/issues/632
.. _Sev: https://github.com/sevmonster
.. _test_frigate.py: https://github.com/jpmens/mqttwarn/blob/main/examples/frigate/test_frigate.py
.. _Unsplash License: https://unsplash.com/license
6 changes: 4 additions & 2 deletions examples/frigate/assets/frigate-event-full.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,11 @@
"stationary": false,
"motionless_count": 1,
"position_changes": 2,
"current_zones": [],
"current_zones": [
"barn"
],
"entered_zones": [
"zone1"
"lawn"
],
"has_clip": true,
"has_snapshot": true
Expand Down
6 changes: 4 additions & 2 deletions examples/frigate/assets/frigate-event-update-good.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,9 +25,11 @@
"false_positive": false,
"start_time": 1680791459.255384,
"end_time": null,
"current_zones": [],
"current_zones": [
"barn"
],
"entered_zones": [
"zone1"
"lawn"
],
"has_clip": true,
"has_snapshot": true
Expand Down
30 changes: 15 additions & 15 deletions examples/frigate/frigate.ini
Original file line number Diff line number Diff line change
@@ -1,30 +1,30 @@
[defaults]
functions = frigate.py
launch = apprise-ntfy, store-jpeg
launch = ntfy, store-image

status_publish = True



# =====================
# Frigate event to Ntfy
# Frigate event to ntfy
# =====================

# Format: JSON
# Docs: https://docs.frigate.video/integrations/mqtt/#frigateevents



[config:apprise-ntfy]
module = apprise_single
baseuri = ntfy://localhost:5555/frigate
filename_template = '/tmp/mqttwarn-frigate-{camera}-{label}.jpg'

[config:ntfy]
targets = {
'test': {
'url': 'http://username:password@localhost:5555/frigate-testdrive',
'attachment': '/tmp/mqttwarn-frigate-{camera}-{label}.png',
}
}

[frigate/events]
filter = frigate_events_filter()
alldata = frigate_events()
targets = apprise-ntfy
targets = ntfy:test
title = {title}
format = {format}
click = {click}
Expand All @@ -39,14 +39,14 @@ frigate_skip_rules = {
# Frigate image to file
# =====================

# Format: JPEG
# Format: Binary (PNG or JPEG)
# Docs: https://docs.frigate.video/integrations/mqtt/#frigatecamera_nameobject_namesnapshot

[config:store-jpeg]
[config:store-image]
module = file
targets = {
'cam-testdrive-goat': ['/tmp/mqttwarn-frigate-cam-testdrive-goat.jpg'],
'cam-testdrive-squirrel': ['/tmp/mqttwarn-frigate-cam-testdrive-squirrel.jpg'],
'cam-testdrive-goat': ['/tmp/mqttwarn-frigate-cam-testdrive-goat.png'],
'cam-testdrive-squirrel': ['/tmp/mqttwarn-frigate-cam-testdrive-squirrel.png'],
}

# Configure `file` plugin to pass through payload 1:1.
Expand All @@ -56,4 +56,4 @@ overwrite = True

[frigate/+/+/snapshot]
alldata = frigate_snapshot_decode_topic()
targets = store-jpeg:{camera_name}-{object_name}
targets = store-image:{camera_name}-{object_name}
20 changes: 12 additions & 8 deletions examples/frigate/frigate.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*-
import dataclasses
import re
from collections import OrderedDict
from datetime import datetime, timezone
import typing as t

Expand Down Expand Up @@ -48,7 +49,7 @@ def to_dict(self) -> t.Dict[str, str]:
@dataclasses.dataclass
class NtfyParameters:
"""
Manage outbound parameter data for Apprise/Ntfy.
Manage outbound parameter data for ntfy.
"""
title: str
format: str
Expand All @@ -63,12 +64,12 @@ def to_dict(self) -> t.Dict[str, str]:

def frigate_events(topic, data, srv: Service):
"""
mqttwarn transformation function which computes options to be submitted to Apprise/Ntfy.
mqttwarn transformation function which computes options to be submitted to ntfy.
"""

# Acceptable hack to get attachment filename template from service configuration.
context: RuntimeContext = srv.mwcore["context"]
service_config = context.get_service_config("apprise-ntfy")
service_config = context.get_service_config("ntfy")
filename_template = service_config.get("filename_template")

# Decode JSON message.
Expand All @@ -84,16 +85,19 @@ def frigate_events(topic, data, srv: Service):
)

# Interpolate event data into attachment filename template.
attach_filename = filename_template.format(**event.to_dict())
# attach_filename = filename_template.format(**event.to_dict())

# Compute parameters for outbound Apprise / Ntfy URL.
# Compute parameters for outbound ntfy URL.
ntfy_parameters = NtfyParameters(
title=f"{event.label} entered {event.entered_zones_str} at {event.time}",
format=f"{event.label} was in {event.current_zones_str}",
click=f"https://frigate/events?camera={event.camera}&label={event.label}&zone={event.entered_zones[0]}",
format=f"{event.label} was in {event.current_zones_str} before",
click=f"https://frigate.local/events?camera={event.camera}&label={event.label}&zone={event.entered_zones[0]}",
#attach=attach_filename,
)
return ntfy_parameters.to_dict()
params = OrderedDict()
params.update(event.to_dict())
params.update(ntfy_parameters.to_dict())
return params


def frigate_events_filter(topic, message, section, srv: Service):
Expand Down
7 changes: 3 additions & 4 deletions examples/frigate/publish.sh
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,12 @@ for program in ${prerequisites}; do
done

# Acquire image for publishing.
if [ ! -f goat.jpg ]; then
if [ ! -f goat.png ]; then
wget -O goat.png https://user-images.githubusercontent.com/453543/231550862-5a64ac7c-bdfa-4509-86b8-b1a770899647.png
convert goat.png goat.jpg
fi

# 1. Publish picture snapshot in JPEG format.
mosquitto_pub -f goat.jpg -t 'frigate/cam-testdrive/goat/snapshot'
# 1. Publish picture snapshot in PNG format.
mosquitto_pub -f goat.png -t 'frigate/cam-testdrive/goat/snapshot'

# 2. Publish event in JSON format.
# shellcheck disable=SC2002
Expand Down
Loading

0 comments on commit 2d4f487

Please sign in to comment.