diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f6f9a9d --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea/ +venv/ +__pycache__/ diff --git a/app.py b/app.py index 09ca5b2..b077fa3 100644 --- a/app.py +++ b/app.py @@ -1,242 +1,242 @@ -from flask import Flask, render_template, request, flash, redirect -import datetime -import sendNotifications -from sqlalchemy import create_engine, Column, Integer, String, Date -from sqlalchemy.ext.declarative import declarative_base -from sqlalchemy.orm import sessionmaker -from flask_apscheduler import APScheduler - -# Set to True to simplify testing -TESTING = False -notificationHour = 10 -textSent = False -emailSent = False - -class Config: - SCHEDULER_API_ENABLED = True - SCHEDULER_TIMEZONE = 'US/Eastern' - -app = Flask(__name__) -app.config['SECRET_KEY'] = 'fa6166b0218186fb852429060105aca18e0f979240be8ebf' -app.config.from_object(Config()) - -scheduler = APScheduler() -scheduler.init_app(app) -# Needed below to access native APSchedule objects -sched = scheduler.scheduler - -Base = declarative_base() - - -class Dates(Base): - __tablename__ = 'Dates' - id = Column(Integer, primary_key=True, autoincrement=True) - dateTypeID = Column(Integer) - dateValue = Column(Date) - - -class DatesMetadata(Base): - __tablename__ = 'DatesMetadata' - id = Column(Integer, primary_key=True, autoincrement=True) - dateTypeID = Column(Integer) - DateTypeName = Column(String(50)) - - -class Settings(Base): - __tablename__ = 'Settings' - id = Column(Integer, primary_key=True, autoincrement=True) - settingType = Column(Integer) - settingValue = Column(String(50)) - - -class SettingsMetadata(Base): - __tablename__ = 'SettingsMetadata' - id = Column(Integer, primary_key=True, autoincrement=True) - settingTypeID = Column(Integer) - settingTypeName = Column(String(50)) - - -engine = create_engine('mysql+pymysql://hydro:pRnCWH/M)dujdifi@db.dandembinski.com:3306/Hydro') -Dates.__table__.create(bind=engine, checkfirst=True) -Settings.__table__.create(bind=engine, checkfirst=True) -DatesMetadata.__table__.create(bind=engine, checkfirst=True) -SettingsMetadata.__table__.create(bind=engine, checkfirst=True) - -Session = sessionmaker(bind=engine) - - -@scheduler.task('cron', id='send_notifications', hour=notificationHour) -def Checknotifications(): - session = Session() - global textSent - global emailSent - - nextFeed = session.query(Dates).filter_by(dateTypeID=3).first().dateValue - nextClean = session.query(Dates).filter_by(dateTypeID=5).first().dateValue - clean = False - today = datetime.date.today() - - if nextClean <= today or TESTING is True: - clean = True - else: - clean = False - # Check if notifications need to be sent out - if nextFeed <= today or TESTING is True: - # Check what notifications should be sent out grab the grab relevant contact info and pass it to the appropriate - # notification method - notifications = {'text': session.query(Settings).filter_by(settingType=1).first().settingValue, - 'email': session.query(Settings).filter_by(settingType=2).first().settingValue} - if notifications['text'] and textSent is False: - contact = session.query(Settings).filter_by(settingType=4).first().settingValue - sendNotifications.sendText(contact, clean) - textSent = True - if notifications['email'] and emailSent is False: - contact = session.query(Settings).filter_by(settingType=5).first().settingValue - sendNotifications.sendEmail(contact, clean) - print('sent any selected notifications') - # print(today) - # print(nextFeed) - if TESTING is True: - resetNotifcations() - else: - print('Not time to Send') - session.close() - - -@scheduler.task('cron', id='reset_notifications', hour=notificationHour+1) -def resetNotifcations(): - global textSent - global emailSent - - if textSent is True: - textSent = False - if emailSent is True: - emailSent = False - return - - -scheduler.start() - -# If in testing mode reschedule the notification check to run every minute -if TESTING is True: - sched.reschedule_job('send_notifications', trigger='cron', minute='*') - print('Sending notifications every minute') - - -@app.route('/', methods=('GET', 'POST')) -@app.route('/index.html', methods=('GET', 'POST')) -def index(): - session = Session() - - installCheck = session.query(Dates).first() is None - if installCheck is True: - # session.close() - return redirect('install.html') - - # Init the dates dict - dates = {'plant': '', 'last': '', 'next': '', 'freq': '', 'lastClean': '', 'nextClean': '', 'cleanFreq': ''} - alerts = {'text': False, 'email': False} - - # Get the feeding frequency and cleaning frequency set them to ints - dates['freq'] = int(session.query(Settings).filter_by(settingType=3).first().settingValue) - dates['cleanFreq'] = int(session.query(Settings).filter_by(settingType=6).first().settingValue) - - # If clicked the update button for dates, grab the new values and save them to the db. Then render the template - if request.method == 'POST': - dates['plant'] = request.form['plantDate'] - dates['last'] = request.form['lastDate'] - dates['next'] = datetime.datetime.strptime(dates['last'], '%Y-%m-%d') + datetime.timedelta(days=dates['freq']) - dates['lastClean'] = request.form['lastClean'] - dates['cleanFreq'] = datetime.datetime.strptime(dates['lastClean'], '%Y-%m-%d') + datetime.timedelta(days=dates['cleanFreq']) - session.query(Dates).filter_by(dateTypeID=1).update({Dates.dateValue: dates['plant']}) - session.query(Dates).filter_by(dateTypeID=2).update({Dates.dateValue: dates['last']}) - session.query(Dates).filter_by(dateTypeID=3).update({Dates.dateValue: dates['next']}) - session.query(Dates).filter_by(dateTypeID=4).update({Dates.dateValue: dates['lastClean']}) - session.query(Dates).filter_by(dateTypeID=5).update({Dates.dateValue: dates['cleanFreq']}) - - # grab text message alert box. Set 'True' if checked or null if unchecked - if request.form.get('AlertText'): - alerts['text'] = 'True' - else: - alerts['text'] = None - # grab email message alert box. Set 'True' if checked or null if unchecked - if request.form.get('AlertEmail'): - alerts['email'] = 'True' - else: - alerts['email'] = None - # Update the alert settings to the database - session.query(Settings).filter_by(settingType=1).update({Settings.settingValue: alerts['text']}) - session.query(Settings).filter_by(settingType=2).update({Settings.settingValue: alerts['email']}) - - session.commit() - # return render_template("index.html", plant=dates, alerts=alerts) - return redirect('index.html') - # If regular page load, grab all the dates from the db and render the template - else: - dates['plant'] = session.query(Dates).filter_by(dateTypeID=1).first().dateValue - dates['last'] = session.query(Dates).filter_by(dateTypeID=2).first().dateValue - dates['next'] = session.query(Dates).filter_by(dateTypeID=3).first().dateValue - dates['lastClean'] = session.query(Dates).filter_by(dateTypeID=4).first().dateValue - dates['nextClean'] = session.query(Dates).filter_by(dateTypeID=5).first().dateValue - - alerts['text'] = session.query(Settings).filter_by(settingType=1).first().settingValue - alerts['email'] = session.query(Settings).filter_by(settingType=2).first().settingValue - - return render_template("index.html", plant=dates, alerts=alerts) - - -@app.route('/updateFeed') -def updateFeed(): - session = Session() - - dates = {'plant': '', 'last': '', 'next': '', 'freq': ''} - dates['freq'] = int(session.query(Settings).filter_by(settingType=3).first().settingValue) - dates['last'] = datetime.date.today() - dates['next'] = dates['last'] + datetime.timedelta(days=dates['freq']) - session.query(Dates).filter_by(dateTypeID=2).update({Dates.dateValue: dates['last']}) - session.query(Dates).filter_by(dateTypeID=3).update({Dates.dateValue: dates['next']}) - - session.commit() - session.close() - return redirect('/index.html') - - -@app.route('/install.html') -def install(): - session = Session() - - populateDate = datetime.date.today() - - # Populate Dates Table - session.add(Dates(dateTypeID=1, dateValue=populateDate)) - session.add(Dates(dateTypeID=2, dateValue=populateDate)) - session.add(Dates(dateTypeID=3, dateValue=populateDate)) - - # Populate DatesMetadata - session.add(DatesMetadata(dateTypeID=1, DateTypeName='Plant Date')) - session.add(DatesMetadata(dateTypeID=2, DateTypeName='Last Feeding Date')) - session.add(DatesMetadata(dateTypeID=3, DateTypeName='Next Feeding Date')) - - # Populate Settings - session.add(Settings(settingType=1, settingValue='False')) - session.add(Settings(settingType=2, settingValue='False')) - session.add(Settings(settingType=3, settingValue='14')) - session.add(Settings(settingType=4, settingValue=None)) - session.add(Settings(settingType=5, settingValue=None)) - session.add(Settings(settingType=6, settingValue='28')) - - # Populate SettingsMetadata - session.add(SettingsMetadata(settingTypeID=1, settingTypeName='Text')) - session.add(SettingsMetadata(settingTypeID=2, settingTypeName='Email')) - session.add(SettingsMetadata(settingTypeID=3, settingTypeName='Feeding Frequency')) - session.add(SettingsMetadata(settingTypeID=4, settingTypeName='Alert Phone Number')) - session.add(SettingsMetadata(settingTypeID=5, settingTypeName='Alert Email')) - session.add(SettingsMetadata(settingTypeID=6, settingTypeName='Cleaning Frequency')) - - session.commit() - - return redirect('index.html') - - -if __name__ == '__main__': - serve(app, host='0.0.0.0', port=8000) +from flask import Flask, render_template, request, flash, redirect +import datetime +import sendNotifications +from sqlalchemy import create_engine, Column, Integer, String, Date +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import sessionmaker +from flask_apscheduler import APScheduler + +# Set to True to simplify testing +TESTING = False +notificationHour = 10 +textSent = False +emailSent = False + +class Config: + SCHEDULER_API_ENABLED = True + SCHEDULER_TIMEZONE = 'US/Eastern' + +app = Flask(__name__) +app.config['SECRET_KEY'] = 'fa6166b0218186fb852429060105aca18e0f979240be8ebf' +app.config.from_object(Config()) + +scheduler = APScheduler() +scheduler.init_app(app) +# Needed below to access native APSchedule objects +sched = scheduler.scheduler + +Base = declarative_base() + + +class Dates(Base): + __tablename__ = 'Dates' + id = Column(Integer, primary_key=True, autoincrement=True) + dateTypeID = Column(Integer) + dateValue = Column(Date) + + +class DatesMetadata(Base): + __tablename__ = 'DatesMetadata' + id = Column(Integer, primary_key=True, autoincrement=True) + dateTypeID = Column(Integer) + DateTypeName = Column(String(50)) + + +class Settings(Base): + __tablename__ = 'Settings' + id = Column(Integer, primary_key=True, autoincrement=True) + settingType = Column(Integer) + settingValue = Column(String(50)) + + +class SettingsMetadata(Base): + __tablename__ = 'SettingsMetadata' + id = Column(Integer, primary_key=True, autoincrement=True) + settingTypeID = Column(Integer) + settingTypeName = Column(String(50)) + + +engine = create_engine('mysql+pymysql://hydro:pRnCWH/M)dujdifi@db.dandembinski.com:3306/Hydro') +Dates.__table__.create(bind=engine, checkfirst=True) +Settings.__table__.create(bind=engine, checkfirst=True) +DatesMetadata.__table__.create(bind=engine, checkfirst=True) +SettingsMetadata.__table__.create(bind=engine, checkfirst=True) + +Session = sessionmaker(bind=engine) + + +@scheduler.task('cron', id='send_notifications', hour=notificationHour) +def Checknotifications(): + session = Session() + global textSent + global emailSent + + nextFeed = session.query(Dates).filter_by(dateTypeID=3).first().dateValue + nextClean = session.query(Dates).filter_by(dateTypeID=5).first().dateValue + clean = False + today = datetime.date.today() + + if nextClean <= today or TESTING is True: + clean = True + else: + clean = False + # Check if notifications need to be sent out + if nextFeed <= today or TESTING is True: + # Check what notifications should be sent out grab the grab relevant contact info and pass it to the appropriate + # notification method + notifications = {'text': session.query(Settings).filter_by(settingType=1).first().settingValue, + 'email': session.query(Settings).filter_by(settingType=2).first().settingValue} + if notifications['text'] and textSent is False: + contact = session.query(Settings).filter_by(settingType=4).first().settingValue + sendNotifications.sendText(contact, clean) + textSent = True + if notifications['email'] and emailSent is False: + contact = session.query(Settings).filter_by(settingType=5).first().settingValue + sendNotifications.sendEmail(contact, clean) + print('sent any selected notifications') + # print(today) + # print(nextFeed) + if TESTING is True: + resetNotifcations() + else: + print('Not time to Send') + session.close() + + +@scheduler.task('cron', id='reset_notifications', hour=notificationHour+1) +def resetNotifcations(): + global textSent + global emailSent + + if textSent is True: + textSent = False + if emailSent is True: + emailSent = False + return + + +scheduler.start() + +# If in testing mode reschedule the notification check to run every minute +if TESTING is True: + sched.reschedule_job('send_notifications', trigger='cron', minute='*') + print('Sending notifications every minute') + + +@app.route('/', methods=('GET', 'POST')) +@app.route('/index.html', methods=('GET', 'POST')) +def index(): + session = Session() + + installCheck = session.query(Dates).first() is None + if installCheck is True: + # session.close() + return redirect('install.html') + + # Init the dates dict + dates = {'plant': '', 'last': '', 'next': '', 'freq': '', 'lastClean': '', 'nextClean': '', 'cleanFreq': ''} + alerts = {'text': False, 'email': False} + + # Get the feeding frequency and cleaning frequency set them to ints + dates['freq'] = int(session.query(Settings).filter_by(settingType=3).first().settingValue) + dates['cleanFreq'] = int(session.query(Settings).filter_by(settingType=6).first().settingValue) + + # If clicked the update button for dates, grab the new values and save them to the db. Then render the template + if request.method == 'POST': + dates['plant'] = request.form['plantDate'] + dates['last'] = request.form['lastDate'] + dates['next'] = datetime.datetime.strptime(dates['last'], '%Y-%m-%d') + datetime.timedelta(days=dates['freq']) + dates['lastClean'] = request.form['lastClean'] + dates['cleanFreq'] = datetime.datetime.strptime(dates['lastClean'], '%Y-%m-%d') + datetime.timedelta(days=dates['cleanFreq']) + session.query(Dates).filter_by(dateTypeID=1).update({Dates.dateValue: dates['plant']}) + session.query(Dates).filter_by(dateTypeID=2).update({Dates.dateValue: dates['last']}) + session.query(Dates).filter_by(dateTypeID=3).update({Dates.dateValue: dates['next']}) + session.query(Dates).filter_by(dateTypeID=4).update({Dates.dateValue: dates['lastClean']}) + session.query(Dates).filter_by(dateTypeID=5).update({Dates.dateValue: dates['cleanFreq']}) + + # grab text message alert box. Set 'True' if checked or null if unchecked + if request.form.get('AlertText'): + alerts['text'] = 'True' + else: + alerts['text'] = None + # grab email message alert box. Set 'True' if checked or null if unchecked + if request.form.get('AlertEmail'): + alerts['email'] = 'True' + else: + alerts['email'] = None + # Update the alert settings to the database + session.query(Settings).filter_by(settingType=1).update({Settings.settingValue: alerts['text']}) + session.query(Settings).filter_by(settingType=2).update({Settings.settingValue: alerts['email']}) + + session.commit() + # return render_template("index.html", plant=dates, alerts=alerts) + return redirect('index.html') + # If regular page load, grab all the dates from the db and render the template + else: + dates['plant'] = session.query(Dates).filter_by(dateTypeID=1).first().dateValue + dates['last'] = session.query(Dates).filter_by(dateTypeID=2).first().dateValue + dates['next'] = session.query(Dates).filter_by(dateTypeID=3).first().dateValue + dates['lastClean'] = session.query(Dates).filter_by(dateTypeID=4).first().dateValue + dates['nextClean'] = session.query(Dates).filter_by(dateTypeID=5).first().dateValue + + alerts['text'] = session.query(Settings).filter_by(settingType=1).first().settingValue + alerts['email'] = session.query(Settings).filter_by(settingType=2).first().settingValue + + return render_template("index.html", plant=dates, alerts=alerts) + + +@app.route('/updateFeed') +def updateFeed(): + session = Session() + + dates = {'plant': '', 'last': '', 'next': '', 'freq': ''} + dates['freq'] = int(session.query(Settings).filter_by(settingType=3).first().settingValue) + dates['last'] = datetime.date.today() + dates['next'] = dates['last'] + datetime.timedelta(days=dates['freq']) + session.query(Dates).filter_by(dateTypeID=2).update({Dates.dateValue: dates['last']}) + session.query(Dates).filter_by(dateTypeID=3).update({Dates.dateValue: dates['next']}) + + session.commit() + session.close() + return redirect('/index.html') + + +@app.route('/install.html') +def install(): + session = Session() + + populateDate = datetime.date.today() + + # Populate Dates Table + session.add(Dates(dateTypeID=1, dateValue=populateDate)) + session.add(Dates(dateTypeID=2, dateValue=populateDate)) + session.add(Dates(dateTypeID=3, dateValue=populateDate)) + + # Populate DatesMetadata + session.add(DatesMetadata(dateTypeID=1, DateTypeName='Plant Date')) + session.add(DatesMetadata(dateTypeID=2, DateTypeName='Last Feeding Date')) + session.add(DatesMetadata(dateTypeID=3, DateTypeName='Next Feeding Date')) + + # Populate Settings + session.add(Settings(settingType=1, settingValue='False')) + session.add(Settings(settingType=2, settingValue='False')) + session.add(Settings(settingType=3, settingValue='14')) + session.add(Settings(settingType=4, settingValue=None)) + session.add(Settings(settingType=5, settingValue=None)) + session.add(Settings(settingType=6, settingValue='28')) + + # Populate SettingsMetadata + session.add(SettingsMetadata(settingTypeID=1, settingTypeName='Text')) + session.add(SettingsMetadata(settingTypeID=2, settingTypeName='Email')) + session.add(SettingsMetadata(settingTypeID=3, settingTypeName='Feeding Frequency')) + session.add(SettingsMetadata(settingTypeID=4, settingTypeName='Alert Phone Number')) + session.add(SettingsMetadata(settingTypeID=5, settingTypeName='Alert Email')) + session.add(SettingsMetadata(settingTypeID=6, settingTypeName='Cleaning Frequency')) + + session.commit() + + return redirect('index.html') + + +if __name__ == '__main__': + serve(app, host='0.0.0.0', port=8000) diff --git a/requirements.txt b/requirements.txt index 5533aa7..52c83e2 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,26 +1,26 @@ -APScheduler==3.8.1 -certifi==2021.10.8 -charset-normalizer==2.0.11 -click==8.0.3 -colorama==0.4.4 -Flask==2.0.2 -Flask-APScheduler==1.12.3 -greenlet==1.1.2 -gunicorn==20.1.0 -idna==3.3 -itsdangerous==2.0.1 -Jinja2==3.0.3 -MarkupSafe==2.0.1 -PyJWT==2.3.0 -PyMySQL==1.0.2 -python-dateutil==2.8.2 -pytz==2021.3 -pytz-deprecation-shim==0.1.0.post0 -requests==2.27.1 -six==1.16.0 -SQLAlchemy==1.4.30 -twilio==7.6.0 -tzdata==2021.5 -tzlocal==4.1 -urllib3==1.26.8 -Werkzeug==2.0.2 +APScheduler==3.8.1 +certifi==2021.10.8 +charset-normalizer==2.0.11 +click==8.0.3 +colorama==0.4.4 +Flask==2.0.2 +Flask-APScheduler==1.12.3 +greenlet==1.1.2 +gunicorn==20.1.0 +idna==3.3 +itsdangerous==2.0.1 +Jinja2==3.0.3 +MarkupSafe==2.0.1 +PyJWT==2.3.0 +PyMySQL==1.0.2 +python-dateutil==2.8.2 +pytz==2021.3 +pytz-deprecation-shim==0.1.0.post0 +requests==2.27.1 +six==1.16.0 +SQLAlchemy==1.4.30 +twilio==7.6.0 +tzdata==2021.5 +tzlocal==4.1 +urllib3==1.26.8 +Werkzeug==2.0.2 diff --git a/sendNotifications.py b/sendNotifications.py index cfc119f..8fb058a 100644 --- a/sendNotifications.py +++ b/sendNotifications.py @@ -1,59 +1,59 @@ -from twilio.rest import Client -from smtplib import SMTP -from email.mime.multipart import MIMEMultipart -from email.mime.text import MIMEText -from email.mime.base import MIMEBase - -# Twilio Account Setup -account_sid = 'AC051785f6dd5a93184641d01103eb8cd4' -auth_token = 'd40c831e56785afaa9294fd3c5a88e6e' -client = Client(account_sid, auth_token) - -# Email Account Setup -smtp_server = 'in-v3.mailjet.com' -smtp_port = 587 - - -def sendText(contact, clean): - - if clean is True: - cleanMsg = 'Feed the Hydroponics. It also needs to be cleaned today' - else: - cleanMsg = 'Feed the Hydroponics.' - - message = client.messages.create( - messaging_service_sid='MG864145600a43493122488250262ccbc9', - body=cleanMsg, - to=contact - ) - return - - -def sendEmail(contact, clean): - - from_addr = 'Hydro@dandembinski.com' - - smtp = SMTP() - smtp.connect(smtp_server, smtp_port) - smtp.login('bef546c3019739fff8a2dbbfc26ec74a', 'dbe2b63a3f1fa5e4f00217c2784a8055') - - if clean is True: - cleanMsg = 'Feed the Hydroponics. It also needs to be cleaned today' - else: - cleanMsg = 'Feed the Hydroponics.' - - bodyHTML = MIMEText(cleanMsg, "html") - - msg = MIMEMultipart() - msg['Subject'] = 'Feed Hydroponics' - msg['To'] = contact - msg['From'] = from_addr - - msg.add_header('Content-Type', 'text/html') - msg.attach(bodyHTML) - - try: - smtp.send_message(msg) - except Exception as e: - print(e) - return +from twilio.rest import Client +from smtplib import SMTP +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText +from email.mime.base import MIMEBase + +# Twilio Account Setup +account_sid = 'AC051785f6dd5a93184641d01103eb8cd4' +auth_token = 'd40c831e56785afaa9294fd3c5a88e6e' +client = Client(account_sid, auth_token) + +# Email Account Setup +smtp_server = 'in-v3.mailjet.com' +smtp_port = 587 + + +def sendText(contact, clean): + + if clean is True: + cleanMsg = 'Feed the Hydroponics. It also needs to be cleaned today' + else: + cleanMsg = 'Feed the Hydroponics.' + + message = client.messages.create( + messaging_service_sid='MG864145600a43493122488250262ccbc9', + body=cleanMsg, + to=contact + ) + return + + +def sendEmail(contact, clean): + + from_addr = 'Hydro@dandembinski.com' + + smtp = SMTP() + smtp.connect(smtp_server, smtp_port) + smtp.login('bef546c3019739fff8a2dbbfc26ec74a', 'dbe2b63a3f1fa5e4f00217c2784a8055') + + if clean is True: + cleanMsg = 'Feed the Hydroponics. It also needs to be cleaned today' + else: + cleanMsg = 'Feed the Hydroponics.' + + bodyHTML = MIMEText(cleanMsg, "html") + + msg = MIMEMultipart() + msg['Subject'] = 'Feed Hydroponics' + msg['To'] = contact + msg['From'] = from_addr + + msg.add_header('Content-Type', 'text/html') + msg.attach(bodyHTML) + + try: + smtp.send_message(msg) + except Exception as e: + print(e) + return diff --git a/static/scripts.js b/static/scripts.js index a8fa4e3..7ca3b01 100644 --- a/static/scripts.js +++ b/static/scripts.js @@ -1,3 +1,3 @@ -function updateFeed() { - fetch('/updateFeed') +function updateFeed() { + fetch('/updateFeed') } \ No newline at end of file diff --git a/templates/base.html b/templates/base.html index 7f09348..eeb885e 100644 --- a/templates/base.html +++ b/templates/base.html @@ -1,20 +1,20 @@ - - - - Hydro - - - -
Hydro: home
-
- {% with messages = get_flashed_messages() %} - {% if messages %} - {% for message in messages %} - {{ message }} - {% endfor %} - {% endif %} - {% endwith %} -
- {% block content %}{% endblock %} - + + + + Hydro + + + +
Hydro: home
+
+ {% with messages = get_flashed_messages() %} + {% if messages %} + {% for message in messages %} + {{ message }} + {% endfor %} + {% endif %} + {% endwith %} +
+ {% block content %}{% endblock %} + \ No newline at end of file diff --git a/templates/index.html b/templates/index.html index eadbc28..8901b71 100644 --- a/templates/index.html +++ b/templates/index.html @@ -1,33 +1,33 @@ -{% extends "base.html" %} -{% block content %} -

Information

-
-

Feeding Information

- - -
- - -
- - Next Feed Date: {{ plant.next }} -
- Feed Frequency: {{ plant.freq }} days -

Cleaning Information

- - -
- Next Clean Date: {{ plant.nextClean }} -
- Cleaning Frequency: {{ plant.cleanFreq }} days -

Alerts

- - - -
- -
- - +{% extends "base.html" %} +{% block content %} +

Information

+
+

Feeding Information

+ + +
+ + +
+ + Next Feed Date: {{ plant.next }} +
+ Feed Frequency: {{ plant.freq }} days +

Cleaning Information

+ + +
+ Next Clean Date: {{ plant.nextClean }} +
+ Cleaning Frequency: {{ plant.cleanFreq }} days +

Alerts

+ + + +
+ +
+ + {% endblock %} \ No newline at end of file