Skip to content

Instantly share code, notes, and snippets.

@WxBDM
Created March 18, 2023 01:50
Show Gist options
  • Save WxBDM/82869afd9eeccbe00e9b8d023453dc0c to your computer and use it in GitHub Desktop.
Save WxBDM/82869afd9eeccbe00e9b8d023453dc0c to your computer and use it in GitHub Desktop.
Make a request from the National Weather Service API. This uses a flask server to make the request and returns a few weather parameters for a given station (currently KJFK). This also comes coupled together with a front-end.
<!DOCTYPE html>
<html>
<head>
<title>Weather Data</title>
<link rel="stylesheet" href="static/style.css">
<script src="static/weather.js"></script>
</head>
<body>
<h1>Current Weather for <span class="station"></span></h1>
<p>Temperature: <span class="temperature"></span></p>
<p>Wind Speed: <span class="wind-speed"></span></p>
<p>Pressure: <span class="pressure"></span></p>
<h2>Weather Data History</h2>
<table class="weather-data-history">
<thead>
<tr>
<th>Date</th>
<th>Temperature</th>
<th>Wind Speed</th>
<th>Pressure</th>
</tr>
</thead>
<tbody>
</tbody>
</table>
</body>
</html>
import threading
from flask import Flask, jsonify, make_response
import logging
import aiohttp
import asyncio
from datetime import datetime
import logging.handlers
logging.basicConfig(level=logging.INFO)
# == IMPORTANT==
# The css, javascript, and html file must be put into
# the static/ directory. Your structure should look like:
# folder/
# ├── server.py
# └── static/
# ├── index.html
# ├── style.css
# └── weather.js
# ===============
# === modify the following, as they're required by the api, otherwise a 403 forbidden error will happen.
application_name = "app_name"
your_email = "your_email"
station = 'KJFK'
# ====
API_ENDPOINT = f'https://api.weather.gov/stations/{station}/observations/latest'
app = Flask(__name__)
weather_data = {}
async def get_weather_data():
global weather_data
headers = {'User-Agent': application_name + ", " + your_email}
async with aiohttp.ClientSession() as session:
try:
async with session.get(API_ENDPOINT, headers=headers) as response:
response.raise_for_status()
data = await response.json()
temperature = data['properties']['temperature']['value']
wind_speed = data['properties']['windSpeed']['value']
pressure = data['properties']['barometricPressure']['value']
# etc. - extract any other weather data you need
# Update the weather data
weather_data.update({
'temperature': temperature,
'wind_speed': wind_speed,
'pressure' : pressure,
'station' : station
})
# Log the weather data
logging.info(f"{datetime.now()}: Temperature: {temperature}°C, Wind Speed: {wind_speed} mph")
except aiohttp.ClientError as err:
logging.error(f"{datetime.now()}: Error occurred during API request: {err}")
async def main():
while True:
await get_weather_data()
await asyncio.sleep(60) # wait for 60 seconds
def start_loop(loop):
asyncio.set_event_loop(loop)
loop.create_task(main())
try:
loop.run_forever()
finally:
loop.close()
def configure_logging():
logger = logging.getLogger(__name__)
logger.setLevel(logging.INFO)
handler = logging.handlers.RotatingFileHandler('logger.log', maxBytes=100000, backupCount=1)
formatter = logging.Formatter('%(asctime)s - %(levelname)s - %(message)s')
handler.setFormatter(formatter)
logger.addHandler(handler)
@app.route('/')
def index():
return app.send_static_file('index.html')
@app.route('/api/weather', methods=['GET'])
def get_latest_weather():
return jsonify(weather_data)
if __name__ == '__main__':
configure_logging()
logging.info("Starting the server.")
loop = asyncio.new_event_loop()
t = threading.Thread(target=start_loop, args=(loop,))
t.start()
app.run()
body {
font-family: Arial, sans-serif;
margin: 1;
}
.container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
h1 {
text-align: center;
font-size: 2rem;
margin-bottom: 20px;
}
.weather-data {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 20px;
}
.weather-data .weather-label {
font-weight: bold;
}
.weather-data .weather-value {
font-size: 1.5rem;
}
.weather-data-history {
width: 100%;
border-collapse: collapse;
margin-bottom: 20px;
}
.weather-data-history th {
font-weight: bold;
padding: 10px;
text-align: left;
border-bottom: 2px solid #ccc;
}
.weather-data-history td {
padding: 10px;
border-bottom: 1px solid #ccc;
}
.temperature {
color: #ff8c00;
}
.wind-speed {
color: #0000ff;
}
.pressure {
color: #008000;
}
.station {
font-size: 1.5rem;
text-align: center;
margin-bottom: 20px;
}
const WEATHER_DATA_URL = '/api/weather';
// Function to fetch the latest weather data and update the display
async function updateWeatherData() {
const response = await fetch(WEATHER_DATA_URL);
const weatherData = await response.json();
// Update the current weather display
const currentTempElem = document.querySelector('.temperature');
currentTempElem.textContent = `${weatherData.temperature} °F`;
const currentWindElem = document.querySelector('.wind-speed');
currentWindElem.textContent = `${weatherData.wind_speed} mph`;
const currentPressureElem = document.querySelector('.pressure');
currentPressureElem.textContent = `${weatherData.pressure} inHg`;
// Update the station name
const stationElem = document.querySelector('.station');
stationElem.textContent = weatherData.station;
// Update the weather data history table
const historyTableBody = document.querySelector('.weather-data-history tbody');
const newRow = historyTableBody.insertRow(0);
const dateCell = newRow.insertCell(0);
const tempCell = newRow.insertCell(1);
const windCell = newRow.insertCell(2);
const pressureCell = newRow.insertCell(3);
const date = new Date();
dateCell.textContent = `${date.toLocaleDateString()} ${date.toLocaleTimeString()}`;
tempCell.textContent = `${weatherData.temperature} °F`;
windCell.textContent = `${weatherData.wind_speed} mph`;
pressureCell.textContent = `${weatherData.pressure} inHg`;
}
// Function to update the weather data every minute
async function updateWeatherDataLoop() {
await updateWeatherData();
setTimeout(updateWeatherDataLoop, 60000); // update every 60 seconds
}
// Call the updateWeatherDataLoop function to start updating the weather data
updateWeatherDataLoop();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment