mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-30 13:10:47 +00:00
Added expected payback years
This commit is contained in:
parent
693698d5de
commit
28c70d0afb
4 changed files with 107 additions and 20 deletions
|
|
@ -159,19 +159,42 @@ class GoogleSolarApi:
|
||||||
# We now start finding the solar panel configurations
|
# We now start finding the solar panel configurations
|
||||||
self.optimise_solar_configuration(energy_consumption=energy_consumption, is_building=is_building)
|
self.optimise_solar_configuration(energy_consumption=energy_consumption, is_building=is_building)
|
||||||
|
|
||||||
def save_to_db(self, session, uprns_to_location):
|
def save_to_db(self, session, uprns_to_location, scenario_type):
|
||||||
if self.insights_data is None:
|
if self.insights_data is None:
|
||||||
raise ValueError("No api data to store")
|
raise ValueError("No api data to store")
|
||||||
|
|
||||||
|
if scenario_type not in ["unit", "building"]:
|
||||||
|
raise Exception("Invalid scenario type. Must be either 'unit' or 'building'")
|
||||||
|
|
||||||
if not self.need_to_store:
|
if not self.need_to_store:
|
||||||
return
|
return
|
||||||
|
|
||||||
logger.info("Storing to database")
|
logger.info("Storing to database")
|
||||||
|
|
||||||
|
scenarios_data = self.panel_performance.head(1)[
|
||||||
|
["n_panels", "yearly_dc_energy", "total_cost", "panneled_roof_area", "array_warrage",
|
||||||
|
"initial_ac_kwh_per_year", "lifetime_ac_kwh", "roi"]
|
||||||
|
].rename(
|
||||||
|
columns={
|
||||||
|
"n_panels": "number_panels",
|
||||||
|
"yearly_dc_energy": "yearly_dc_kwh",
|
||||||
|
"total_cost": "cost",
|
||||||
|
"panneled_roof_area": "panelled_roof_area",
|
||||||
|
"array_warrage": "array_kwhp",
|
||||||
|
"initial_ac_kwh_per_year": "yearly_ac_kwh",
|
||||||
|
"lifetime_ac_kwh": "lifetime_ac_kwh",
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Adding missing fields with default values
|
||||||
|
scenarios_data["is_default"] = True
|
||||||
|
scenarios_data["scenario_type"] = scenario_type
|
||||||
|
|
||||||
store_batch_data(
|
store_batch_data(
|
||||||
session=session,
|
session=session,
|
||||||
api_data=self.insights_data,
|
api_data=self.insights_data,
|
||||||
uprns_to_location=uprns_to_location
|
uprns_to_location=uprns_to_location,
|
||||||
|
scenarios_data=scenarios_data
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
|
|
@ -286,13 +309,21 @@ class GoogleSolarApi:
|
||||||
roi = (generation_value + surplus_value) / panel_config["total_cost"]
|
roi = (generation_value + surplus_value) / panel_config["total_cost"]
|
||||||
generation_deficit = surplus_value
|
generation_deficit = surplus_value
|
||||||
|
|
||||||
|
# Calculate expected payback years
|
||||||
|
if generation_value > 0:
|
||||||
|
expected_payback_years = panel_config["total_cost"] / (
|
||||||
|
generation_value / self.installation_life_span)
|
||||||
|
else:
|
||||||
|
expected_payback_years = None # or some high value indicating no payback
|
||||||
|
|
||||||
# Generation deficit tells us how much more energy we need to meet the generation demand.
|
# Generation deficit tells us how much more energy we need to meet the generation demand.
|
||||||
roi_results.append(
|
roi_results.append(
|
||||||
{
|
{
|
||||||
"n_panels": panel_config["n_panels"],
|
"n_panels": panel_config["n_panels"],
|
||||||
"roi": roi,
|
"roi": roi,
|
||||||
"generation_value": generation_value,
|
"generation_value": generation_value,
|
||||||
"generation_deficit": generation_deficit
|
"generation_deficit": generation_deficit,
|
||||||
|
"expected_payback_years": expected_payback_years
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -309,6 +340,8 @@ class GoogleSolarApi:
|
||||||
["roi", "generation_deficit", "generation_value"], ascending=[False, True, False]
|
["roi", "generation_deficit", "generation_value"], ascending=[False, True, False]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
panel_performance["expected_payback_years"] = np.ceil(panel_performance["expected_payback_years"]).astype(int)
|
||||||
|
|
||||||
self.panel_performance = panel_performance
|
self.panel_performance = panel_performance
|
||||||
|
|
||||||
def exclude_north_facing_segments(self):
|
def exclude_north_facing_segments(self):
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ import datetime
|
||||||
import pytz
|
import pytz
|
||||||
from sqlalchemy.orm import Session
|
from sqlalchemy.orm import Session
|
||||||
from sqlalchemy.orm.exc import NoResultFound
|
from sqlalchemy.orm.exc import NoResultFound
|
||||||
from backend.app.db.models.solar import Solar
|
from backend.app.db.models.solar import Solar, SolarScenario
|
||||||
|
|
||||||
|
|
||||||
def get_solar_data(session: Session, longitude: float = None, latitude: float = None, uprn: str = None):
|
def get_solar_data(session: Session, longitude: float = None, latitude: float = None, uprn: str = None):
|
||||||
|
|
@ -35,28 +35,56 @@ def get_solar_data(session: Session, longitude: float = None, latitude: float =
|
||||||
return None, None, False
|
return None, None, False
|
||||||
|
|
||||||
|
|
||||||
def store_batch_data(session: Session, api_data: dict, uprns_to_location: list):
|
def store_batch_data(session: Session, api_data: dict, uprns_to_location: list, scenarios_data: list):
|
||||||
"""
|
"""
|
||||||
This function will store the API data to the solar table against all of the UPRNs with longitude and latitude.
|
This function will store the API data to the solar table against all of the UPRNs with longitude and latitude.
|
||||||
:param session: The database session
|
:param session: The database session
|
||||||
:param api_data: The API data to store
|
:param api_data: The API data to store
|
||||||
:param data_list: A list of dictionaries containing uprn, longitude, and latitude
|
:param uprns_to_location: A list of dictionaries containing uprn, longitude, and latitude
|
||||||
|
:param scenarios_data: A list of dictionaries containing scenario data for each UPRN
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# Convert the data_list to a list of dicts for bulk insert
|
# Insert data into the Solar table and get the IDs
|
||||||
records_to_update = []
|
solar_records = []
|
||||||
for data in uprns_to_location:
|
for data in uprns_to_location:
|
||||||
record = {
|
solar_record = Solar(
|
||||||
'uprn': data['uprn'],
|
uprn=data['uprn'],
|
||||||
'longitude': data['longitude'],
|
longitude=data['longitude'],
|
||||||
'latitude': data['latitude'],
|
latitude=data['latitude'],
|
||||||
'google_api_response': api_data,
|
google_api_response=api_data,
|
||||||
'updated_at': datetime.datetime.now(pytz.utc)
|
updated_at=datetime.datetime.now(pytz.utc)
|
||||||
}
|
)
|
||||||
records_to_update.append(record)
|
solar_records.append(solar_record)
|
||||||
|
|
||||||
# Perform bulk insert or update
|
session.bulk_save_objects(solar_records)
|
||||||
session.bulk_insert_mappings(Solar, records_to_update)
|
session.commit()
|
||||||
|
|
||||||
|
# Retrieve the IDs of the inserted records
|
||||||
|
inserted_ids = [record.id for record in solar_records]
|
||||||
|
|
||||||
|
# Prepare the data for SolarScenario
|
||||||
|
scenario_records = []
|
||||||
|
for index, solar_id in enumerate(inserted_ids):
|
||||||
|
scenarios = scenarios_data[index] # Assuming scenarios_data has the same order as uprns_to_location
|
||||||
|
for scenario in scenarios:
|
||||||
|
scenario_record = SolarScenario(
|
||||||
|
solar_id=solar_id,
|
||||||
|
scenario_type=scenario['scenario_type'],
|
||||||
|
number_panels=scenario['number_panels'],
|
||||||
|
array_kwhp=scenario['array_kwhp'],
|
||||||
|
lifetime_dc_kwh=scenario['lifetime_dc_kwh'],
|
||||||
|
yearly_dc_kwh=scenario['yearly_dc_kwh'],
|
||||||
|
lifetime_ac_kwh=scenario.get('lifetime_ac_kwh'), # Optional field
|
||||||
|
yearly_ac_kwh=scenario.get('yearly_ac_kwh'), # Optional field
|
||||||
|
cost=scenario['cost'],
|
||||||
|
expected_payback_years=scenario.get('expected_payback_years'), # Optional field
|
||||||
|
panelled_roof_area=scenario['panelled_roof_area'],
|
||||||
|
is_default=scenario['is_default']
|
||||||
|
)
|
||||||
|
scenario_records.append(scenario_record)
|
||||||
|
|
||||||
|
# Insert data into the SolarScenario table
|
||||||
|
session.bulk_save_objects(scenario_records)
|
||||||
session.commit()
|
session.commit()
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import datetime
|
import datetime
|
||||||
import pytz
|
import pytz
|
||||||
from sqlalchemy import Column, Integer, Float, DateTime, JSON
|
from enum import Enum as PyEnum
|
||||||
|
from sqlalchemy import Column, Integer, Float, DateTime, JSON, BigInteger, ForeignKey, Enum, Boolean
|
||||||
from sqlalchemy.ext.declarative import declarative_base
|
from sqlalchemy.ext.declarative import declarative_base
|
||||||
|
|
||||||
Base = declarative_base()
|
Base = declarative_base()
|
||||||
|
|
@ -19,3 +20,26 @@ class Solar(Base):
|
||||||
DateTime, nullable=False, default=datetime.datetime.now(pytz.utc), onupdate=datetime.datetime.now(pytz.utc)
|
DateTime, nullable=False, default=datetime.datetime.now(pytz.utc), onupdate=datetime.datetime.now(pytz.utc)
|
||||||
)
|
)
|
||||||
google_api_response = Column(JSON, nullable=False)
|
google_api_response = Column(JSON, nullable=False)
|
||||||
|
|
||||||
|
|
||||||
|
class ScenarioType(PyEnum):
|
||||||
|
unit = "unit"
|
||||||
|
building = "building"
|
||||||
|
|
||||||
|
|
||||||
|
class SolarScenario(Base):
|
||||||
|
__tablename__ = 'solar_scenario'
|
||||||
|
|
||||||
|
id = Column(BigInteger, primary_key=True, autoincrement=True)
|
||||||
|
solar_id = Column(BigInteger, ForeignKey('solar.id'), nullable=False)
|
||||||
|
scenario_type = Column(Enum(ScenarioType), nullable=False)
|
||||||
|
number_panels = Column(Integer, nullable=False)
|
||||||
|
array_kwhp = Column(Integer, nullable=False)
|
||||||
|
lifetime_dc_kwh = Column(Float, nullable=False)
|
||||||
|
yearly_dc_kwh = Column(Float, nullable=False)
|
||||||
|
lifetime_ac_kwh = Column(Float)
|
||||||
|
yearly_ac_kwh = Column(Float)
|
||||||
|
cost = Column(Float, nullable=False)
|
||||||
|
expected_payback_years = Column(Float)
|
||||||
|
panelled_roof_area = Column(Float, nullable=False)
|
||||||
|
is_default = Column(Boolean, nullable=False)
|
||||||
|
|
|
||||||
|
|
@ -431,7 +431,9 @@ async def trigger_plan(body: PlanTriggerRequest):
|
||||||
}
|
}
|
||||||
|
|
||||||
# Store the data in the database
|
# Store the data in the database
|
||||||
solar_api_client.save_to_db(session=session, uprns_to_location=building_uprns[building_id])
|
solar_api_client.save_to_db(
|
||||||
|
session=session, uprns_to_location=building_uprns[building_id], scenario_type="building"
|
||||||
|
)
|
||||||
|
|
||||||
# Insert this into the properties that have this building id
|
# Insert this into the properties that have this building id
|
||||||
for p in input_properties:
|
for p in input_properties:
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue