diff --git a/custom_components/weishaupt_modbus/__init__.py b/custom_components/weishaupt_modbus/__init__.py index 91f2242..623144f 100644 --- a/custom_components/weishaupt_modbus/__init__.py +++ b/custom_components/weishaupt_modbus/__init__.py @@ -2,26 +2,30 @@ from homeassistant.core import HomeAssistant from .const import CONST +from .heatpump import HeatPump PLATFORMS: list[str] = [ "number", "select", "sensor", -# "switch", + # "switch", ] + # Return boolean to indicate that initialization was successful. # return True async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: # Store an instance of the "connecting" class that does the work of speaking # with your actual devices. # hass.data.setdefault(DOMAIN, {})[entry.entry_id] = hub.Hub(hass, entry.data["host"]) - + myHeatpump = HeatPump(entry) + myHeatpump.poll() # This creates each HA object for each platform your device requires. # It's done by calling the `async_setup_entry` function in each platform module. await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) return True + async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: # This is called when an entry/configured device is to be removed. The class # needs to unload itself, and remove callbacks. See the classes for further diff --git a/custom_components/weishaupt_modbus/heatpump.py b/custom_components/weishaupt_modbus/heatpump.py new file mode 100644 index 0000000..8198b8d --- /dev/null +++ b/custom_components/weishaupt_modbus/heatpump.py @@ -0,0 +1,66 @@ +import warnings + +from pymodbus.client import ModbusTcpClient as ModbusClient + +from homeassistant.const import CONF_HOST, CONF_PORT + +from .const import TYPES +from .hpconst import MODBUS_SYS_ITEMS + + +class HeatPump: + _ip = None + _port = None + _ModbusClient = None + + def __init__(self, config_entry): + self._ip = config_entry.data[CONF_HOST] + self._port = config_entry.data[CONF_PORT] + self._ModbusClient = None + + def connect(self): + # try: + self._ModbusClient = ModbusClient(host=self._ip, port=self._port) + return self._ModbusClient.connected # noqa: TRY300 + + # except: # noqa: E722 + # return None + + def getValue(self, ModbusItem): + try: + if not self._ModbusClient.connected: + self.connect() + match ModbusItem.type: + case TYPES.SENSOR | TYPES.SENSOR_CALC: + # Sensor entities are read-only + ModbusItem._value = self._ModbusClient.read_input_registers( + ModbusItem.address, slave=1 + ).registers[0] + case TYPES.SELECT | TYPES.NUMBER | TYPES.NUMBER_RO: + ModbusItem._value = self._ModbusClient.read_holding_registers( + ModbusItem.address, slave=1 + ).registers[0] + + except: # noqa: E722 + warnings.warn("Getting value of " & ModbusItem.name & " failed") + return None + + def setValue(self, ModbusItem, value) -> None: + try: + match ModbusItem.type: + case TYPES.SENSOR | TYPES.NUMBER_RO | TYPES.SENSOR_CALC: + # Sensor entities are read-only + return + case _: + self.connect() + self._ModbusClient.write_register( + ModbusItem.address, int(value), slave=1 + ) + except: # noqua: E722 + return None + + def poll(self): + for item in MODBUS_SYS_ITEMS: + # warnings.warn(str(item.address)) + self.getValue(item) + warnings.warn(str(item._value)) diff --git a/custom_components/weishaupt_modbus/items.py b/custom_components/weishaupt_modbus/items.py index df3e83c..acedd11 100644 --- a/custom_components/weishaupt_modbus/items.py +++ b/custom_components/weishaupt_modbus/items.py @@ -1,14 +1,15 @@ from .const import TYPES + # An item of a status, e.g. error code and error text along with a precise description -# A class is intentionally defined here because the assignment via dictionaries would not work so elegantly in the end, +# A class is intentionally defined here because the assignment via dictionaries would not work so elegantly in the end, # especially when searching backwards. (At least I don't know how...) -class StatusItem(): +class StatusItem: _number = None _text = None _description = None - def __init__(self, number, text, description = None): + def __init__(self, number, text, description=None): self._number = number self._text = text self._description = description @@ -37,31 +38,34 @@ def description(self): def description(self, value) -> None: self._description = value -# A Modbus item, consisting of address, name, + +# A Modbus item, consisting of address, name, # format (temperature, status, ..), # type (sensor, number, ..), # device (System, Heatpump, ..) and # optional result list from status items # (number entities: status = limits? -class ModbusItem(): +class ModbusItem: _address = None _name = "empty" _format = None _type = TYPES.SENSOR _resultlist = None _device = None + _value = None - def __init__(self, address, name, format, type, device, resultlist = None): + def __init__(self, address, name, format, type, device, resultlist=None): self._address = address self._name = name self._format = format self._type = type self._device = device self._resultlist = resultlist - + @property def address(self): return self._address + @property def name(self): return self._name