kk7ds / pynx584

Python library and server for talking to NX584/NX8E interfaces
GNU General Public License v3.0
29 stars 26 forks source link

Email notifications #38

Closed gdlesage closed 2 years ago

gdlesage commented 4 years ago

I need some helping getting email notifications. I have pynx584 installed on raspberry pi zero wh, I have sendmail working with smtp.gmail.com as host on a dedicated separate gmail account for my alarm. My understanding is with alarm events mail.py will send email to the system mail of the raspberry pi, which I plan to forward my personal email address, so I can see the alerts immediately when away. I have the fromaddress and smtphost set for my alarm gmail account.

[email] fromaddr = alarmxxxxx@gmail.com smtphost = smtp.gmail.com

I get no emails when alarm is set off. Smtplib seems to require "recipient". smtp.sendmail(fromaddr, recips, msg.as_string()) but I do not see how recips is defined.

Has someone gotten email notifications to work and if so how did they do it. open issue #6 from 3 years ago indicates mail notifications works but does not tell me how.

gdlesage commented 4 years ago

I was able to get email notifications working with some changes in mail.py which are shown below. There remains one problem. The reported zone which triggers the alarm is one less than the actual zone, for instance, if I trigger zone 2, the email message reports zone 1. I have confirmed this with triggering 6 other zones.

My example config.ini file below shows that you must provide:

  1. Email addresses for recipients, either as system or alarms. With system, you get emails when nx584 starts, and when the global siren asserts or de-asserts. With alarms, you get emails when alarm is triggered telling you zone and alarm triggered or restored. I will be using the alarms recipient. You can provide multiple emails separated by commas, or your as a text msg if you provider allows, with Verizon its phonenumber@vtext.com.

  2. Smtphost which is smtp.gmail.com. You will need to set up google smtp which forwards your emails from your alarm. I made dedicated gmail account for my alarm. Be sure to set up two factor authorization with your account and create a application password for your google account. Use your application password for "password" entry in the config.ini file. https://www.hostinger.com/tutorials/how-to-use-free-google-smtp-server.

I tested by alarm gmail smtp by installing msmtp https://www.techrapid.uk/2017/04/send-email-on-raspberry-pi-with-msmtp.html.

sample emails from alarm are at the end of the post

config.ini"

[config] max_zone = 32 [email] fromaddr = YourAlarmEmail@gmail.com smtphost = smtp.gmail.com password = YourAlarmGmailPassword alarms = recipient1Email.com, recipient2Email.com, phonenumber@vtext.com

system = recipient1Email.com #(uncomment if you want system emails)

[zones] 1 = GARAGE INT DR 2 = GREAT RM MOTION 3 = BSMT DEN MOTION 4 = FRONT DOOR ……..

mail.py

try: import ConfigParser as configparser except ImportError: import configparser import email import email.mime import email.mime.text import email.utils import smtplib

class MissingEmailConfig(Exception): pass

def _send_system_email(config, subject, recips, body): try: fromaddr = config.get('email', 'fromaddr') smtphost = config.get('email', 'smtphost') password = config.get('email', 'password') except (configparser.NoOptionError, configparser.NoSectionError): raise MissingEmailConfig() msg = email.mime.text.MIMEText(body) msg['Subject'] = subject msg['From'] = fromaddr msg['Date'] = email.utils.formatdate() msg['Message-Id'] = email.utils.make_msgid('nx584') for addr in recips: msg['To'] = addr smtp = smtplib.SMTP('smtp.gmail.com: 587') smtp.starttls() smtp.login(fromaddr, password) smtp.sendmail(fromaddr, recips, msg.as_string()) smtp.quit()

def send_system_email(config, deasserted, asserted): try: emails = config.get('email', 'system').split(',') except (configparser.NoOptionError, configparser.NoSectionError): return

if not emails:
    return

body = ('Security System alert.\n' +
        '\n' +
        'The following new flags have been asserted:\n' +
        ('%s\n' % ','.join(asserted)) +
        '\n' +
        'The following flags are now de-asserted:\n' +
        ('%s\n' % ','.join(deasserted)))

try:
    _send_system_email(config, 'Security System Alert',
                       emails, body)
except MissingEmailConfig:
    pass

def send_partitionemail(config, partition, deasserted, asserted): try: emails = config.get('partition%i' % partition.number, 'flags').split(',') except (configparser.NoOptionError, configparser.NoSectionError): return

try:
    ignore = set(config.get('partition_%i' % partition.number,
                            'ignore_flags').split(','))
except configparser.NoOptionError:
    ignore = set([])

deasserted = deasserted - ignore
asserted = asserted - ignore
if not asserted and not deasserted:
    return
if not emails:
    return

body = ('Security System partition %i alert.\n' % partition.number +
        '\n' +
        'The following new flags have been asserted:\n' +
        ('%s\n' % ','.join(asserted)) +
        '\n' +
        'The following flags are now de-asserted:\n' +
        ('%s\n' % ','.join(deasserted)))

try:
    _send_system_email(
        config,
        'Security System Partition %i Alert' % partition.number,
        emails, body)
except MissingEmailConfig:
    pass

def send_partition_status_email(config, partition, recipkey, sub, message): try: emails = config.get('partition%i' % partition.number, recip_key).split(',') except (configparser.NoOptionError, configparser.NoSectionError): return

if not emails:
    return

body = 'Security System alert:\n%s' % message
try:
    _send_system_email(
        config,
        'Security: %s' % sub,
        emails, body)
except MissingEmailConfig:
    pass

def send_log_event_mail(config, event): try: alarm_emails = set(config.get('email', 'alarms').split(',')) except (configparser.NoOptionError, configparser.NoSectionError): alarm_emails = set([])

try:
    alarm_events = set(config.get('email', 'alarm_events').split(','))
except (configparser.NoOptionError, configparser.NoSectionError):a_

try:
    event_emails = set(config.get('email', 'events').split(','))
except (configparser.NoOptionError, configparser.NoSectionError):
    event_emails = set([])

emails = set(event_emails)
if event.event in alarm_events:
    emails |= alarm_emails

if not emails:
    return

body = '%s at %s' % (event.event_string, event.timestamp)

_send_system_email(
    config, 'Security: %s' % event.event,
    emails, body)

EOF

sample emails from alarm:

using alarms as recipient

"Zone 1 Alarm at 2020-01-12 14:21:00" "Zone 1 Alarm restore at 2020-01-12 14:21:00 \"

using system as recipient

"Security System alert.

The following new flags have been asserted:

The following flags are now de-asserted: Global Siren on"

"Security System alert.

when nx584 starts "The following new flags have been asserted: AC power on,Valid partition 1,PIN required for local download

The following flags are now de-asserted:"

kk7ds commented 2 years ago

Were you going to submit a PR for this? I don't use gmail SMTP so I can't really help. I'll go ahead and close it because it's very old and mostly resolved. If there's something to add via the PR we can look it over there. Thanks!