Index: leahi_dialin/common/dd_defs.py =================================================================== diff -u -r272d33ed055f9d107788a17a76f2b9bc5bb510aa -r5f16af73fb80a76c6dc767661f11a8f3508770a1 --- leahi_dialin/common/dd_defs.py (.../dd_defs.py) (revision 272d33ed055f9d107788a17a76f2b9bc5bb510aa) +++ leahi_dialin/common/dd_defs.py (.../dd_defs.py) (revision 5f16af73fb80a76c6dc767661f11a8f3508770a1) @@ -1187,17 +1187,21 @@ @unique class DDServiceRecordFields(RecordsBaseEnum): IS_HDF_ONLINE_FLUID = (0, DataTypes.BOOL) # DD Is HDF Online - WATER_RECOVERY = (1, DataTypes.U32) # DD Water Recovery - SERVICE_LOC = (2, DataTypes.U08) # DD service location - LAST_SERVICE_EPOCH_DATE = (3, DataTypes.U32) # DD last service date in epoch - SERVICE_INTERVAL_SECONDS = (4, DataTypes.U32) # DD service interval in seconds - LAST_RESET_TIME_EPOCH = (5, DataTypes.U32) # Last time the record was reset in epoch - NUM_OF_SERVICE_RECORD_FIELDS = (6, DataTypes.NONE) # Number of Service Record Fields + UF_1_REPLACEMENT_DATE = (1, DataTypes.U32) # Last replacement date of Ultrafilter 1 + UF_2_REPLACEMENT_DATE = (2, DataTypes.U32) # Last replacement date of Ultrafilter 2 + UF_PUMP_TUBING_REPLACEMENT_DATE = (3, DataTypes.U32) # Last replacement date of UF Pump Tubing + SERVICE_LOC = (4, DataTypes.U32) # DD service location + LAST_SERVICE_EPOCH_DATE = (5, DataTypes.U32) # DD last service date in epoch + SERVICE_INTERVAL_SECONDS = (6, DataTypes.U32) # DD service interval in seconds + LAST_RESET_TIME_EPOCH = (7, DataTypes.U32) # Last time the record was reset in epoch + NUM_OF_SERVICE_RECORD_FIELDS = (8, DataTypes.NONE) # Number of Service Record Fields DDServiceRecordFields._str_list = { # Official Name : Accepted strings 'IS_HDF_ONLINE_FLUID': [], - 'WATER_RECOVERY': [], + 'UF_1_REPLACEMENT_DATE': [], + 'UF_2_REPLACEMENT_DATE': [], + 'UF_PUMP_TUBING_REPLACEMENT_DATE': [], 'SERVICE_LOC': [], 'LAST_SERVICE_EPOCH_DATE': [], 'SERVICE_INTERVAL_SECONDS': [], @@ -1288,17 +1292,29 @@ class DDUsageInformationRecordFields(RecordsBaseEnum): RO_WATER_GEN_TOTAL_L = (0, DataTypes.F32) # Total RO water generated in liters. (Cannot be reset) RO_WATER_GEN_SINCE_LAST_SERVICE_L = (1, DataTypes.F32) # RO water generated since last treatment in liters - LAST_BASIC_FLUSH_COMPLETE_DATE_EPOCH = (2, DataTypes.U32) # Last basic flush complete date in epoch. - LAST_HEAT_DISINFECT_COMPLETE_DATE_EPOCH = (3, DataTypes.U32) # Last heat disinfect complete date in epoch. - LAST_HEAT_ACTIVE_COOL_COMPLETE_DATE_EPOCH = (4, DataTypes.U32) # Last heat disinfect active cool complete date in epoch. - LAST_FILTER_FLUSH_COMPLETE_DATE_EPOCH = (5, DataTypes.U32) # Last filter flush complete date in epoch. - LAST_RESET_TIME_EPOCH = (6, DataTypes.U32) # Last time the record was reset in epoch. - NUM_OF_USAGE_INFO_RECORD_FIELDS = (7, DataTypes.NONE) # Number of Usage Information Record Fields + UF_1_TREATMENT_COUNT = (2, DataTypes.U32) # Number of treatments performed on ultrafilter 1 since last replaced + UF_1_DISINFECTION_COUNT = (3, DataTypes.U32) # Number of disinfections performed on ultrafilter 1 since last replaced + UF_2_TREATMENT_COUNT = (4, DataTypes.U32) # Number of treatments performed on ultrafilter 2 since last replaced + UF_2_DISINFECTION_COUNT = (5, DataTypes.U32) # Number of disinfections performed on ultrafilter 2 since last replaced + UF_PUMP_TUBING_TREATMENT_COUNT = (6, DataTypes.U32) # Number of treatments performed on UF Pump Tubing since last replaced + UF_PUMP_TUBING_DISINFECTION_COUNT = (7, DataTypes.U32) # Number of disinfections performed on UF Pump Tubing since last replaced + LAST_BASIC_FLUSH_COMPLETE_DATE_EPOCH = (8, DataTypes.U32) # Last basic flush complete date in epoch. + LAST_HEAT_DISINFECT_COMPLETE_DATE_EPOCH = (9, DataTypes.U32) # Last heat disinfect complete date in epoch. + LAST_HEAT_ACTIVE_COOL_COMPLETE_DATE_EPOCH = (10, DataTypes.U32) # Last heat disinfect active cool complete date in epoch. + LAST_FILTER_FLUSH_COMPLETE_DATE_EPOCH = (11, DataTypes.U32) # Last filter flush complete date in epoch. + LAST_RESET_TIME_EPOCH = (12, DataTypes.U32) # Last time the record was reset in epoch. + NUM_OF_USAGE_INFO_RECORD_FIELDS = (13, DataTypes.NONE) # Number of Usage Information Record Fields DDUsageInformationRecordFields._str_list = { # Official Name : Accepted strings 'RO_WATER_GEN_TOTAL_L': [], 'RO_WATER_GEN_SINCE_LAST_SERVICE_L': [], + 'UF_1_TREATMENT_COUNT': [], + 'UF_1_DISINFECTION_COUNT': [], + 'UF_2_TREATMENT_COUNT': [], + 'UF_2_DISINFECTION_COUNT': [], + 'UF_PUMP_TUBING_TREATMENT_COUNT': [], + 'UF_PUMP_TUBING_DISINFECTION_COUNT': [], 'LAST_BASIC_FLUSH_COMPLETE_DATE_EPOCH': [], 'LAST_HEAT_DISINFECT_COMPLETE_DATE_EPOCH': [], 'LAST_HEAT_ACTIVE_COOL_COMPLETE_DATE_EPOCH': [], Index: leahi_dialin/common/fp_defs.py =================================================================== diff -u -r167accc09150c3cf8bb258d7ccf364b8ec673b07 -r5f16af73fb80a76c6dc767661f11a8f3508770a1 --- leahi_dialin/common/fp_defs.py (.../fp_defs.py) (revision 167accc09150c3cf8bb258d7ccf364b8ec673b07) +++ leahi_dialin/common/fp_defs.py (.../fp_defs.py) (revision 5f16af73fb80a76c6dc767661f11a8f3508770a1) @@ -760,3 +760,53 @@ DDCalibrationRecordFields._str_list[member] = [] return DDCalibrationRecordFields + + +@unique +class FPServiceRecordFields(RecordsBaseEnum): + WATER_RECOVERY = (0, DataTypes.BOOL) # Low : 0, Medium : 1, High : 2. + PRIMARY_FILTER_REPLACEMENT_DATE = (1, DataTypes.U32) # Last replacement date of primary carbon filter + SECONDARY_FILTER_REPLACEMENT_DATE = (2, DataTypes.U32) # Last replacement date of secondary carbon filter + RO_MEMBRANE_REPLACEMENT_DATE = (3, DataTypes.U32) # Last replacement date of RO Membrane + SERVICE_LOC = (4, DataTypes.U32) # FP service location. + LAST_SERVICE_EPOCH_DATE = (5, DataTypes.U32) # FP last service date in epoch. + SERVICE_INTERVAL_SECONDS = (6, DataTypes.U32) # FP service interval in seconds. + LAST_RESET_TIME_EPOCH = (7, DataTypes.U32) # Last time the record was reset in epoch. + NUM_OF_SERVICE_RECORD_FIELDS = (8, DataTypes.NONE) # Number of Service Record Fields + +FPServiceRecordFields._str_list = { + # Official Name : Accepted strings + 'WATER_RECOVERY': [], + 'PRIMARY_FILTER_REPLACEMENT_DATE': [], + 'SECONDARY_FILTER_REPLACEMENT_DATE': [], + 'RO_MEMBRANE_REPLACEMENT_DATE': [], + 'SERVICE_LOC': [], + 'LAST_SERVICE_EPOCH_DATE': [], + 'SERVICE_INTERVAL_SECONDS': [], + 'LAST_RESET_TIME_EPOCH': [], + 'NUM_OF_SERVICE_RECORD_FIELDS': [], +} + + +@unique +class FPUsageInformationRecordFields(RecordsBaseEnum): + PRIMARY_FILTER_TREATMENT_COUNT = (0, DataTypes.U32) # Number of treatments performed on ultrafilter 1 since last replaced + PRIMARY_FILTER_DISINFECTION_COUNT = (1, DataTypes.U32) # Number of disinfections performed on ultrafilter 1 since last replaced + SECONDARY_FILTER_TREATMENT_COUNT = (2, DataTypes.U32) # Number of treatments performed on ultrafilter 2 since last replaced + SECONDARY_FILTER_DISINFECTION_COUNT = (3, DataTypes.U32) # Number of disinfections performed on ultrafilter 2 since last replaced + RO_MEMBRANE_TREATMENT_COUNT = (4, DataTypes.U32) # Number of treatments performed on UF Pump Tubing since last replaced + RO_MEMBRANE_DISINFECTION_COUNT = (5, DataTypes.U32) # Number of disinfections performed on UF Pump Tubing since last replaced + LAST_RESET_TIME_EPOCH = (6, DataTypes.U32) # Last time the record was reset in epoch. + NUM_OF_USAGE_INFO_RECORD_FIELDS = (7, DataTypes.NONE) # Number of Usage Information Record Fields + +FPUsageInformationRecordFields._str_list = { + # Official Name : Accepted strings + 'PRIMARY_FILTER_TREATMENT_COUNT': [], + 'PRIMARY_FILTER_DISINFECTION_COUNT': [], + 'SECONDARY_FILTER_TREATMENT_COUNT': [], + 'SECONDARY_FILTER_DISINFECTION_COUNT': [], + 'RO_MEMBRANE_TREATMENT_COUNT': [], + 'RO_MEMBRANE_DISINFECTION_COUNT': [], + 'LAST_RESET_TIME_EPOCH': [], + 'NUM_OF_USAGE_INFO_RECORD_FIELDS': [], +} Index: leahi_dialin/common/fp_defs_proxy.py =================================================================== diff -u -r6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1 -r5f16af73fb80a76c6dc767661f11a8f3508770a1 --- leahi_dialin/common/fp_defs_proxy.py (.../fp_defs_proxy.py) (revision 6d104d3185ac3ed7c18c97ecdc13fd59bf53a8d1) +++ leahi_dialin/common/fp_defs_proxy.py (.../fp_defs_proxy.py) (revision 5f16af73fb80a76c6dc767661f11a8f3508770a1) @@ -21,49 +21,54 @@ class FP_Defs(): # Operation Modes - Lvl 1 - FPOpModes = fp_defs.FPOpModes + FPOpModes = fp_defs.FPOpModes # Operation Modes - Lvl 2 - FPFaultStates = fp_defs.FPFaultStates - FPServiceStates = fp_defs.FPServiceStates - FPPostStates = fp_defs.FPPostStates - FPStandbyStates = fp_defs.FPStandbyStates - FPPreGenPermeateStates = fp_defs.FPPreGenPermeateStates - FPPreGenPDefStates = fp_defs.FPPreGenPDefStates - FPGenPermeateStates = fp_defs.FPGenPermeateStates - FPGenPermeateDefStates = fp_defs.FPGenPermeateDefStates - FPNotLegalStates = fp_defs.FPNotLegalStates + FPFaultStates = fp_defs.FPFaultStates + FPServiceStates = fp_defs.FPServiceStates + FPPostStates = fp_defs.FPPostStates + FPStandbyStates = fp_defs.FPStandbyStates + FPPreGenPermeateStates = fp_defs.FPPreGenPermeateStates + FPPreGenPDefStates = fp_defs.FPPreGenPDefStates + FPGenPermeateStates = fp_defs.FPGenPermeateStates + FPGenPermeateDefStates = fp_defs.FPGenPermeateDefStates + FPNotLegalStates = fp_defs.FPNotLegalStates # Operation Modes - Lvl 3 - FPFaultNVDataStates = fp_defs.FPFaultNVDataStates - FPInletPresCheckStates = fp_defs.FPInletPresCheckStates - FPFilterFlushStates = fp_defs.FPFilterFlushStates - FPPermeateFlushStates = fp_defs.FPPermeateFlushStates - FPConcentrateFlushStates = fp_defs.FPConcentrateFlushStates - FPDefFlushStates = fp_defs.FPDefFlushStates + FPFaultNVDataStates = fp_defs.FPFaultNVDataStates + FPInletPresCheckStates = fp_defs.FPInletPresCheckStates + FPFilterFlushStates = fp_defs.FPFilterFlushStates + FPPermeateFlushStates = fp_defs.FPPermeateFlushStates + FPConcentrateFlushStates = fp_defs.FPConcentrateFlushStates + FPDefFlushStates = fp_defs.FPDefFlushStates # Events - FPEventList = fp_defs.FPEventList - DataTypes = generic_defs.DataTypes + FPEventList = fp_defs.FPEventList + DataTypes = generic_defs.DataTypes # Sensor Names - FPBoostPumpNames = fp_defs.FPBoostPumpNames - FPConductivitySensorNames = fp_defs.FPConductivitySensorNames - FPRORejectionRatioNames = fp_defs.FPRORejectionRatioNames - FPFlowSensorNames = fp_defs.FPFlowSensorNames - FPFloaterLevelSensorNames = fp_defs.FPFloaterLevelSensorNames - FPPressureSensorNames = fp_defs.FPPressureSensorNames - FPROPumpNames = fp_defs.FPROPumpNames - FPTemperatureSensorNames = fp_defs.FPTemperatureSensorNames - FPValveNames = fp_defs.FPValveNames - FPAllPumpNames = fp_defs.FPAllPumpNames + FPBoostPumpNames = fp_defs.FPBoostPumpNames + FPConductivitySensorNames = fp_defs.FPConductivitySensorNames + FPRORejectionRatioNames = fp_defs.FPRORejectionRatioNames + FPFlowSensorNames = fp_defs.FPFlowSensorNames + FPFloaterLevelSensorNames = fp_defs.FPFloaterLevelSensorNames + FPPressureSensorNames = fp_defs.FPPressureSensorNames + FPROPumpNames = fp_defs.FPROPumpNames + FPTemperatureSensorNames = fp_defs.FPTemperatureSensorNames + FPValveNames = fp_defs.FPValveNames + FPAllPumpNames = fp_defs.FPAllPumpNames # Sensor Attributes - FPBoostPumpStates = fp_defs.FPBoostPumpStates - FPFloaterLevels = fp_defs.FPFloaterLevels - FPPumpAttributes = fp_defs.FPPumpAttributes - FPROPumpStates = fp_defs.FPROPumpStates - FPRecoveryOptions = fp_defs.FPRecoveryOptions - FPValveStates = fp_defs.FPValveStates + FPBoostPumpStates = fp_defs.FPBoostPumpStates + FPFloaterLevels = fp_defs.FPFloaterLevels + FPPumpAttributes = fp_defs.FPPumpAttributes + FPROPumpStates = fp_defs.FPROPumpStates + FPRecoveryOptions = fp_defs.FPRecoveryOptions + FPValveStates = fp_defs.FPValveStates + # Records + RecordTypes = generic_defs.RecordTypes + FPServiceRecordFields = fp_defs.FPServiceRecordFields + FPUsageInformationRecordFields = fp_defs.FPUsageInformationRecordFields + fp_enum_repository = FP_Defs() Index: leahi_dialin/dd/modules/records.py =================================================================== diff -u -r436742844a3fbbb6a3b0bc81dc87bc6385c3e368 -r5f16af73fb80a76c6dc767661f11a8f3508770a1 --- leahi_dialin/dd/modules/records.py (.../records.py) (revision 436742844a3fbbb6a3b0bc81dc87bc6385c3e368) +++ leahi_dialin/dd/modules/records.py (.../records.py) (revision 5f16af73fb80a76c6dc767661f11a8f3508770a1) @@ -422,7 +422,7 @@ reset = None, channel_id = CanChannels.dialin_to_dd_ch_id, msg_id = MsgIds.MSG_ID_DD_SET_OPERATION_MODE_OVERRIDE_REQUEST, - entity_name = 'DD Operation Mode', + entity_name = 'FP/DD Operation Mode', override_text = f'set to {service_mode.name}', logger = self.logger, can_interface = self.can_interface) Index: leahi_dialin/dd/modules/records_get_responses.py =================================================================== diff -u -rb723797c80a2ad6a535f9071dd657ce45259ff40 -r5f16af73fb80a76c6dc767661f11a8f3508770a1 --- leahi_dialin/dd/modules/records_get_responses.py (.../records_get_responses.py) (revision b723797c80a2ad6a535f9071dd657ce45259ff40) +++ leahi_dialin/dd/modules/records_get_responses.py (.../records_get_responses.py) (revision 5f16af73fb80a76c6dc767661f11a8f3508770a1) @@ -128,7 +128,7 @@ msg_list.append((type(self).get_service_rec_rr, DataTypes.U32)) for member in dd_enum_repository.DDServiceRecordFields: if member is not dd_enum_repository.DDServiceRecordFields.NUM_OF_SERVICE_RECORD_FIELDS: - msg_list.append((self.system_records, member.name, member.datatype())) + msg_list.append((self.service_records, member.name, member.datatype())) self.process_into_vars(decoder_list = msg_list, message = message) Index: leahi_dialin/dd/modules/records_set_requests.py =================================================================== diff -u -r63dcccf308248c312b5f82b65f46605e6d90402d -r5f16af73fb80a76c6dc767661f11a8f3508770a1 --- leahi_dialin/dd/modules/records_set_requests.py (.../records_set_requests.py) (revision 63dcccf308248c312b5f82b65f46605e6d90402d) +++ leahi_dialin/dd/modules/records_set_requests.py (.../records_set_requests.py) (revision 5f16af73fb80a76c6dc767661f11a8f3508770a1) @@ -83,7 +83,9 @@ def cmd_set_service_records(self, is_hdf_online: bool=False, - water_recovery: int=0, + uf_1_replacement_date: int=0, + uf_2_replacement_date: int=0, + uf_pump_tubing_replacement_date: int=0, service_loc: int=0, last_service_date: int=0, service_interval_sec: int=0, @@ -97,8 +99,10 @@ @return: 1 if successful, zero otherwise """ payload = integer_to_bytearray(is_hdf_online) - payload += integer_to_bytearray(water_recovery) - payload += byte_to_bytearray(service_loc) + payload += integer_to_bytearray(uf_1_replacement_date) + payload += integer_to_bytearray(uf_2_replacement_date) + payload += integer_to_bytearray(uf_pump_tubing_replacement_date) + payload += integer_to_bytearray(service_loc) payload += integer_to_bytearray(last_service_date) payload += integer_to_bytearray(service_interval_sec) payload += integer_to_bytearray(last_reset_time) @@ -448,6 +452,12 @@ def cmd_set_usage_info_records(self, ro_water_gen_total_l: float=0.0, ro_water_gen_since_last_serv_l: float=0.0, + uf_1_treatment_count: int=0, + uf_1_disinfection_count: int=0, + uf_2_treatment_count: int=0, + uf_2_disinfection_count: int=0, + uf_pump_tubing_treatment_count: int=0, + uf_pump_tubing_disinfection_count: int=0, last_basic_flush_date: int=0, last_heat_disinfect_date: int=0, last_heat_active_cool_date: int=0, @@ -463,6 +473,12 @@ """ payload = float_to_bytearray(ro_water_gen_total_l) payload += float_to_bytearray(ro_water_gen_since_last_serv_l) + payload += integer_to_bytearray(uf_1_treatment_count) + payload += integer_to_bytearray(uf_1_disinfection_count) + payload += integer_to_bytearray(uf_2_treatment_count) + payload += integer_to_bytearray(uf_2_disinfection_count) + payload += integer_to_bytearray(uf_pump_tubing_treatment_count) + payload += integer_to_bytearray(uf_pump_tubing_disinfection_count) payload += integer_to_bytearray(last_basic_flush_date) payload += integer_to_bytearray(last_heat_disinfect_date) payload += integer_to_bytearray(last_heat_active_cool_date) Index: leahi_dialin/fp/modules/records.py =================================================================== diff -u --- leahi_dialin/fp/modules/records.py (revision 0) +++ leahi_dialin/fp/modules/records.py (revision 5f16af73fb80a76c6dc767661f11a8f3508770a1) @@ -0,0 +1,218 @@ +########################################################################### +# +# Copyright (c) 2020-2024 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 records.py +# +# @author (last) Zoltan Miskolci +# @date (last) 11-Aug-2026 +# @author (original) Zoltan Miskolci +# @date (original) 11-Aug-2026 +# +############################################################################ + +# Module imports +from logging import Logger + +# Project imports +from leahi_dialin.fp.modules.records_get_responses import FPRecordsGetHandlers +from leahi_dialin.fp.modules.records_get_requests import FPRecordsGetRequests +from leahi_dialin.fp.modules.records_set_responses import FPRecordsSetHandlers +from leahi_dialin.fp.modules.records_set_requests import FPRecordsSetRequests +from leahi_dialin.common import fp_enum_repository +from leahi_dialin.common.msg_defs import RequestRejectReasons +from leahi_dialin.common.msg_ids import MsgIds +from leahi_dialin.common.override_templates import cmd_generic_override +from leahi_dialin.protocols.CAN import CanMessenger, CanChannels +from leahi_dialin.utils.conversions import integer_to_bytearray + + +class FPRecords(FPRecordsGetHandlers, FPRecordsGetRequests, FPRecordsSetHandlers, FPRecordsSetRequests): + """ + FP interface containing pressure related commands. + """ + + def __init__(self, can_interface: CanMessenger, logger: Logger): + """ + The main record class to handle all the subclasses. + + :param can_interface: (CanMessenger) The CanMessenger object + :param logger: (Logger) The Logger object + """ + self.can_interface = can_interface + self.logger = logger + + self.get_service_rec_timestamp = 0 #: The timestamp of the latest Service Records message + self.get_service_rec_ack = False + self.get_service_rec_rr = RequestRejectReasons.REQUEST_REJECT_REASON_NONE + + self.service_records = { } + + self.set_service_rec_rr_timestamp = 0 #: The timestamp of the latest Set Service Reject Reason message + self.set_service_rec_ack = False + self.set_service_rec_rr = { } + + self.get_usage_info_rec_timestamp = 0 #: The timestamp of the latest Usage Information Records message + self.get_usage_info_rec_ack = False + self.get_usage_info_rec_rr = RequestRejectReasons.REQUEST_REJECT_REASON_NONE + + self.usage_info_records = { } + + self.set_usage_info_rec_rr_timestamp = 0 #: The timestamp of the latest Set Usage Information Reject Reason message + self.set_usage_info_rec_ack = False + self.set_usage_info_rec_rr = { } + + # Calling the Sub classes: DDRecordsGetHandlers, DDRecordsGetRequests, DDRecordsSetHandlers, DDRecordsSetRequests + # Doing it after initializeing the parameters will make those parameters accessable to the sub classes + super().__init__() + + + +# ============================================================ Properties ============================================================ + @property + def service_records(self) -> dict: + """ + The Service Records data + """ + return self._service_records + + @service_records.setter + def service_records(self, value): + self._service_records = value + + + @property + def usage_info_records(self) -> dict: + """ + The Usage Information Records data + """ + return self._usage_info_records + + @usage_info_records.setter + def usage_info_records(self, value): + self._usage_info_records = value + + + @property + def get_service_rec_ack(self) -> bool: + """ + The Get Service Records message acceptance + """ + return self._get_service_rec_ack + + @get_service_rec_ack.setter + def get_service_rec_ack(self, value): + self._get_service_rec_ack = value + + + @property + def get_usage_info_rec_ack(self) -> bool: + """ + The Get Usage Information Records message acceptance + """ + return self._get_usage_info_rec_ack + + @get_usage_info_rec_ack.setter + def get_usage_info_rec_ack(self, value): + self._get_usage_info_rec_ack = value + + + @property + def get_service_rec_rr(self) -> dict: + """ + The Get Service Records Request reject reason data + """ + return self._get_service_rec_rr + + @get_service_rec_rr.setter + def get_service_rec_rr(self, value): + self._get_service_rec_rr = value + + + @property + def get_usage_info_rec_rr(self) -> dict: + """ + The Get Usage Information Records Request reject reason data + """ + return self._get_usage_info_rec_rr + + @get_usage_info_rec_rr.setter + def get_usage_info_rec_rr(self, value): + self._get_usage_info_rec_rr = value + + + @property + def set_service_rec_ack(self) -> bool: + """ + The Set Service Records message acceptance + """ + return self._set_service_rec_ack + + @set_service_rec_ack.setter + def set_service_rec_ack(self, value): + self._set_service_rec_ack = value + + + @property + def set_usage_info_rec_ack(self) -> bool: + """ + The Set Usage Information Records message acceptance + """ + return self._set_usage_info_rec_ack + + @set_usage_info_rec_ack.setter + def set_usage_info_rec_ack(self, value): + self._set_usage_info_rec_ack = value + + + @property + def set_service_rec_rr(self) -> dict: + """ + The Set Service Records Request reject reason data + """ + return self._set_service_rec_rr + + @set_service_rec_rr.setter + def set_service_rec_rr(self, value): + self._set_service_rec_rr = value + + + @property + def set_usage_info_rec_rr(self) -> dict: + """ + The Set Usage Information Records Request reject reason data + """ + return self._set_usage_info_rec_rr + + @set_usage_info_rec_rr.setter + def set_usage_info_rec_rr(self, value): + self._set_usage_info_rec_rr = value + + + +# ================================================= Go to Service Mode Method ================================================= + def cmd_initiate_service_mode(self) -> int: + """ + Constructs and sends a request to change to Service operation mode via CAN bus. + Constraints: + Must be logged into DD. + Transition from current to requested op mode must be legal. + + @return: 1 if successful, zero otherwise + """ + service_mode = fp_enum_repository.FPOpModes.MODE_SERV + + payload = integer_to_bytearray(service_mode.value) + + return cmd_generic_override( + payload = payload, + reset = None, + channel_id = CanChannels.dialin_to_dd_ch_id, + msg_id = MsgIds.MSG_ID_DD_SET_OPERATION_MODE_OVERRIDE_REQUEST, + entity_name = 'FP/DD Operation Mode', + override_text = f'set to {service_mode.name}', + logger = self.logger, + can_interface = self.can_interface) Index: leahi_dialin/fp/modules/records_get_requests.py =================================================================== diff -u --- leahi_dialin/fp/modules/records_get_requests.py (revision 0) +++ leahi_dialin/fp/modules/records_get_requests.py (revision 5f16af73fb80a76c6dc767661f11a8f3508770a1) @@ -0,0 +1,74 @@ +########################################################################### +# +# Copyright (c) 2020-2024 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 records_get_requests.py +# +# @author (last) Zoltan Miskolci +# @date (last) 11-Aug-2026 +# @author (original) Zoltan Miskolci +# @date (original) 11-Aug-2026 +# +############################################################################ + +# Project imports +from leahi_dialin.common.msg_ids import MsgIds +from leahi_dialin.common.override_templates import cmd_generic_override +from leahi_dialin.protocols.CAN import CanChannels +from leahi_dialin.utils.abstract_classes import AbstractSubSystem + + +class FPRecordsGetRequests(AbstractSubSystem): + """ + Part of the FP Records + """ + def __init__(self, *args, **kwargs): + """ + The sub record class to handle all the get handlers. + """ + # Passing the arguments over to the next class too + super().__init__(*args, **kwargs) + + + # ================================================= Request Records Methods ================================================= + def cmd_request_service_records(self) -> int: + """ + Constructs and sends a request for FP Service Records. + Constraints: + Must be logged into FP. + Must be in Service mode. + + @return: 1 if successful, zero otherwise + """ + return cmd_generic_override( + payload = None, + reset = None, + channel_id = CanChannels.dialin_to_dd_ch_id, + msg_id = MsgIds.MSG_ID_UI_FP_NVM_GET_SERVICE_RECORD_REQUEST, + entity_name = f'FP Service Record request', + override_text = '', + logger = self.logger, + can_interface = self.can_interface) + + + def cmd_request_usage_information_records(self) -> int: + """ + Constructs and sends a request for FP Usage Information Records. + Constraints: + Must be logged into FP. + Must be in Service mode. + + @return: 1 if successful, zero otherwise + """ + return cmd_generic_override( + payload = None, + reset = None, + channel_id = CanChannels.dialin_to_dd_ch_id, + msg_id = MsgIds.MSG_ID_UI_FP_NVM_GET_USAGE_INFO_RECORD_REQUEST, + entity_name = f'FP Usage Information Record request', + override_text = '', + logger = self.logger, + can_interface = self.can_interface) Index: leahi_dialin/fp/modules/records_get_responses.py =================================================================== diff -u --- leahi_dialin/fp/modules/records_get_responses.py (revision 0) +++ leahi_dialin/fp/modules/records_get_responses.py (revision 5f16af73fb80a76c6dc767661f11a8f3508770a1) @@ -0,0 +1,96 @@ +########################################################################### +# +# Copyright (c) 2020-2024 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 records_get_responses.py +# +# @author (last) Zoltan Miskolci +# @date (last) 11-Aug-2026 +# @author (original) Zoltan Miskolci +# @date (original) 11-Aug-2026 +# +############################################################################ + +# Project imports +from leahi_dialin.common import dd_enum_repository, disp_enum_repository, fp_enum_repository +from leahi_dialin.common.generic_defs import DataTypes +from leahi_dialin.common.msg_defs import RequestRejectReasons +from leahi_dialin.common.msg_ids import MsgIds +from leahi_dialin.protocols.CAN import CanChannels +from leahi_dialin.utils.abstract_classes import AbstractSubSystem, LocalVars +from leahi_dialin.utils.base import publish + + +class FPRecordsGetHandlers(AbstractSubSystem): + """ + Part of the FP Records + """ + + def __init__(self, *args, **kwargs): + """ + The sub record class to handle all the get handlers. + """ + if self.can_interface is not None: + # Data Request Response messages + self.can_interface.register_receiving_publication_function(channel_id = CanChannels.fp_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_FP_UI_NVM_GET_SERVICE_RECORD_RESPONSE.value, + function = self._handler_service_record_sync) + self.can_interface.register_receiving_publication_function(channel_id = CanChannels.fp_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_FP_UI_NVM_GET_USAGE_INFO_RECORD_RESPONSE.value, + function = self._handler_usage_info_record_sync) + + # Passing the arguments over to the next class too + super().__init__(*args, **kwargs) + + + +# ================================================= CAN Message Handler Methods ================================================= + @publish([MsgIds.MSG_ID_FP_UI_NVM_GET_SERVICE_RECORD_RESPONSE.name.lower(), "get_service_rec_ack", "get_service_rec_rr", "service_records", "get_service_rec_timestamp"]) + def _handler_service_record_sync(self, message, timestamp = 0.0): + """ + Handles published FP Service Record data messages. + FP Service Records are captured for reference. + + @param message: published data message + @return: none + """ + msg_list = [] + msg_list.append((type(self).get_service_rec_ack, DataTypes.BOOL)) + msg_list.append((type(self).get_service_rec_rr, DataTypes.U32)) + for member in fp_enum_repository.FPServiceRecordFields: + if member is not fp_enum_repository.FPServiceRecordFields.NUM_OF_SERVICE_RECORD_FIELDS: + msg_list.append((self.service_records, member.name, member.datatype())) + + self.process_into_vars(decoder_list = msg_list, message = message) + + # Convert to enum + if isinstance(self.get_service_rec_rr, int): + self.get_service_rec_rr = RequestRejectReasons(self.get_service_rec_rr) + self.get_service_rec_timestamp = timestamp + + + @publish([MsgIds.MSG_ID_FP_UI_NVM_GET_USAGE_INFO_RECORD_RESPONSE.name.lower(), "get_usage_info_rec_ack", "get_usage_info_rec_rr", "usage_info_records", "get_usage_info_rec_timestamp"]) + def _handler_usage_info_record_sync(self, message, timestamp = 0.0): + """ + Handles published FP Usage Information Record data messages. + FP Usage Information Records are captured for reference. + + @param message: published data message + @return: none + """ + msg_list = [] + msg_list.append((type(self).get_usage_info_rec_ack, DataTypes.BOOL)) + msg_list.append((type(self).get_usage_info_rec_rr, DataTypes.U32)) + for member in fp_enum_repository.FPUsageInformationRecordFields: + if member is not fp_enum_repository.FPUsageInformationRecordFields.NUM_OF_USAGE_INFO_RECORD_FIELDS: + msg_list.append((self.usage_info_records, member.name, member.datatype())) + + self.process_into_vars(decoder_list = msg_list, message = message) + + # Convert to enum + if isinstance(self.get_usage_info_rec_rr, int): + self.get_usage_info_rec_rr = RequestRejectReasons(self.get_usage_info_rec_rr) + self.get_usage_info_rec_timestamp = timestamp Index: leahi_dialin/fp/modules/records_set_requests.py =================================================================== diff -u --- leahi_dialin/fp/modules/records_set_requests.py (revision 0) +++ leahi_dialin/fp/modules/records_set_requests.py (revision 5f16af73fb80a76c6dc767661f11a8f3508770a1) @@ -0,0 +1,109 @@ +########################################################################### +# +# Copyright (c) 2020-2024 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 records_set_requests.py +# +# @author (last) Zoltan Miskolci +# @date (last) 11-Aug-2026 +# @author (original) Zoltan Miskolci +# @date (original) 11-Aug-2026 +# +############################################################################ + +# Project imports +from leahi_dialin.common.msg_ids import MsgIds +from leahi_dialin.common.override_templates import cmd_generic_override +from leahi_dialin.protocols.CAN import CanChannels +from leahi_dialin.utils.abstract_classes import AbstractSubSystem +from leahi_dialin.utils.conversions import integer_to_bytearray + + +class FPRecordsSetRequests(AbstractSubSystem): + """ + Part of the FP Records + """ + + def __init__(self, *args, **kwargs): + """ + The sub record class to handle all the set requests. + """ + # Passing the arguments over to the next class too + super().__init__(*args, **kwargs) + + + +# ================================================= Set Records Main Methods ================================================= + def cmd_set_service_records(self, + water_recovery: int=0, + primary_filter_replacement_date: int=0, + secondary_filter_replacement_date: int=0, + ro_membrane_replacement_date: int=0, + service_loc: int=0, + last_service_date: int=0, + service_interval_sec: int=0, + last_reset_time: int=0) -> int: + """ + Constructs and sends a command for setting the Service Records. + Constraints: + Must be logged into FP. + Must be in Service mode. + + @return: 1 if successful, zero otherwise + """ + payload = integer_to_bytearray(water_recovery) + payload += integer_to_bytearray(primary_filter_replacement_date) + payload += integer_to_bytearray(secondary_filter_replacement_date) + payload += integer_to_bytearray(ro_membrane_replacement_date) + payload += integer_to_bytearray(service_loc) + payload += integer_to_bytearray(last_service_date) + payload += integer_to_bytearray(service_interval_sec) + payload += integer_to_bytearray(last_reset_time) + + return cmd_generic_override( + payload = payload, + reset = None, + channel_id = CanChannels.dialin_to_dd_ch_id, + msg_id = MsgIds.MSG_ID_UI_FP_NVM_SET_SERVICE_RECORD_REQUEST, + entity_name = f'New FP Service Record', + override_text = 'being set', + logger = self.logger, + can_interface = self.can_interface) + + + def cmd_set_usage_info_records(self, + primary_filter_treatment_count: int=0, + primary_filter_disinfection_count: int=0, + secondary_filter_treatment_count: int=0, + secondary_filter_disinfection_count: int=0, + ro_membrane_treatment_count: int=0, + ro_membrane_disinfection_count: int=0, + last_reset_time: int=0) -> int: + """ + Constructs and sends a command for setting the Usage Information Records. + Constraints: + Must be logged into FP. + Must be in Service mode. + + @return: 1 if successful, zero otherwise + """ + payload = integer_to_bytearray(primary_filter_treatment_count) + payload += integer_to_bytearray(primary_filter_disinfection_count) + payload += integer_to_bytearray(secondary_filter_treatment_count) + payload += integer_to_bytearray(secondary_filter_disinfection_count) + payload += integer_to_bytearray(ro_membrane_treatment_count) + payload += integer_to_bytearray(ro_membrane_disinfection_count) + payload += integer_to_bytearray(last_reset_time) + + return cmd_generic_override( + payload = payload, + reset = None, + channel_id = CanChannels.dialin_to_dd_ch_id, + msg_id = MsgIds.MSG_ID_UI_FP_NVM_SET_USAGE_INFO_RECORD_REQUEST, + entity_name = f'New FP Usage Information Record', + override_text = 'being set', + logger = self.logger, + can_interface = self.can_interface) Index: leahi_dialin/fp/modules/records_set_responses.py =================================================================== diff -u --- leahi_dialin/fp/modules/records_set_responses.py (revision 0) +++ leahi_dialin/fp/modules/records_set_responses.py (revision 5f16af73fb80a76c6dc767661f11a8f3508770a1) @@ -0,0 +1,92 @@ +########################################################################### +# +# Copyright (c) 2020-2024 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 records_set_responses.py +# +# @author (last) Zoltan Miskolci +# @date (last) 11-Aug-2026 +# @author (original) Zoltan Miskolci +# @date (original) 11-Aug-2026 +# +############################################################################ + +# Project imports +from leahi_dialin.common import fp_enum_repository +from leahi_dialin.common.generic_defs import DataTypes +from leahi_dialin.common.msg_defs import RequestRejectReasons +from leahi_dialin.common.msg_ids import MsgIds +from leahi_dialin.protocols.CAN import CanChannels +from leahi_dialin.utils.abstract_classes import AbstractSubSystem +from leahi_dialin.utils.base import publish + + +class FPRecordsSetHandlers(AbstractSubSystem): + """ + Part of the FP Records + """ + + def __init__(self, *args, **kwargs): + """ + The sub record class to handle all the set handlers. + """ + if self.can_interface is not None: + self.can_interface.register_receiving_publication_function(channel_id = CanChannels.fp_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_FP_UI_NVM_SET_SERVICE_RECORD_RESPONSE.value, + function = self._handler_set_service_rec_rr_sync) + self.can_interface.register_receiving_publication_function(channel_id = CanChannels.fp_sync_broadcast_ch_id, + message_id = MsgIds.MSG_ID_FP_UI_NVM_SET_USAGE_INFO_RECORD_RESPONSE.value, + function = self._handler_set_usage_info_rec_rr_sync) + + # Passing the arguments over to the next class too + super().__init__(*args, **kwargs) + + +# ================================================= Reject Reason Message Handler Methods ================================================= + @publish([MsgIds.MSG_ID_FP_UI_NVM_SET_SERVICE_RECORD_RESPONSE.name.lower(), "set_service_rec_ack", "set_service_rec_rr", "set_service_rec_rr_timestamp"]) + def _handler_set_service_rec_rr_sync(self, message, timestamp = 0.0): + """ + Handles published FP Set FP Service Records Reject Reason data messages. + FP Set FP Service Records Reject Reason are captured for reference. + + @param message: published data message + @return: none + """ + msg_list = [] + msg_list.append((type(self).set_service_rec_ack, DataTypes.BOOL)) + for ser_rec in fp_enum_repository.FPServiceRecordFields: + msg_list.append((self.set_service_rec_rr, ser_rec, DataTypes.U32)) + + self.process_into_vars(decoder_list = msg_list, message = message) + + # Convert to enum + for ser_rec in self.set_service_rec_rr: + if isinstance(self.set_service_rec_rr[ser_rec], int): + self.set_service_rec_rr[ser_rec] = RequestRejectReasons(self.set_service_rec_rr[ser_rec]) + self.set_service_rec_rr_timestamp = timestamp + + + @publish([MsgIds.MSG_ID_FP_UI_NVM_SET_USAGE_INFO_RECORD_RESPONSE.name.lower(), "set_usage_info_rec_ack", "set_usage_info_rec_rr", "set_usage_info_rec_rr_timestamp"]) + def _handler_set_usage_info_rec_rr_sync(self, message, timestamp = 0.0): + """ + Handles published FP Set FP Usage Information Records Reject Reason data messages. + FP Set FP Usage Information Records Reject Reason are captured for reference. + + @param message: published data message + @return: none + """ + msg_list = [] + msg_list.append((type(self).set_usage_info_rec_ack, DataTypes.BOOL)) + for info_rec in fp_enum_repository.FPUsageInformationRecordFields: + msg_list.append((self.set_usage_info_rec_rr, info_rec, DataTypes.U32)) + + self.process_into_vars(decoder_list = msg_list, message = message) + + # Convert to enum + for info_rec in self.set_usage_info_rec_rr: + if isinstance(self.set_usage_info_rec_rr[info_rec], int): + self.set_usage_info_rec_rr[info_rec] = RequestRejectReasons(self.set_usage_info_rec_rr[info_rec]) + self.set_usage_info_rec_rr_timestamp = timestamp Index: leahi_dialin/utils/enum_updater.py =================================================================== diff -u -re9dfb2412b14f3d28824cb3e37c364b8194bb24e -r5f16af73fb80a76c6dc767661f11a8f3508770a1 --- leahi_dialin/utils/enum_updater.py (.../enum_updater.py) (revision e9dfb2412b14f3d28824cb3e37c364b8194bb24e) +++ leahi_dialin/utils/enum_updater.py (.../enum_updater.py) (revision 5f16af73fb80a76c6dc767661f11a8f3508770a1) @@ -32,13 +32,15 @@ """ Read the enums from the C++ file and then update the Python Enum definitions """ - cpp_repo_loc = path.abspath(f'{path.dirname(__file__)}/../../../leahi-dialin/leahi_common') if path.exists(cpp_repo_loc) is False: cpp_repo_loc = path.abspath(f'{path.dirname(__file__)}/../../../leahi-dialin/leahi-common') + if path.exists(cpp_repo_loc) is False: + cpp_repo_loc = path.abspath(f'{path.dirname(__file__)}/../../../leahi-common') if path.exists(cpp_repo_loc) is False: return print(f'C++ repo location not found: {cpp_repo_loc}, skipping enum updates!') + files_to_check = [] files_to_check.append(f'{cpp_repo_loc}/AlarmDefs.h') files_to_check.append(f'{cpp_repo_loc}/MsgDefs.h')