Skip to content

Commit

Permalink
✨ Add support for Apprise notifications
Browse files Browse the repository at this point in the history
📝 Update README

update-docs
  • Loading branch information
BHSPitMonkey authored and juftin committed May 5, 2023
1 parent e48ff71 commit f843db6
Show file tree
Hide file tree
Showing 14 changed files with 165 additions and 47 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ camply campgrounds --search "Fire Lookout Towers" --state CA
Search for available campsites, get a notification whenever one becomes
available, and continue searching after the first one is found. The below command
is using `silent` notifications as an example but camply also supports `Email`,
`Slack`, `Twilio` (SMS), `Pushover`, `Pushbullet`, and `Telegram`.
`Slack`, `Twilio` (SMS), `Pushover`, `Pushbullet`, `Ntfy`, `Apprise`, and `Telegram`.

```commandline
camply campsites \
Expand Down
2 changes: 2 additions & 0 deletions camply/config/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from .data_columns import CampsiteContainerFields, DataColumns
from .file_config import FileConfig
from .notification_config import (
AppriseConfig,
EmailConfig,
NtfyConfig,
PushbulletConfig,
Expand All @@ -24,6 +25,7 @@
"CampsiteContainerFields",
"DataColumns",
"FileConfig",
"AppriseConfig",
"EmailConfig",
"NtfyConfig",
"PushbulletConfig",
Expand Down
1 change: 1 addition & 0 deletions camply/config/file_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ class FileConfig:
"default": "",
"notes": "NTFY Notification Topic",
},
APPRISE_URL={"default": "", "notes": "Apprise notification URL"},
RIDB_API_KEY={
"default": "",
"notes": "Personal Recreation.gov API Key (not required)",
Expand Down
8 changes: 8 additions & 0 deletions camply/config/notification_config.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ class PushoverConfig:
PUSH_USER: str = getenv("PUSHOVER_PUSH_USER", None)


class AppriseConfig:
"""
Apprise Notification Config Class
"""

APPRISE_URL: str = getenv("APPRISE_URL", None)


class EmailConfig:
"""
Email Notification Config Class
Expand Down
2 changes: 2 additions & 0 deletions camply/notifications/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Notifications __init__ file
"""

from .apprise import AppriseNotifications
from .email_notifications import EmailNotifications
from .multi_provider_notifications import CAMPSITE_NOTIFICATIONS, MultiNotifierProvider
from .pushbullet import PushbulletNotifications
Expand All @@ -12,6 +13,7 @@
from .twilio import TwilioNotifications

__all__ = [
"AppriseNotifications",
"PushbulletNotifications",
"PushoverNotifications",
"TelegramNotifications",
Expand Down
77 changes: 77 additions & 0 deletions camply/notifications/apprise.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
"""
Push Notifications via Apprise
"""

import logging
from typing import List

from camply.config import AppriseConfig
from camply.containers import AvailableCampsite
from camply.notifications.base_notifications import BaseNotifications

logger = logging.getLogger(__name__)
logging.getLogger("apprise").setLevel(logging.ERROR)


class AppriseNotifications(BaseNotifications):
"""
Push Notifications via Apprise
"""

def __init__(self):
super().__init__()
try:
import apprise
except ImportError as ie:
raise RuntimeError(
"Looks like `apprise` isn't installed. Install it with `pip install camply[apprise]`"
) from ie

if any(
[
AppriseConfig.APPRISE_URL is None,
]
):
warning_message = (
"Apprise is not configured properly. To send Apprise notifications "
"make sure to run `camply configure` or set the "
"proper environment variable: `APPRISE_URL`."
)
logger.error(warning_message)
raise EnvironmentError(warning_message)
self.client = apprise.Apprise()
self.client.add(AppriseConfig.APPRISE_URL)
logger.info("Apprise: will notify specified URL")

def send_message(self, message: str, **kwargs):
"""
Send a message via Apprise - if environment variables are configured
Parameters
----------
message: str
"""
self.client.notify(
body=message,
title="Camply Notification",
)

def send_campsites(self, campsites: List[AvailableCampsite], **kwargs):
"""
Send a message with a campsite object
Parameters
----------
campsites: AvailableCampsite
"""
for campsite in campsites:
message_title, formatted_dict = self.format_standard_campsites(
campsite=campsite,
)
fields = [f"🏕{message_title}", ""]
for key, value in formatted_dict.items():
fields.append(f"{key}: {value}")
fields.append("")
fields.append("camply, the campsite finder ⛺️")
composed_message = "\n".join(fields)
self.send_message(message=composed_message)
2 changes: 2 additions & 0 deletions camply/notifications/multi_provider_notifications.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from typing import Dict, List, Type, Union

from camply.containers import AvailableCampsite
from camply.notifications.apprise import AppriseNotifications
from camply.notifications.base_notifications import BaseNotifications, NotificationError
from camply.notifications.email_notifications import EmailNotifications
from camply.notifications.ntfy import NtfyNotifications
Expand All @@ -22,6 +23,7 @@
"pushover": PushoverNotifications,
"email": EmailNotifications,
"ntfy": NtfyNotifications,
"apprise": AppriseNotifications,
"pushbullet": PushbulletNotifications,
"slack": SlackNotifications,
"telegram": TelegramNotifications,
Expand Down
16 changes: 15 additions & 1 deletion docs/command_line_usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ and a link to make the booking. Required parameters include `--start-date`, `--e
[\*\*_example_](#continue-looking-after-the-first-match-is-found)
- `--notifications`: `NOTIFICATIONS`
- Enables continuous searching. Types of notifications to receive. Options available
are `pushover`, `email`, `ntfy`, `pushbullet`, `slack`, `telegram`, `twilio`, `silent`.
are `pushover`, `email`, `ntfy`, `apprise`, `pushbullet`, `slack`, `telegram`, `twilio`, `silent`.
Defaults to `silent` - which just logs messages to console.
[\*\*_example_](#send-a-push-notification)
- `--equipment`
Expand Down Expand Up @@ -436,6 +436,7 @@ camply supports notifications via a number of services:
- [Pushover](https://pushover.net)
- Email
- [Ntfy](https://ntfy.sh)
- [Apprise](https://github.com/caronc/apprise)
- [Pushbullet](https://www.pushbullet.com/#settings/account)
- [Slack](https://slack.com)
- [Telegram](https://core.telegram.org/bots)
Expand Down Expand Up @@ -504,6 +505,19 @@ camply campsites \
--notifications pushover
```

### Send a Notification Using Apprise-Compatible Services

In addition to the built-in notification providers, you can also send notifications using one of the
many popular services supported by [Apprise](https://github.com/caronc/apprise). You'll need
to set up a supported notification URL using the `APPRISE_URL` config value; Refer to the Apprise
documentation to learn how to format a URL to fit your needs.

Using Apprise notifications requires the `apprise` extras:

```
pip install camply[apprise]
```

### Searching for Specific Weekdays

The below search spans across a three-month time window, but it only looks for campsites that
Expand Down
3 changes: 3 additions & 0 deletions docs/examples/example.camply
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@ EMAIL_SUBJECT_LINE="Camply Notification"
# REQUIRED TO SEND NTFY NOTIFICATIONS
NTFY_TOPIC=""

# REQUIRED TO SEND APPRISE NOTIFICATIONS
APPRISE_URL=""

# PERSONAL PUSHOVER API TOKEN (OPTIONAL)
PUSHOVER_PUSH_TOKEN=""
# PERSONAL RECREATION.GOV API KEY: https://ridb.recreation.gov/profile (OPTIONAL)
Expand Down
2 changes: 2 additions & 0 deletions docs/how_to_run.md
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,8 @@ available.

- Pushover Notifications
- `PUSHOVER_PUSH_USER`
- Apprise Notifications
- `APPRISE_URL`
- Email Notifications
- `EMAIL_TO_ADDRESS`
- `EMAIL_USERNAME`
Expand Down
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ becomes available, camply sends you a notification to book your spot!
- [Send a Text Message](command_line_usage.md#send-a-text-message)
- [Send a Notification to Different Services](command_line_usage.md#send-a-notification-to-different-services)
- [Searching for Specific Weekdays](command_line_usage.md#searching-for-specific-weekdays)
- [Send a Notification Using Apprise-Compatible Services](command_line_usage.md#send-a-notification-using-apprise-compatible-services)
- [Look for Weekend Campsite Availabilities](command_line_usage.md#look-for-weekend-campsite-availabilities)
- [Look for Consecutive Nights at the Same Campsite](command_line_usage.md#look-for-consecutive-nights-at-the-same-campsite)
- [Look for a Campsite Inside of Yellowstone](command_line_usage.md#look-for-a-campsite-inside-of-yellowstone)
Expand Down
4 changes: 4 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -38,8 +38,12 @@ requires-python = ">=3.8,<4"

[project.optional-dependencies]
all = [
"apprise~=1.3.0",
"twilio~=7.17.0"
]
apprise = [
"apprise~=1.3.0"
]
twilio = [
"twilio~=7.17.0"
]
Expand Down
55 changes: 21 additions & 34 deletions requirements/requirements-dev.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
#
# This file is autogenerated by pip-compile with Python 3.9
# This file is autogenerated by pip-compile with Python 3.11
# by the following command:
#
# pip-compile --all-extras --generate-hashes --output-file=requirements/requirements-dev.txt --resolver=backtracking
#
apprise==1.3.0 \
--hash=sha256:2c50c19a5dd41317b1f659c52b21a990febe6c15e08464228a1ce8e6098f11bf \
--hash=sha256:ef0c1413a32182272b6ed60ddcee6057744dc683725651015332e063b9a6a4ad
# via camply (pyproject.toml)
black==23.3.0 \
--hash=sha256:064101748afa12ad2291c2b91c960be28b817c0c7eaa35bec09cc63aa56493c5 \
--hash=sha256:0945e13506be58bf7db93ee5853243eb368ace1c08a24c65ce108986eac65915 \
Expand Down Expand Up @@ -38,7 +42,9 @@ build==0.10.0 \
certifi==2022.12.7 \
--hash=sha256:35824b4c3a97115964b408844d64aa14db1cc518f6562e8d7261699d1350a9e3 \
--hash=sha256:4ad3232f5e926d6718ec31cfc1fcadfde020920e278684144551c91769c7bc18
# via requests
# via
# apprise
# requests
charset-normalizer==3.1.0 \
--hash=sha256:04afa6387e2b282cf78ff3dbce20f0cc071c12dc8f685bd40960cc68644cfea6 \
--hash=sha256:04eefcee095f58eaabe6dc3cc2262f3bcd776d2c67005880894f447b3f2cb9c1 \
Expand Down Expand Up @@ -121,6 +127,7 @@ click==8.1.3 \
--hash=sha256:bb4d8133cb15a609f44e8213d9b391b0809795062913b383c62be0ee95b1db48
# via
# camply (pyproject.toml)
# apprise
# black
# mkdocs
# mkdocs-click
Expand Down Expand Up @@ -185,10 +192,6 @@ coverage[toml]==7.2.3 \
--hash=sha256:fd214917cabdd6f673a29d708574e9fbdb892cb77eb426d0eae3490d95ca7859 \
--hash=sha256:fff5aaa6becf2c6a1699ae6a39e2e6fb0672c2d42eca8eb0cafa91cf2e9bd312
# via pytest-cov
exceptiongroup==1.1.1 \
--hash=sha256:232c37c63e4f682982c8b6459f33a8981039e5fb8756b2074364e5055c498c9e \
--hash=sha256:d484c3090ba2889ae2928419117447a14daf3c1231d5e30d0aae34f354f01785
# via pytest
execnet==1.9.0 \
--hash=sha256:8f694f3ba9cc92cab508b152dcfe322153975c29bda272e2fd7f3f00f36e47c5 \
--hash=sha256:a295f7cc774947aac58dde7fdc85f4aa00c42adf5d8f5468fc630c1acf30a142
Expand All @@ -211,16 +214,6 @@ idna==3.4 \
# via
# requests
# yarl
importlib-metadata==6.6.0 \
--hash=sha256:43dd286a2cd8995d5eaef7fee2066340423b818ed3fd70adf0bad5f1fac53fed \
--hash=sha256:92501cdf9cc66ebd3e612f1b4f0c0765dfa42f0fa38ffb319b6bd84dd675d705
# via
# markdown
# mkdocs
importlib-resources==5.12.0 \
--hash=sha256:4be82589bf5c1d7999aedf2a45159d10cb3ca4f19b2271f8792bc8e6da7b22f6 \
--hash=sha256:7b1deeebbf351c7578e09bf2f63fa2ce8b5ffec296e0d349139d43cca061a81a
# via fake-useragent
iniconfig==2.0.0 \
--hash=sha256:2d91e135bf72d31a410b17c16da610a82cb55f6b0477d1a902134b24a455b8b3 \
--hash=sha256:b6a85871a79d2e3b22d2d1b94ac2824226a63c6b741c88f7ae975f18b6778374
Expand All @@ -236,6 +229,7 @@ markdown==3.3.7 \
--hash=sha256:cbb516f16218e643d8e0a95b309f77eb118cb138d39a4f27851e6a63581db874 \
--hash=sha256:f5da449a6e1c989a4cea2631aa8ee67caa5a2ef855d551c88f9e309f4634c621
# via
# apprise
# mkdocs
# mkdocs-autorefs
# mkdocs-click
Expand Down Expand Up @@ -497,6 +491,10 @@ numpy==1.24.2 \
--hash=sha256:f64bb98ac59b3ea3bf74b02f13836eb2e24e48e0ab0145bbda646295769bd780 \
--hash=sha256:f9006288bcf4895917d02583cf3411f98631275bc67cce355a7f39f8c14338fa
# via pandas
oauthlib==3.2.2 \
--hash=sha256:8139f29aac13e25d502680e9e19963e83f16838d48a0d71c287fe40e7067fbca \
--hash=sha256:9859c40929662bec5d64f34d01c99e093149682a3f38915dc0655d5a633dd918
# via requests-oauthlib
packaging==23.1 \
--hash=sha256:994793af429502c4ea2ebf6bf664629d07c1a9fe974af92966e4b8d2df7edc61 \
--hash=sha256:a392980d2b6cffa644431898be54b0045151319d1e7ec34f0cfed48767dd334f
Expand Down Expand Up @@ -697,6 +695,7 @@ pyyaml==6.0 \
--hash=sha256:f84fbc98b019fef2ee9a1cb3ce93e3187a6df0b2538a651bfb890254ba9f90b5
# via
# camply (pyproject.toml)
# apprise
# mkdocs
# pymdown-extensions
# pyyaml-env-tag
Expand Down Expand Up @@ -775,8 +774,14 @@ requests==2.28.2 \
--hash=sha256:98b1b2782e3c6c4904938b84c0eb932721069dfdb9134313beff7c83c2df24bf
# via
# camply (pyproject.toml)
# apprise
# mkdocs-material
# requests-oauthlib
# twilio
requests-oauthlib==1.3.1 \
--hash=sha256:2577c501a2fb8d05a304c09d090d6e47c306fef15809d102b327cf8364bddab5 \
--hash=sha256:75beac4a47881eeb94d5ea5d6ad31ef88856affe2332b9aafb52c6452ccf0d7a
# via apprise
rich==13.3.4 \
--hash=sha256:22b74cae0278fd5086ff44144d3813be1cedc9115bdfabbfefd86400cb88b20a \
--hash=sha256:b5d573e13605423ec80bdd0cd5f8541f7844a0e71a13f74cf454ccb2f490708b
Expand Down Expand Up @@ -816,16 +821,6 @@ tenacity==8.2.2 \
--hash=sha256:2f277afb21b851637e8f52e6a613ff08734c347dc19ade928e519d7d2d8569b0 \
--hash=sha256:43af037822bd0029025877f3b2d97cc4d7bb0c2991000a3d59d71517c5c969e0
# via camply (pyproject.toml)
tomli==2.0.1 \
--hash=sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc \
--hash=sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f
# via
# black
# build
# coverage
# mypy
# pyproject-hooks
# pytest
twilio==7.17.0 \
--hash=sha256:312e25b0a1ca782974a359d95123f270574e6e4b195b0e2095a156219ad7b7ec \
--hash=sha256:f43de32cdc27f8853bb02ab0b8703a487beffbb9dcc8118398b6757e1376e6ed
Expand All @@ -838,8 +833,6 @@ typing-extensions==4.5.0 \
--hash=sha256:5cb5f4a79139d699607b3ef622a1dedafa84e115ab0024e0d9c044a9479ca7cb \
--hash=sha256:fb33085c39dd998ac16d1431ebc293a8b3eedd00fd4a32de0ff79002c19511b4
# via
# black
# mkdocstrings
# mypy
# pydantic
urllib3==1.26.15 \
Expand Down Expand Up @@ -1036,12 +1029,6 @@ yarl==1.9.1 \
--hash=sha256:f878a78ed2ccfbd973cab46dd0933ecd704787724db23979e5731674d76eb36f \
--hash=sha256:f8e73f526140c1c32f5fca4cd0bc3b511a1abcd948f45b2a38a95e4edb76ca72
# via vcrpy
zipp==3.15.0 \
--hash=sha256:112929ad649da941c23de50f356a2b5570c954b65150642bccdd66bf194d224b \
--hash=sha256:48904fc76a60e542af151aded95726c1a5c34ed43ab4134b597665c86d7ad556
# via
# importlib-metadata
# importlib-resources

# WARNING: The following packages were not pinned, but pip requires them to be
# pinned when the requirements file includes hashes. Consider using the --allow-unsafe flag.
Expand Down
Loading

0 comments on commit f843db6

Please sign in to comment.