Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,11 @@ front end. All these are new to me so forgive / correct any noob mistakes.

[Flask]: http://flask.pocoo.org/

#### Aug 2025 Update - Added Signal Notifications

GaragePi now supports Signal notifications. Setup Signal CLI Rest API with https://github.com/bbernhard/signal-cli-rest-api
Once setup, add the server details to app.cfg and get signal notifications.


#### Dec 2020 Update - Added Telegram Notifications

Expand Down
13 changes: 13 additions & 0 deletions backend/app.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
from common import constants
from common.iftt import IftttEvent
from common.telegram import TelegramNotification
from common.signal import SignalNotification
import RPi.GPIO as GPIO
import atexit
import signal
Expand Down Expand Up @@ -66,6 +67,18 @@
tg_opened_event = None # type: TelegramNotification
tg_closed_event = None # type: TelegramNotification
tg_warning_event = None # type: TelegramNotification
if config['SIGNAL_SERVICE']:
logger.info('Creating Signal events')
sig_changed_event = SignalNotification(config['SIGNAL_SERVICE'], config['SIGNAL_GROUP_ID'], config['SIGNAL_NUMBER'], "Garage Door Changed", logger)
sig_opened_event = SignalNotification(config['SIGNAL_SERVICE'], config['SIGNAL_GROUP_ID'], config['SIGNAL_NUMBER'], "Garage Door Opened", logger)
sig_closed_event = SignalNotification(config['SIGNAL_SERVICE'], config['SIGNAL_GROUP_ID'], config['SIGNAL_NUMBER'], "Garage Door Closed", logger)
sig_warning_event = SignalNotification(config['SIGNAL_SERVICE'], config['SIGNAL_GROUP_ID'], config['SIGNAL_NUMBER'], "Garage Door Still Open", logger)
else:
logger.info('No Signal service provided. No events will be raised.')
sig_changed_event = None # type: SignalNotification
sig_opened_event = None # type: SignalNotification
sig_closed_event = None # type: SignalNotification
sig_warning_event = None # type: SignalNotification

# Set up GPIO using BCM numbering
logger.info('Setting GPIO numbering')
Expand Down
3 changes: 3 additions & 0 deletions backend/controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -118,14 +118,17 @@ def door_opened_or_closed(self, pin_changed: int):
change = 'opened'
specific_event = app.opened_event
tg_specific_event = app.tg_opened_event
sig_specific_event = app.sig_opened_event
else:
change = 'closed'
specific_event = app.closed_event
tg_specific_event = app.tg_closed_event
sig_specific_event = app.sig_closed_event

if app.changed_event is not None: app.changed_event.trigger(change)
if specific_event is not None: specific_event.trigger()
if tg_specific_event is not None: tg_specific_event.trigger()
if sig_specific_event is not None: sig_specific_event.trigger()

app.logger.info("door {0} (pin {1} is {2})".format("OPENED" if new_state else "CLOSED", pin_changed, new_state))

Expand Down
63 changes: 63 additions & 0 deletions common/signal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import logging
import requests
import json

class SignalNotification:
signal_service = ''
signal_group_id = ''
signal_number = ''

def __init__(self,signal_service: str, signal_group_id: str, signal_number, event_name: str, logger: logging.Logger):
"""
:param signal_service: The ip/hostname that signal-cli is running on
:param signal_group_id: The signal group id for the notification delivery
:param signal_number: The sender account number for the sinal account
:param event_name: The name of the event to trigger
:param logger: Logger for logging purposes
"""
if logger is None:
raise Exception("Logger is missing!")
if not signal_service:
logger.debug('Signal: Signal Service provided!')
raise Exception("NO Signal Service provided!")
if not signal_group_id:
logger.debug('Signal: NO signal_group_id provided!')
raise Exception("NO signal_group_id provided!")
if not signal_number:
logger.debug('Signal: NO signal_number provided!')
raise Exception("NO signal_number provided!")
if not event_name:
logger.debug('Signal: NO event name provided')
raise Exception("NO event name provided!")
logger.info('Created SignalNotification object %s' %(event_name))
self.signal_service = signal_service
self.signal_group_id = signal_group_id
self.signal_number = signal_number
self.event_name = event_name
self.logger = logger

def trigger(self):
self.logger.info("Works.")
self.logger.debug(self.signal_service)
payload = {
"message": self.event_name,
"number": self.signal_number,
"recipients": [self.signal_group_id],
"text_mode": "normal",
"notify_self": False
}
url = "http://" + self.signal_service + "/v2/send"
self.logger.info('Trying to hit the signal cli service %s' %(url))
try:
response = requests.post(
url,
headers={
"accept": "application/json",
"Content-Type": "application/json"
},
data=json.dumps(payload)
)
response.raise_for_status()
except requests.RequestException as e:
self.logger.info('Signal notification failed')
self.logger.info(e)
6 changes: 3 additions & 3 deletions common/telegram.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,13 +15,13 @@ def __init__(self,telegram_key: str, telegram_chat_id: str, event_name: str, log
if logger is None:
raise Exception("Logger is missing!")
if not telegram_key:
logger.debug('IFTT: NO Telegram bot key provided')
logger.debug('Telegram: NO Telegram bot key provided')
raise Exception("NO Telegram bot key provided!")
if not telegram_chat_id:
logger.debug('IFTT: NO Telegram_chat_id provided')
logger.debug('Telegram: NO Telegram_chat_id provided')
raise Exception("NO Telegram chat id provided!")
if not event_name:
logger.debug('IFTT: NO event name provided')
logger.debug('Telegram: NO event name provided')
raise Exception("NO event name provided!")
logger.info('Created TelegramNotification object %s' %(event_name))
self.telegram_key = telegram_key
Expand Down
1 change: 1 addition & 0 deletions requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ schedule==0.6.0
Werkzeug==1.0.1
wheel==0.36.2
apprise==0.8.9
requests==2.25.0
7 changes: 7 additions & 0 deletions resource/default_app.cfg
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,13 @@ IFTTT_MAKER_KEY = ''
APPRISE_TELEGRAM_KEY = ''
APPRISE_TELEGRAM_CHAT_ID = ''

# Enter Signal CLI Details here
# Signal service is the hostname or ip and port of your signal-cli instance
# Signal number is your sending phone number with + and country code
SIGNAL_SERVICE = ''
SIGNAL_NUMBER = '+'
SIGNAL_GROUP_ID = ''

# Use the following to have an IFTTT warning event sent if
# the garage door is open at the given time in 24 hour time.
# For example, alert at 9:30PM would be '21:30'.
Expand Down
17 changes: 16 additions & 1 deletion webserver/garage.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from common.db import GarageDb
from common.iftt import IftttEvent
from common.telegram import TelegramNotification
from common.signal import SignalNotification
from webserver.client_api import GaragePiClient
import time
import csv
Expand Down Expand Up @@ -225,4 +226,18 @@ def test_telegram():

event = TelegramNotification(telegram_key, telegram_chat_id, "Test notification from GaragePi", app.logger)
event.trigger()
return redirect(url_for('show_control'))
return redirect(url_for('show_control'))

@app.route('/test_signal')
def test_signal():
if not app.debug: return 'Only available when debug is set to True in application config.'
signal_service = str(app.config['SIGNAL_SERVICE'])
signal_group_id = str(app.config['SIGNAL_GROUP_ID'])
signal_number = str(app.config['SIGNAL_NUMBER'])
if not signal_service: return 'No Signal key provided!'
app.logger.debug("signal_service %s" % (signal_service,))
app.logger.debug("signal_group_id %s" % (signal_group_id))
app.logger.debug("signal_number %s" % (signal_number))
event = SignalNotification(signal_service, signal_group_id, signal_number, "Test notification from GaragePi", app.logger)
event.trigger()
return redirect(url_for('show_control'))