mirror of
https://github.com/dptech-corp/Uni-Lab-OS.git
synced 2025-12-14 13:14:39 +00:00
162 lines
6.7 KiB
Python
162 lines
6.7 KiB
Python
# coding=utf-8
|
|
from enum import Enum
|
|
from abc import ABC, abstractmethod
|
|
|
|
from pymodbus.client import ModbusBaseSyncClient
|
|
from pymodbus.client.mixin import ModbusClientMixin
|
|
from typing import Tuple, Union, Optional
|
|
|
|
DataType = ModbusClientMixin.DATATYPE
|
|
|
|
class WorderOrder(Enum):
|
|
BIG = "big"
|
|
LITTLE = "little"
|
|
|
|
class DeviceType(Enum):
|
|
COIL = 'coil'
|
|
DISCRETE_INPUTS = 'discrete_inputs'
|
|
HOLD_REGISTER = 'hold_register'
|
|
INPUT_REGISTER = 'input_register'
|
|
|
|
|
|
class Base(ABC):
|
|
def __init__(self, client: ModbusBaseSyncClient, name: str, address: int, typ: DeviceType, data_type: DataType):
|
|
self._address: int = address
|
|
self._client = client
|
|
self._name = name
|
|
self._type = typ
|
|
self._data_type = data_type
|
|
|
|
@abstractmethod
|
|
def read(self, value, data_type: Optional[DataType] = None, word_order: WorderOrder = WorderOrder.BIG, slave = 1,) -> Tuple[Union[int, float, str, list[bool], list[int], list[float]], bool]:
|
|
pass
|
|
|
|
@abstractmethod
|
|
def write(self, value: Union[int, float, bool, str, list[bool], list[int], list[float]], data_type: Optional[DataType]= None, word_order: WorderOrder = WorderOrder.LITTLE, slave = 1) -> bool:
|
|
pass
|
|
|
|
@property
|
|
def type(self) -> DeviceType:
|
|
return self._type
|
|
|
|
@property
|
|
def address(self) -> int:
|
|
return self._address
|
|
|
|
@property
|
|
def name(self) -> str:
|
|
return self._name
|
|
|
|
|
|
class Coil(Base):
|
|
def __init__(self, client,name, address: int, data_type: DataType):
|
|
super().__init__(client, name, address, DeviceType.COIL, data_type)
|
|
|
|
def read(self, value, data_type: Optional[DataType] = None, word_order: WorderOrder = WorderOrder.BIG, slave = 1,) -> Tuple[Union[int, float, str, list[bool], list[int], list[float]], bool]:
|
|
resp = self._client.read_coils(
|
|
address = self.address,
|
|
count = value,
|
|
slave = slave)
|
|
|
|
return resp.bits, resp.isError()
|
|
|
|
def write(self,value: Union[int, float, bool, str, list[bool], list[int], list[float]], data_type: Optional[DataType ]= None, word_order: WorderOrder = WorderOrder.LITTLE, slave = 1) -> bool:
|
|
if isinstance(value, list):
|
|
for v in value:
|
|
if not isinstance(v, bool):
|
|
raise ValueError(f'value invalidate: {value}')
|
|
|
|
return self._client.write_coils(
|
|
address = self.address,
|
|
values = [bool(v) for v in value],
|
|
slave = slave).isError()
|
|
else:
|
|
return self._client.write_coil(
|
|
address = self.address,
|
|
value = bool(value),
|
|
slave = slave).isError()
|
|
|
|
|
|
class DiscreteInputs(Base):
|
|
def __init__(self, client,name, address: int, data_type: DataType):
|
|
super().__init__(client, name, address, DeviceType.COIL, data_type)
|
|
|
|
def read(self, value, data_type: Optional[DataType] = None, word_order: WorderOrder = WorderOrder.BIG, slave = 1,) -> Tuple[Union[int, float, str, list[bool], list[int], list[float]], bool]:
|
|
if not data_type and not self._data_type:
|
|
raise ValueError('data type is required')
|
|
if not data_type:
|
|
data_type = self._data_type
|
|
resp = self._client.read_discrete_inputs(
|
|
self.address,
|
|
count = value,
|
|
slave = slave)
|
|
|
|
# noinspection PyTypeChecker
|
|
return self._client.convert_from_registers(resp.registers, data_type, word_order=word_order.value), resp.isError()
|
|
|
|
def write(self,value: Union[int, float, bool, str, list[bool], list[int], list[float]], data_type: Optional[DataType ]= None, word_order: WorderOrder = WorderOrder.LITTLE, slave = 1) -> bool:
|
|
raise ValueError('discrete inputs only support read')
|
|
|
|
class HoldRegister(Base):
|
|
def __init__(self, client,name, address: int, data_type: DataType):
|
|
super().__init__(client, name, address, DeviceType.COIL, data_type)
|
|
|
|
def read(self, value, data_type: Optional[DataType] = None, word_order: WorderOrder = WorderOrder.BIG, slave = 1,) -> Tuple[Union[int, float, str, list[bool], list[int], list[float]], bool]:
|
|
if not data_type and not self._data_type:
|
|
raise ValueError('data type is required')
|
|
|
|
if not data_type:
|
|
data_type = self._data_type
|
|
|
|
resp = self._client.read_holding_registers(
|
|
address = self.address,
|
|
count = value,
|
|
slave = slave)
|
|
# noinspection PyTypeChecker
|
|
return self._client.convert_from_registers(resp.registers, data_type, word_order=word_order.value), resp.isError()
|
|
|
|
|
|
def write(self,value: Union[int, float, bool, str, list[bool], list[int], list[float]], data_type: Optional[DataType ]= None, word_order: WorderOrder = WorderOrder.LITTLE, slave = 1) -> bool:
|
|
if not data_type and not self._data_type:
|
|
raise ValueError('data type is required')
|
|
|
|
if not data_type:
|
|
data_type = self._data_type
|
|
|
|
if isinstance(value , bool):
|
|
if value:
|
|
return self._client.write_register(self.address, 1, slave= slave).isError()
|
|
else:
|
|
return self._client.write_register(self.address, 0, slave= slave).isError()
|
|
elif isinstance(value, int):
|
|
return self._client.write_register(self.address, value, slave= slave).isError()
|
|
else:
|
|
# noinspection PyTypeChecker
|
|
encoder_resp = self._client.convert_to_registers(value, data_type=data_type, word_order=word_order.value)
|
|
return self._client.write_registers(self.address, encoder_resp, slave=slave).isError()
|
|
|
|
|
|
|
|
class InputRegister(Base):
|
|
def __init__(self, client,name, address: int, data_type: DataType):
|
|
super().__init__(client, name, address, DeviceType.COIL, data_type)
|
|
|
|
|
|
def read(self, value, data_type: Optional[DataType] = None, word_order: WorderOrder = WorderOrder.BIG, slave = 1) -> Tuple[Union[int, float, str, list[bool], list[int], list[float]], bool]:
|
|
if not data_type and not self._data_type:
|
|
raise ValueError('data type is required')
|
|
|
|
if not data_type:
|
|
data_type = self._data_type
|
|
|
|
resp = self._client.read_holding_registers(
|
|
address = self.address,
|
|
count = value,
|
|
slave = slave)
|
|
# noinspection PyTypeChecker
|
|
return self._client.convert_from_registers(resp.registers, data_type, word_order=word_order.value), resp.isError()
|
|
|
|
def write(self,value: Union[int, float, bool, str, list[bool], list[int], list[float]], data_type: Optional[DataType ]= None, word_order: WorderOrder = WorderOrder.LITTLE, slave = 1) -> bool:
|
|
raise ValueError('input register only support read')
|
|
|