Index: leahi_dialin/common/msg_ids.py =================================================================== diff -u -r9a2c2774952a68e8f075f32a28d3f99d77bf6f43 -re9ec8f58857765ba4e5d1e49680ccdbc7895029f --- leahi_dialin/common/msg_ids.py (.../msg_ids.py) (revision 9a2c2774952a68e8f075f32a28d3f99d77bf6f43) +++ leahi_dialin/common/msg_ids.py (.../msg_ids.py) (revision e9ec8f58857765ba4e5d1e49680ccdbc7895029f) @@ -531,6 +531,9 @@ MSG_ID_DD_BICART_DEPRESSURISE_REQUEST_OVERRIDE_REQUEST = 0xA074 # DD dry bicart depressurise overrride request MSG_ID_DD_TREATMENT_PARAMS_OVERRIDE_REQUEST = 0xA075 # DD Treatment parameters override request MSG_ID_DD_NVM_RECORD_CRC_OVERRIDE_REQUEST = 0xA076 # DD NVM Record CRC override Request + MSG_ID_DD_HEAT_DISINFECT_STATE_DATA = 0xA077 # DD Heat Disinfection state data + MSG_ID_DD_HEAT_DISINFECT_REQUEST_DATA = 0xA078 # DD heat disinfect start/stop request + MSG_ID_DD_HEAT_DISINFECT_MODE_DATA_PUBLISH_OVERRIDE_REQUEST = 0xA079 # DD heat disinfect mode data publish interval override request MSG_ID_DD_ALARM_STATE_OVERRIDE_REQUEST = 0xAF03 # DD alarm state override request MSG_ID_DD_STOP_GEN_DIALYSATE_MODE_OVERRIDE_REQUEST = 0xAF04 # DD stop general dialysate mode override request Index: leahi_dialin/dd/dialysate_delivery.py =================================================================== diff -u -r489ce5ef49041b863501b7fecd6e4716e7dcaa9f -re9ec8f58857765ba4e5d1e49680ccdbc7895029f --- leahi_dialin/dd/dialysate_delivery.py (.../dialysate_delivery.py) (revision 489ce5ef49041b863501b7fecd6e4716e7dcaa9f) +++ leahi_dialin/dd/dialysate_delivery.py (.../dialysate_delivery.py) (revision e9ec8f58857765ba4e5d1e49680ccdbc7895029f) @@ -39,6 +39,7 @@ from .modules.ultrafiltration import DDUltrafiltration from .modules.valves import DDValves from .modules.voltages import DDVoltages +from .modules.heatdisinfect import DDHeatDisinfect from .proxies.ro_proxy import ROProxy from .proxies.td_proxy import TDProxy @@ -143,6 +144,7 @@ self.ultrafiltration = DDUltrafiltration(self.can_interface, self.logger) #: The Ultrafiltration module self.valves = DDValves(self.can_interface, self.logger) #: The Valves module self.voltages = DDVoltages(self.can_interface, self.logger) #: The Voltages module + self.heatdisinfect = DDHeatDisinfect(self.can_interface, self.logger) #: The Heat disinfect module self.ro_proxy = ROProxy(self.can_interface, self.logger) #: The RO Proxy module (imitates commands sent by DD) self.td_proxy = TDProxy(self.can_interface, self.logger) #: The TD Proxy module (imitates commands sent by UI) Index: leahi_dialin/dd/modules/heatdisinfect.py =================================================================== diff -u --- leahi_dialin/dd/modules/heatdisinfect.py (revision 0) +++ leahi_dialin/dd/modules/heatdisinfect.py (revision e9ec8f58857765ba4e5d1e49680ccdbc7895029f) @@ -0,0 +1,127 @@ +########################################################################### +# +# Copyright (c) 2020-2026 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 heat_disinfect.py +# +# @author (last) Jashwant Gantyada +# @date (last) 19-Aug-2026 +# @author (original) Jashwant Gantyada +# @date (original) 19-Aug-2026 +# +############################################################################ + +# Module imports +from logging import Logger + +# Project imports +from leahi_dialin.common.constants import NO_RESET +from leahi_dialin.common.generic_defs import DataTypes +from leahi_dialin.common.msg_ids import MsgIds +from leahi_dialin.common.override_templates import cmd_generic_broadcast_interval_override, cmd_generic_override +from leahi_dialin.protocols.CAN import CanMessenger, CanChannels +from leahi_dialin.utils.abstract_classes import AbstractSubSystem +from leahi_dialin.utils.base import publish +from leahi_dialin.utils.conversions import integer_to_bytearray + + +class DDHeatDisinfect(AbstractSubSystem): + """ + Heat Disinfect + + Dialysate Delivery (DD) Dialin API sub-class for Heat Disinfect related commands. + """ + + def __init__(self, can_interface: CanMessenger, logger: Logger): + """ + @param can_interface: Can Messenger object + """ + super().__init__() + + self.can_interface = can_interface + self.logger = logger + + if self.can_interface is not None: + self.can_interface.register_receiving_publication_function(channel_id = CanChannels.dd_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_DD_HEAT_DISINFECT_STATE_DATA.value, + function = self._handler_heat_disinfect_sync) + + self.execution_state = 0 #: heatDisinfectExecState + self.sub_state = 0 #: heatDisinfectSubState + self.dd_recirc_dwell_time_ms = 0 #: ddRecircDwellTimeMS + self.wcid_recirc_dwell_time_ms = 0 #: wcidRecircDwellTimeMS + self.dd_dwell_at_target = 0 #: ddDwellAtTarget + self.wcid_dwell_at_target = 0 #: wcidDwellAtTarget + self.dd_heat_disinfect_timestamp = 0 #: The timestamp of the last message + + + @publish(["msg_id_dd_heat_disinfect_state_data", + "execution_state", "sub_state", + "dd_recirc_dwell_time_ms", "wcid_recirc_dwell_time_ms", + "dd_dwell_at_target", "wcid_dwell_at_target", + "dd_heat_disinfect_timestamp"]) + def _handler_heat_disinfect_sync(self, message, timestamp=0.0): + """ + Handles published heat disinfect data messages. + + @param message: published heat disinfect data message + @return: None + """ + msg_list = [] + msg_list.append(('self.execution_state', DataTypes.U32)) + msg_list.append(('self.sub_state', DataTypes.U32)) + msg_list.append(('self.dd_recirc_dwell_time_ms', DataTypes.U32)) + msg_list.append(('self.wcid_recirc_dwell_time_ms', DataTypes.U32)) + msg_list.append(('self.dd_dwell_at_target', DataTypes.U32)) + msg_list.append(('self.wcid_dwell_at_target', DataTypes.U32)) + + self.process_into_vars(decoder_list = msg_list, + message = message) + + self.dd_heat_disinfect_timestamp = timestamp + + + def cmd_heat_disinfect_broadcast_interval_override(self, ms: int, reset: int = NO_RESET) -> int: + """ + Constructs and sends the heat disinfect data broadcast interval override command + Constraints: + Must be logged into DD. + Given interval must be non-zero and a multiple of the DD 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 + """ + return cmd_generic_broadcast_interval_override( + ms = ms, + reset = reset, + channel_id = CanChannels.dialin_to_dd_ch_id, + msg_id = MsgIds.MSG_ID_DD_HEAT_DISINFECT_MODE_DATA_PUBLISH_OVERRIDE_REQUEST, + module_name = 'DD Heat Disinfect', + logger = self.logger, + can_interface = self.can_interface) + + + def cmd_heat_disinfect_start_stop(self, start: int) -> int: + """ + Constructs and sends the heat disinfect start stop request + Constraints: + Must be logged into DD. + + @param start: int - value to start or stop heat disinfect ( start = 1, stop = 0 ) + @return: 1 if successful, zero otherwise + """ + payload = integer_to_bytearray(start) + + return cmd_generic_override( + payload = payload, + reset = NO_RESET, + channel_id = CanChannels.dialin_to_dd_ch_id, + msg_id = MsgIds.MSG_ID_DD_HEAT_DISINFECT_REQUEST_DATA, + entity_name = 'Heat Disinfect Start' if start == 1 else 'Heat Disinfect Stop', + override_text = str(start), + logger = self.logger, + can_interface = self.can_interface) Index: leahi_dialin/dd/modules/valves.py =================================================================== diff -u -r38da5065a6cbe169b433d7430bb5a3739517db0e -re9ec8f58857765ba4e5d1e49680ccdbc7895029f --- leahi_dialin/dd/modules/valves.py (.../valves.py) (revision 38da5065a6cbe169b433d7430bb5a3739517db0e) +++ leahi_dialin/dd/modules/valves.py (.../valves.py) (revision e9ec8f58857765ba4e5d1e49680ccdbc7895029f) @@ -184,6 +184,7 @@ @param message: published DD valves states message @return: none """ + start = time.perf_counter() valves = LocalVars('valves') bc_valves = LocalVars('bc_valves') spare_valves = LocalVars('spare_valves') @@ -240,10 +241,11 @@ start = DataTypes.U32.size() msg_list_2 = [] for valve_id in self.valves_sensed_states: - msg_list.append((self.valves_sensed_states, valve_id, DataTypes.U08)) + msg_list.append((self.valves_sensed_states, valve_id, DataTypes.U08)) self.process_into_vars(decoder_list = msg_list_2, message = message, start_from_byte = start) self.dd_valves_states_timestamp = timestamp + self.handler_execution_times.append((timestamp, message, time.perf_counter() - start)) Index: tests/dd_login.py =================================================================== diff -u --- tests/dd_login.py (revision 0) +++ tests/dd_login.py (revision e9ec8f58857765ba4e5d1e49680ccdbc7895029f) @@ -0,0 +1,37 @@ +from leahi_dialin.dd.dialysate_delivery import DD +from leahi_dialin.dd.modules.blood_leak import EmbModeCommands +from time import sleep +import os + +def get_blood_leak_info(): + info = ('Blood_leak_state, {}, Blood_leak_status, {}, Blood_leak_intensity, {}, Blood_leak_detect, {}, ' + 'Blood_leak_int_mv_avg, {}, ' + .format(dd.blood_leak.get_blood_leak_state(), dd.blood_leak.get_blood_leak_status(), + dd.blood_leak.blood_leak_intensity, dd.blood_leak.blood_leak_blood_detect, + dd.blood_leak.blood_leak_intensity_moving_average)) + return info + + +if __name__ == "__main__": + address = os.path.join(os.getcwd(), "leahi_zero.log") + f = open(address, "w") + dd = DD() + dd.cmd_log_in_to_dd() + sleep(0.1) + dd.td_proxy.cmd_td_override_treatment_parameter(0, 0) + dd.blood_leak.cmd_blood_leak_data_broadcast_interval_override(50) + var = get_blood_leak_info() + '\r' + f.write(var) + print(var) + sleep(0.1) + dd.blood_leak.cmd_blood_leak_zero_request() + #dd.blood_leak.cmd_blood_leak_set_embedded_mode_command(EmbModeCommands.I.value, msg_payload=0) + + while True: + var = get_blood_leak_info() + '\r' + sleep(0.05) + #print("Detect", dd.blood_leak.get_blood_leak_emb_mode_command_response(EmbModeCommands.V.value)) + print(var) + f.write(var) + + f.close() Index: tests/td_login.py =================================================================== diff -u --- tests/td_login.py (revision 0) +++ tests/td_login.py (revision e9ec8f58857765ba4e5d1e49680ccdbc7895029f) @@ -0,0 +1,25 @@ +from leahi_dialin.td.treatment_delivery import TD +from time import sleep +import os + +if __name__ == "__main__": + address = os.path.join(os.getcwd(), "td_valves.log") + #f = open(address, "w") + td = TD() + td.cmd_log_in_to_td() + sleep(0.5) + + td.valves.cmd_valves_broadcast_interval_override(50) + sleep(0.5) + td.valves.cmd_set_valve_position(0, 1) + #td.valves.cmd_home_valve(0, 1, 0) + #sleep(0.5) + #td.valves.cmd_home_valve(1, 1, 0) + + #td.blood_flow.cmd_home_blood_pump() + #sleep(25) + + #td.blood_flow.cmd_blood_flow_set_speed_rate_request(1000) + #sleep(15) + + #td.blood_flow.cmd_hard_stop_blood_pump()