from base64 import b64encode import os from helix.constants.system_type import SystemType from helix.constants.version import version class DocGenParamsBuilder(object): def __init__(self, user_values, system_type, calculator, image_presenter): self.user_values = user_values self.system_type = system_type self.calculator = calculator self.image_presenter = image_presenter def build(self): if self.user_values.system_type() == SystemType.singleTilt: template_name = 'Helix_Single_Tilt_Template' else: template_name = 'Helix_Dual_Tilt_Template' body = { **self.site_characterization(), **self.calculator.documentation_summary_values(), **self.panel_attributes(), **self.bom(), **self.power_stations(), **self.standalone_inverters(), **self.subarray_summary(), } image_dicts = self.array_image() list_params = self.convert_dict_params_to_list(body) images = self.convert_dict_params_to_list(image_dicts, key_name='imageKey', value_name='base64encodedImage') api_key = os.getenv('SP_DOCGEN_API_KEY', '') params = { "apiKey": api_key, "templateName": template_name, "nameValuePairs": list_params, "dynamicImages": images, } return params def site_characterization(self): panels = self.calculator.get_computed_csv_columns() return { 'project_name': self.user_values.project_name(), 'building_height': self.user_values.building_height(), 'building_width': self.user_values.building_width(), 'building_length': self.user_values.building_length(), 'parapet_height': self.user_values.building_parapet_height(), 'ballast_block_weight': self.user_values.ballast_block_weight(), 'max_allowable_system_pressure': self.user_values.max_system_pressure(), 'anchor_type': self.user_values.anchor_type().value, 'exposure_category': self.user_values.exposure_category().value, 'exposure_category_transition_distance': self.user_values.exposure_category_transition_distance(), 'wind_speed': self.user_values.wind_speed(), 'spectral_response': self.user_values.spectral_response(), 'seismic_importance_factor': self.user_values.importance_factor(), 'module_type': self.user_values.module_type().value, 'system_type': self.user_values.system_type().display_name(), 'total_modules': len(panels), 'version': version(), 'lb': round(self.calculator.L_B(), 2), 'kz': round(self.calculator.k_z(), 2), 'qz': round(self.calculator.q_z(), 2), } def panel_attributes(self): summary_table = self.calculator.summary_table() minimum_array_sizes = self.calculator.minimum_array_sizes() result = {} for panel_type, values in summary_table.items(): ballast_blocks = values['ballast blocks'] pressure = values['pressure'] anchors = values['anchors'] for wind_zone_index in range(len(ballast_blocks)): wind_zone = self.system_type.system_constants().wind_zones[wind_zone_index].lower() prefix = '%d_%s_' % (panel_type.number(), wind_zone) result[prefix + 'bb'] = ballast_blocks[wind_zone_index] result[prefix + 'psf'] = pressure[wind_zone_index] result[prefix + 'anc'] = anchors[wind_zone_index] for idx, array_size in enumerate(minimum_array_sizes): wind_zone = self.system_type.system_constants().wind_zones[idx].lower() result['min_' + wind_zone] = array_size return result def bom(self): bom_values = self.calculator.documentation_bom() result = {} for row in bom_values: result['total_' + row[0]] = row[1] return result def power_stations(self): power_station_string = "" power_stations = self.user_values.power_stations() if len(power_stations) > 0: power_station_string = "\n" for power_station in self.user_values.power_stations(): power_station_string += "Description: %s\n" % power_station['power_station_description'] power_station_string += "\tQuantity: %s\n" % power_station['power_station_quantity'] power_station_string += "\tAC Run Length: %s\n" % power_station['ac_run_length'] power_station_string += "\tInverters:\n" for inverter in power_station['inverters']: power_station_string += "\t\tModel: %s\n" % inverter['model'].label power_station_string += "\t\tStrings per inverter: %s\n" % inverter['strings_per_inverter'] if inverter.get('sunshade'): power_station_string += "\t\tSunShade: Yes\n" if inverter.get('dc_switch'): power_station_string += "\t\tDC Switch: Yes\n" power_station_string += "\n" return {'power_station_string': power_station_string} def standalone_inverters(self): inverters_string = "" for inverter in self.user_values.standalone_inverters(): inverters_string += "\n" inverters_string += "\tAC Run Length: %s\n" % inverter['ac_run_length'] inverters_string += "\tAttachment Point: %s\n" % inverter['attachment_point'][0] inverters_string += "\tModel: %s\n" % inverter['model'].label inverters_string += "\tStrings per inverter: %s\n" % inverter['strings_per_inverter'] if inverter.get('sunshade'): inverters_string += "\tSunShade: Yes\n" if inverter.get('dc_switch'): inverters_string += "\tDC Switch: Yes\n" return {'standalone_inverter_string': inverters_string} def subarray_summary(self): subarray_string = "" for subarray in self.calculator.subarray_summary(): subarray_string += "\n" subarray_string += "\tSubarray: %d\n" % subarray.subarray_number subarray_string += "\tSeismic Anchors: %d\n" % subarray.required_seismic_anchors subarray_string += "\tWeight: %s lbs\n" % "{:,}".format(round(subarray.weight)) return {'subarrays_string': subarray_string} def array_image(self): png_data = self.image_presenter.generate_image(self.calculator.get_computed_csv_columns(), self.calculator.subarrays) return {'array_image': b64encode(png_data).decode('utf-8')} @staticmethod def convert_list_params_to_dict(list_params): dict_params = {} for datum in list_params: dict_params[datum['name']] = datum['value'] return dict_params @staticmethod def convert_dict_params_to_list(dict_params, key_name='name', value_name='value'): list_params = [] for k, v in dict_params.items(): list_params.append({ key_name: k, value_name: v }) return sorted(list_params, key=lambda k: k[key_name])