Merge remote-tracking branch 'origin/main' into main
# Conflicts: # hub_api/mockup/building.py
This commit is contained in:
commit
31b52f6d37
12
bootstrap.py
12
bootstrap.py
|
@ -9,6 +9,7 @@ import datetime
|
||||||
|
|
||||||
import flask
|
import flask
|
||||||
import yaml
|
import yaml
|
||||||
|
from pathlib import Path
|
||||||
from flasgger import LazyJSONEncoder, Swagger
|
from flasgger import LazyJSONEncoder, Swagger
|
||||||
from flask import Response
|
from flask import Response
|
||||||
from flask_restful import Api
|
from flask_restful import Api
|
||||||
|
@ -47,20 +48,21 @@ api.add_resource(Costs, '/v1.4/workflow/costs')
|
||||||
api.add_resource(EnergyPlus, '/v1.4/workflow/energy-plus')
|
api.add_resource(EnergyPlus, '/v1.4/workflow/energy-plus')
|
||||||
api.add_resource(InselMonthlyEnergyBalance, '/v1.4/workflow/insel-monthly-energy-balance')
|
api.add_resource(InselMonthlyEnergyBalance, '/v1.4/workflow/insel-monthly-energy-balance')
|
||||||
|
|
||||||
|
yml_path = Path('./docs/openapi-specs.yml').resolve()
|
||||||
|
|
||||||
with open("hub_api/docs/openapi-specs.yml", "r") as stream:
|
with open(yml_path, "r") as stream:
|
||||||
swagger_config = {
|
swagger_config = {
|
||||||
"headers": [],
|
"headers": [],
|
||||||
"specs": [
|
"specs": [
|
||||||
{
|
{
|
||||||
"endpoint": 'apispec',
|
"endpoint": '/api/apispec',
|
||||||
"route": '/v1.4/apispec.json',
|
"route": '/api/apispec/apispec.json',
|
||||||
"rule_filter": lambda rule: True, # all in
|
"rule_filter": lambda rule: True, # all in
|
||||||
"model_filter": lambda tag: True, # all in
|
"model_filter": lambda tag: True, # all in
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"static_url_path": "/api/v1.4/static",
|
"static_url_path": "/api/static",
|
||||||
"specs_route": "/v1.4/api-docs/",
|
"specs_route": "/api/api-docs/",
|
||||||
"openapi": "3.0.0"
|
"openapi": "3.0.0"
|
||||||
}
|
}
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -15,9 +15,9 @@ from hub.catalog_factories.energy_systems_catalog_factory import EnergySystemsCa
|
||||||
class Config:
|
class Config:
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
dotenv_path = "{}/.env".format(os.path.expanduser('~'))
|
dotenv_path = "{}/.local/etc/hub_api/.env".format(os.path.expanduser('~'))
|
||||||
if platform.system() == 'Linux':
|
if platform.system() == 'Linux':
|
||||||
dotenv_path = Path('/home/guille/.local/etc/hub/.env').resolve()
|
dotenv_path = Path(dotenv_path).resolve()
|
||||||
|
|
||||||
environment = 'TEST'
|
environment = 'TEST'
|
||||||
database_name = 'montreal_retrofit_test'
|
database_name = 'montreal_retrofit_test'
|
||||||
|
|
|
@ -9,7 +9,7 @@ externalDocs:
|
||||||
description: Find out more about Swagger
|
description: Find out more about Swagger
|
||||||
url: http://swagger.io
|
url: http://swagger.io
|
||||||
paths:
|
paths:
|
||||||
/v1.4/uptime:
|
/api/v1.4/uptime:
|
||||||
get:
|
get:
|
||||||
parameters:
|
parameters:
|
||||||
[]
|
[]
|
||||||
|
@ -26,7 +26,7 @@ paths:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/uptime'
|
$ref: '#/components/schemas/uptime'
|
||||||
|
|
||||||
/v1.4/session/start:
|
/api/v1.4/session/start:
|
||||||
put:
|
put:
|
||||||
parameters:
|
parameters:
|
||||||
- in: header
|
- in: header
|
||||||
|
@ -78,7 +78,7 @@ paths:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/unauthorized'
|
$ref: '#/components/schemas/unauthorized'
|
||||||
|
|
||||||
/v1.4/session/keep-alive:
|
/api/v1.4/session/keep-alive:
|
||||||
put:
|
put:
|
||||||
security:
|
security:
|
||||||
- session-id: []
|
- session-id: []
|
||||||
|
@ -111,7 +111,7 @@ paths:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/unauthorized'
|
$ref: '#/components/schemas/unauthorized'
|
||||||
|
|
||||||
/v1.4/session/end:
|
/api/v1.4/session/end:
|
||||||
put:
|
put:
|
||||||
security:
|
security:
|
||||||
- session-id: []
|
- session-id: []
|
||||||
|
@ -144,7 +144,7 @@ paths:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/unauthorized'
|
$ref: '#/components/schemas/unauthorized'
|
||||||
|
|
||||||
/v1.4/persistence/retrofit-results:
|
/api/v1.4/persistence/retrofit-results:
|
||||||
post:
|
post:
|
||||||
security:
|
security:
|
||||||
- session-id: [ ]
|
- session-id: [ ]
|
||||||
|
@ -192,7 +192,7 @@ paths:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/unauthorized'
|
$ref: '#/components/schemas/unauthorized'
|
||||||
|
|
||||||
/v1.4/workflow/costs:
|
/api/v1.4/workflow/costs:
|
||||||
post:
|
post:
|
||||||
security:
|
security:
|
||||||
- session-id: [ ]
|
- session-id: [ ]
|
||||||
|
@ -213,7 +213,7 @@ paths:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/not-implemented-error'
|
$ref: '#/components/schemas/not-implemented-error'
|
||||||
|
|
||||||
/v1.4/workflow/energy-plus:
|
/api/v1.4/workflow/energy-plus:
|
||||||
post:
|
post:
|
||||||
security:
|
security:
|
||||||
- session-id: [ ]
|
- session-id: [ ]
|
||||||
|
@ -234,7 +234,7 @@ paths:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/not-implemented-error'
|
$ref: '#/components/schemas/not-implemented-error'
|
||||||
|
|
||||||
/v1.4/workflow/insel-monthly-energy-balance:
|
/api/v1.4/workflow/insel-monthly-energy-balance:
|
||||||
post:
|
post:
|
||||||
security:
|
security:
|
||||||
- session-id: [ ]
|
- session-id: [ ]
|
||||||
|
@ -579,4 +579,4 @@ components:
|
||||||
properties:
|
properties:
|
||||||
error:
|
error:
|
||||||
type: string
|
type: string
|
||||||
example: 'NotImplementedError'
|
example: 'NotImplementedError'
|
||||||
|
|
|
@ -23,13 +23,14 @@ def expired_sessions_collector(session_timeout_duration):
|
||||||
"""
|
"""
|
||||||
while True:
|
while True:
|
||||||
if bool(sessions):
|
if bool(sessions):
|
||||||
for _session in list(sessions):
|
for session_uuid in sessions:
|
||||||
print(_session)
|
print(sessions)
|
||||||
_expire = datetime.datetime.strptime(_session['expire'], '%Y-%m-%d %H:%M:%S.%f')
|
print(sessions[session_uuid]['expire'])
|
||||||
|
_expire = datetime.datetime.strptime(sessions[session_uuid]['expire'], '%Y-%m-%d %H:%M:%S.%f')
|
||||||
if _expire < datetime.datetime.now():
|
if _expire < datetime.datetime.now():
|
||||||
print("session for user: ", _session['username'], "expired.")
|
print("session for user: ", sessions[session_uuid]['user'], "expired.")
|
||||||
|
|
||||||
del sessions[session]
|
del sessions[session_uuid]
|
||||||
time.sleep(60 * int(session_timeout_duration))
|
time.sleep(60 * int(session_timeout_duration))
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,14 +5,19 @@ Copyright © 2023 Concordia CERC group
|
||||||
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
Project Coder Pilar Monsalvete Alvarez de Uribarri pilar.monsalvete@concordia.ca
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from properties import *
|
import hub.helpers.constants as cte
|
||||||
|
from hub.helpers.dictionaries import Dictionaries
|
||||||
|
|
||||||
|
|
||||||
|
from hub_api.mockup.properties import *
|
||||||
|
import pandas as pd
|
||||||
|
|
||||||
|
|
||||||
class Building:
|
class Building:
|
||||||
"""
|
"""
|
||||||
Building class
|
Building class
|
||||||
"""
|
"""
|
||||||
def __init__(self, building_info, catalog_archetype):
|
def __init__(self, building_info, results, catalog_archetype):
|
||||||
self._function = building_info.function
|
self._function = building_info.function
|
||||||
self._area = building_info.area
|
self._area = building_info.area
|
||||||
self._volume = building_info.volume
|
self._volume = building_info.volume
|
||||||
|
@ -21,14 +26,48 @@ class Building:
|
||||||
self._windows_area = building_info.windows_area
|
self._windows_area = building_info.windows_area
|
||||||
self._roof_area = building_info.roof_area
|
self._roof_area = building_info.roof_area
|
||||||
self._total_pv_area = building_info.total_pv_area
|
self._total_pv_area = building_info.total_pv_area
|
||||||
self._heating_consumption = building_info.heating_consumption
|
self._energy_systems_archetype_name = building_info.system_name
|
||||||
self._cooling_consumption = building_info.cooling_consumption
|
self._heating_consumption = {
|
||||||
self._domestic_hot_water_consumption = building_info.domestic_hot_water_consumption
|
cte.YEAR: results['yearly_heating_consumption'],
|
||||||
self._lighting_electrical_demand = building_info.lighting_electrical_demand
|
cte.MONTH: results['monthly_heating_consumption']
|
||||||
self._appliances_electrical_demand = building_info.appliances_electrical_demand
|
}
|
||||||
self._heating_peak_load = building_info.heating_peak_load
|
print(self._heating_consumption)
|
||||||
self._cooling_peak_load = building_info.cooling_peak_load
|
self._cooling_consumption = {
|
||||||
self._onsite_electrical_production = building_info.onsite_electrical_production
|
cte.YEAR: results['yearly_cooling_consumption'],
|
||||||
|
cte.MONTH: results['monthly_cooling_consumption']
|
||||||
|
}
|
||||||
|
self._domestic_hot_water_consumption = {
|
||||||
|
cte.YEAR: results['yearly_domestic_hot_water_consumption'],
|
||||||
|
cte.MONTH: results['monthly_domestic_hot_water_consumption']
|
||||||
|
}
|
||||||
|
self._lighting_electrical_demand = {
|
||||||
|
cte.YEAR: pd.DataFrame(results['yearly_lighting_electrical_demand'], columns=['insel meb']),
|
||||||
|
cte.MONTH: pd.DataFrame(results['monthly_lighting_electrical_demand'], columns=['insel meb'])
|
||||||
|
}
|
||||||
|
self._appliances_electrical_demand = {
|
||||||
|
cte.YEAR: pd.DataFrame(results['yearly_appliances_electrical_demand'], columns=['insel meb']),
|
||||||
|
cte.MONTH: pd.DataFrame(results['monthly_appliances_electrical_demand'], columns=['insel meb'])
|
||||||
|
}
|
||||||
|
self._heating_peak_load = {
|
||||||
|
cte.YEAR: results['yearly_heating_peak_load'],
|
||||||
|
cte.MONTH: results['monthly_heating_peak_load']
|
||||||
|
}
|
||||||
|
self._cooling_peak_load = {
|
||||||
|
cte.YEAR: results['yearly_cooling_peak_load'],
|
||||||
|
cte.MONTH: results['monthly_cooling_peak_load']
|
||||||
|
}
|
||||||
|
self._lighting_peak_load = {
|
||||||
|
cte.YEAR: results['yearly_lighting_peak_load'],
|
||||||
|
cte.MONTH: results['monthly_lighting_peak_load']
|
||||||
|
}
|
||||||
|
self._appliances_peak_load = {
|
||||||
|
cte.YEAR: results['yearly_appliances_peak_load'],
|
||||||
|
cte.MONTH: results['monthly_appliances_peak_load']
|
||||||
|
}
|
||||||
|
self._onsite_electrical_production = {
|
||||||
|
cte.YEAR: results['yearly_on_site_electrical_production'],
|
||||||
|
cte.MONTH: results['monthly_on_site_electrical_production']
|
||||||
|
}
|
||||||
self._catalog_archetype = catalog_archetype
|
self._catalog_archetype = catalog_archetype
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -137,6 +176,14 @@ class Building:
|
||||||
"""
|
"""
|
||||||
return self._cooling_peak_load
|
return self._cooling_peak_load
|
||||||
|
|
||||||
|
@property
|
||||||
|
def lighting_peak_load(self):
|
||||||
|
return self._lighting_peak_load
|
||||||
|
|
||||||
|
@property
|
||||||
|
def appliances_peak_load(self):
|
||||||
|
return self._appliances_peak_load
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def onsite_electrical_production(self):
|
def onsite_electrical_production(self):
|
||||||
"""
|
"""
|
||||||
|
@ -145,6 +192,10 @@ class Building:
|
||||||
"""
|
"""
|
||||||
return self._onsite_electrical_production
|
return self._onsite_electrical_production
|
||||||
|
|
||||||
|
@property
|
||||||
|
def energy_systems_archetype_name(self):
|
||||||
|
return self._energy_systems_archetype_name
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def energy_systems(self) -> [EnergySystem]:
|
def energy_systems(self) -> [EnergySystem]:
|
||||||
"""
|
"""
|
||||||
|
@ -154,8 +205,12 @@ class Building:
|
||||||
_energy_systems = []
|
_energy_systems = []
|
||||||
|
|
||||||
for system in self._catalog_archetype.systems:
|
for system in self._catalog_archetype.systems:
|
||||||
demands = system.demand_types
|
_hub_demand_types = []
|
||||||
fuel_type = system.generation_system.fuel_type
|
for demand_type in system.demand_types:
|
||||||
|
# todo: generalize this when we have more catalogs
|
||||||
|
_hub_demand_types.append(Dictionaries().montreal_demand_type_to_hub_energy_demand_type[demand_type])
|
||||||
|
demands = _hub_demand_types
|
||||||
|
fuel_type = Dictionaries().montreal_custom_fuel_to_hub_fuel[system.generation_system.fuel_type]
|
||||||
generic_generation_system = GenericGenerationSystem()
|
generic_generation_system = GenericGenerationSystem()
|
||||||
generic_generation_system.fuel_type = fuel_type
|
generic_generation_system.fuel_type = fuel_type
|
||||||
generation_system = GenerationSystem()
|
generation_system = GenerationSystem()
|
||||||
|
|
|
@ -3,6 +3,8 @@ import json
|
||||||
from flask import Response, request
|
from flask import Response, request
|
||||||
from flask_restful import Resource
|
from flask_restful import Resource
|
||||||
|
|
||||||
|
from costs.cost import Cost
|
||||||
|
from co2_emission.co2_emission import Co2Emission
|
||||||
from hub_api.config import Config
|
from hub_api.config import Config
|
||||||
from hub_api.helpers.session_helper import session, refresh_session
|
from hub_api.helpers.session_helper import session, refresh_session
|
||||||
from hub_api.mockup.building import Building
|
from hub_api.mockup.building import Building
|
||||||
|
@ -16,6 +18,7 @@ class RetrofitResults(Resource, Config):
|
||||||
"""
|
"""
|
||||||
API call for requesting a specified list of enriched persistence
|
API call for requesting a specified list of enriched persistence
|
||||||
"""
|
"""
|
||||||
|
# todo: cost and co2 libraries are using default canadians values, in the future need to be optionally API configurable
|
||||||
session_id = request.headers.get('session-id', None)
|
session_id = request.headers.get('session-id', None)
|
||||||
token = request.headers.get('token', None)
|
token = request.headers.get('token', None)
|
||||||
application_uuid = request.headers.get('application-uuid', None)
|
application_uuid = request.headers.get('application-uuid', None)
|
||||||
|
@ -29,32 +32,70 @@ class RetrofitResults(Resource, Config):
|
||||||
if 'scenarios' not in payload:
|
if 'scenarios' not in payload:
|
||||||
return Response(json.dumps({'error': 'Bad request'}), status=400, headers=token)
|
return Response(json.dumps({'error': 'Bad request'}), status=400, headers=token)
|
||||||
|
|
||||||
# retrieve the buildings info
|
|
||||||
buildings = []
|
|
||||||
buildings_info = []
|
|
||||||
scenario_name = None
|
|
||||||
|
|
||||||
for scenario in payload['scenarios']:
|
|
||||||
scenario_name = next(iter(scenario))
|
|
||||||
for name in scenario[scenario_name]:
|
|
||||||
if name not in buildings:
|
|
||||||
buildings.append(name)
|
|
||||||
for building in buildings:
|
|
||||||
building_info = self.database.building(building, user_id, application_id, scenario_name)
|
|
||||||
archetype = self.energy_systems_catalog.get_entry(building_info.system_name)
|
|
||||||
buildings_info.append(building_info)
|
|
||||||
buildings.append(Building(building_info, archetype))
|
|
||||||
|
|
||||||
results = self.database.results(user_id, application_id, payload)
|
results = self.database.results(user_id, application_id, payload)
|
||||||
if results == {}:
|
if results == {}:
|
||||||
# no data found for the given parameters
|
# no data found for the given parameters
|
||||||
return Response(json.dumps({'result': 'succeed', 'results': results}), status=200, headers=token)
|
return Response(json.dumps({'result': 'succeed', 'results': results}), status=200, headers=token)
|
||||||
|
|
||||||
# deserialize the response to return pure json
|
# deserialize the response to return pure json
|
||||||
scenario = next(iter(results))
|
|
||||||
for building_results in results[scenario]:
|
for scenario in results:
|
||||||
values = []
|
for building_results in results[scenario]:
|
||||||
for value in building_results['insel meb']:
|
values = []
|
||||||
key = next(iter(value))
|
building_info = self.database.building(building_results['building'], user_id, application_id, scenario)
|
||||||
values.append({key: json.loads(str(value[key]))})
|
results_dictionary = {}
|
||||||
building_results['insel meb'] = values
|
archetype = self.energy_systems_catalog.get_entry(building_info.system_name)
|
||||||
|
for value in building_results['insel meb']:
|
||||||
|
key = next(iter(value))
|
||||||
|
values.append({key: json.loads(str(value[key]))})
|
||||||
|
results_dictionary[key] = json.loads(str(value[key]))
|
||||||
|
building_results['insel meb'] = values
|
||||||
|
mockup_building = Building(building_info, results_dictionary, archetype)
|
||||||
|
life_cycle = Cost(mockup_building, retrofit_scenario=scenario).life_cycle
|
||||||
|
|
||||||
|
operational_co2 = Co2Emission(mockup_building).operational_co2
|
||||||
|
global_capital_costs = life_cycle[f'Scenario {scenario}']['global_capital_costs']
|
||||||
|
global_operational_costs = life_cycle[f'Scenario {scenario}']['global_operational_costs']
|
||||||
|
global_capital_incomes = life_cycle[f'Scenario {scenario}']['global_capital_incomes']
|
||||||
|
global_maintenance_costs = life_cycle[f'Scenario {scenario}']['global_maintenance_costs']
|
||||||
|
building_results['costs'] = {
|
||||||
|
'total_capital_costs_skin': life_cycle[f'Scenario {scenario}']['total_capital_costs_skin'],
|
||||||
|
'total_capital_costs_systems': life_cycle[f'Scenario {scenario}']['total_capital_costs_systems'],
|
||||||
|
'end_of_life_costs': life_cycle[f'Scenario {scenario}']['end_of_life_costs'],
|
||||||
|
'total_operational_costs': life_cycle[f'Scenario {scenario}']['total_operational_costs'],
|
||||||
|
'total_maintenance_costs': life_cycle[f'Scenario {scenario}']['total_maintenance_costs'],
|
||||||
|
'operational_incomes': life_cycle[f'Scenario {scenario}']['operational_incomes'],
|
||||||
|
'capital_incomes': life_cycle[f'Scenario {scenario}']['capital_incomes'],
|
||||||
|
'global_capital_costs': {
|
||||||
|
'B2010_opaque_walls': global_capital_costs['B2010_opaque_walls'].tolist(),
|
||||||
|
'B2020_transparent': global_capital_costs['B2020_transparent'].tolist(),
|
||||||
|
'B3010_opaque_roof': global_capital_costs['B3010_opaque_roof'].tolist(),
|
||||||
|
'B10_superstructure': global_capital_costs['B10_superstructure'].tolist(),
|
||||||
|
'D3020_heat_generating_systems': global_capital_costs['D3020_heat_generating_systems'].tolist(),
|
||||||
|
'D3030_cooling_generation_systems': global_capital_costs['D3030_cooling_generation_systems'].tolist(),
|
||||||
|
'D3080_other_hvac_ahu': global_capital_costs['D3080_other_hvac_ahu'].tolist(),
|
||||||
|
'D5020_lighting_and_branch_wiring': global_capital_costs['D5020_lighting_and_branch_wiring'].tolist(),
|
||||||
|
'D301010_photovoltaic_system': global_capital_costs['D301010_photovoltaic_system'].tolist(),
|
||||||
|
},
|
||||||
|
'global_end_of_life_costs': life_cycle[f'Scenario {scenario}']['global_end_of_life_costs']['End_of_life_costs'].tolist(),
|
||||||
|
'global_operational_costs': {
|
||||||
|
'fixed_costs_electricity_peak': global_operational_costs['Fixed_costs_electricity_peak'].tolist(),
|
||||||
|
'fixed_costs_electricity_monthly': global_operational_costs['Fixed_costs_electricity_monthly'].tolist(),
|
||||||
|
'variable_costs_electricity': global_operational_costs['Variable_costs_electricity'].tolist(),
|
||||||
|
'fixed_costs_gas': global_operational_costs['Fixed_costs_gas'].tolist(),
|
||||||
|
'variable_costs_gas': global_operational_costs['Variable_costs_gas'].tolist()
|
||||||
|
},
|
||||||
|
'global_maintenance_costs': {
|
||||||
|
'heating_maintenance': global_maintenance_costs['Heating_maintenance'].tolist(),
|
||||||
|
'cooling_maintenance': global_maintenance_costs['Cooling_maintenance'].tolist(),
|
||||||
|
'pv_maintenance': global_maintenance_costs['PV_maintenance'].tolist(),
|
||||||
|
},
|
||||||
|
'global_operational_incomes': life_cycle[f'Scenario {scenario}']['global_operational_incomes']['Incomes electricity'].tolist(),
|
||||||
|
'global_capital_incomes': {
|
||||||
|
'subsidies_construction': global_capital_incomes['Subsidies construction'].tolist(),
|
||||||
|
'subsidies_hvac': global_capital_incomes['Subsidies HVAC'].tolist(),
|
||||||
|
'subsidies_pv': global_capital_incomes['Subsidies PV'].tolist()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
building_results['operational_co2'] = operational_co2
|
||||||
return Response(json.dumps({'result': 'succeed', 'results': results}), status=200, headers=token)
|
return Response(json.dumps({'result': 'succeed', 'results': results}), status=200, headers=token)
|
||||||
|
|
Loading…
Reference in New Issue
Block a user