Skip to content

Commit

Permalink
Add device ID to log messages to improve debugging multuiple devicest…
Browse files Browse the repository at this point in the history
… at once (#187)

* Move response payload logging up into the device class so they can be associated with specific devices

* Use __str__ for payload logs

* Add property to access raw capabilities
  • Loading branch information
mill1000 authored Jan 30, 2025
1 parent 294e74b commit 1624ccf
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 28 deletions.
19 changes: 6 additions & 13 deletions msmart/device/AC/command.py
Original file line number Diff line number Diff line change
Expand Up @@ -420,6 +420,9 @@ def __init__(self, payload: memoryview) -> None:
self._id = payload[0]
self._payload = bytes(payload)

def __str__(self) -> str:
return self.payload.hex()

@property
def id(self) -> int:
return self._id
Expand Down Expand Up @@ -487,11 +490,11 @@ def __init__(self, payload: memoryview) -> None:
self._capabilities = {}
self._additional_capabilities = False

_LOGGER.debug("Capabilities response payload: %s", payload.hex())

self._parse_capabilities(payload)

_LOGGER.debug("Raw capabilities: %s", self._capabilities)
@property
def raw_capabilities(self) -> Mapping[str, Any]:
return self._capabilities

def _parse_capabilities(self, payload: memoryview) -> None:
# Clear existing capabilities
Expand Down Expand Up @@ -657,8 +660,6 @@ def merge(self, other: CapabilitiesResponse) -> None:
# Add other's capabilities to ours
self._capabilities.update(other._capabilities)

_LOGGER.debug("Merged raw capabilities: %s", self._capabilities)

@property
def additional_capabilities(self) -> bool:
return self._additional_capabilities
Expand Down Expand Up @@ -829,8 +830,6 @@ def __init__(self, payload: memoryview) -> None:
self.purifier = None
self.target_humidity = None

_LOGGER.debug("State response payload: %s", payload.hex())

self._parse(payload)

def _parse(self, payload: memoryview) -> None:
Expand Down Expand Up @@ -937,8 +936,6 @@ def __init__(self, payload: memoryview) -> None:

self._properties = {}

_LOGGER.debug("Properties response payload: %s", payload.hex())

self._parse(payload)

def _parse(self, payload: memoryview) -> None:
Expand Down Expand Up @@ -1008,8 +1005,6 @@ def __init__(self, payload: memoryview) -> None:
self.current_energy_binary = None
self.real_time_power_binary = None

_LOGGER.debug("Energy response payload: %s", payload.hex())

self._parse(payload)

def _parse(self, payload: memoryview) -> None:
Expand Down Expand Up @@ -1077,8 +1072,6 @@ def __init__(self, payload: memoryview) -> None:

self.humidity = None

_LOGGER.debug("Humidity response payload: %s", payload.hex())

self._parse(payload)

def _parse(self, payload: memoryview) -> None:
Expand Down
56 changes: 41 additions & 15 deletions msmart/device/AC/device.py
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,9 @@ def _update_state(self, res: Response) -> None:
"""Update the local state from a device state response."""

if isinstance(res, StateResponse):
_LOGGER.debug("State response payload from device %s: %s",
self.id, res)

self._power_state = res.power_on

self._target_temperature = res.target_temperature
Expand Down Expand Up @@ -208,6 +211,9 @@ def _update_state(self, res: Response) -> None:
self._target_humidity = res.target_humidity

elif isinstance(res, PropertiesResponse):
_LOGGER.debug(
"Properties response payload from device %s: %s", self.id, res)

if (angle := res.get_property(PropertyId.SWING_LR_ANGLE)) is not None:
self._horizontal_swing_angle = cast(
AirConditioner.SwingAngle,
Expand Down Expand Up @@ -243,16 +249,22 @@ def _update_state(self, res: Response) -> None:
self._ieco = value

elif isinstance(res, EnergyUsageResponse):
_LOGGER.debug("Energy response payload from device %s: %s",
self.id, res)

self._total_energy_usage = res.total_energy_binary if self._use_binary_energy else res.total_energy
self._current_energy_usage = res.current_energy_binary if self._use_binary_energy else res.current_energy
self._real_time_power_usage = res.real_time_power_binary if self._use_binary_energy else res.real_time_power

elif isinstance(res, HumidityResponse):
_LOGGER.debug(
"Humidity response payload from device %s: %s", self.id, res)

self._indoor_humidity = res.humidity

else:
_LOGGER.debug("Ignored unknown response from %s:%d: %s",
self.ip, self.port, res.payload.hex())
_LOGGER.debug("Ignored unknown response from device %s: %s",
self.id, res)

def _update_capabilities(self, res: CapabilitiesResponse) -> None:
# Build list of supported operation modes
Expand Down Expand Up @@ -399,8 +411,8 @@ async def _send_command_get_response_with_id(self, command, response_id: Respons
if response.id == response_id:
return response

_LOGGER.debug("Ignored response with ID %d from %s:%d: %s",
response.id, self.ip, self.port, response.payload.hex())
_LOGGER.debug("Ignored response with ID %d from device %s: %s",
response.id, self.id, response)

return None

Expand All @@ -414,9 +426,13 @@ async def get_capabilities(self) -> None:

if response is None:
_LOGGER.error(
"Failed to query capabilities from %s:%d.", self.ip, self.port)
"Failed to query capabilities from device %s.", self.id)
return

_LOGGER.debug("Capabilities response payload from device %s: %s",
self.id, response)
_LOGGER.debug("Raw capabilities: %s", response.raw_capabilities)

# Send 2nd capabilities request if needed
if response.additional_capabilities:
cmd = GetCapabilitiesCommand(True)
Expand All @@ -425,11 +441,18 @@ async def get_capabilities(self) -> None:
CapabilitiesResponse, additional_response)

if additional_response:
_LOGGER.debug(
"Additional capabilities response payload from device %s: %s", self.id, response)

# Merge additional capabilities
response.merge(additional_response)

_LOGGER.debug("Merged raw capabilities: %s",
response.raw_capabilities)

else:
_LOGGER.warning(
"Failed to query additional capabilities from %s:%d.", self.ip, self.port)
"Failed to query additional capabilities from device %s.", self.id)

# Update device capabilities
self._update_capabilities(response)
Expand All @@ -438,7 +461,8 @@ async def toggle_display(self) -> None:
"""Toggle the device display if the device supports it."""

if not self._supports_display_control:
_LOGGER.warning("Device is not capable of display control.")
_LOGGER.warning(
"Device %s is not capable of display control.", self.id)

cmd = ToggleDisplayCommand()
cmd.beep_on = self._beep_on
Expand Down Expand Up @@ -486,7 +510,8 @@ async def _apply_properties(self, properties: dict[PropertyId, Union[int, bool]]

# Warn if attempting to update a property that isn't supported
for prop in (properties.keys() - self._supported_properties):
_LOGGER.warning("Device is not capable of property %r.", prop)
_LOGGER.warning(
"Device %s is not capable of property %r.", self.id, prop)

# Always add buzzer property
properties[PropertyId.BUZZER] = self._beep_on
Expand All @@ -502,29 +527,30 @@ async def apply(self) -> None:
# Warn if trying to apply unsupported modes
if self._operational_mode not in self._supported_op_modes:
_LOGGER.warning(
"Device is not capable of operational mode %r.", self._operational_mode)
"Device %s is not capable of operational mode %r.", self.id, self._operational_mode)

if (self._fan_speed not in self._supported_fan_speeds
and not self._supports_custom_fan_speed):
_LOGGER.warning(
"Device is not capable of fan speed %r.", self._fan_speed)
"Device %s is not capable of fan speed %r.", self.id, self._fan_speed)

if self._swing_mode not in self._supported_swing_modes:
_LOGGER.warning(
"Device is not capable of swing mode %r.", self._swing_mode)
"Device %s is not capable of swing mode %r.", self.id, self._swing_mode)

if self._turbo and not self._supports_turbo:
_LOGGER.warning("Device is not capable of turbo mode.")
_LOGGER.warning("Device %s is not capable of turbo mode.", self.id)

if self._eco and not self._supports_eco:
_LOGGER.warning("Device is not capable of eco mode.")
_LOGGER.warning("Device %s is not capable of eco mode.", self.id)

if self._freeze_protection and not self._supports_freeze_protection:
_LOGGER.warning("Device is not capable of freeze protection.")
_LOGGER.warning(
"Device %s is not capable of freeze protection.", self.id)

if self._rate_select != AirConditioner.RateSelect.OFF and self._rate_select not in self._supported_rate_selects:
_LOGGER.warning(
"Device is not capable of rate select %r.", self._rate_select)
"Device %s is not capable of rate select %r.", self.id, self._rate_select)

# Define function to return value or a default if value is None
def or_default(v, d) -> Any: return v if v is not None else d
Expand Down

0 comments on commit 1624ccf

Please sign in to comment.