Clean up and define session start message

This commit is contained in:
Guille Gutierrez 2023-02-14 04:32:04 -05:00
parent 5f6b7339c4
commit f39ffedc87
18 changed files with 222 additions and 152291 deletions

View File

@ -14,11 +14,12 @@ from flask import Response
from flask_restful import Api from flask_restful import Api
import hub_api.helpers.session_helper as sh import hub_api.helpers.session_helper as sh
from hub_api.construction_catalog import ConstructionCatalogEntry, ConstructionCatalogEntries, ConstructionCatalogNames from hub_api.catalogs.construction_catalog import ConstructionCatalogEntry, ConstructionCatalogEntries, ConstructionCatalogNames
from hub_api.greenery_catalog import GreeneryCatalogEntry, GreeneryCatalogEntries, GreeneryCatalogNames from hub_api.catalogs.greenery_catalog import GreeneryCatalogEntry, GreeneryCatalogEntries, GreeneryCatalogNames
from hub_api.catalogs.usage_catalog import UsageCatalogEntry, UsageCatalogEntries, UsageCatalogNames
from hub_api.session import SessionStart, SessionEnd, KeepSessionAlive from hub_api.session import SessionStart, SessionEnd, KeepSessionAlive
from hub_api.uptime import Uptime from hub_api.uptime import Uptime
from hub_api.usage_catalog import UsageCatalogEntry, UsageCatalogEntries, UsageCatalogNames
sh.begin_time = datetime.datetime.now() sh.begin_time = datetime.datetime.now()
app = flask.Flask('cerc_api') app = flask.Flask('cerc_api')

1
cache/.gitignore vendored
View File

@ -1 +0,0 @@
!.gitignore

File diff suppressed because it is too large Load Diff

File diff suppressed because one or more lines are too long

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

Binary file not shown.

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +0,0 @@
,Monthly HP Electricity Demand (kWh),Monthly Fuel Consumption of Auxiliary Heater (m3)
Jan,1889256.0,7.91282225
Feb,1682865.12,6.06568241
Mar,1387834.62,0.068873927
Apr,590983.75,-0.0
May,0.0,11.7348537
Jun,0.0,1.51432967
Jul,0.0,0.327990711
Aug,0.0,0.534922004
Sept,0.0,5.72120714
Oct,372460.781,0.000307567185
Nov,829471.875,-0.0
Dec,1673153.38,2.49482107
Total,8426025.526,36.375810449184996
1 Monthly HP Electricity Demand (kWh) Monthly Fuel Consumption of Auxiliary Heater (m3)
2 Jan 1889256.0 7.91282225
3 Feb 1682865.12 6.06568241
4 Mar 1387834.62 0.068873927
5 Apr 590983.75 -0.0
6 May 0.0 11.7348537
7 Jun 0.0 1.51432967
8 Jul 0.0 0.327990711
9 Aug 0.0 0.534922004
10 Sept 0.0 5.72120714
11 Oct 372460.781 0.000307567185
12 Nov 829471.875 -0.0
13 Dec 1673153.38 2.49482107
14 Total 8426025.526 36.375810449184996

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,156 @@
"""
Construction catalog
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2022 Project Author name guillermo.gutierrezmorote@concordia.ca
"""
import json
from flask import request, Response
from flask_restful import Resource
from hub_api.helpers.session_helper import refresh_session
class ToJson:
@staticmethod
def usage_to_json(usage):
dictionary = {
'usage': usage.usage,
'hours_day': usage.hours_day,
'days_year': usage.days_year,
'mechanical_air_change': usage.mechanical_air_change if usage.mechanical_air_change is not None else '',
'ventilation_rate': usage.ventilation_rate if usage.ventilation_rate is not None else '',
'occupancy': ToJson.occupancy_to_json(usage.occupancy),
'lighting': ToJson.lighting_to_json(usage.lighting),
'appliances': ToJson.appliances_to_json(usage.appliances),
'thermal_control': ToJson.thermal_control_to_json(usage.thermal_control)
}
return dictionary
@staticmethod
def occupancy_to_json(occupancy):
dictionary = {
'occupancy_density': occupancy.occupancy_density,
'sensible_convective_internal_gain': occupancy.sensible_convective_internal_gain,
'sensible_radiative_internal_gain': occupancy.sensible_radiative_internal_gain,
'latent_internal_gain': occupancy.latent_internal_gain,
'schedules': []
}
for schedule in occupancy.schedules:
dictionary['schedules'].append(ToJson.schedule_to_json(schedule))
return dictionary
@staticmethod
def lighting_to_json(lighting):
dictionary = {
'density': lighting.density,
'convective_fraction': lighting.convective_fraction,
'radiative_fraction': lighting.radiative_fraction,
'latent_fraction': lighting.latent_fraction,
'schedules': []
}
for schedule in lighting.schedules:
dictionary['schedules'].append(ToJson.schedule_to_json(schedule))
return dictionary
@staticmethod
def appliances_to_json(appliances):
dictionary = {
'density': appliances.density,
'convective_fraction': appliances.convective_fraction,
'radiative_fraction': appliances.radiative_fraction,
'latent_fraction': appliances.latent_fraction,
'schedules': []
}
for schedule in appliances.schedules:
dictionary['schedules'].append(ToJson.schedule_to_json(schedule))
return dictionary
@staticmethod
def thermal_control_to_json(thermal_control):
dictionary = {
'mean_heating_set_point': thermal_control.mean_heating_set_point,
'heating_set_back': thermal_control.heating_set_back,
'mean_cooling_set_point': thermal_control.mean_cooling_set_point,
'hvac_availability_schedules': [],
'heating_set_point_schedules': [],
'cooling_set_point_schedules': [],
}
for schedule in thermal_control.hvac_availability_schedules:
dictionary['hvac_availability_schedules'].append(ToJson.schedule_to_json(schedule))
for schedule in thermal_control.heating_set_point_schedules:
dictionary['heating_set_point_schedules'].append(ToJson.schedule_to_json(schedule))
for schedule in thermal_control.cooling_set_point_schedules:
dictionary['cooling_set_point_schedules'].append(ToJson.schedule_to_json(schedule))
return dictionary
@staticmethod
def schedule_to_json(schedule):
schedule_dictionary = {
'type': schedule.type,
'data_type': schedule.data_type,
'time_step': schedule.time_step,
'time_range': schedule.time_range,
'day_types': schedule.day_types,
'values': schedule.values,
}
return schedule_dictionary
class UsageCatalogEntry(Resource):
def __init__(self):
pass
@staticmethod
def post():
session = refresh_session(request)
if session is None:
return Response(json.dumps({'error': 'invalid session'}), status=401)
headers = session.headers
catalog = session.usage_catalog
name = None
if request.data == b'' or request.json['name'] is None:
response = {'error': 'Mandatory parameter "name" is missing'}
return Response(json.dumps(response), headers=headers, status=400)
try:
name = request.json['name']
entry = catalog.get_entry(name)
output = {'usages': [ToJson.usage_to_json(entry)]}
return Response(json.dumps(output), headers=headers)
except IndexError:
response = {'error': f'Name "{name}" unknown'}
return Response(json.dumps(response), headers=headers, status=400)
class UsageCatalogEntries(Resource):
def __init__(self):
pass
@staticmethod
def post():
session = refresh_session(request)
if session is None:
return Response(json.dumps({'error': 'invalid session'}), status=401)
headers = session.headers
catalog = session.usage_catalog
output = {'usages': []}
content = catalog.entries()
for usage in content.usages:
output['usages'].append(ToJson.usage_to_json(usage))
return Response(json.dumps(output), headers=headers)
class UsageCatalogNames(Resource):
def __init__(self):
pass
@staticmethod
def post():
session = refresh_session(request)
if session is None:
return Response(json.dumps({'error': 'invalid session'}), status=401)
headers = session.headers
catalog = session.usage_catalog
return Response(json.dumps(catalog.names()), headers=headers)

View File

@ -24,13 +24,69 @@ paths:
content: content:
application/json: application/json:
schema: schema:
$ref: '#/components/schemas/Uptime' $ref: '#/components/schemas/uptime'
/v1.4/session/start:
put:
parameters:
- in: header
name: username
schema:
type: string
required: true
description: the application username accessing this API
- in: header
name: password
schema:
type: string
required: true
description: the password for the user accessing this API
- in: header
name: application_id
schema:
type: string
required: true
description: the Id of the application accessing this API
tags:
- Session start
summary: Starts an user session
operationId: session_start
description: Authenticate and initialize an user session in the api
responses:
'200':
description: Authorized
content:
application/json:
schema:
$ref: '#/components/schemas/authorized'
'403':
description: Unauthorized
content:
application/json:
schema:
$ref: '#/components/schemas/unauthorized'
components: components:
schemas: schemas:
Uptime: uptime:
type: object type: object
properties: properties:
uptime: uptime:
type: string type: string
format: hh:mm:ss.ms format: hh:mm:ss.ms
example: "00:09:53.600281" example: "00:09:53.600281"
authorized:
type: object
properties:
session_id:
type: string
format: uuid
example: "ad0720ed-0f31-4f3e-9686-1177d4624ec1"
token:
type: string
format: uuid
example: "660d1aa0-d24f-4cb1-902d-13c7bd29793c"
unauthorized:
type: object
properties:
error:
type: string
example: "unauthorized"

View File

@ -1,396 +0,0 @@
import json
from flask import request, Response
from flask_restful import Resource
from pathlib import Path
from geomeppy import IDF
import os
import glob
import hub_api.helpers.session_helper as sh
import hub.helpers.constants as cte
import csv
from hub_api.helpers.auth import role_required
from hub.persistence.models import UserRoles
from hub_api.config import Config
class EnergyDemand(Resource, Config):
_THERMOSTAT = 'HVACTEMPLATE:THERMOSTAT'
_IDEAL_LOAD_AIR_SYSTEM = 'HVACTEMPLATE:ZONE:IDEALLOADSAIRSYSTEM'
_SURFACE = 'BUILDINGSURFACE:DETAILED'
_WINDOW_SURFACE = 'FENESTRATIONSURFACE:DETAILED'
_CONSTRUCTION = 'CONSTRUCTION'
_MATERIAL = 'MATERIAL'
_MATERIAL_NOMASS = 'MATERIAL:NOMASS'
_ROUGHNESS = 'MediumRough'
_HOURLY_SCHEDULE = 'SCHEDULE:DAY:HOURLY'
_COMPACT_SCHEDULE = 'SCHEDULE:COMPACT'
_FILE_SCHEDULE = 'SCHEDULE:FILE'
_ZONE = 'ZONE'
_LIGHTS = 'LIGHTS'
_PEOPLE = 'PEOPLE'
_APPLIANCES = 'OTHEREQUIPMENT'
_HEATING_COOLING = 'THERMOSTATSETPOINT:DUALSETPOINT'
_INFILTRATION = 'ZONEINFILTRATION:DESIGNFLOWRATE'
_BUILDING_SURFACE = 'BuildingSurfaceDetailed'
_SCHEDULE_LIMIT = 'SCHEDULETYPELIMITS'
_ON_OFF = 'On/Off'
_FRACTION = 'Fraction'
_ANY_NUMBER = 'Any Number'
_CONTINUOUS = 'Continuous'
_DISCRETE = 'Discrete'
_BUILDING = 'BUILDING'
_SIZING_PERIODS = 'SIZINGPERIOD:DESIGNDAY'
_LOCATION = 'SITE:LOCATION'
_WINDOW_MATERIAL_SIMPLE = 'WINDOWMATERIAL:SIMPLEGLAZINGSYSTEM'
_WINDOW = 'WINDOW'
_MATERIAL_ROOFVEGETATION = 'MATERIAL:ROOFVEGETATION'
_SIMPLE = 'Simple'
idf_surfaces = {
# todo: make an enum for all the surface types
cte.WALL: 'wall',
cte.GROUND: 'floor',
cte.ROOF: 'roof'
}
idf_usage = {
# todo: make an enum for all the usage types
cte.RESIDENTIAL: 'residential_building'
}
idf_type_limits = {
cte.ON_OFF: 'on/off',
cte.FRACTION: 'Fraction',
cte.ANY_NUMBER: 'Any Number',
cte.CONTINUOUS: 'Continuous',
cte.DISCRETE: 'Discrete',
cte.TEMPERATURE: 'Any Number'
}
idf_day_types = {
cte.MONDAY: 'Monday',
cte.TUESDAY: 'Tuesday',
cte.WEDNESDAY: 'Wednesday',
cte.THURSDAY: 'Thursday',
cte.FRIDAY: 'Friday',
cte.SATURDAY: 'Saturday',
cte.SUNDAY: 'Sunday',
cte.HOLIDAY: 'Holidays',
cte.WINTER_DESIGN_DAY: 'WinterDesignDay',
cte.SUMMER_DESIGN_DAY: 'SummerDesignDay'
}
idf_schedule_types = {
'compact': 'Compact',
cte.DAY: 'Day',
cte.WEEK: 'Week',
cte.YEAR: 'Year',
'file': 'File'
}
idf_schedule_data_type = {
'compact': 'Compact',
'hourly': 'Hourly',
'daily': 'Daily',
'interval': 'Interval',
'list': 'List',
}
def __init__(self):
# this class is mostly hardcoded, as is intended to be used only for Dompark project,
# other projects should use the normal idf workflow instead.
super().__init__()
self._output_path = Path(Path(__file__).parent.parent / 'tmp').resolve()
self._data_path = Path(Path(__file__).parent.parent / 'data').resolve()
self._city = None
self._greenery_percentage = 0
def _set_layers(self, _idf, name, layers, vegetation=None):
if vegetation is not None:
_kwargs = {'Name': name, 'Outside_Layer': vegetation.name}
for i in range(0, len(layers)):
_kwargs[f'Layer_{i + 2}'] = layers[i].material.name
else:
_kwargs = {'Name': name, 'Outside_Layer': layers[0].material.name}
for i in range(1, len(layers)):
_kwargs[f'Layer_{i + 1}'] = layers[i].material.name
_idf.newidfobject(self._CONSTRUCTION, **_kwargs)
def _update_constructions(self, _idf, ground, roof, wall, vegetation):
for construction in _idf.idfobjects[self._CONSTRUCTION]:
if construction.Name == 'Project ground floor':
# floor
self._set_layers(_idf, 'user_floor', ground)
elif construction.Name == 'Dompark Roof':
# roof
self._set_layers(_idf, 'user_roof', roof)
elif construction.Name == 'Dompark Roof Vegetation':
# roof
self._set_layers(_idf, 'user_roof_vegetation', roof, vegetation)
elif construction.Name == 'Dompark Wall':
# wall
self._set_layers(_idf, 'user_wall', wall)
else:
continue
for surface in _idf.idfobjects[self._SURFACE]:
if surface.Construction_Name == 'Project ground floor':
# floor
surface.Construction_Name = 'user_floor'
elif surface.Construction_Name == 'Dompark Wall':
# wall
surface.Construction_Name = 'user_wall'
elif surface.Construction_Name == 'Dompark Roof' or surface.Construction_Name == 'Dompark Roof Vegetation':
# roof
surface.Construction_Name = 'user_roof'
if self._greenery_percentage > 0:
if surface.Name in sh.roofs_associated_to_percentage[str(self._greenery_percentage)]:
surface.Construction_Name = 'user_roof_vegetation'
else:
continue
for window in _idf.idfobjects[self._WINDOW_SURFACE]:
window.Construction_Name = 'window_construction_1'
def _add_material(self, _idf, layers):
for layer in layers:
for material in _idf.idfobjects[self._MATERIAL]:
if material.Name == layer.material.name:
return
for material in _idf.idfobjects[self._MATERIAL_NOMASS]:
if material.Name == layer.material.name:
return
if str(layer.material.no_mass) == 'True':
_idf.newidfobject(self._MATERIAL_NOMASS,
Name=layer.material.name,
Roughness=self._ROUGHNESS,
Thermal_Resistance=layer.material.thermal_resistance,
Thermal_Absorptance=layer.material.thermal_absorptance,
Solar_Absorptance=layer.material.solar_absorptance,
Visible_Absorptance=layer.material.visible_absorptance
)
else:
_idf.newidfobject(self._MATERIAL,
Name=layer.material.name,
Roughness=self._ROUGHNESS,
Thickness=layer.thickness,
Conductivity=layer.material.conductivity,
Density=layer.material.density,
Specific_Heat=layer.material.specific_heat,
Thermal_Absorptance=layer.material.thermal_absorptance,
Solar_Absorptance=layer.material.solar_absorptance,
Visible_Absorptance=layer.material.visible_absorptance
)
def _add_vegetation_material(self, _idf, vegetation):
for vegetation_material in _idf.idfobjects[self._MATERIAL_ROOFVEGETATION]:
if vegetation_material.Name == vegetation.name:
return
soil = vegetation.soil
height = 0
leaf_area_index = 0
leaf_reflectivity = 0
leaf_emissivity = 0
minimal_stomatal_resistance = 0
for plant in vegetation.plants:
percentage = float(plant.percentage) / 100
height += percentage * float(plant.height)
leaf_area_index += percentage * float(plant.leaf_area_index)
leaf_reflectivity += percentage * float(plant.leaf_reflectivity)
leaf_emissivity += percentage * float(plant.leaf_emissivity)
minimal_stomatal_resistance += percentage * float(plant.minimal_stomatal_resistance)
_idf.newidfobject(self._MATERIAL_ROOFVEGETATION,
Name=vegetation.name,
Height_of_Plants=height,
Leaf_Area_Index=leaf_area_index,
Leaf_Reflectivity=leaf_reflectivity,
Leaf_Emissivity=leaf_emissivity,
Minimum_Stomatal_Resistance=minimal_stomatal_resistance,
Soil_Layer_Name=soil.name,
Roughness=soil.roughness,
Thickness=vegetation.soil_thickness,
Conductivity_of_Dry_Soil=soil.dry_conductivity,
Density_of_Dry_Soil=soil.dry_density,
Specific_Heat_of_Dry_Soil=soil.dry_specific_heat,
Thermal_Absorptance=soil.thermal_absorptance,
Solar_Absorptance=soil.solar_absorptance,
Visible_Absorptance=soil.visible_absorptance,
Saturation_Volumetric_Moisture_Content_of_the_Soil_Layer=
soil.saturation_volumetric_moisture_content,
Residual_Volumetric_Moisture_Content_of_the_Soil_Layer=
soil.residual_volumetric_moisture_content,
Initial_Volumetric_Moisture_Content_of_the_Soil_Layer=
soil.initial_volumetric_moisture_content,
Moisture_Diffusion_Calculation_Method=self._SIMPLE
)
def _add_window_construction_and_material(self, _idf, window):
name = 'glazing_1'
_kwargs = {'Name': name, 'UFactor': window.overall_u_value,
'Solar_Heat_Gain_Coefficient': window.g_value}
_idf.newidfobject(self._WINDOW_MATERIAL_SIMPLE, **_kwargs)
window_construction_name = 'window_construction_1'
_kwargs = {'Name': window_construction_name, 'Outside_Layer': name}
return _idf.newidfobject(self._CONSTRUCTION, **_kwargs)
def _add_materials(self, _idf):
building = self._city.buildings[0]
ground_surface = building.grounds[0]
roof_surface = building.roofs[0]
wall_surface = building.walls[0]
internal_zone = building.internal_zones[0]
thermal_zone = internal_zone.thermal_zones[0]
ground = None
roof = None
roof_vegetation = None
wall = None
window = None
for thermal_boundary in thermal_zone.thermal_boundaries:
if thermal_boundary.parent_surface.id == wall_surface.id:
wall = thermal_boundary.layers
if thermal_boundary.parent_surface.id == roof_surface.id:
roof = thermal_boundary.layers
roof_vegetation = thermal_boundary.vegetation
if thermal_boundary.parent_surface.id == ground_surface.id:
ground = thermal_boundary.layers
if thermal_boundary.thermal_openings is not None and len(thermal_boundary.thermal_openings) > 0:
window = thermal_boundary.thermal_openings[0]
if ground is not None and roof is not None and wall is not None and window is not None:
# we have all the needed surfaces type
break
self._add_material(_idf, ground)
self._add_material(_idf, roof)
self._add_material(_idf, wall)
if roof_vegetation is not None:
self._add_vegetation_material(_idf, roof_vegetation)
self._update_constructions(_idf, ground, roof, wall, roof_vegetation)
self._add_window_construction_and_material(_idf, window)
def _add_standard_compact_hourly_schedule(self, _idf, schedule_name, schedules):
_kwargs = {'Name': f'{schedule_name}',
'Schedule_Type_Limits_Name': self.idf_type_limits[schedules[0].data_type],
'Field_1': 'Through: 12/31'}
for j, schedule in enumerate(schedules):
_val = schedule.values
_new_field = ''
for day_type in schedule.day_types:
_new_field += f' {self.idf_day_types[day_type]}'
_kwargs[f'Field_{j * 25 + 2}'] = f'For:{_new_field}'
for i in range(0, len(_val)):
_kwargs[f'Field_{j * 25 + 3 + i}'] = f'Until: {i + 1:02d}:00,{_val[i]}'
_idf.newidfobject(self._COMPACT_SCHEDULE, **_kwargs)
def _add_schedules(self, _idf, thermal_zone):
self._add_standard_compact_hourly_schedule(_idf, 'user_occupancy_schedule',
thermal_zone.occupancy.occupancy_schedules)
self._add_standard_compact_hourly_schedule(_idf, 'user_lighting_schedule',
thermal_zone.lighting.schedules)
self._add_standard_compact_hourly_schedule(_idf, 'user_appliances_schedule',
thermal_zone.appliances.schedules)
self._add_standard_compact_hourly_schedule(_idf, 'user_heating_schedule',
thermal_zone.thermal_control.heating_set_point_schedules)
self._add_standard_compact_hourly_schedule(_idf, 'user_cooling_schedule',
thermal_zone.thermal_control.cooling_set_point_schedules)
def _add_usage(self, _idf):
_thermal_zone = None
for building in self._city.buildings:
for internal_zone in building.internal_zones:
for thermal_zone in internal_zone.thermal_zones:
_thermal_zone = thermal_zone
# Dompark project share schedules and usages among all the buildings so we could add just the first one
break
break
break
self._add_schedules(_idf, _thermal_zone)
fraction_radiant = _thermal_zone.occupancy.sensible_radiative_internal_gain / \
(_thermal_zone.occupancy.sensible_radiative_internal_gain +
_thermal_zone.occupancy.sensible_convective_internal_gain)
for idf_object in _idf.idfobjects[self._PEOPLE]:
idf_object['Number_of_People_Schedule_Name'] = 'user_occupancy_schedule'
idf_object['People_per_Zone_Floor_Area'] = _thermal_zone.occupancy.occupancy_density
idf_object['Fraction_Radiant'] = fraction_radiant
for idf_object in _idf.idfobjects[self._LIGHTS]:
idf_object['Schedule_Name'] = 'user_lighting_schedule'
idf_object['Watts_per_Zone_Floor_Area'] = _thermal_zone.lighting.density
for idf_object in _idf.idfobjects[self._APPLIANCES]:
idf_object['Schedule_Name'] = 'user_appliances_schedule'
idf_object['Power_per_Zone_Floor_Area'] = _thermal_zone.appliances.density
for idf_object in _idf.idfobjects[self._HEATING_COOLING]:
idf_object['Heating_Setpoint_Temperature_Schedule_Name'] = 'user_heating_schedule'
idf_object['Cooling_Setpoint_Temperature_Schedule_Name'] = 'user_cooling_schedule'
return
@role_required([UserRoles.Admin.value, UserRoles.Hub_Reader.value])
def get(self, city_id):
payload = request.get_json()
self._city = self.get_city(city_id)
self._greenery_percentage = round(float(payload['greenery_percentage']) / 10) * 10
output_file = str((self._output_path / 'dompark.idf').resolve())
idd_file = str((self._data_path / 'energy+.idd').resolve())
epw_file = str((self._data_path / 'CAN_PQ_Montreal.Intl.AP.716270_CWEC.epw').resolve())
idf_file = str((self._data_path / 'dompark.idf').resolve())
IDF.setiddname(idd_file)
_idf = IDF(idf_file, epw_file)
self._add_materials(_idf)
self._add_usage(_idf)
_idf.newidfobject(
"OUTPUT:VARIABLE",
Variable_Name="Zone Ideal Loads Supply Air Total Heating Energy",
Reporting_Frequency="Hourly",
)
_idf.newidfobject(
"OUTPUT:VARIABLE",
Variable_Name="Zone Ideal Loads Supply Air Total Cooling Energy",
Reporting_Frequency="Hourly",
)
# From EnergyPlus documentation: Lights Electric Energy [J]
# The lighting electrical consumption including ballasts, if present. These will have the same value as Lights
# Total Heating Energy (above).
_idf.newidfobject(
"OUTPUT:VARIABLE",
Variable_Name="Lights Total Heating Energy",
Reporting_Frequency="Hourly",
)
_idf.newidfobject(
"OUTPUT:VARIABLE",
Variable_Name="Other Equipment Total Heating Energy",
Reporting_Frequency="Hourly",
)
_idf.match()
_idf.saveas(str(output_file))
_idf.run(expandobjects=True, readvars=True, output_directory=self._output_path, output_prefix='dompark_')
# Todo: set the heating and cooling
heating = []
cooling = []
lighting = []
appliances = []
with open((self._output_path / f'dompark_out.csv').resolve()) as f:
reader = csv.reader(f, delimiter=',')
for row in reader:
if '00:00' in row[0]:
cooling_value = 0.0
heating_value = 0.0
lighting_value = 0.0
appliances_value = 0.0
for i in range(1, 38):
lighting_value += float(row[i])
for i in range(38, 73):
appliances_value += float(row[i])
for i in range(73, 133, 2):
heating_value += float(row[i])
cooling_value += float(row[i + 1])
cooling.append(cooling_value)
heating.append(heating_value)
lighting.append(lighting_value)
appliances.append(appliances_value)
files = glob.glob(f'{self._output_path}/dompark*')
for file in files:
os.remove(file)
continue
response = {'heating_demand': heating,
'cooling_demand': cooling,
'lighting_demand': lighting,
'appliances_demand': appliances
}
return Response(json.dumps(response), status=200)

View File

@ -1,76 +0,0 @@
"""
HeatPump Service
SPDX - License - Identifier: LGPL - 3.0 - or -later
Copyright © 2023 Project Author Peter Yefi peteryefi@gmail.com
"""
import json
from flask import Response, request
from flask_restful import Resource
from hub.hub_logger import logger
from hub_api.helpers.auth import generate_auth_token, role_required
from hub.persistence.models import UserRoles
from hub_api.config import Config
headers = {'Content-Type': 'application/json'}
class User(Resource, Config):
def __init__(self):
super().__init__()
@role_required([UserRoles.Admin.value])
def post(self):
try:
payload = request.get_json()
user = self.user_factory.create_user(name=payload["name"], email=payload["email"], password=payload["password"],
role=payload["role"])
if type(user) is dict:
return Response(response=json.dumps(user), status=400, headers=headers)
return Response(response=json.dumps({'user': {'id': user.id, 'name': user.name, 'email': user.email,
'password': user.password, 'role': user.role.value}}), status=201,
headers=headers)
except Exception as err:
logger.error(err)
return Response(response=json.dumps({'err_msg': 'Sorry an error occurred while creating user'}), status=400,
headers=headers)
@role_required([UserRoles.Admin.value])
def put(self):
try:
payload = request.get_json()
res = self.user_factory.update_user(user_id=payload['id'], name=payload['name'], password=payload['password'],
role=payload['role'], email=payload['email'])
if res:
return Response(response=json.dumps(res), status=400, headers=headers)
return Response(response=json.dumps({'success': 'user updated successfully'}), status=200, headers=headers)
except Exception as err:
logger.error(err)
return Response(response=json.dumps({'err_msg': 'Sorry, an error occurred while updating user'}),
status=400, headers=headers)
class UserLogin(Resource, Config):
def __init__(self):
super().__init__()
def post(self):
try:
payload = request.get_json()
user = self.ex_user_factory.login_user(email=payload["email"], password=payload["password"])
if type(user) is dict:
return Response(response=json.dumps(user), status=400, headers=headers)
user = user[0]
user_dict = {
'user': {
'id': user.id,
'name': user.name,
'email': user.email,
'password': user.password,
'role': user.role.value,
}
}
user_dict['token'] = generate_auth_token(user_dict)
return Response(response=json.dumps(user_dict), status=200, headers=headers)
except Exception as err:
logger.error(err)
return Response(response=json.dumps({'err_msg': 'An error occurred while authenticating user'}), status=400)

View File

@ -24,4 +24,6 @@ pyecore==0.12.2
jwt==1.3.1 jwt==1.3.1
flagger==3.1.0 flagger==3.1.0
flasgger flasgger
cerc-hub cerc-hub
python-dotenv