mirror of
https://github.com/Hestia-Homes/Model.git
synced 2026-06-08 11:17:27 +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
|
||||
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:
|
||||
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:
|
||||
return
|
||||
|
||||
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(
|
||||
session=session,
|
||||
api_data=self.insights_data,
|
||||
uprns_to_location=uprns_to_location
|
||||
uprns_to_location=uprns_to_location,
|
||||
scenarios_data=scenarios_data
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
|
|
@ -286,13 +309,21 @@ class GoogleSolarApi:
|
|||
roi = (generation_value + surplus_value) / panel_config["total_cost"]
|
||||
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.
|
||||
roi_results.append(
|
||||
{
|
||||
"n_panels": panel_config["n_panels"],
|
||||
"roi": roi,
|
||||
"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]
|
||||
)
|
||||
|
||||
panel_performance["expected_payback_years"] = np.ceil(panel_performance["expected_payback_years"]).astype(int)
|
||||
|
||||
self.panel_performance = panel_performance
|
||||
|
||||
def exclude_north_facing_segments(self):
|
||||
|
|
|
|||
|
|
@ -2,7 +2,7 @@ import datetime
|
|||
import pytz
|
||||
from sqlalchemy.orm import Session
|
||||
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):
|
||||
|
|
@ -35,28 +35,56 @@ def get_solar_data(session: Session, longitude: float = None, latitude: float =
|
|||
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.
|
||||
:param session: The database session
|
||||
: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:
|
||||
# Convert the data_list to a list of dicts for bulk insert
|
||||
records_to_update = []
|
||||
# Insert data into the Solar table and get the IDs
|
||||
solar_records = []
|
||||
for data in uprns_to_location:
|
||||
record = {
|
||||
'uprn': data['uprn'],
|
||||
'longitude': data['longitude'],
|
||||
'latitude': data['latitude'],
|
||||
'google_api_response': api_data,
|
||||
'updated_at': datetime.datetime.now(pytz.utc)
|
||||
}
|
||||
records_to_update.append(record)
|
||||
solar_record = Solar(
|
||||
uprn=data['uprn'],
|
||||
longitude=data['longitude'],
|
||||
latitude=data['latitude'],
|
||||
google_api_response=api_data,
|
||||
updated_at=datetime.datetime.now(pytz.utc)
|
||||
)
|
||||
solar_records.append(solar_record)
|
||||
|
||||
# Perform bulk insert or update
|
||||
session.bulk_insert_mappings(Solar, records_to_update)
|
||||
session.bulk_save_objects(solar_records)
|
||||
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()
|
||||
|
||||
except Exception as e:
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
import datetime
|
||||
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
|
||||
|
||||
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)
|
||||
)
|
||||
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
|
||||
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
|
||||
for p in input_properties:
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue