M lazy-lock.json M lua/custom/configs/lspconfig.lua M lua/custom/init.lua A lua/custom/journal.lua A nvim_venv/bin/Activate.ps1 A nvim_venv/bin/activate A nvim_venv/bin/activate.csh A nvim_venv/bin/activate.fish
130 lines
4.3 KiB
Python
130 lines
4.3 KiB
Python
"""Remote datastore."""
|
|
from pymodbus.datastore import ModbusBaseSlaveContext
|
|
from pymodbus.exceptions import NotImplementedException
|
|
from pymodbus.logging import Log
|
|
|
|
|
|
# ---------------------------------------------------------------------------#
|
|
# Context
|
|
# ---------------------------------------------------------------------------#
|
|
class RemoteSlaveContext(ModbusBaseSlaveContext):
|
|
"""TODO.
|
|
|
|
This creates a modbus data model that connects to
|
|
a remote device (depending on the client used)
|
|
"""
|
|
|
|
def __init__(self, client, slave=None):
|
|
"""Initialize the datastores.
|
|
|
|
:param client: The client to retrieve values with
|
|
:param slave: Unit ID of the remote slave
|
|
"""
|
|
self._client = client
|
|
self.slave = slave
|
|
self.result = None
|
|
self.__build_mapping()
|
|
if not self.__set_callbacks:
|
|
Log.error("Init went wrong.")
|
|
|
|
def reset(self):
|
|
"""Reset all the datastores to their default values."""
|
|
raise NotImplementedException()
|
|
|
|
def validate(self, _fc_as_hex, _address, _count):
|
|
"""Validate the request to make sure it is in range.
|
|
|
|
:returns: True
|
|
"""
|
|
return True
|
|
|
|
def getValues(self, fc_as_hex, _address, _count=1):
|
|
"""Get values from real call in validate."""
|
|
if fc_as_hex in self._write_fc:
|
|
return [0]
|
|
group_fx = self.decode(fc_as_hex)
|
|
func_fc = self.__get_callbacks[group_fx]
|
|
self.result = func_fc(_address, _count)
|
|
return self.__extract_result(self.decode(fc_as_hex), self.result)
|
|
|
|
def setValues(self, fc_as_hex, address, values):
|
|
"""Set the datastore with the supplied values."""
|
|
group_fx = self.decode(fc_as_hex)
|
|
if fc_as_hex not in self._write_fc:
|
|
raise ValueError(f"setValues() called with an non-write function code {fc_as_hex}")
|
|
func_fc = self.__set_callbacks[f"{group_fx}{fc_as_hex}"]
|
|
if fc_as_hex in {0x0F, 0x10}: # Write Multiple Coils, Write Multiple Registers
|
|
self.result = func_fc(address, values)
|
|
else:
|
|
self.result = func_fc(address, values[0])
|
|
# if self.result.isError():
|
|
# return self.result
|
|
|
|
def __str__(self):
|
|
"""Return a string representation of the context.
|
|
|
|
:returns: A string representation of the context
|
|
"""
|
|
return f"Remote Slave Context({self._client})"
|
|
|
|
def __build_mapping(self):
|
|
"""Build the function code mapper."""
|
|
params = {}
|
|
if self.slave:
|
|
params["slave"] = self.slave
|
|
self.__get_callbacks = {
|
|
"d": lambda a, c: self._client.read_discrete_inputs(
|
|
a, count=c, **params
|
|
),
|
|
"c": lambda a, c: self._client.read_coils(
|
|
a, count=c, **params
|
|
),
|
|
"h": lambda a, c: self._client.read_holding_registers(
|
|
a, count=c, **params
|
|
),
|
|
"i": lambda a, c: self._client.read_input_registers(
|
|
a, count=c, **params
|
|
),
|
|
}
|
|
self.__set_callbacks = {
|
|
"d5": lambda a, v: self._client.write_coil(
|
|
a, v, **params
|
|
),
|
|
"d15": lambda a, v: self._client.write_coils(
|
|
a, v, **params
|
|
),
|
|
"c5": lambda a, v: self._client.write_coil(
|
|
a, v, **params
|
|
),
|
|
"c15": lambda a, v: self._client.write_coils(
|
|
a, v, **params
|
|
),
|
|
"h6": lambda a, v: self._client.write_register(
|
|
a, v, **params
|
|
),
|
|
"h16": lambda a, v: self._client.write_registers(
|
|
a, v, **params
|
|
),
|
|
"i6": lambda a, v: self._client.write_register(
|
|
a, v, **params
|
|
),
|
|
"i16": lambda a, v: self._client.write_registers(
|
|
a, v, **params
|
|
),
|
|
}
|
|
self._write_fc = (0x05, 0x06, 0x0F, 0x10)
|
|
|
|
def __extract_result(self, fc_as_hex, result):
|
|
"""Extract the values out of a response.
|
|
|
|
TODO make this consistent (values?)
|
|
"""
|
|
if not result.isError():
|
|
if fc_as_hex in {"d", "c"}:
|
|
return result.bits
|
|
if fc_as_hex in {"h", "i"}:
|
|
return result.registers
|
|
else:
|
|
return result
|
|
return None
|