Compare commits

..

No commits in common. "f4caad52ff8b70e7974872dce72cd2f8a54d407a" and "4ab145c62a71f07121effd532b0e05790dee2f09" have entirely different histories.

2 changed files with 25 additions and 46 deletions

2
.gitignore vendored
View File

@ -1,2 +0,0 @@
laundry_notifier/laundry_notifier.conf

View File

@ -1,16 +1,20 @@
import configparser
import logging
import math
import smtplib
import time import time
from datetime import datetime import datetime
import smtplib
import math
from email.mime.text import MIMEText from email.mime.text import MIMEText
from datetime import datetime
import requests
from microstacknode.hardware.accelerometer.mma8452q import MMA8452Q from microstacknode.hardware.accelerometer.mma8452q import MMA8452Q
RECIPIENT_EMAILS = ['ianonavy@gmail.com'] EMAIL_USERNAME = 'noreply@ianonavy.com'
EMAIL_PASSWORD = 'S2PENjQbO6=cHgchw@CXs.bJ'
RECIPIENT_EMAILS = [
'ianonavy@gmail.com',
'dmurvihill@gmail.com',
'5038304363@tmomail.net'
]
ALERT_EMAIL_TEXT = """Hi, ALERT_EMAIL_TEXT = """Hi,
Your laundry is done. Or maybe your roomate's. I don't know. Your laundry is done. Or maybe your roomate's. I don't know.
@ -23,8 +27,6 @@ INTERVAL = 0.005 # seconds
WINDOW_SIZE = 1000 # intervals WINDOW_SIZE = 1000 # intervals
THRESHOLD = 0.025 # G's THRESHOLD = 0.025 # G's
MAX_EMAIL_FREQUENCY = 60 # seconds MAX_EMAIL_FREQUENCY = 60 # seconds
MAX_NOTIFICATION_FREQUENCY = 60 # seconds
CONFIG_FILE_PATH = '/home/pi/laundry-notifier/laundry_notifier/laundry_notifier.conf'
def average(s): def average(s):
@ -39,8 +41,8 @@ def stdev(s):
return math.sqrt(average(list(variance))) return math.sqrt(average(list(variance)))
def notify_user(username, password, recipient_email_address): def notify_user(recipient_email_address):
logging.info("Alerting " + recipient_email_address) print("Alerting " + recipient_email_address)
msg = MIMEText(ALERT_EMAIL_TEXT) msg = MIMEText(ALERT_EMAIL_TEXT)
@ -51,6 +53,8 @@ def notify_user(username, password, recipient_email_address):
msg['To'] = recipient_email_address msg['To'] = recipient_email_address
# Send the message via our own SMTP server. # Send the message via our own SMTP server.
username = EMAIL_USERNAME
password = EMAIL_PASSWORD
server = smtplib.SMTP('smtp.gmail.com:587') server = smtplib.SMTP('smtp.gmail.com:587')
server.starttls() server.starttls()
server.login(username, password) server.login(username, password)
@ -67,37 +71,21 @@ def enqueue(sliding_window, item):
def amplitude_stdev(sliding_window): def amplitude_stdev(sliding_window):
standard_deviations = {} standard_deviations = {}
for key in ('x', 'y', 'z'): for key in ('x', 'y', 'z'):
values = [measurement[key] for measurement in sliding_window] values = [instance[key] for instance in sliding_window]
standard_deviations[key] = stdev(values) standard_deviations[key] = stdev(values)
return standard_deviations return standard_deviations
def send_notifications(last_notification_sent_at, iftttkey): def send_emails(last_email_sent_at):
seconds_since_last_notification = \ print((datetime.now() - last_email_sent_at).seconds) # for debugging
(datetime.now() - last_notification_sent_at).seconds # limit frequency of emails
logging.info("Sending notification after %ds" % seconds_since_last_notification) if (datetime.now() - last_email_sent_at).seconds > MAX_EMAIL_FREQUENCY:
# limit frequency of notifications
if seconds_since_last_notification > MAX_NOTIFICATION_FREQUENCY:
[notify_user(email) for email in RECIPIENT_EMAILS] [notify_user(email) for email in RECIPIENT_EMAILS]
# Notify if this, then that
requests.get(
'https://maker.ifttt.com/trigger/laundry_done/with/key/%s'
% iftttkey)
return datetime.now() return datetime.now()
return last_notification_sent_at return last_email_sent_at
def main(): def main():
LOG_FORMAT = '%(asctime)-15s %(message)s'
logging.basicConfig(format=LOG_FORMAT)
logging.getLogger().setLevel(logging.INFO)
logging.info('Started laundry notifier')
config = configparser.ConfigParser()
config.read(CONFIG_FILE_PATH)
notifications_section = config['notifications']
iftttkey = notifications_section['ifttt_key']
email_username = notifications_section['email_username']
email_password = notifications_section['email_password']
with MMA8452Q() as accelerometer: with MMA8452Q() as accelerometer:
# Configure accelerometer # Configure accelerometer
accelerometer.standby() accelerometer.standby()
@ -109,27 +97,20 @@ def main():
sliding_window = [] sliding_window = []
dryer_state = 'off' dryer_state = 'off'
last_notification_sent_at = datetime(1970, 1, 1, 0, 0, 0) last_email_sent_at = datetime(1970, 1, 1, 0, 0, 0)
while True: while True:
g_values = accelerometer.get_xyz() g_values = accelerometer.get_xyz()
enqueue(sliding_window, g_values) enqueue(sliding_window, g_values)
sliding_stdev = amplitude_stdev(sliding_window) sliding_stdev = amplitude_stdev(sliding_window)
print(sliding_stdev, dryer_state, len(sliding_window))
# don't send emails right at the beginning
if g_values: if g_values:
if sliding_stdev['x'] < THRESHOLD: if sliding_stdev['x'] < THRESHOLD:
# Notify recipients on state transitions from 'on' to 'off'
if dryer_state == 'on': if dryer_state == 'on':
logging.info('Dryer turned off; sliding stdev is %f' % sliding_stdev['x']) last_email_sent_at = send_emails(last_email_sent_at)
last_notification_sent_at = send_notifications(
last_notification_sent_at,
email_username,
email_password,
iftttkey)
dryer_state = 'off' dryer_state = 'off'
else: else:
# Log state transitions from 'off' to 'on'
if dryer_state == 'off':
logging.info('Dryer turned on; sliding stdev is %f' % sliding_stdev['x'])
dryer_state = 'on' dryer_state = 'on'
time.sleep(INTERVAL) time.sleep(INTERVAL)