Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial commit #3

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
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
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
venv/
*__pycache__/
4 changes: 4 additions & 0 deletions .idea/encodings.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

7 changes: 7 additions & 0 deletions .idea/misc.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions .idea/modules.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 6 additions & 0 deletions .idea/vcs.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions .idea/weatheralert.iml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

401 changes: 401 additions & 0 deletions .idea/workspace.xml

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.


50 changes: 50 additions & 0 deletions app/__init__.py
Original file line number Diff line number Diff line change
@@ -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()


55 changes: 55 additions & 0 deletions app/fetch_data.py
Original file line number Diff line number Diff line change
@@ -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'
17 changes: 17 additions & 0 deletions app/models.py
Original file line number Diff line number Diff line change
@@ -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)

31 changes: 31 additions & 0 deletions app/routes.py
Original file line number Diff line number Diff line change
@@ -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
10 changes: 10 additions & 0 deletions app/setup.py
Original file line number Diff line number Diff line change
@@ -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
41 changes: 41 additions & 0 deletions app/templates/base.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">

<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
<title>Weather App</title>
</head>
<body style="font-size:small">
<nav class="navbar navbar-dark bg-dark">
<div class="container-fluid">
<span class="navbar-brand mb-0 h1">Weather App</span>
</div>
</nav>

<div class="container">
{% block container %}

{% endblock %}
</div>
<!-- Optional JavaScript; choose one of the two! -->

<!-- Option 1: Bootstrap Bundle with Popper -->
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-ka7Sk0Gln4gmtz2MlQnikT1wXgYsOg+OMhuP+IlRH9sENBO0LRn5q+8nbTov4+1p" crossorigin="anonymous"></script>

<!-- Option 2: Separate Popper and Bootstrap JS -->
<!--
<script src="https://cdn.jsdelivr.net/npm/@popperjs/[email protected]/dist/umd/popper.min.js" integrity="sha384-7+zCNj/IqJ95wo16oMtfsKbZ9ccEh31eOz1HGyDuCQ6wgnyJNSYdrPa03rtR1zdB" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.min.js" integrity="sha384-QJHtvGhmr9XOIpI6YVutG+2QOK9T+ZnN4kzFN1RtK3zEFEIsxhlmWl5/YESvpZ13" crossorigin="anonymous"></script>
-->
<script>
{% block javascript %}

{% endblock %}
</script>
</body>
</html>
57 changes: 57 additions & 0 deletions app/templates/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
{% extends 'base.html' %}

{% block container %}

<form class="row" action="{{ url_for('index') }}", method="post">

<div class="col-sm-2">
<label for="long" class="form-label">Longitude</label>
<input type="text" class="form-control form-control-sm" name="longitude" id="long" value="{{data['longitude']}}">
</div>
<div class="col-sm-2">
<label for="lat" class="form-label">Latitude</label>
<input type="text" class="form-control form-control-sm" name="latitude" id="lat" value="{{data['latitude']}}" >
</div>
<div class="col-sm-3">
<label for="temp_threshold" class="form-label">Tempreature Threshold Value</label>
<input type="number" class="form-control form-control-sm" name="threshold_value" id="temp_threshold" value="{{data['threshold_value']}}">
</div>
<div class="col-sm-2">
<label for="check_in_frequency" class="form-label">Check in frequency</label>
<input type="number" class="form-control form-control-sm" name="check_in_frequency" id="check_in_frequency" value="{{data['check_in_frequency']}}">
</div>
<div class="col-sm-1" style="margin-top:20px">
<button type="submit" class="btn btn-primary">Update</button>
</div>
</div>

</form>
<div style="margin-top: 10vh; text-align: center">
<h6>Previous Records</h6>
</div>
<div id="previous_records">
{{ table|safe }}
</div>
{% 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 %}
28 changes: 28 additions & 0 deletions app/templates/table.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<table class="table">
<thead>
<tr>
<th scope="col">Time Stamp</th>
<th scope="col">Latitude</th>
<th scope="col">Longitude</th>
<th scope="col">First Forecast</th>
<th scope="col">First Forecast</th>
<th scope="col">First Forecast</th>
<th scope="col">Alert Generated</th>
<th scope="col">Alert ID</th>
</tr>
</thead>
<tbody>
{% for rec in li %}
<tr>
<th scope="row">{{ rec['timestamp'] }}</th>
<td>{{rec['lat']}}</td>
<td>{{rec['long']}}</td>
<td>{{rec['first_forecast']}}</td>
<td>{{rec['second_forecast']}}</td>
<td>{{rec['third_forecast']}}</td>
<td>{{rec['alert_generated']}}</td>
<td>{{rec['alert_id']}}</td>
</tr>
{% endfor %}
</tbody>
</table>
Binary file added data/app.db
Binary file not shown.
8 changes: 8 additions & 0 deletions main.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from app import app




if __name__ == '__main__':
app.run()

Loading