diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6f1c80f
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,2 @@
+venv/
+*__pycache__/
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000..15a15b2
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..4ccb8ac
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..6a1d28a
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..94a25f7
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/weatheralert.iml b/.idea/weatheralert.iml
new file mode 100644
index 0000000..e942587
--- /dev/null
+++ b/.idea/weatheralert.iml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
new file mode 100644
index 0000000..47da673
--- /dev/null
+++ b/.idea/workspace.xml
@@ -0,0 +1,401 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ forcast_hourly_url
+ lat
+ mb-3
+ 3
+
+
+ check_in_frequency
+ col-mb-3
+ 2
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1646850051322
+
+
+ 1646850051322
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/README.md b/README.md
index 0f278a8..4e331ac 100644
--- a/README.md
+++ b/README.md
@@ -50,3 +50,13 @@ This project is an assessment test for dev candidates. The scope of the project
4. The task will prove that you are able to code in python and self sufficient by reading online documentation. If you have a major design question which blocks you of completing the task, please send your question to our HR representative.
Good Luck!
+
+##Running the flask application
+1. Clone the branch using git clone.
+2. Make sure the python version is `Python 3.7.2`.
+2. Make sure you are in the weatheralert folder and execute below command:
+`pip install -r requirements.txt`
+3. Run `main.py` file.
+4. Open the url generated in the terminal.
+
+
diff --git a/app/__init__.py b/app/__init__.py
new file mode 100644
index 0000000..577f645
--- /dev/null
+++ b/app/__init__.py
@@ -0,0 +1,50 @@
+from flask import Flask, redirect
+from .setup import Config
+from app.fetch_data import extract_variables, get_data_from_noaa, send_alert
+from datetime import datetime
+from flask_sqlalchemy import SQLAlchemy
+from apscheduler.schedulers.background import BackgroundScheduler
+
+
+app = Flask(__name__)
+app.config.from_object(Config)
+print(app.config)
+db = SQLAlchemy(app)
+
+from app import routes, models
+
+from .models import ForecastModel
+
+db.create_all()
+
+
+def data_fetch():
+ print('running scheduler!!')
+ data_dic = extract_variables()
+ global timer
+ timer = data_dic['check_in_frequency']
+ timestamp = datetime.now()
+ long = data_dic['longitude']
+ lat = data_dic['latitude']
+ data = get_data_from_noaa(lat, long)
+ alert_generated = False
+ alert_id = None
+ for key, value in data.items():
+ if value > data_dic['threshold_value']:
+ hours = {'first_forecast': 1, 'second_forecast': 2,
+ 'third_forecast': 3}
+ alert_id = send_alert(hours[key], value)
+ if 'Error' not in alert_id:
+ alert_generated = True
+ break
+ rec = ForecastModel(**data, timestamp=timestamp, long=long, lat=lat, alert_generated=alert_generated, alert_id=alert_id)
+ db.session.add(rec)
+ db.session.commit()
+
+
+sched = BackgroundScheduler(daemon=True)
+timer = extract_variables()['check_in_frequency']
+sched.add_job(data_fetch, 'interval', seconds=int(timer))
+sched.start()
+
+
diff --git a/app/fetch_data.py b/app/fetch_data.py
new file mode 100644
index 0000000..0d70dde
--- /dev/null
+++ b/app/fetch_data.py
@@ -0,0 +1,55 @@
+import os
+import requests
+import xml.etree.ElementTree as ET
+
+dir_path = os.path.dirname(os.path.dirname(__file__))
+
+
+def extract_variables():
+ with open(os.path.join(dir_path, 'settings.txt')) as file:
+ lines = file.readlines()
+ lines = [line.split('=') for line in lines if '=' in line]
+ var_dict = {i[0].strip(): i[1].replace('\n', '').strip() for i in lines}
+ return var_dict
+
+def set_variables(dic):
+ content = []
+ for key, value in dic.items():
+ content.append('{} = {}\n'.format(key, value))
+ with open(os.path.join(dir_path, 'settings.txt'), "w") as file:
+ file.writelines(content)
+
+def get_data_from_noaa(long, lat):
+ # fetching the data from NOAA API
+ resp = requests.get(r'https://api.weather.gov/points/{},{}'.format(long, lat))
+ # selecting the URL for the forcast hourly
+ forcast_hourly_url = resp.json()['properties']['forecastHourly']
+ print(forcast_hourly_url)
+
+ headers = {
+ "accept": "application/vnd.noaa.dwml+xml",
+ 'Feature - Flag': 'forecast_temperature_qv'
+ }
+ resp = requests.get(forcast_hourly_url, headers=headers)
+ print(resp.status_code)
+ root = ET.fromstring(resp.content)
+ xpath = r"./data[@type='forecast']/parameters/temperature[2]/value"
+ temperature = root.findall(xpath)
+ data = [temperature[i].text for i in range(0, 3)]
+ forcast_data = {'first_forecast': data[0], 'second_forecast': data[1],
+ 'third_forecast': data[2]}
+ return forcast_data
+
+
+def send_alert(hour, temp):
+ data = {
+ "presetId": 2206,
+ "presetName": "Dev Candidate - Evacuate",
+ "text": "An EVACUATION ORDER has been issued. In {} hours temperature is expected to be {}F".format(hour, temp)
+ }
+ url = r'https://demo.alertus.com/alertusmw/services/rest/activation/preset'
+ resp = requests.post(url, auth=('devcandidate', 'gooWmJQe'), json=data)
+ if resp.status_code == 200:
+ return resp.content
+ else:
+ return 'Error in generating the alert'
diff --git a/app/models.py b/app/models.py
new file mode 100644
index 0000000..51757e0
--- /dev/null
+++ b/app/models.py
@@ -0,0 +1,17 @@
+from app import db
+
+
+class ForecastModel(db.Model):
+ id = db.Column(db.Integer, primary_key=True)
+ timestamp = db.Column(db.DateTime)
+ long = db.Column(db.Float)
+ lat = db.Column(db.Float)
+ first_forecast = db.Column(db.Integer)
+ second_forecast = db.Column(db.Integer)
+ third_forecast = db.Column(db.Integer)
+ alert_generated = db.Column(db.Boolean)
+ alert_id = db.Column(db.Integer)
+
+ def __repr__(self):
+ return 'timestamp <{}>'.format(self.timestamp)
+
diff --git a/app/routes.py b/app/routes.py
new file mode 100644
index 0000000..0fb2d2b
--- /dev/null
+++ b/app/routes.py
@@ -0,0 +1,31 @@
+from app import app
+from flask import render_template, request
+from .fetch_data import extract_variables,set_variables
+from .models import ForecastModel
+
+
+@app.route('/', methods=['GET', 'POST'])
+@app.route('/index', methods=['GET', 'POST'])
+def index():
+
+ if request.method == 'POST':
+ set_variables(request.form.to_dict())
+
+ var_data = extract_variables()
+ table = get_table()
+ frequency = int(var_data['check_in_frequency']) * 1000
+ print(frequency)
+ return render_template('index.html', data=var_data, table=table, frequency=frequency)
+
+
+@app.route('/get_table', methods=['GET', 'POST'])
+def get_table():
+ forecast_data = ForecastModel.query.order_by(ForecastModel.id.desc()).limit(10).all()
+ li = []
+ for data in forecast_data:
+ li.append({'timestamp': data.timestamp, 'first_forecast': data.first_forecast,
+ 'second_forecast': data.second_forecast, 'third_forecast': data.third_forecast,
+ 'id': data.id, 'long': data.long, 'lat': data.lat, 'alert_id': data.alert_id,
+ 'alert_generated': data.alert_generated})
+ rec = render_template('table.html', li=li)
+ return rec
diff --git a/app/setup.py b/app/setup.py
new file mode 100644
index 0000000..6aee3f0
--- /dev/null
+++ b/app/setup.py
@@ -0,0 +1,10 @@
+import os
+
+dir_path = os.path.dirname(os.path.dirname(__file__))
+
+
+class Config(object):
+ SECRET_KEY = os.environ.get('SECRET_KEY') or 'you-will-never-guess'
+ SQLALCHEMY_DATABASE_URI = os.environ.get('DATABASE_URL') or \
+ 'sqlite:///' + os.path.join(dir_path, 'data', 'app.db')
+ SQLALCHEMY_TRACK_MODIFICATIONS = False
diff --git a/app/templates/base.html b/app/templates/base.html
new file mode 100644
index 0000000..f624365
--- /dev/null
+++ b/app/templates/base.html
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+ Weather App
+
+
+
+
+
+ {% block container %}
+
+ {% endblock %}
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/templates/index.html b/app/templates/index.html
new file mode 100644
index 0000000..2bfbca2
--- /dev/null
+++ b/app/templates/index.html
@@ -0,0 +1,57 @@
+{% extends 'base.html' %}
+
+{% block container %}
+
+
+
+
Previous Records
+
+
+ {{ table|safe }}
+
+{% endblock %}
+
+
+{% block javascript %}
+ setInterval(updateTable, {{ frequency }})
+ function updateTable(){
+ console.log('Making ajax call');
+ console.log(" {{ url_for('get_table') }}");
+ $.ajax({
+ type : 'POST',
+ data: JSON.stringify({
+ 'get' : 'get_table'
+ }),
+ contentType: 'application/json; charset=utf-8',
+ url : "{{url_for('get_table')}}",
+ success: function(res) {
+ $('#previous_records').empty();
+ $('#previous_records').append(res);
+ }
+
+ });
+ }
+{% endblock %}
\ No newline at end of file
diff --git a/app/templates/table.html b/app/templates/table.html
new file mode 100644
index 0000000..c07177b
--- /dev/null
+++ b/app/templates/table.html
@@ -0,0 +1,28 @@
+
+
+
+ Time Stamp |
+ Latitude |
+ Longitude |
+ First Forecast |
+ First Forecast |
+ First Forecast |
+ Alert Generated |
+ Alert ID |
+
+
+
+ {% for rec in li %}
+
+ {{ rec['timestamp'] }} |
+ {{rec['lat']}} |
+ {{rec['long']}} |
+ {{rec['first_forecast']}} |
+ {{rec['second_forecast']}} |
+ {{rec['third_forecast']}} |
+ {{rec['alert_generated']}} |
+ {{rec['alert_id']}} |
+
+ {% endfor %}
+
+
\ No newline at end of file
diff --git a/data/app.db b/data/app.db
new file mode 100644
index 0000000..f2a1555
Binary files /dev/null and b/data/app.db differ
diff --git a/main.py b/main.py
new file mode 100644
index 0000000..209031b
--- /dev/null
+++ b/main.py
@@ -0,0 +1,8 @@
+from app import app
+
+
+
+
+if __name__ == '__main__':
+ app.run()
+
diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..3045b74
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,25 @@
+APScheduler==3.9.1
+backports.zoneinfo==0.2.1
+certifi==2021.10.8
+charset-normalizer==2.0.12
+click==8.0.4
+colorama==0.4.4
+Flask==2.0.3
+Flask-SQLAlchemy==2.5.1
+greenlet==1.1.2
+idna==3.3
+importlib-metadata==4.11.2
+itsdangerous==2.1.1
+Jinja2==3.0.3
+MarkupSafe==2.1.0
+pytz==2021.3
+pytz-deprecation-shim==0.1.0.post0
+requests==2.27.1
+six==1.16.0
+SQLAlchemy==1.4.32
+typing-extensions==4.1.1
+tzdata==2021.5
+tzlocal==4.1
+urllib3==1.26.8
+Werkzeug==2.0.3
+zipp==3.7.0
diff --git a/settings.txt b/settings.txt
index 1b8d204..4e25e30 100644
--- a/settings.txt
+++ b/settings.txt
@@ -1,7 +1,4 @@
-# Location Information
-latitude = 39.7456
longitude = -97.0892
-
-# Application Settings
-threshold_value = 80
+latitude = 39.7456
+threshold_value = 81
check_in_frequency = 30