Source code for duco.duco
"""Duco."""
import logging
from duco.const import (
PROJECT_PACKAGE_NAME,
DUCO_REG_ADDR_INPUT_MODULE_TYPE,
DUCO_MODBUS_MASTER_DEFAULT_UNIT_ID
)
from duco.enum_types import (ModuleType)
from duco.helpers import (to_register_addr)
from duco.modbus import (
create_client_config,
ModbusHub
)
from duco.nodes import (Node)
_LOGGER = logging.getLogger(PROJECT_PACKAGE_NAME)
[docs]class DucoBox:
"""The summary line for a class docstring should fit on one line.
If the class has public attributes, they may be documented here
in an ``Attributes`` section and follow the same formatting as a
function's ``Args`` section. Alternatively, attributes may be documented
inline with the attribute's declaration (see __init__ method below).
Properties created with the ``@property`` decorator should be documented
in the property's getter method.
Attributes:
attr1 (str): Description of `attr1`.
attr2 (:obj:`int`, optional): Description of `attr2`.
"""
def __init__(self, modbus_client_type, modbus_client_port,
modbus_client_host=None,
modbus_master_unit_id=DUCO_MODBUS_MASTER_DEFAULT_UNIT_ID):
"""Initialize DucoBox.
The __init__ method may be documented in either the class level
docstring, or as a docstring on the __init__ method itself.
Either form is acceptable, but the two should not be mixed. Choose one
convention to document the __init__ method and be consistent with it.
Note:
Do not include the `self` parameter in the ``Args`` section.
Args:
param1 (str): Description of `param1`.
param2 (:obj:`int`, optional): Description of `param2`. Multiple
lines are supported.
param3 (:obj:`list` of :obj:`str`): Description of `param3`.
"""
client_config = create_client_config(modbus_client_type,
modbus_client_port,
modbus_client_host,
modbus_master_unit_id)
self._modbus_hub = ModbusHub(client_config)
self.node_list = list()
def __enter__(self):
"""Enter."""
self._modbus_hub.setup()
self.__enumerate_node_tree()
return self
def __exit__(self, exc_type, _exc_value, traceback):
"""Exit."""
self._modbus_hub.close()
def __enumerate_node_tree(self):
"""Enumerate Duco node tree."""
node_id = 1
node_found = True
self.node_list = list()
while node_found:
node_type = self.__probe_node_id(node_id)
if node_type is False:
node_found = False
else:
self.node_list.append(
Node.factory(node_id, node_type, self._modbus_hub))
node_id = node_id + 1
def __probe_node_id(self, node_id):
"""Probe Modbus for node_id module type."""
_LOGGER.debug("probe node_id %d", node_id)
modbus_result = self._modbus_hub.read_input_registers(
to_register_addr(node_id, DUCO_REG_ADDR_INPUT_MODULE_TYPE), 1)
try:
register = modbus_result.registers
response = register[0]
except AttributeError:
_LOGGER.debug("No response from node_id %d", node_id)
return False
if ModuleType.supported(response):
module_type = ModuleType(response)
_LOGGER.debug("node_id %d is a module of type %s",
node_id, module_type)
return module_type
return False