diff --git a/feeder/README.md b/feeder/README.md index 15e799b..b78481f 100644 --- a/feeder/README.md +++ b/feeder/README.md @@ -4,7 +4,8 @@ This is an MQTT sensor to send NOAA space weather data to Home Assistant. Fetchi 1. Create an account at 2. `pip install -r requirements.txt` -3. `sudo apt install p7zip-full` +3. `sudo apt install p7zip-full redis-server` +4. `sudo systemctl enable --now redis-server` ### Google Chrome diff --git a/feeder/global-image.py b/feeder/global-image.py index 6cd3c59..f62c338 100644 --- a/feeder/global-image.py +++ b/feeder/global-image.py @@ -1,10 +1,11 @@ import io import logging import pickle -import sys +import time from datetime import datetime from typing import List +import schedule from PIL import Image from redis import Redis @@ -17,30 +18,40 @@ LAT_RANGE_MAX = 90 LON_RANGE_MIN = -180 LON_RANGE_MAX = 180 -redis = Redis(host='localhost', port=6379, db=0) -utc_hr = datetime.utcnow().hour -logging.info(f'Generating plot for hour {utc_hr}') +def main(): + redis = Redis(host='localhost', port=6379, db=0) -ionex_data: List = pickle.loads(redis.get('tecmap_data')) -if ionex_data is None: - logging.critical('Redis has not been populated yet. Is cache.py running?') - sys.exit(1) + while True: + utc_hr = datetime.utcnow().hour + logging.info(f'Generating plot for hour {utc_hr}') -for tecmap, epoch in ionex_data: - if epoch.hour == utc_hr: - plt = plot_tec_map(tecmap, [float(LON_RANGE_MIN), float(LON_RANGE_MAX)], [float(LAT_RANGE_MIN), float(LAT_RANGE_MAX)])[1] + ionex_data: List = pickle.loads(redis.get('tecmap_data')) + while ionex_data is None: + logging.warning('Redis has not been populated yet. Is cache.py running? Sleeping 10s...') + time.sleep(10) - buf = io.BytesIO() - plt.savefig(buf, format='png', bbox_inches='tight', pad_inches=0, dpi=110) - plt.close() - del plt + for tecmap, epoch in ionex_data: + if epoch.hour == utc_hr: + plt = plot_tec_map(tecmap, [float(LON_RANGE_MIN), float(LON_RANGE_MAX)], [float(LAT_RANGE_MIN), float(LAT_RANGE_MAX)], timestamp=epoch)[1] - buf.seek(0) - img = Image.open(buf) - # img = img.resize((img.size[0], 500), Image.LANCZOS) - buf = io.BytesIO() - img.save(buf, format='PNG') + buf = io.BytesIO() + plt.savefig(buf, format='png', bbox_inches='tight', pad_inches=0, dpi=110) + plt.close() + del plt - redis.set('global_map', buf.getvalue()) - buf.close() + buf.seek(0) + img = Image.open(buf) + buf = io.BytesIO() + img.save(buf, format='PNG') + + redis.set('global_map', buf.getvalue()) + buf.close() + + +if __name__ == '__main__': + main() + schedule.every().hour.at(":00").do(main) + while True: + schedule.run_pending() + time.sleep(1) diff --git a/feeder/lib/tecmap.py b/feeder/lib/tecmap.py index 67c595a..ad228b2 100644 --- a/feeder/lib/tecmap.py +++ b/feeder/lib/tecmap.py @@ -32,7 +32,7 @@ def get_tecmaps(ionex: str): yield parse_map(tecmap), epoch -def plot_tec_map(tecmap, lon_range: list, lat_range: list): +def plot_tec_map(tecmap, lon_range: list, lat_range: list, timestamp: datetime = None): proj = ccrs.PlateCarree() f, ax = plt.subplots(1, 1, subplot_kw=dict(projection=proj)) @@ -54,7 +54,8 @@ def plot_tec_map(tecmap, lon_range: list, lat_range: list): # Make graph pretty ax.coastlines() - plt.title(datetime.now().strftime('%H:%M %d-%m-%Y'), fontsize=12, y=1.04) + if timestamp: + plt.title(timestamp.strftime('%H:%M %d-%m-%Y'), fontsize=12, y=1.04) plt.suptitle('Vertical Total Electron Count', fontsize=16, y=0.87) divider = make_axes_locatable(ax) ax_cb = divider.new_horizontal(size='5%', pad=0.1, axes_class=plt.Axes) diff --git a/feeder/mqtt.py b/feeder/mqtt.py index c8428d5..3dc1b41 100644 --- a/feeder/mqtt.py +++ b/feeder/mqtt.py @@ -3,7 +3,6 @@ import os import pickle import sys import time -import traceback from datetime import datetime from typing import List @@ -61,27 +60,28 @@ def publish(topic: str, msg): def main(): - try: - redis = Redis(host='localhost', port=6379, db=0) + redis = Redis(host='localhost', port=6379, db=0) - while True: - utc_hr = datetime.utcnow().hour - logging.info('Fetching latest IONEX data') - logging.info(f'Using hour {utc_hr}') - ionex_data: List = pickle.loads(redis.get('tecmap_data')) - avg_tec = None - for tecmap, epoch in ionex_data: - parsed_dt = parse_ionex_datetime(epoch) - if parsed_dt.hour == utc_hr: - avg_tec = np.mean(plot_tec_map(tecmap, [float(LON_RANGE_MIN), float(LON_RANGE_MAX)], [float(LAT_RANGE_MIN), float(LAT_RANGE_MAX)])[0]) - logging.info(f'Data timestamp: {parsed_dt.isoformat()}') - break - latest = round(avg_tec, 1) - publish('vtec', latest) - time.sleep(60) - except: - logging.critical(traceback.format_exc()) - sys.exit(1) + while True: + utc_hr = datetime.utcnow().hour + logging.info('Fetching latest IONEX data') + logging.info(f'Using hour {utc_hr}') + + ionex_data: List = pickle.loads(redis.get('tecmap_data')) + while ionex_data is None: + logging.warning('Redis has not been populated yet. Is cache.py running? Sleeping 10s...') + time.sleep(10) + + avg_tec = None + for tecmap, epoch in ionex_data: + parsed_dt = parse_ionex_datetime(epoch) + if parsed_dt.hour == utc_hr: + avg_tec = np.mean(plot_tec_map(tecmap, [float(LON_RANGE_MIN), float(LON_RANGE_MAX)], [float(LAT_RANGE_MIN), float(LAT_RANGE_MAX)])[0]) + logging.info(f'Data timestamp: {parsed_dt.isoformat()}') + break + latest = round(avg_tec, 1) + publish('vtec', latest) + time.sleep(60) if __name__ == '__main__': diff --git a/feeder/requirements.txt b/feeder/requirements.txt index 6717783..d976678 100644 --- a/feeder/requirements.txt +++ b/feeder/requirements.txt @@ -8,4 +8,5 @@ numpy==2.0.1 redis==5.0.8 async-timeout==4.0.3 Pillow -flask==3.0.3 \ No newline at end of file +flask==3.0.3 +schedule==1.2.2 \ No newline at end of file diff --git a/feeder/server.py b/feeder/server.py index cbe197a..c7f5941 100644 --- a/feeder/server.py +++ b/feeder/server.py @@ -11,7 +11,7 @@ redis_client = redis.Redis(host='localhost', port=6379) def serve_global_map(): global_map_data = redis_client.get('global_map') if global_map_data is None: - return "No global map available", 404 + return "No global map available", 400 buf = io.BytesIO(global_map_data) buf.seek(0)