Index: dialin/common/msg_ids.py =================================================================== diff -u -r8ff49bb248b9b98b18dde057d836b5c2d308922c -r0251ff11e97b1f71ddf669272a343639db9373c6 --- dialin/common/msg_ids.py (.../msg_ids.py) (revision 8ff49bb248b9b98b18dde057d836b5c2d308922c) +++ dialin/common/msg_ids.py (.../msg_ids.py) (revision 0251ff11e97b1f71ddf669272a343639db9373c6) @@ -396,6 +396,8 @@ MSG_ID_DG_SET_SW_CONFIG_RECORD = 0xA04B MSG_ID_DG_SEND_SW_CONFIG_RECORD = 0xA04C MSG_ID_DG_FANS_DUTY_CYCLE_OVERRIDE = 0xA04D + MSG_ID_DG_USED_ACID_VOLUME_ML_OVERRIDE = 0xA04F + MSG_ID_DG_USED_BICARB_VOLUME_ML_OVERRIDE = 0xA050 MSG_ID_HD_DEBUG_EVENT = 0xFFF1 MSG_ID_DG_DEBUG_EVENT = 0xFFF2 Index: dialin/dg/dialysate_fill.py =================================================================== diff -u --- dialin/dg/dialysate_fill.py (revision 0) +++ dialin/dg/dialysate_fill.py (revision 0251ff11e97b1f71ddf669272a343639db9373c6) @@ -0,0 +1,187 @@ +########################################################################### +# +# Copyright (c) 2020-2022 Diality Inc. - All Rights Reserved. +# +# THIS CODE MAY NOT BE COPIED OR REPRODUCED IN ANY FORM, IN PART OR IN +# WHOLE, WITHOUT THE EXPLICIT PERMISSION OF THE COPYRIGHT OWNER. +# +# @file dialysate_fill.py +# +# @author (last) Dara Navaei +# @date (last) 10-Nov-2021 +# @author (original) Hung Nguyen +# @date (original) 10-Mar-2022 +# +############################################################################ +import struct +from logging import Logger + +from .constants import RESET, NO_RESET +from ..common.msg_defs import MsgIds, MsgFieldPositions +from ..protocols.CAN import DenaliMessage, DenaliChannels +from ..utils.base import AbstractSubSystem, publish, DialinEnum +from ..utils.checks import check_broadcast_interval_override_ms +from ..utils.conversions import integer_to_bytearray, float_to_bytearray + + +class DialysateFillEnum(DialinEnum): + AcidVolume = 0 + BicarbVolume = 1 + + +class DialysateFill(AbstractSubSystem): + """ + DialysateFill + + Dialysate Fill Dialin API sub-class to override the used acid and bicarb volume during fill. + """ + + def __init__(self, can_interface, logger: Logger): + """ + + @param can_interface: Denali Can Messenger object + """ + super().__init__() + + self.can_interface = can_interface + self.logger = logger + + if self.can_interface is not None: + channel_id = DenaliChannels.dg_sync_broadcast_ch_id + msg_id = MsgIds.MSG_ID_DG_CONCENTRATE_PUMP_DATA.value + self.can_interface.register_receiving_publication_function(channel_id, msg_id, + self._handler_dialysate_fill_monitor_sync) + + self.concentrate_pump_cp1_current_set_speed = 0.0 + self.concentrate_pump_cp1_measured_speed = 0.0 + self.concentrate_pump_cp2_current_set_speed = 0.0 + self.concentrate_pump_cp2_measured_speed = 0.0 + + def get_dialysate_fill(self): + """ + Gets the current concentrate pump data value + + @return: List containing concentrate pump data values: + [ concentrate_pump_cp1_current_set_speed, concentrate_pump_cp1_measured_speed, + concentrate_pump_cp2_current_set_speed, concentrate_pump_cp2_measured_speed ] + """ + return [self.concentrate_pump_cp1_current_set_speed, self.concentrate_pump_cp1_measured_speed, + self.concentrate_pump_cp2_current_set_speed, self.concentrate_pump_cp2_measured_speed] + + @publish(["concentrate_pump_cp1_current_set_speed", "concentrate_pump_cp1_measured_speed", + "concentrate_pump_cp2_current_set_speed", "concentrate_pump_cp2_measured_speed"]) + def _handler_dialysate_fill_sync(self, message): + """ + Handles published dialysate fill monitor' data messages. Dialysate fill data are captured + for reference. + + @param message: published dialysate fill' data message + @return: None + """ + + self.concentrate_pump_cp1_current_set_speed = struct.unpack('f', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_1:MsgFieldPositions.END_POS_FIELD_1]))[0] + self.concentrate_pump_cp1_measured_speed = struct.unpack('f', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_2:MsgFieldPositions.END_POS_FIELD_2]))[0] + self.concentrate_pump_cp2_current_set_speed = struct.unpack('f', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_3:MsgFieldPositions.END_POS_FIELD_3]))[0] + self.concentrate_pump_cp2_measured_speed = struct.unpack('f', bytearray( + message['message'][MsgFieldPositions.START_POS_FIELD_4:MsgFieldPositions.END_POS_FIELD_4]))[0] + + def cmd_dialysate_fill_used_acid_volume_override(self, volume: float) -> int: + """ + Constructs and sends the concentrate pump target speed override command + + @param volume: float - desired used acid volume to override + @return: 1 if successful, zero otherwise + + """ + + reset_byte_array = integer_to_bytearray(NO_RESET) + volume_byte_array = float_to_bytearray(volume) + + payload = reset_byte_array + volume_byte_array + + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, + message_id=MsgIds.MSG_ID_DG_USED_ACID_VOLUME_ML_OVERRIDE.value, + payload=payload) + + self.logger.debug("override the used acid volume") + + # Send message + received_message = self.can_interface.send(message) + + # If there is content... + if received_message is not None: + # response payload is OK or not OK + return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] + else: + self.logger.error("Timeout!!!!") + return False + + def cmd_dialysate_fill_used_bicarb_volume_override(self, volume: float) -> int: + """ + Constructs and sends the concentrate pump target speed override command + + @param volume: float - desired used acid volume to override + @return: 1 if successful, zero otherwise + + """ + + reset_byte_array = integer_to_bytearray(NO_RESET) + volume_byte_array = float_to_bytearray(volume) + + payload = reset_byte_array + volume_byte_array + + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, + message_id=MsgIds.MSG_ID_DG_USED_BICARB_VOLUME_ML_OVERRIDE.value, + payload=payload) + + self.logger.debug("override the used bicarb volume") + + # Send message + received_message = self.can_interface.send(message) + + # If there is content... + if received_message is not None: + # response payload is OK or not OK + return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] + else: + self.logger.error("Timeout!!!!") + return False + + def cmd_dialysate_fill_broadcast_interval_override(self, ms: int, reset: int = NO_RESET) -> int: + """ + Constructs and sends the dialysate fill data broadcast interval override command + Constraints: + Must be logged into DG. + Given interval must be non-zero and a multiple of the DG general task interval (50 ms). + + @param ms: integer - interval (in ms) to override with + @param reset: integer - 1 to reset a previous override, 0 to override + @return: 1 if successful, zero otherwise + """ + + if not check_broadcast_interval_override_ms(ms): + return False + + reset_byte_array = integer_to_bytearray(reset) + ms_byte_array = integer_to_bytearray(ms) + payload = reset_byte_array + ms_byte_array + + message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_dg_ch_id, + message_id=MsgIds.MSG_ID_CONCENTRATE_PUMP_PUBLISH_INTERVAL_OVERRIDE.value, + payload=payload) + + self.logger.debug("override dialysate fill data broadcast interval") + + # Send message + received_message = self.can_interface.send(message) + + # If there is content... + if received_message is not None: + # response payload is OK or not OK + return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] + else: + self.logger.error("Timeout!!!!") + return False Index: tests/test_conductivity.py =================================================================== diff -u -rda38ea23e487b717e2671fdfc06af915dfc17929 -r0251ff11e97b1f71ddf669272a343639db9373c6 --- tests/test_conductivity.py (.../test_conductivity.py) (revision da38ea23e487b717e2671fdfc06af915dfc17929) +++ tests/test_conductivity.py (.../test_conductivity.py) (revision 0251ff11e97b1f71ddf669272a343639db9373c6) @@ -5,6 +5,7 @@ import os import csv + directory = 'DG Cond' file_name = 'Test 1' notes = 'None' @@ -15,9 +16,9 @@ if not os.path.isdir(cwd + f'/{directory}'): os.mkdir(cwd + f'/{directory}') + current_time = datetime.now().strftime('%b-%d-%Y %H-%M-%S') result_file_name = f'{directory}/{file_name} - {current_time}.csv' - dg = DG() if dg.cmd_log_in_to_dg() == 0: sys.exit('Unable to login into DG') @@ -49,8 +50,36 @@ # DG Op modes dg_mode = dg.get_operation_mode() - dg_sub_mode = dg.dg_operation_sub_mode() + dg_sub_mode = dg.get_operation_sub_mode() + if dg_mode == 6: + + if dg_sub_mode == 1: # TEST INLET WATER + dg.temperatures.cmd_temperatures_value_override(17, 31.0) # override the TPi temperature sensor + dg.conductivity_sensors.cmd_conductivity_sensor_override(0, 2100) # override CPI conductivity + dg.pressures.cmd_pressure_override(0, 30) # override inlet water pressure + + elif dg_sub_mode == 4: # TEST BICARB CONDUCTIVITY + dg.temperatures.cmd_temperatures_value_override(17, 34.0) # override the TPi temperature sensor + dg.conductivity_sensors.cmd_conductivity_sensor_override(3, 6821.0) # bicarb CD2 conductivity + + elif dg_sub_mode == 5: # TEST ACID CONDUCTIVITY + dg.temperatures.cmd_temperatures_value_override(17, 35.0) # override the TPi temperature sensor + dg.conductivity_sensors.cmd_conductivity_sensor_override(2, 12252.0) # Acid CD1 conductivity + dg.conductivity_sensors.cmd_conductivity_sensor_override(3, 12252.0) # Bicarb CD2 conductivity + + elif dg_sub_mode == 6: # TEST PRODUCE DIALYSATE + dg.temperatures.cmd_temperatures_value_override(17, 36.0) # override the TPi temperature sensor + dg.conductivity_sensors.cmd_conductivity_sensor_override(0, 2100) # override the inlet conductivity + + elif dg_sub_mode == 7: # TEST DELIVER DIALYSATE + dg.temperatures.cmd_temperatures_value_override(17, 37.0) # override the TPi temperature sensor + dg.conductivity_sensors.cmd_conductivity_sensor_override(0, 2100) # override the inlet conductivity + + else: + dg.temperatures.cmd_temperatures_value_override(17, 30.0) # override the TPi temperature sensor + dg.conductivity_sensors.cmd_conductivity_sensor_override(0, 2100) # override the inlet conductivity + # flows fmp = dg.ro_pump.get_measured_flow_rate() raw_fmp = dg.ro_pump.get_ro_pump_measured_raw_flow_rate_mlp() @@ -72,8 +101,9 @@ lc_b1 = dg.load_cells.load_cell_B1 lc_b2 = dg.load_cells.load_cell_B2 + # f'DG SubMode, {dg_sub_mode}, ' \ data_string = f'DG Mode, {dg_mode}, ' \ - f'DG SubMode, {dg_sub_mode}, ' \ + f'SubMode, {dg_sub_mode}, ' \ f'CPi, {cpi:.4f}, ' \ f'CPo, {cpo:.4f}, ' \ f'CD1, {cd1:.4f}, ' \