Skip to content

Commit

Permalink
Merge pull request #59 from LarsK1/fixes
Browse files Browse the repository at this point in the history
Fixes & Version string parsing
  • Loading branch information
LarsK1 authored Nov 24, 2024
2 parents 35f7c0e + a8078ea commit 8f34c4c
Show file tree
Hide file tree
Showing 7 changed files with 88 additions and 24 deletions.
5 changes: 5 additions & 0 deletions custom_components/solvis_control/const.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ class ModbusFieldConfig:
# Possibilities:
# sensor (0), select (1), number (2), switch (3)
input_type: int = 0
# Option to further process data
# 0: no processing, 1: version string split
data_processing: int = 0


PORT = 502
Expand Down Expand Up @@ -760,6 +763,7 @@ class ModbusFieldConfig:
state_class=None,
multiplier=1,
entity_category="diagnostic",
data_processing=1,
),
ModbusFieldConfig( # VersionNBG
name="version_nbg",
Expand All @@ -769,6 +773,7 @@ class ModbusFieldConfig:
state_class=None,
multiplier=1,
entity_category="diagnostic",
data_processing=1,
),
ModbusFieldConfig(
name="digin_error",
Expand Down
15 changes: 11 additions & 4 deletions custom_components/solvis_control/coordinator.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
"""Solvis Modbus Data Coordinator"""

import struct
from datetime import timedelta
import logging

Expand Down Expand Up @@ -71,7 +72,6 @@ async def _async_update_data(self):
if entity_entry and entity_entry.disabled:
_LOGGER.debug(f"Skipping disabled entity: {entity_id}")
continue

try:
if register.register == 1:
result = await self.modbus.read_input_registers(
Expand All @@ -94,9 +94,16 @@ async def _async_update_data(self):
f"Value from previous register before modification: {register_value}"
)
value = round(register_value * register.multiplier, 2)
parsed_data[register.name] = (
abs(value) if register.absolute_value else value
)
try:
value = round(
decoder.decode_16bit_int() * register.multiplier, 2
)
except struct.error:
parsed_data[register.name] = -300
else:
parsed_data[register.name] = (
abs(value) if register.absolute_value else value
)
# if "version" in register.name:
# parsed_data[register.name] = ".".join(
# parsed_data[register.name].split(0, 2)
Expand Down
2 changes: 1 addition & 1 deletion custom_components/solvis_control/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,5 @@
"iot_class": "local_polling",
"issue_tracker": "https://github.com/LarsK1/hass_solvis_control/issues",
"requirements": ["pymodbus"],
"version": "1.1.4"
"version": "1.1.5"
}
20 changes: 15 additions & 5 deletions custom_components/solvis_control/number.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ async def async_setup_entry(
register.step_size,
register.address,
register.multiplier,
register.data_processing,
)
)

Expand All @@ -109,6 +110,7 @@ def __init__(
step_size: int | None = None,
modbus_address: int = None,
multiplier: float = 1,
data_processing: int = 0,
):
"""Initialize the Solvis number entity."""
super().__init__(coordinator)
Expand All @@ -135,6 +137,7 @@ def __init__(
if range_data:
self.native_min_value = range_data[0]
self.native_max_value = range_data[1]
self.data_processing = data_processing

@callback
def _handle_coordinator_update(self) -> None:
Expand All @@ -151,22 +154,29 @@ def _handle_coordinator_update(self) -> None:

response_data = self.coordinator.data.get(self._response_key)
if response_data is None:
_LOGGER.warning("No data available for (%s)", self._response_key)
_LOGGER.warning(f"No data available for {self._response_key}")
self._attr_available = False
return

# Validate the data type received from the coordinator
if not isinstance(response_data, (int, float, complex, Decimal)):
_LOGGER.warning(
"Invalid response data type from coordinator. %s has type %s",
response_data,
type(response_data),
f"Invalid response data type from coordinator. {response_data} has type {type(response_data)}"
)
self._attr_available = False
return

if response_data == -300:
_LOGGER.warning(
f"The coordinator failed to fetch data for entity: {self._response_key}"
)
self._attr_available = False
return

self._attr_available = True
self._attr_native_value = response_data # Update the number value
match self.data_processing:
case _:
self._attr_native_value = response_data # Update the number value
self.async_write_ha_state()

async def async_set_native_value(self, value: float) -> None:
Expand Down
22 changes: 17 additions & 5 deletions custom_components/solvis_control/select.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ async def async_setup_entry(
register.enabled_by_default,
register.options, # These are the options for the select entity
register.address,
register.data_processing,
)
)

Expand All @@ -98,6 +99,7 @@ def __init__(
enabled_by_default: bool = True,
options: tuple = None, # Renamed for clarity
modbus_address: int = None,
data_processing: int = None,
):
"""Initialize the Solvis select entity."""
super().__init__(coordinator)
Expand All @@ -113,6 +115,7 @@ def __init__(
self.translation_key = name
self._attr_current_option = None
self._attr_options = options # Set the options for the select entity
self.data_processing = data_processing

@callback
def _handle_coordinator_update(self) -> None:
Expand All @@ -129,22 +132,31 @@ def _handle_coordinator_update(self) -> None:

response_data = self.coordinator.data.get(self._response_key)
if response_data is None:
_LOGGER.warning("No data available for (%s)", self._response_key)
_LOGGER.warning(f"No data available for {self._response_key}")
self._attr_available = False
return

# Validate the data type received from the coordinator
if not isinstance(response_data, (int, float, complex, Decimal)):
_LOGGER.warning(
"Invalid response data type from coordinator. %s has type %s",
response_data,
type(response_data),
f"Invalid response data type from coordinator. {response_data} has type {type(response_data)}"
)
self._attr_available = False
return

if response_data == -300:
_LOGGER.warning(
f"The coordinator failed to fetch data for entity: {self._response_key}"
)
self._attr_available = False
return

self._attr_available = True
self._attr_current_option = str(response_data) # Update the selected option
match self.data_processing:
case _:
self._attr_current_option = str(
response_data
) # Update the selected option
self.async_write_ha_state()

async def async_select_option(self, option: str) -> None:
Expand Down
32 changes: 27 additions & 5 deletions custom_components/solvis_control/sensor.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ async def async_setup_entry(
register.state_class,
register.entity_category,
register.enabled_by_default,
register.data_processing,
)
)

Expand All @@ -100,6 +101,7 @@ def __init__(
state_class: str | None = None,
entity_category: str | None = None,
enabled_by_default: bool = True,
data_processing: int = 0,
):
"""Initialize the Solvis sensor."""
super().__init__(coordinator)
Expand All @@ -117,6 +119,7 @@ def __init__(
self._attr_has_entity_name = True
self.unique_id = f"{re.sub('^[A-Za-z0-9_-]*$', '', name)}_{name}"
self.translation_key = name
self.data_processing = data_processing

@callback
def _handle_coordinator_update(self) -> None:
Expand All @@ -134,20 +137,39 @@ def _handle_coordinator_update(self) -> None:

response_data = self.coordinator.data.get(self._response_key)
if response_data is None:
_LOGGER.warning("No data available for (%s)", self._response_key)
_LOGGER.warning(f"No data available for {self._response_key}")
self._attr_available = False
return

# Validate the data type received from the coordinator
if not isinstance(response_data, (int, float, complex, Decimal)):
_LOGGER.warning(
"Invalid response data type from coordinator. %s has type %s",
response_data,
type(response_data),
f"Invalid response data type from coordinator. {response_data} has type {type(response_data)}"
)
self._attr_available = False
return

if response_data == -300:
_LOGGER.warning(
f"The coordinator failed to fetch data for entity: {self._response_key}"
)
self._attr_available = False
return
self._attr_available = True
self._attr_native_value = response_data # Update the sensor value
match self.data_processing:
case 1: # Version
if len(str(response_data)) == 5:
response_data = str(response_data)
self._attr_native_value = (
f"{response_data[0]}.{response_data[1-2]}.{response_data[3-4]}"
)
if self._address == 32770:
self.device_info.sw_version = self._attr_native_value
elif self._address == 32771:
self.device_info.hw_version = self._attr_native_value
else:
_LOGGER.warning("Couldn't process version string to Version.")
self._attr_native_value = response_data
case _:
self._attr_native_value = response_data # Update the sensor value
self.async_write_ha_state()
16 changes: 12 additions & 4 deletions custom_components/solvis_control/switch.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ async def async_setup_entry(
register.name,
register.enabled_by_default,
register.address,
register.data_processing,
)
)

Expand All @@ -96,6 +97,7 @@ def __init__(
name: str,
enabled_by_default: bool = True,
modbus_address: int = None,
data_processing: int = 0,
):
"""Initialize the Solvis switch."""
super().__init__(coordinator)
Expand All @@ -110,6 +112,7 @@ def __init__(
self.unique_id = f"{re.sub('^[A-Za-z0-9_-]*$', '', name)}_{name}"
self.translation_key = name
self._attr_current_option = None
self.data_processing = data_processing

@callback
def _handle_coordinator_update(self) -> None:
Expand All @@ -127,16 +130,21 @@ def _handle_coordinator_update(self) -> None:

response_data = self.coordinator.data.get(self._response_key)
if response_data is None:
_LOGGER.warning("No data available for (%s)", self._response_key)
_LOGGER.warning(f"No data available for {self._response_key}")
self._attr_available = False
return

# Validate the data type received from the coordinator
if not isinstance(response_data, (int, float, complex, Decimal)):
_LOGGER.warning(
"Invalid response data type from coordinator. %s has type %s",
response_data,
type(response_data),
f"Invalid response data type from coordinator. {response_data} has type {type(response_data)}"
)
self._attr_available = False
return

if response_data == -300:
_LOGGER.warning(
f"The coordinator failed to fetch data for entity: {self._response_key}"
)
self._attr_available = False
return
Expand Down

0 comments on commit 8f34c4c

Please sign in to comment.