diff --git a/.gitignore b/.gitignore index 32e5c2fe6d39c39244773d78ed08d793965577f7..1464721599f01a846af9f5c40e99ce6a0203f7e1 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,6 @@ build .coverage coverage* htmlcov + +# pptx files +*.pptx diff --git a/bpeng/reports/cbra_diag.py b/bpeng/reports/cbra_diag.py index d5e56916d5c6d6529b360557cbd09870e93efb92..fddea4b957f41e216aa5c9ea7fac503d834e7d5c 100644 --- a/bpeng/reports/cbra_diag.py +++ b/bpeng/reports/cbra_diag.py @@ -22,6 +22,7 @@ from pptx.enum.text import ( ) from pptx.util import Inches, Pt +from .constants import ECM_TO_SLIDE, RETROFIT_TO_CBRA_RETROFIT class CbraDiagnostic: """ @@ -71,9 +72,40 @@ class CbraDiagnostic: heat_loss_val = heat_loss_data['heat_loss_val'] ecm_list = ecm_data['ecm_list'] - ecm_delete_list = ecm_data['ecm_delete_list'] ecm_heat_save = ecm_data['ecm_heat_save'] ecm_elec_save = ecm_data['ecm_elec_save'] + # Convert database strings to presentation strings + # Also calculate new heat or elec save in cases where + # database ecm's are combined to a single presentation ecm + new_ecm_list = [] + new_ecm_heat_save = [] + new_ecm_elec_save = [] + for name, heat, elec in zip(ecm_list, ecm_heat_save, ecm_elec_save): + presentation_name = ECM_TO_SLIDE[name]['slide_name'] + if presentation_name in new_ecm_list: + combine_index = new_ecm_list.index(presentation_name) + # Right now we just add together heat and elec. + # In the future we might want to calculate the combined value for + # heat and elec differently based on the ECM + new_ecm_heat_save[combine_index] += heat + new_ecm_elec_save[combine_index] += elec + else: + new_ecm_list.append(presentation_name) + new_ecm_heat_save.append(heat) + new_ecm_elec_save.append(elec) + ecm_list = new_ecm_list + ecm_heat_save = new_ecm_heat_save + ecm_elec_save = new_ecm_elec_save + + # Create a delete list by adding everything not in the ecm_list + ecm_delete_list = set() + for slide in ECM_TO_SLIDE.values(): + if slide['slide_name'] not in ecm_list: + ecm_delete_list.add(slide['slide_index']) + + ecm_delete_list = list(ecm_delete_list) + # Put delete list in reverse order so we delete from the back + ecm_delete_list.sort(reverse=True) # Define presentation to edit as the finished template diag_rep = Presentation(template_file) @@ -328,14 +360,11 @@ class CbraDiagnostic: ecm_table.table.cell(ecm_count+1, 2).text = str(annual_energy_percent) + '\N{PERCENT SIGN}' # Slides 5-end: removing slides based on recommendations - deleted_slide_counter = 0 - NUM_NON_ECM_SLIDES = 4 for ecm_index in ecm_delete_list: diag_rep.slides.delete_slide( diag_rep, - ecm_index + NUM_NON_ECM_SLIDES - deleted_slide_counter, + ecm_index, ) - deleted_slide_counter += 1 return project_address, diag_rep @@ -410,22 +439,19 @@ class CbraDiagnostic: } ecm_list = [] - ecm_delete_list = [] ecm_heat_save = [] ecm_elec_save = [] for j in range(len(input_values)): if input_values[j] == 'Y': - ecm_list.append(input_list[j]) + # Convert to database string + ecm_list.append( + RETROFIT_TO_CBRA_RETROFIT[input_list[j]] + ) ecm_heat_save.append(input_values[j+1]) ecm_elec_save.append(input_values[j+2]) - if input_values[j] == 'N': - ecm_index = int((j-20)/3) - ecm_delete_list.append(ecm_index) - ecm_data = { 'ecm_list': ecm_list, - 'ecm_delete_list': ecm_delete_list, 'ecm_heat_save': ecm_heat_save, 'ecm_elec_save': ecm_elec_save, } @@ -453,7 +479,19 @@ class CbraDiagnostic: file_name = repgen_list[i] file_input = pd.ExcelFile(file_name) sheet_input = file_input.parse("Inputs", header=None) - proj_loc, diag_rep = CbraDiagnostic._generate_report(template_file, sheet_input) + ( + project_summary_data, + util_break_data, + heat_loss_data, + ecm_data + ) = CbraDiagnostic.parse_arguments(sheet_input) + proj_loc, diag_rep = CbraDiagnostic._generate_report( + template_file, + project_summary_data, + util_break_data, + heat_loss_data, + ecm_data, + ) diag_rep.save('EEDR {}.pptx'.format(proj_loc)) print('Reports generated!') else: diff --git a/bpeng/reports/constants.py b/bpeng/reports/constants.py new file mode 100644 index 0000000000000000000000000000000000000000..8e23267507d27e52c0cffb4f381a63e1346a7023 --- /dev/null +++ b/bpeng/reports/constants.py @@ -0,0 +1,212 @@ +ECM_TO_SLIDE = { + 'Weatherstripping (Exterior Doors)': { + 'slide_index': 4, + 'slide_name': 'Install Weather-stripping', + }, + 'Weatherstripping (Windows)': { + 'slide_index': 4, + 'slide_name': 'Install Weather-stripping', + }, + 'Weatherstripping (A/C Units)': { + 'slide_index': 4, + 'slide_name': 'Install Weather-stripping', + }, + 'Window Replacement': { + 'slide_index': 5, + 'slide_name': 'Replace Windows', + }, + 'Insulation (Roof)': { + 'slide_index': 6, + 'slide_name': 'Install Roof Insulation', + }, + 'Cool Roof ': { + 'slide_index': 7, + 'slide_name': 'Install Cool Roof', + }, + 'Boiler Control(Indoor Feedback)': { + 'slide_index': 8, + 'slide_name': 'Install Boiler Control (Indoor Feedback)', + }, + 'Boiler Control(Outdoor Reset)': { + 'slide_index': 9, + 'slide_name': 'Install Boiler Control (Outdoor Reset)', + }, + 'Smart Thermostat w/ Indoor Sensor': { + 'slide_index': 10, + 'slide_name': 'Install Smart Thermostat with Indoor Sensors', + }, + 'Building Management System/ Energy Management system': { + 'slide_index': 11, + 'slide_name': 'Integrate EMS/BMS Systems', + }, + 'Oil to Gas Conversion': { + 'slide_index': 12, + 'slide_name': 'Convert from Oil to Gas', + }, + 'Boiler Replacement': { + 'slide_index': 13, + 'slide_name': 'Replace Boiler', + }, + 'Burner Replacement': { + 'slide_index': 14, + 'slide_name': 'Replace Burner & Controls', + }, + 'Modulating Burner Controls': { + 'slide_index': 14, + 'slide_name': 'Replace Burner & Controls', + }, + 'Sealed Combustion/Power Burner Installation': { + 'slide_index': 14, + 'slide_name': 'Replace Burner & Controls', + }, + 'Pipe Insulation': { + 'slide_index': 15, + 'slide_name': 'Install Pipe Insulation', + }, + 'Smart Pumps': { + 'slide_index': 16, + 'slide_name': 'Install Smart Pumps', + }, + 'Variable Frequency Drive Pumps': { + 'slide_index': 16, + 'slide_name': 'Install Smart Pumps', + }, + 'TRVs (Steam, 1 pipe)': { + 'slide_index': 17, + 'slide_name': 'Install Thermostatic Radiator Valves (TRVs)', + }, + 'TRVs (Steam, 2 pipe)': { + 'slide_index': 17, + 'slide_name': 'Install Thermostatic Radiator Valves (TRVs)', + }, + 'TRVs (Hydronic)': { + 'slide_index': 17, + 'slide_name': 'Install Thermostatic Radiator Valves (TRVs)', + }, + 'Baseboard Replacement': { + 'slide_index': 18, + 'slide_name': 'Clean/Replace Baseboards', + }, + 'Hydronic Conversion': { + 'slide_index': 19, + 'slide_name': 'Convert from Steam to Hydronic', + }, + 'Master Venting': { + 'slide_index': 20, + 'slide_name': 'Install Master Venting', + }, + 'Steam Boiler Setting Optimization': { + 'slide_index': 21, + 'slide_name': 'Optimize Boiler\'s Pressure', + }, + 'Air Vent Installation/Replacement': { + 'slide_index': 22, + 'slide_name': 'Install Air Vents', + }, + 'Steam Trap Installation/Replacement (1 pipe)': { + 'slide_index': 23, + 'slide_name': 'Install Steam Traps', + }, + 'Steam Trap Installation/Replacement (2 pipe)': { + 'slide_index': 23, + 'slide_name': 'Install Steam Traps', + }, + 'Condensate Removal System Upgrade': { + 'slide_index': 24, + 'slide_name': 'Install Effective Condensate Removal', + }, + 'Vented Condensate Pumps': { + 'slide_index': 24, + 'slide_name': 'Install Effective Condensate Removal', + }, + 'Steam Boiler Anode Bars': { + 'slide_index': 25, + 'slide_name': 'Install Anode Bars in Boiler Tank', + }, + 'Rooftop Unit Replacement': { + 'slide_index': 26, + 'slide_name': 'Replace Roof Top Units', + }, + 'DHW Temperature Controls': { + 'slide_index': 27, + 'slide_name': 'Improve DHW Temperature Control', + }, + 'Tankless Water Heater': { + 'slide_index': 28, + 'slide_name': 'Install Tankless Water Heater', + }, + 'Tanked Water Heater': { + 'slide_index': 29, + 'slide_name': 'Install Tanked Water Heater', + }, + 'Solar Water Heater': { + 'slide_index': 30, + 'slide_name': 'Install Solar Water Heaters', + }, + 'Low-Flow Water Fixtures': { + 'slide_index': 31, + 'slide_name': 'Install Low-Flow Water Fixtures', + }, + 'Automatic Water Meter Reader': { + 'slide_index': 32, + 'slide_name': 'Install Automated Meter Reader', + }, + 'LED Lighting Install': { + 'slide_index': 33, + 'slide_name': 'Install LEDs and Lighting Controls', + }, + 'Lighting Controls (Motion Sensors/Timer)': { + 'slide_index': 33, + 'slide_name': 'Install LEDs and Lighting Controls', + }, + 'Solar Panels': { + 'slide_index': 34, + 'slide_name': 'Install Solar Panels', + }, + 'Replace Unit Appliances w/ Energy Star Models': { + 'slide_index': 35, + 'slide_name': 'Replace Appliances with Energy Star Appliances', + }, + 'Replace Laundry Room Appliances w/ Energy Star Models': { + 'slide_index': 35, + 'slide_name': 'Replace Appliances with Energy Star Appliances', + }, +} + +# Convert template ECM names to the names that are in the database +# Template ECM to database ECM is a 1 to n mapping so we just take the first one + +RETROFIT_TO_CBRA_RETROFIT = { + 'Install Weather-stripping': 'Weatherstripping (Exterior Doors)', + 'Replace Windows': 'Window Replacement', + 'Install Roof Insulation': 'Insulation (Roof)', + 'Install Cool Roof': 'Cool Roof ', + 'Install Boiler Control (Indoor Feedback)': 'Boiler Control(Indoor Feedback)', + 'Install Boiler Control (Outdoor Reset)': 'Boiler Control(Outdoor Reset)', + 'Install Smart Thermostat with Indoor Sensors': 'Smart Thermostat w/ Indoor Sensor', + 'Integrate EMS/BMS Systems': 'Building Management System/ Energy Management system', + 'Convert from Oil to Gas': 'Oil to Gas Conversion', + 'Replace Boiler': 'Boiler Replacement', + 'Replace Burner & Controls': 'Burner Replacement', + 'Install Pipe Insulation': 'Pipe Insulation', + 'Install Smart Pumps': 'Smart Pumps', + 'Install Thermostatic Radiator Valves (TRVs)': 'TRVs (Steam, 1 pipe)', + 'Clean/Replace Baseboards': 'Baseboard Replacement', + 'Convert from Steam to Hydronic': 'Hydronic Conversion', + 'Install Master Venting': 'Master Venting', + 'Optimize Boiler\'s Pressure': 'Steam Boiler Setting Optimization', + 'Install Air Vents': 'Air Vent Installation/Replacement', + 'Install Steam Traps': 'Steam Trap Installation/Replacement (1 pipe)', + 'Install Effective Condensate Removal': 'Condensate Removal System Upgrade', + 'Install Anode Bars in Boiler Tank': 'Steam Boiler Anode Bars', + 'Replace Roof Top Units': 'Rooftop Unit Replacement', + 'Improve DHW Temperature Control': 'DHW Temperature Controls', + 'Install Tankless Water Heater': 'Tankless Water Heater', + 'Install Tanked Water Heater': 'Tanked Water Heater', + 'Install Solar Water Heaters': 'Solar Water Heater', + 'Install Low-Flow Water Fixtures': 'Low-Flow Water Fixtures', + 'Install Automated Meter Reader': 'Automatic Water Meter Reader', + 'Install LEDs and Lighting Controls ': 'LED Lighting Install', + 'Install Solar Panels': 'Solar Panels', + 'Replace Appliances with Energy Star Appliances': 'Replace Unit Appliances w/ Energy Star Models', +} diff --git a/bpeng/tests/data/test_reports.xlsx b/bpeng/tests/data/test_reports.xlsx index e425486b87c7241958ae5f72c2e050d04a6b218f..086495765ff121ba502d3fb8b9ec124b04237ba7 100644 Binary files a/bpeng/tests/data/test_reports.xlsx and b/bpeng/tests/data/test_reports.xlsx differ diff --git a/bpeng/tests/test_reports.py b/bpeng/tests/test_reports.py index c2a2bbc30848f0216119a33cfc8c0f40b8763a7c..3e29ba71e53d74c86220b3fad5758cdb354b12b8 100644 --- a/bpeng/tests/test_reports.py +++ b/bpeng/tests/test_reports.py @@ -29,25 +29,28 @@ class TestReports: assert heat_loss_data['heat_loss_val'][12] == 18.44 assert len(ecm_data['ecm_list']) == 16 - assert ecm_data['ecm_list'][1] == 'Replace Windows' - -# def test_report_generator(self): -# with open(os.path.join(BASE_DIR, 'data/test_reports.xlsx'), 'r+b') as f: -# file_input = pd.ExcelFile(f) -# sheet_input = file_input.parse("Inputs", header=None) -# ( -# project_summary_data, -# util_break_data, -# heat_loss_data, -# ecm_data -# ) = CbraDiagnostic.parse_arguments(sheet_input) -# -# -# project_address, diag_rep = CbraDiagnostic._generate_report( -# 'bpeng/tests/data/cbra_template.pptx', -# project_summary_data, -# util_break_data, -# heat_loss_data, -# ecm_data, -# ) -# diag_rep.save('EEDR_test.pptx') + assert ecm_data['ecm_list'][1] == 'Window Replacement' + + def test_report_generator(self): + with open(os.path.join(BASE_DIR, 'data/test_reports.xlsx'), 'r+b') as f: + file_input = pd.ExcelFile(f) + sheet_input = file_input.parse("Inputs", header=None) + ( + project_summary_data, + util_break_data, + heat_loss_data, + ecm_data + ) = CbraDiagnostic.parse_arguments(sheet_input) + ecm_data['ecm_list'].append('Weatherstripping (Windows)') + ecm_data['ecm_heat_save'].append(500) + ecm_data['ecm_elec_save'].append(25) + + + project_address, diag_rep = CbraDiagnostic._generate_report( + 'bpeng/tests/data/cbra_template.pptx', + project_summary_data, + util_break_data, + heat_loss_data, + ecm_data, + ) + diag_rep.save('EEDR_test.pptx')