Index: dialin/hd/battery.py =================================================================== diff -u -r171d79a4dd35aa06f7216513c4d44f584561f76c -re56dc8e8243fb7f7a4600e093898bc008633a53f --- dialin/hd/battery.py (.../battery.py) (revision 171d79a4dd35aa06f7216513c4d44f584561f76c) +++ dialin/hd/battery.py (.../battery.py) (revision e56dc8e8243fb7f7a4600e093898bc008633a53f) @@ -1,89 +1,169 @@ ########################################################################### # -# Copyright (c) 2020-2022 Diality Inc. - All Rights Reserved. +# Copyright (c) 2019-2020 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 battery.py +# @file battery.py # -# @author (last) Michael Garthwaite -# @date (last) 3-28-2022 -# @author (original) Michael Garthwaite -# @date (original) 3-28-2022 +# @author (last) Peter Lucia +# @date (last) 03-Nov-2020 +# @author (original) Peter Lucia +# @date (original) 02-Apr-2020 # ############################################################################ import struct from logging import Logger -from .constants import RESET, NO_RESET +#from .constants import RESET, NO_RESET from ..common.msg_defs import MsgIds, MsgFieldPositions -from ..protocols.CAN import DenaliMessage, DenaliCanMessenger, DenaliChannels +from ..protocols.CAN import DenaliMessage, DenaliChannels from ..utils.base import AbstractSubSystem, publish -from ..utils.conversions import integer_to_bytearray +from ..utils.checks import check_broadcast_interval_override_ms +from ..utils.conversions import integer_to_bytearray, float_to_bytearray class HDBattery(AbstractSubSystem): """ - Hemodialysis Device (HD) Dialin API sub-class for battery related commands. + Hemodialysis Delivery (HD) Dialin API sub-class for battery subsystem. """ - def __init__(self, can_interface: DenaliCanMessenger, logger: Logger): + def __init__(self, can_interface, logger: Logger): """ HDBattery constructor - @param can_interface: the Denali CAN interface object """ - super().__init__() self.can_interface = can_interface self.logger = logger - self.battery_percentage = 0 - def get_battery_percentage_remaining(self): - """ - Gets the battery percentage remaining + if self.can_interface is not None: + channel_id = DenaliChannels.hd_sync_broadcast_ch_id + msg_id = MsgIds.MSG_ID_HD_BATTERY_MANAGEMENT_DATA.value + self.can_interface.register_receiving_publication_function(channel_id, msg_id, + self._handler_battery_sync) - @return: int value of the back up battery. - """ + self.RemainingCapacity1 = 0 + self.BatteryStatus1 = 0 + self.RemainingCapacityAlarm = 0 + self.RemainingTimeAlarm = 0 + self.BatteryMode = 0 + self.AtRate = 0 + self.RemainingCapacity2 = 0 + self.BatteryStatus2 = 0 + self.AtRateTimeToFull = 0 + self.AtRateTimeToEmpty = 0 + self.AtRateOK = 0 + self.Temperature = 0 + self.Voltage = 0 + self.Current = 0 + self.RemainingCapacity3 = 0 + self.BatteryStatus3 = 0 + self.AverageCurrent = 0 + self.MaxError = 0 + self.RelativeStateOfCharge = 0 + self.AbsoluteStateOfCharge = 0 + self.FullChargeCapacity = 0 + self.RunTimeToEmpty = 0 + self.AverageTimeToEmpty = 0 + self.AverageTimeToFull = 0 + self.ChargingCurrent = 0 + self.RemainingCapacity4 = 0 + self.BatteryStatus4 = 0 + self.ChargingVoltage = 0 + self.CycleCount = 0 + self.DesignCapacity = 0 + self.DesignVoltage = 0 + self.SpecificationInfo = 0 + self.ManufactureDate = 0 + self.SerialNumber = 0 + self.RemainingCapacity5 = 0 + self.BatteryStatus5 = 0 + self.ManufacturerName = "" + self.DeviceName = "" + self.DeviceChemistry = "" - return self.battery_percentage - - def cmd_battery_percentage_remaining_override(self, percentage: int, reset: int = NO_RESET) -> int: + self.allvalues = [ + [self.RemainingCapacity1, "RemainingCapacity1", "int", "mAh"], + [self.BatteryStatus1, "BatteryStatus1", "bits", None], + [self.RemainingCapacityAlarm, "RemainingCapacityAlarm", "int", "mAh"], + [self.RemainingTimeAlarm, "RemainingTimeAlarm", "int", "minutes"], + [self.BatteryMode, "BatteryMode", "bits", None], + [self.AtRate, "AtRate", "int", "mA"], + [self.RemainingCapacity2, "RemainingCapacity2", "int", "mAh"], + [self.BatteryStatus2, "BatteryStatus2", "bits", None], + [self.AtRateTimeToFull, "AtRateTimeToFull", "int", "minutes"], + [self.AtRateTimeToEmpty, "AtRateTimeToEmpty", "int", "minutes"], + [self.AtRateOK, "AtRateOK", "bool", None], + [self.Temperature, "Temperature", "temperature", "degC"], + [self.Voltage, "Voltage", "int", "mV"], + [self.Current, "Current", "int", "mA"], + [self.RemainingCapacity3, "RemainingCapacity3", "int", "mAh"], + [self.BatteryStatus3, "BatteryStatus3", "bits", None], + [self.AverageCurrent, "AverageCurrent", "int", "mA"], + [self.MaxError, "MaxError", "int", "percent"], + [self.RelativeStateOfCharge, "RelativeStateOfCharge", "int", "percent"], + [self.AbsoluteStateOfCharge, "AbsoluteStateOfCharge", "int", "percent"], + [self.FullChargeCapacity, "FullChargeCapacity", "int", "mAh"], + [self.RunTimeToEmpty, "RunTimeToEmpty", "int", "minutes"], + [self.AverageTimeToEmpty, "AverageTimeToEmpty", "int", "minutes"], + [self.AverageTimeToFull, "AverageTimeToFull", "int", "minutes"], + [self.ChargingCurrent, "ChargingCurrent", "int", "mA"], + [self.RemainingCapacity4, "RemainingCapacity4", "int", "mAh"], + [self.BatteryStatus4, "BatteryStatus4", "bits", None], + [self.ChargingVoltage, "ChargingVoltage", "int", "mV"], + [self.CycleCount, "CycleCount", "int", "percent"], + [self.DesignCapacity, "DesignCapacity", "int", "mAh"], + [self.DesignVoltage, "DesignVoltage", "int", "mV"], + [self.SpecificationInfo, "SpecificationInfo", "int", None], + [self.ManufactureDate, "ManufactureDate", "int", "percent"], + [self.SerialNumber, "SerialNumber", "int", None], + [self.RemainingCapacity5, "RemainingCapacity5", "int", "mAh"], + [self.BatteryStatus5, "BatteryStatus5", "bits", None], + [self.ManufacturerName, "ManufacturerName", "string", None], + [self.DeviceName, "DeviceName", "string", None], + [self.DeviceChemistry, "DeviceChemistry", "string", None]] + + """@publish([ + ]) + """ + def _handler_battery_sync(self, message): """ - Constructs and sends the battery percentage remaining override. - Constraints: - Must be logged into HD. + Handles published battery data messages. Battery data are captured + for reference. - @param percentage: integer - Remaining percentage of the back up battery. - @param reset: integer - 1 to reset a previous override, 0 to override - @return: 1 if successful, zero otherwise + @param message: published battery data message + @return: none """ + #first unpack all of the values into byte arrays + index = 6 + for value in self.all_values: + value[0] = bytearray(message['message'][index, index+4]) - rst = integer_to_bytearray(reset) - pct = integer_to_bytearray(percentage) - payload = rst + pct + #parse according to type of data + for value in self.all_values: + if value[2] == "int": + value[0] = struct.unpack('H', value[0]) + elif value[2] == "string": + value[0] = struct.unpack('s', value[0]) + elif value[2] == "temperature": + temp = struct.unpack('H', value[0]) + value[0] = temp / 10.0 + elif value[2] == "bool": + temp = struct.unpack('H', value[0]) + value[0] = "False" + if temp > 0: + value[0] = "True" + elif value[2] == "bits": + #convert integer to string representing bits + temp = struct.unpack('H', value[0]) + value[0] = format(temp, 'b') - message = DenaliMessage.build_message(channel_id=DenaliChannels.dialin_to_hd_ch_id, - message_id=MsgIds.MSG_ID_HD_BATTERY_REMAINING_PERCENT_OVERRIDE.value, - payload=payload) - - self.logger.debug("override battery percentage remaining") - - # Send message - received_message = self.can_interface.send(message) - - # If there is content... - if received_message is not None: - if reset == RESET: - str_res = "reset back to normal" - else: - str_res = str(pct) + "% " - - self.logger.debug("Battery percentage overridden to " + str_res + ":" + - str(received_message['message'][DenaliMessage.PAYLOAD_START_INDEX])) - # response payload is OK or not OK - return received_message['message'][DenaliMessage.PAYLOAD_START_INDEX] - else: - self.logger.debug("Timeout!!!!") - return False + #print out the converted values + for value in self.all_values: + units = value[3] + if not units: + units = "" + print (value[1], value[0], units) +