Index: dialin/hd/sw_config.py =================================================================== diff -u -rdc3b97933c58b8854781f2984083a2f8eccd3217 -r4ec12397809c5820ee654aaffe5924e67a79a072 --- dialin/hd/sw_config.py (.../sw_config.py) (revision dc3b97933c58b8854781f2984083a2f8eccd3217) +++ dialin/hd/sw_config.py (.../sw_config.py) (revision 4ec12397809c5820ee654aaffe5924e67a79a072) @@ -291,7 +291,8 @@ @return: none """ # Create the excel report - self._utilities.prepare_excel_report(self._FIRMWARE_STACK_NAME, self._NON_VOLATILE_RECORD_NAME, report_address) + self._utilities.prepare_excel_report(self._FIRMWARE_STACK_NAME, self._NON_VOLATILE_RECORD_NAME, report_address, + protect_sheet=True) # Request the latest software configuration record from firmware self._cmd_request_hd_sw_config_record() # Create ab object of the observer class to observe the dictionary Index: dialin/utils/excel_ops.py =================================================================== diff -u -rdc3b97933c58b8854781f2984083a2f8eccd3217 -r4ec12397809c5820ee654aaffe5924e67a79a072 --- dialin/utils/excel_ops.py (.../excel_ops.py) (revision dc3b97933c58b8854781f2984083a2f8eccd3217) +++ dialin/utils/excel_ops.py (.../excel_ops.py) (revision 4ec12397809c5820ee654aaffe5924e67a79a072) @@ -17,7 +17,7 @@ import os import math import datetime -from openpyxl.styles import PatternFill, Font, Alignment +from openpyxl.styles import PatternFill, Font, Alignment, Protection from openpyxl.utils import get_column_letter from openpyxl import Workbook, load_workbook @@ -39,14 +39,15 @@ return Workbook() -def setup_excel_worksheet(workbook_obj, title, index=None): +def setup_excel_worksheet(workbook_obj, title, index=None, protection=False): """ Creates the worksheets in the created excel file with the name of each software_project_name as the name of the worksheet. @param workbook_obj: Excel workbook object @param title: Title of the created worksheet @param index: Index of the worksheet. If a sheet needs to be at a certain place (default none) + @param protection: Flag to indicate whether the worksheet is write protected or not (default False) @return none """ @@ -65,6 +66,10 @@ # Create a tab and name the tab with the name of the projects dictionary workbook_obj.create_sheet(title=title, index=index) + # Check if the created worksheet must be write protected and if yes, protect it + if protection: + workbook_obj[title].protection.sheet = True + # If the first tab is Sheet or Sheet1, remove it # The other tabs must be created first before removing the default tab if workbook_obj.sheetnames[0] == 'Sheet' or workbook_obj.sheetnames[0] == 'Sheet1': @@ -73,7 +78,7 @@ def write_to_excel(workbook_obj, project, row, column, data, name='Calibri', font=11, bold=False, color=None, - merge=None, horizontal='left', freeze=False, max_col_len=None): + merge=None, horizontal='left', freeze=False, max_col_len=None, protect_cell=False): """ This function writes data at the specified row and column in an excel file (object). @@ -90,6 +95,7 @@ @param horizontal: Horizontal alignment (default left) @param freeze: Freeze top row (default false) @param max_col_len: maximum length of a column (default none, means it is not restricted) + @param protect_cell: flag to indicate whether to write protect cell or not (default False) @return: None """ @@ -148,7 +154,9 @@ # To freeze row 1, make the cell is not row 1, that's why A2 was chosen active_sheet.freeze_panes = 'A2' + active_sheet.cell(row, column).protection = Protection(locked=protect_cell) + def load_excel_report(path): """ This function returns an object of a currently existing excel workbook Index: dialin/utils/nv_ops_utils.py =================================================================== diff -u -r4db75b6fc3f6f9219262738bee0bdb3a50f8d971 -r4ec12397809c5820ee654aaffe5924e67a79a072 --- dialin/utils/nv_ops_utils.py (.../nv_ops_utils.py) (revision 4db75b6fc3f6f9219262738bee0bdb3a50f8d971) +++ dialin/utils/nv_ops_utils.py (.../nv_ops_utils.py) (revision 4ec12397809c5820ee654aaffe5924e67a79a072) @@ -105,6 +105,7 @@ _SW_CONFIGS_TITLE_COL = 'SW Configurations' _SW_CONFIGS_VALUE_COL = 'Status' + _SW_CONFIGS_REPORT_NAME = 'SW-Configs' def __init__(self, logger: Logger): """ @@ -150,13 +151,14 @@ os.mkdir(self._workspace_dir) os.chdir(self._workspace_dir) - def prepare_excel_report(self, firmware_stack: str, record_name: str, directory: str): + def prepare_excel_report(self, firmware_stack: str, record_name: str, directory: str, protect_sheet: bool = False): """ Publicly accessible function to prepare the excel report @param firmware_stack: (str) firmware stack name (e.g. "HD" or "DG") @param record_name: (str) record type to check such as calibration, system, ... @param directory: (str) the directory in which to write the excel document. + @param protect_sheet: (bool) flag to indicate whether to write protect the sheet or not (default False) @return none """ path = '' @@ -202,15 +204,14 @@ self._excel_workbook = get_an_excel_workbook() # Setup worksheet and create the current tab - setup_excel_worksheet(self._excel_workbook, self._record_name) + setup_excel_worksheet(self._excel_workbook, self._record_name, protection=protect_sheet) def write_fw_record_to_excel(self, calibration_record: dict): """ Writes a calibration record to excel @param calibration_record: (dict) the record to write to excel @return: None """ - try: row = 1 for group in calibration_record.keys(): @@ -523,13 +524,8 @@ except Exception as e: self.logger.error("Failed to process received record from fw: {0}".format(e)) - def _process_fw_record(self, - calibration_record: dict, - fw_raw_records_bytes: bytearray, - group: str, - key: str, - read_start_index: int, - inner_key=None): + def _process_fw_record(self, calibration_record: dict, fw_raw_records_bytes: bytearray, group: str, key: str, + read_start_index: int, inner_key=None): """ Handles processing the received record from firmware @@ -866,7 +862,7 @@ return padding_size - def write_sw_config_to_excel(self, sw_configs: OrderedDict, stack_name): + def write_sw_config_to_excel(self, sw_configs: OrderedDict, stack_name: str): """ Publicly accessible function to write the software configurations into an excel report @@ -879,26 +875,27 @@ names_col_number = 2 write_to_excel(self._excel_workbook, self._record_name, row, names_col_number, self._SW_CONFIGS_TITLE_COL, - bold=True, freeze=True) + bold=True, freeze=True, protect_cell=True) values_col_number = 3 write_to_excel(self._excel_workbook, self._record_name, row, values_col_number, self._SW_CONFIGS_VALUE_COL, - bold=True) + bold=True, protect_cell=True) # Prepare for writing the values row += 1 for key, values in sw_configs['sw_configs'].items(): - write_to_excel(self._excel_workbook, self._record_name, row, names_col_number, key, bold=True) + write_to_excel(self._excel_workbook, self._record_name, row, names_col_number, key, bold=True, + protect_cell=True) # Get the configuration value config_value = values[1] # If the config value is not 0, color the cell as green otherwise, leave it none colored color = GREEN if config_value != 0 else None write_to_excel(self._excel_workbook, self._record_name, row, values_col_number, config_value, color=color) row += 1 - save_report(self._excel_workbook, self._workspace_dir, 'SW-Configs', stack_name=stack_name) + save_report(self._excel_workbook, self._workspace_dir, self._SW_CONFIGS_REPORT_NAME, stack_name=stack_name) def get_sw_configs_from_excel(self, sw_configs_dict: OrderedDict, excel_path: str, sw_config_excel_tab: str): """ @@ -947,15 +944,32 @@ last_non_empty_row = active_sheet.max_row # Get the dictionary of the provided sw configurations dictionary, this can be either HD or DG fw_sw_configs = sw_configs_dict['sw_configs'] - # Loop through the excel from row 2 since row 1 is the titles row until the last non-empty row + # Loop through the excel from row 2 since row 1 is the titles row until the last non-empty row + 1 since the + # range method does not include that last element so the last non-empty row will not be covered if there is + # not a +1. for row in range(2, last_non_empty_row + 1): config = active_sheet.cell(row=row, column=title_col).value if config is not None: # Check if the software configuration that has been read from excel exists in dictionary that has # been prepared in Dialin if config.strip() in fw_sw_configs: - fw_sw_configs[config.strip()][1] = active_sheet.cell(row=row, column=value_col).value + excel_config_value = active_sheet.cell(row=row, column=value_col).value + # Check if the value is an integer and it is a 1 or a 0 + # The only acceptable values are 1 for enable and 0 for disable + if isinstance(excel_config_value, int) and excel_config_value == 1 or excel_config_value == 0: + fw_sw_configs[config.strip()][1] = excel_config_value + else: + # If the value is not acceptable, set the default value that is sent down to firmware to 0 + # and write incorrect into the report so the user will notice that they had and empty cell + # or a cell with a non-acceptable value (i.e. 123). Color the cell as red. + fw_sw_configs[config.strip()][1] = 0 + write_to_excel(self._excel_workbook, sw_config_excel_tab, row, value_col, 'Incorrect Value', + color=RED) + # Save back the excel workbook with the changes + # This save function is the openpyxl save and not the internal save function that creates + # the save path. The save path already exists + self._excel_workbook.save(filename=excel_path) status = True return status Index: tests/dg_tests.py =================================================================== diff -u -r8841ca865ff616ea3de171bc4037c349aaac7934 -r4ec12397809c5820ee654aaffe5924e67a79a072 --- tests/dg_tests.py (.../dg_tests.py) (revision 8841ca865ff616ea3de171bc4037c349aaac7934) +++ tests/dg_tests.py (.../dg_tests.py) (revision 4ec12397809c5820ee654aaffe5924e67a79a072) @@ -561,10 +561,10 @@ # cmd_set_disinfect_ui_screen() - # collect_treatment_data() + collect_treatment_data() # collect_hd_treatment() # test_hd_fans_alarms() - test_dg_fans_alarms() + # test_dg_fans_alarms() Index: tests/peter/test_dg_records.py =================================================================== diff -u -rdc3b97933c58b8854781f2984083a2f8eccd3217 -r4ec12397809c5820ee654aaffe5924e67a79a072 --- tests/peter/test_dg_records.py (.../test_dg_records.py) (revision dc3b97933c58b8854781f2984083a2f8eccd3217) +++ tests/peter/test_dg_records.py (.../test_dg_records.py) (revision 4ec12397809c5820ee654aaffe5924e67a79a072) @@ -208,14 +208,14 @@ sleep(0.2) print(dg.calibration_record.dg_calibration_record) - + """ dg.calibration_record.dg_calibration_record['flow_sensors']['dialysate_flow_sensor']['offset'][1] = 0.885 dg.calibration_record.dg_calibration_record['flow_sensors']['dialysate_flow_sensor']["cal_time"][1] = \ NVOpsUtils.get_current_time_in_epoch() dg.calibration_record.dg_calibration_record['flow_sensors']['dialysate_flow_sensor']["crc"][1] = \ NVOpsUtils.get_group_record_crc(dg.calibration_record.dg_calibration_record['flow_sensors']['dialysate_flow_sensor']) - """ + # Change the value(s) you are planning to change directly to the dictionary dg.calibration_record.dg_calibration_record["pressure_sensors"]["ppi"]["fourth_order"][1] = 0.0 dg.calibration_record.dg_calibration_record["pressure_sensors"]["ppi"]["gain"][1] = 1.0 @@ -228,34 +228,65 @@ dg.calibration_record.dg_calibration_record["pressure_sensors"]["ppo"]["cal_time"][1] = \ NVOpsUtils.get_current_time_in_epoch() dg.calibration_record.dg_calibration_record["pressure_sensors"]["ppo"]["crc"][1] = \ - NVOpsUtils.get_group_record_crc(dg.calibration_record.dg_calibration_record["pressure_sensors"]["ppo"]) + NVOpsUtils.get_group_record_crc(dg.calibration_record.dg_calibration_record["pressure_sensors"]["ppo"]) + """ - dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_a1"]["gain"][1] = 1.0 + dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_a1"]["gain"][1] = 1.058527274 + dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_a1"]["offset"][1] = -127.3129791 dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_a1"]["cal_time"][1] = \ NVOpsUtils.get_current_time_in_epoch() dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_a1"]["crc"][1] = \ NVOpsUtils.get_group_record_crc(dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_a1"]) - """ - dg.calibration_record.cmd_set_dg_calibration_record(dg.calibration_record.dg_calibration_record) + dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_a2"]["gain"][1] = 0.988036262 + dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_a2"]["offset"][1] = -116.6615859 + dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_a2"]["cal_time"][1] = \ + NVOpsUtils.get_current_time_in_epoch() + dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_a2"]["crc"][1] = \ + NVOpsUtils.get_group_record_crc(dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_a2"]) + dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_b1"]["gain"][1] = 0.992981302 + dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_b1"]["offset"][1] = -49.84277209 + dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_b1"]["cal_time"][1] = \ + NVOpsUtils.get_current_time_in_epoch() + dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_b1"]["crc"][1] = \ + NVOpsUtils.get_group_record_crc(dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_b1"]) + + dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_b2"]["gain"][1] = 0.988057943 + dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_b2"]["offset"][1] = -1.127196988 + dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_b2"]["cal_time"][1] = \ + NVOpsUtils.get_current_time_in_epoch() + dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_b2"]["crc"][1] = \ + NVOpsUtils.get_group_record_crc(dg.calibration_record.dg_calibration_record["load_cells"]["load_cell_b2"]) + print(dg.calibration_record.dg_calibration_record) - record_old_formatted = pprint.pformat(dg.calibration_record.dg_calibration_record, indent=4) - with open("/home/fw/projects/dialin/tests/peter/dg_cal_record.log", 'w') as f: - f.write(record_old_formatted) + dg.calibration_record.cmd_set_dg_calibration_record(dg.calibration_record.dg_calibration_record) + #print(dg.calibration_record.dg_calibration_record) + + #record_old_formatted = pprint.pformat(dg.calibration_record.dg_calibration_record, indent=4) + #with open("/home/fw/projects/dialin/tests/peter/dg_cal_record.log", 'w') as f: + # f.write(record_old_formatted) + #subprocess.call("meld /home/fw/projects/dialin/tests/peter/dialin_test_record_old.log" # " /home/fw/projects/dialin/tests/peter/dialin_test_record_new.log", shell=True) def test_dg_reset_record(): dg = DG(log_level="DEBUG") if dg.cmd_log_in_to_dg(): + dg.calibration_record.cmd_request_dg_calibration_record() + observer = Observer("dg_calibration_record") + dg.calibration_record.attach(observer) + while not observer.received: + sleep(0.2) + print(dg.calibration_record.dg_calibration_record) + dg.calibration_record.cmd_reset_dg_calibration_record() - #sleep(0.25) - #print(dg.calibration_record.dg_calibration_record) + sleep(0.25) + print(dg.calibration_record.dg_calibration_record) #dg.calibration_record.cmd_reset_dg_calibration_record() #sleep(0.25) @@ -267,8 +298,8 @@ #print(dg.service_record.dg_service_record) - def test_dg_service_record(): + dg = DG(log_level="DEBUG") if dg.cmd_log_in_to_dg(): @@ -319,9 +350,9 @@ if __name__ == "__main__": - test_dg_reset_record() + #test_dg_reset_record() # test_dg_sw_config_record() - #test_dg_calibration_record() + test_dg_calibration_record() # test_dg_service_record() #test_dg_system_record() # test_dg_scheduled_runs_record() Index: tests/peter/test_hd_records.py =================================================================== diff -u -rdc3b97933c58b8854781f2984083a2f8eccd3217 -r4ec12397809c5820ee654aaffe5924e67a79a072 --- tests/peter/test_hd_records.py (.../test_hd_records.py) (revision dc3b97933c58b8854781f2984083a2f8eccd3217) +++ tests/peter/test_hd_records.py (.../test_hd_records.py) (revision 4ec12397809c5820ee654aaffe5924e67a79a072) @@ -101,7 +101,8 @@ hd = HD(log_level="DEBUG") if hd.cmd_log_in_to_hd(resend=False): - #hd.calibration_record.cmd_reset_hd_calibration_record() + hd.calibration_record.cmd_reset_hd_calibration_record() + sleep(0.2) #print(hd.calibration_record.hd_calibration_record) #hd.system_record.cmd_reset_hd_system_record() hd.service_record.cmd_reset_hd_service_record() @@ -141,8 +142,8 @@ #hd.sw_configs.cmd_reset_hd_sw_config_record() #sleep(2) - hd.sw_configs.cmd_get_hd_sw_config_record() - #hd.sw_configs.cmd_update_hd_sw_config_record('/home/fw/projects/HD_NV_Records/2022-02-03-HD-SW-CONFIGS-Record.xlsx') + #hd.sw_configs.cmd_get_hd_sw_config_record() + hd.sw_configs.cmd_update_hd_sw_config_record('/home/fw/projects/HD_NV_Records/2022-02-08-HD-SW-CONFIGS-Record.xlsx') #dg.sw_configs.cmd_set_dg_sw_config_record('/home/fw/DG_NV_Records/2022-01-22-SW-CONFIGS-Record.xlsx') """ @@ -159,7 +160,7 @@ if __name__ == "__main__": - #test_hd_reset_record_record() + # test_hd_reset_record_record() test_hd_sw_config_record() #test_hd_calibration_record() #test_hd_service_record()