Skip to content

Commit

Permalink
Created Interfaces
Browse files Browse the repository at this point in the history
  • Loading branch information
MattesKnigge committed Jun 11, 2024
1 parent ae42f9e commit f412911
Show file tree
Hide file tree
Showing 14 changed files with 198 additions and 127 deletions.
21 changes: 17 additions & 4 deletions Controllers/WaterManagementController.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
from flask import abort
from flask_restx import Resource, Namespace

from DataLayer import WaterManagementRepository
from DataLayer.WaterManagementRepository import get_all_water_data, get_volume_by_date
from Services.WaterManagementService import WaterManagementService
from app import water_management_model

water_ns = Namespace('water', description='Endpoints for Water management')
Expand All @@ -11,7 +14,7 @@ class Water(Resource):
@water_ns.marshal_list_with(water_management_model)
def get(self):
try:
data = get_all_water_data()
data = get_all_water_data() # TODO: replace with service layer and if list empty return empty list
if not data:
abort(404, 'Data not found')
return data, 200
Expand All @@ -24,9 +27,9 @@ class Water(Resource):
@water_ns.marshal_with(water_management_model)
def get(self):
try:
data = get_all_water_data()
data = get_all_water_data() # TODO: replace with service layer
if not data:
abort(404, 'Data not found')
abort(404, 'Data not found in database')
return data[-1], 200
except Exception as e:
water_ns.abort(500, f"Internal server error: {str(e)}")
Expand All @@ -37,9 +40,19 @@ class Water(Resource):
@water_ns.marshal_list_with(water_management_model)
def get(self, date):
try:
data = get_volume_by_date(date)
data = WaterManagementRepository.get_volume_by_date(date)
if not data:
abort(404, 'Data not found')
return data, 200
except Exception as e:
water_ns.abort(500, f"Internal server error: {str(e)}")


@water_ns.route('/measure')
class Water(Resource):
def post(self):
try:
WaterManagementService.measure_and_store_volume()
return {'status': 'Water measurement successful'}, 200
except Exception as e:
return {'status': f"Internal server error: {str(e)}"}, 500
10 changes: 4 additions & 6 deletions Controllers/WeatherPredictionController.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
forecast_ns = Namespace('forecast', description='Endpoints for Weather Forecast')


@forecast_ns.route('/get/<date>') # get forecast data from database
@forecast_ns.route('/<date>') # get forecast data from database
class Forecast(Resource):
@forecast_ns.marshal_with(weather_forecast_model)
def get(self, date):
Expand All @@ -23,19 +23,17 @@ def get(self, date):

@forecast_ns.route('/fetch/<date>') # get forecast from API and save to database
class FetchForecast(Resource):
def get(self, date):
def post(self, date):
try:
result = WeatherPredictionService.fetch_weather_forecast(date)
if result['code'] == 500:
abort(500, result['message'])
return {'status': result['message']}, result['code']
return {'status': result['message']}
except Exception as e:
forecast_ns.abort(500, f"Internal server error: {str(e)}")


@forecast_ns.route('/fetch-range/<start_date>/<end_date>') # get forecast from API and save to database for range of dates
class FetchForecastRange(Resource):
def get(self, start_date, end_date):
def post(self, start_date, end_date):
try:
result = WeatherPredictionService.fetch_weather_forecast_range(start_date, end_date)
if result['code'] == 500:
Expand Down
10 changes: 6 additions & 4 deletions Controllers/WeatherStationController.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
from flask import abort
from flask_restx import Resource, Namespace
from DataLayer import WeatherStationRepository
from Services.WeatherStationService import fetch_weather_station_data, fetch_weather_data_by_date
from Services.WeatherStationService import WeatherStationService
from app import weather_station_model

station_ns = Namespace('station', description='Endpoints for the Weather Station')

weather_station_service = WeatherStationService()


@station_ns.route('/data/all')
class Data(Resource):
Expand All @@ -24,7 +26,7 @@ def get(self):
class DataByDate(Resource):
@station_ns.marshal_list_with(weather_station_model)
def get(self, date):
data, error = fetch_weather_data_by_date(date)
data, error = weather_station_service.fetch_weather_data_by_date(date)
if error:
if 'No data found' in error:
abort(404, error)
Expand All @@ -37,9 +39,9 @@ def get(self, date):

@station_ns.route('/fetch')
class Fetch(Resource):
def get(self):
def post(self):
try:
result = fetch_weather_station_data()
result = weather_station_service.fetch_weather_station_data()
return {'status': result['message']}, result['code']
except Exception as e:
station_ns.abort(500, f"Internal server error: {str(e)}")
9 changes: 2 additions & 7 deletions DataLayer/WaterManagementRepository.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,6 @@ def delete_water_data_by_id(id):
db.session.commit()


def add_water_data(volume):
new_data = WaterManagementData(
date=datetime.now().strftime("%Y-%m-%d %H:%M"),
volume=int(round(volume / 1000)),
fetched_at=datetime.utcnow()
)
db.session.add(new_data)
def add_water_data(data):
db.session.add(data)
db.session.commit()
6 changes: 6 additions & 0 deletions DataLayer/WeatherPredictionRepository.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,12 @@ def commit_changes():
db.session.commit()


def add_forecasts(forecasts_data):
for forecast in forecasts_data:
add_forecast_data(forecast)
commit_changes()


def get_forecast_data_by_date(date):
return WeatherForecastData.query.filter_by(date=date).first()

Expand Down
2 changes: 1 addition & 1 deletion Scheduler/SchedulerClass.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ def stop(self):
self.scheduler.shutdown()

def add_job(self, func, trigger, **kwargs):
self.scheduler.add_job(func, trigger, **kwargs)
self.scheduler.add_job(func, trigger, **kwargs)
7 changes: 4 additions & 3 deletions Scheduler/WaterManagementScheduler.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from Scheduler.SchedulerClass import SchedulerService
from Services.WaterManagementService import calculate_and_store_volume
from Services.WaterManagementService import WaterManagementService

scheduler_service = SchedulerService()
water_management_service = WaterManagementService()

scheduler_service = SchedulerService()

scheduler_service.add_job(calculate_and_store_volume, 'interval', hours=8) # run 3 times a day
scheduler_service.add_job(water_management_service.measure_and_store_volume, 'interval', hours=8) # run 3 times a day
6 changes: 4 additions & 2 deletions Scheduler/WeatherStationScheduler.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from Scheduler.SchedulerClass import SchedulerService
from Services.WeatherStationService import fetch_weather_station_data
from Services.WeatherStationService import WeatherStationService

weather_station_service = WeatherStationService()

scheduler_service = SchedulerService()

scheduler_service.add_job(fetch_weather_station_data, 'interval', minutes=15)
scheduler_service.add_job(weather_station_service.fetch_weather_station_data, 'interval', minutes=15)
8 changes: 8 additions & 0 deletions Services/IWaterManagementService.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
from abc import ABC, abstractmethod


class IWaterManagementService(ABC):

@abstractmethod
def measure_and_store_volume(self):
pass
16 changes: 16 additions & 0 deletions Services/IWeatherPredictionService.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from abc import ABC, abstractmethod


class IWeatherPredictionService(ABC):

@abstractmethod
def fetch_weather_forecast(self, date):
pass

@abstractmethod
def fetch_weather_forecast_range(self, start_date, end_date):
pass

@abstractmethod
def get_weather_forecast_by_date(self, date):
pass
16 changes: 16 additions & 0 deletions Services/IWeatherStationService.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
from abc import ABC, abstractmethod


class IWeatherStationService(ABC):

@abstractmethod
def fetch_weather_station_data(self):
pass

@abstractmethod
def handle_partial_json(self, text):
pass

@abstractmethod
def fetch_weather_data_by_date(self, date_str):
pass
96 changes: 50 additions & 46 deletions Services/WaterManagementService.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import time
from datetime import datetime
from DataLayer.WaterManagementRepository import add_water_data
from DataLayer import WaterManagementRepository
from DataLayer.Models.WaterManagementModel import WaterManagementData
from Services.IWaterManagementService import IWaterManagementService


def is_raspberry_pi():
Expand All @@ -18,52 +20,54 @@ def is_raspberry_pi():
GPIO = None # Define GPIO as None to prevent errors in non-Raspberry Pi environments


def measure_distance():
if not is_raspberry_pi():
print("Not running on a Raspberry Pi. Exiting measure_distance.")
return None
else:
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
trigger = 23
echo = 24
GPIO.setup(trigger, GPIO.OUT)
GPIO.setup(echo, GPIO.IN)
GPIO.output(trigger, False)
print("Waiting For Sensor To Settle")
time.sleep(2)
GPIO.output(trigger, True)
time.sleep(0.00001)
GPIO.output(trigger, False)
while GPIO.input(echo) == 0:
pulse_start = time.time()
while GPIO.input(echo) == 1:
pulse_end = time.time()
pulse_duration = pulse_end - pulse_start
distance = pulse_duration * 17150
distance = round(distance, 2)
print("Distance:", distance, "cm")
return distance
class WaterManagementService(IWaterManagementService):

def measure_and_store_volume(self):
if not is_raspberry_pi():
print(datetime.now().strftime('%d-%m %H:%M') + " Not running on a Raspberry Pi, can't measure water volume.")
return
else:
try:
# Measure distance
GPIO.setmode(GPIO.BCM)
GPIO.setwarnings(False)
trigger = 23
echo = 24
GPIO.setup(trigger, GPIO.OUT)
GPIO.setup(echo, GPIO.IN)
GPIO.output(trigger, False)
print("Waiting For Sensor To Settle")
time.sleep(2)
GPIO.output(trigger, True)
time.sleep(0.00001)
GPIO.output(trigger, False)
while GPIO.input(echo) == 0:
pulse_start = time.time()
while GPIO.input(echo) == 1:
pulse_end = time.time()
pulse_duration = pulse_end - pulse_start
distance = pulse_duration * 17150
distance = round(distance, 2)
print("Distance:", distance, "cm")

def calculate_and_store_volume():
if not is_raspberry_pi():
print(datetime.now().strftime('%d-%m %H:%M') + " Not running on a Raspberry Pi, cant measure water volume.")
return
else:
try:
distance = measure_distance()
if distance is None:
return
if distance is None:
return

height = 78
length = 73
width = 54
volume = (height - distance) * length * width
# Calculate and store volume
height = 78
length = 73
width = 54
volume = (height - distance) * length * width

add_water_data(volume)
print(datetime.now().strftime('%d-%m %H:%M') + " Water measurement successful, data saved.")
except Exception as e:
print(f"Error storing volume data: {str(e)}")
finally:
GPIO.cleanup()
new_data = WaterManagementData(
date=datetime.now().strftime("%Y-%m-%d %H:%M"),
volume=int(round(volume / 1000)),
fetched_at=datetime.utcnow()
)

WaterManagementRepository.add_water_data(new_data)
print(datetime.now().strftime('%d-%m %H:%M') + " Water measurement successful, data saved.")
except Exception as e:
print(f"Error storing volume data: {str(e)}")
finally:
GPIO.cleanup()
Loading

0 comments on commit f412911

Please sign in to comment.