diff --git a/backend/app.py b/backend/app.py index 23c5e11..4ef3407 100644 --- a/backend/app.py +++ b/backend/app.py @@ -5,6 +5,7 @@ # Imports from routes.users import users from routes.transportation import transportation_service +from routes.energy import energy_service app = Flask(__name__) @@ -12,6 +13,7 @@ # Services app.register_blueprint(users, url_prefix="/users") app.register_blueprint(transportation_service, url_prefix="/transportation") +app.register_blueprint(energy_service, url_prefix="/energy") CORS(app) diff --git a/backend/models/energy.py b/backend/models/energy.py new file mode 100644 index 0000000..244cde3 --- /dev/null +++ b/backend/models/energy.py @@ -0,0 +1,98 @@ +""" +Energy Model +""" + +from __future__ import annotations +import json +from datetime import datetime +from models.abstract_db_model import DB_MODEL +from bson import ObjectId +from bson import json_util + +class EnergyEntry(DB_MODEL): + oid: ObjectId + user_id: ObjectId + heating_oil: int # measured in L of fuel + natural_gas: int # measured in m3 of gas + electricity: int # measured in kWh + province: str + household: int + carbon_emissions: float # measured in kgs of CO2 + date: datetime + + def __init__(self, oid: ObjectId, user_id: ObjectId, heating_oil: int, natural_gas: int, province: str, + household: int, electricity: int, carbon_emissions: float, date: datetime) -> None: + super().__init__(oid) + self.user_id = ObjectId(user_id) + self.heating_oil = heating_oil + self.natural_gas = natural_gas + self.electricity = electricity + self.province = province + self.household = household + self.carbon_emissions = carbon_emissions + self.date = date + + def to_json(self, for_mongodb: bool = False) -> json: + res = { + '_id': self.oid, + 'user_id': self.user_id, + 'heating_oil': self.heating_oil, + 'natural_gas': self.natural_gas, + 'electricity': self.electricity, + 'province': self.province, + 'household': self.household, + 'carbon_emissions': self.calculate_carbon_emissions(), + 'date': self.date + } + if for_mongodb: + return res + return json.loads(json_util.dumps(res)) + + @staticmethod + def from_json(doc: json) -> EnergyEntry: + return EnergyEntry( + oid=ObjectId(doc["_id"]), + user_id=doc['user_id'], + heating_oil=doc["heating_oil"], + natural_gas=doc["natural_gas"], + electricity=doc["electricity"], + province=doc["province"], + household=doc["household"], + carbon_emissions=doc["carbon_emissions"], + date=doc["date"] + ) + + def calculate_carbon_emissions(self) -> float: + heating_oil_carbon_emissions = self.heating_oil * 2.753 + natural_gas_carbon_emissions = self.natural_gas * 1.96 + + if self.province == "British Colombia": + electricity_carbon_emissions = (self.electricity * 0.015)/self.household + elif self.province == "Alberta": + electricity_carbon_emissions = (self.electricity * 0.54)/self.household + elif self.province == "Saskatchewan": + electricity_carbon_emissions = (self.electricity * 0.73)/self.household + elif self.province == "Manitoba": + electricity_carbon_emissions = (self.electricity * 0.002)/self.household + elif self.province == "Ontario": + electricity_carbon_emissions = (self.electricity * 0.03)/self.household + elif self.province == "Quebec": + electricity_carbon_emissions = (self.electricity * 0.0017)/self.household + elif self.province == "New Brunswick": + electricity_carbon_emissions = (self.electricity * 0.3)/self.household + elif self.province == "Nova Scotia": + electricity_carbon_emissions = (self.electricity * 0.69)/self.household + elif self.province == "PEI": + electricity_carbon_emissions = (self.electricity * 0.3)/self.household + elif self.province == "Newfoundland and Labrador": + electricity_carbon_emissions = (self.electricity * 0.017)/self.household + elif self.province == "Yukon": + electricity_carbon_emissions = (self.electricity * 0.08)/self.household + elif self.province == "Nortwest Territories": + electricity_carbon_emissions = (self.electricity * 0.17)/self.household + else: # self.province == "Nunavut" + electricity_carbon_emissions = (self.electricity * 0.84)/self.household + return sum([heating_oil_carbon_emissions, natural_gas_carbon_emissions, electricity_carbon_emissions]) + + def __repr__(self) -> str: + return f'Energy ID: {self.oid.__str__()}' diff --git a/backend/models/user.py b/backend/models/user.py index 0053594..34f63b8 100644 --- a/backend/models/user.py +++ b/backend/models/user.py @@ -16,14 +16,18 @@ class User(DB_MODEL): badges: list[str] friends: list[str] score: int + province: str + household: int - def __init__(self, oid: ObjectId, full_name: str, email: str, badges: list[str], friends: list[str], score:int) -> None: + def __init__(self, oid: ObjectId, full_name: str, email: str, badges: list[str], friends: list[str], score:int, province:str, household:int) -> None: super().__init__(oid) self.full_name = str(full_name) self.email = str(email) self.badges = badges self.friends = friends self.score = score + self.province = province + self.household = household def to_json(self, for_mongodb: bool = False) -> json: res = { @@ -32,7 +36,9 @@ def to_json(self, for_mongodb: bool = False) -> json: 'email': self.email, 'badges': self.badges, 'friends': self.friends, - 'score': self.score + 'score': self.score, + 'province': self.province, + 'household': self.household } if for_mongodb: return res @@ -46,7 +52,9 @@ def from_json(doc: json) -> User: email=doc["email"], badges=doc["badges"], friends=doc["friends"], - score=doc["score"] + score=doc["score"], + province=doc["province"], + household=doc["household"] ) def __repr__(self) -> str: diff --git a/backend/mongodb_api/carbon_track_db.py b/backend/mongodb_api/carbon_track_db.py index 59bba88..56efc03 100644 --- a/backend/mongodb_api/carbon_track_db.py +++ b/backend/mongodb_api/carbon_track_db.py @@ -13,3 +13,4 @@ class CarbonTrackDB: users_coll: Collection = carbonTrackDB.get_collection("users") transportation_coll: Collection = carbonTrackDB.get_collection("transportation") + energy_coll: Collection = carbonTrackDB.get_collection("energy") \ No newline at end of file diff --git a/backend/routes/energy.py b/backend/routes/energy.py new file mode 100644 index 0000000..2989446 --- /dev/null +++ b/backend/routes/energy.py @@ -0,0 +1,55 @@ +# Python Imports +from datetime import datetime +from bson import ObjectId +from flask import Blueprint, Response, jsonify, request + +from models.energy import EnergyEntry +from mongodb_api.carbon_track_db import CarbonTrackDB +from routes import carbon_auth +from utils.metric_resets import weekly_metric_reset, get_1_day_range + +energy_service = Blueprint('/energy', __name__) + + +@energy_service.route("/energy/", methods=['GET']) +@carbon_auth.auth.login_required +def get_energy(oid: str) -> Response: + query = {"_id": ObjectId(oid)} + item = CarbonTrackDB.energy_coll.find_one(query) + item = EnergyEntry.from_json(item).to_json() + return jsonify({'energy': item}) + + +@energy_service.route("/get_energy_metric_for_today/", methods=['GET']) +@carbon_auth.auth.login_required +def get_energy_metric_for_today(user_id: str) -> Response: + start_of_day, end_of_day = get_1_day_range(datetime.now()) + query = {"user_id": ObjectId(user_id), "date": {"$gte": start_of_day, "$lte": end_of_day}} + item = CarbonTrackDB.energy_coll.find_one(query) + if item is None: + create_energy(ObjectId(user_id)) + return get_energy_metric_for_today(user_id=user_id) + else: + item = EnergyEntry.from_json(item).to_json() + return jsonify({'energy': item}) + + +@carbon_auth.auth.login_required +def create_energy(user_id: ObjectId) -> Response: + energy = EnergyEntry(oid=ObjectId(), user_id=user_id, heating_oil = 0, natural_gas = 0, province = "Ontario", + household = 4, electricity = 0, carbon_emissions=0.0, date=weekly_metric_reset(datetime.today())) + energy = energy.to_json(for_mongodb=True) + inserted_id = CarbonTrackDB.energy_coll.insert_one(energy).inserted_id + energy = EnergyEntry.from_json(CarbonTrackDB.energy_coll.find_one({"_id": inserted_id})).to_json() + return energy + + +@energy_service.route("/energy/", methods=["PATCH"]) +@carbon_auth.auth.login_required +def update_energy(oid: str) -> Response: + query = {"_id": ObjectId(oid)} + energy = EnergyEntry.from_json(request.get_json()['energy']).to_json(for_mongodb=True) + CarbonTrackDB.energy_coll.update_one(query, {'$set': energy}) + item = CarbonTrackDB.energy_coll.find_one(query) + item = EnergyEntry.from_json(item).to_json() + return jsonify({'updated_energy': item})