venv added, updated
This commit is contained in:
473
myenv/lib/python3.12/site-packages/pymodbus/pdu/other_message.py
Normal file
473
myenv/lib/python3.12/site-packages/pymodbus/pdu/other_message.py
Normal file
@@ -0,0 +1,473 @@
|
||||
"""Diagnostic record read/write.
|
||||
|
||||
Currently not all implemented
|
||||
"""
|
||||
|
||||
|
||||
# pylint: disable=missing-type-doc
|
||||
import struct
|
||||
|
||||
from pymodbus.constants import ModbusStatus
|
||||
from pymodbus.device import DeviceInformationFactory, ModbusControlBlock
|
||||
from pymodbus.pdu import ModbusRequest, ModbusResponse
|
||||
|
||||
|
||||
_MCB = ModbusControlBlock()
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------#
|
||||
# TODO Make these only work on serial # pylint: disable=fixme
|
||||
# ---------------------------------------------------------------------------#
|
||||
class ReadExceptionStatusRequest(ModbusRequest):
|
||||
"""This function code is used to read the contents of eight Exception Status outputs in a remote device.
|
||||
|
||||
The function provides a simple method for
|
||||
accessing this information, because the Exception Output references are
|
||||
known (no output reference is needed in the function).
|
||||
"""
|
||||
|
||||
function_code = 0x07
|
||||
function_code_name = "read_exception_status"
|
||||
_rtu_frame_size = 4
|
||||
|
||||
def __init__(self, slave=None, transaction=0, protocol=0, skip_encode=0):
|
||||
"""Initialize a new instance."""
|
||||
ModbusRequest.__init__(self, slave, transaction, protocol, skip_encode)
|
||||
|
||||
def encode(self):
|
||||
"""Encode the message."""
|
||||
return b""
|
||||
|
||||
def decode(self, data):
|
||||
"""Decode data part of the message.
|
||||
|
||||
:param data: The incoming data
|
||||
"""
|
||||
|
||||
async def execute(self, _context=None):
|
||||
"""Run a read exception status request against the store.
|
||||
|
||||
:returns: The populated response
|
||||
"""
|
||||
status = _MCB.Counter.summary()
|
||||
return ReadExceptionStatusResponse(status)
|
||||
|
||||
def __str__(self):
|
||||
"""Build a representation of the request.
|
||||
|
||||
:returns: The string representation of the request
|
||||
"""
|
||||
return f"ReadExceptionStatusRequest({self.function_code})"
|
||||
|
||||
|
||||
class ReadExceptionStatusResponse(ModbusResponse):
|
||||
"""The normal response contains the status of the eight Exception Status outputs.
|
||||
|
||||
The outputs are packed into one data byte, with one bit
|
||||
per output. The status of the lowest output reference is contained
|
||||
in the least significant bit of the byte. The contents of the eight
|
||||
Exception Status outputs are device specific.
|
||||
"""
|
||||
|
||||
function_code = 0x07
|
||||
_rtu_frame_size = 5
|
||||
|
||||
def __init__(self, status=0x00, slave=1, transaction=0, protocol=0, skip_encode=False):
|
||||
"""Initialize a new instance.
|
||||
|
||||
:param status: The status response to report
|
||||
"""
|
||||
ModbusResponse.__init__(self, slave, transaction, protocol, skip_encode)
|
||||
self.status = status if status < 256 else 255
|
||||
|
||||
def encode(self):
|
||||
"""Encode the response.
|
||||
|
||||
:returns: The byte encoded message
|
||||
"""
|
||||
return struct.pack(">B", self.status)
|
||||
|
||||
def decode(self, data):
|
||||
"""Decode a the response.
|
||||
|
||||
:param data: The packet data to decode
|
||||
"""
|
||||
self.status = int(data[0])
|
||||
|
||||
def __str__(self):
|
||||
"""Build a representation of the response.
|
||||
|
||||
:returns: The string representation of the response
|
||||
"""
|
||||
arguments = (self.function_code, self.status)
|
||||
return (
|
||||
"ReadExceptionStatusResponse(%d, %s)" # pylint: disable=consider-using-f-string
|
||||
% arguments
|
||||
)
|
||||
|
||||
|
||||
# Encapsulate interface transport 43, 14
|
||||
# CANopen general reference 43, 13
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------#
|
||||
# TODO Make these only work on serial # pylint: disable=fixme
|
||||
# ---------------------------------------------------------------------------#
|
||||
class GetCommEventCounterRequest(ModbusRequest):
|
||||
"""This function code is used to get a status word.
|
||||
|
||||
And an event count from the remote device's communication event counter.
|
||||
|
||||
By fetching the current count before and after a series of messages, a
|
||||
client can determine whether the messages were handled normally by the
|
||||
remote device.
|
||||
|
||||
The device's event counter is incremented once for each successful
|
||||
message completion. It is not incremented for exception responses,
|
||||
poll commands, or fetch event counter commands.
|
||||
|
||||
The event counter can be reset by means of the Diagnostics function
|
||||
(code 08), with a subfunction of Restart Communications Option
|
||||
(code 00 01) or Clear Counters and Diagnostic Register (code 00 0A).
|
||||
"""
|
||||
|
||||
function_code = 0x0B
|
||||
function_code_name = "get_event_counter"
|
||||
_rtu_frame_size = 4
|
||||
|
||||
def __init__(self, slave=1, transaction=0, protocol=0, skip_encode=False):
|
||||
"""Initialize a new instance."""
|
||||
ModbusRequest.__init__(self, slave, transaction, protocol, skip_encode)
|
||||
|
||||
def encode(self):
|
||||
"""Encode the message."""
|
||||
return b""
|
||||
|
||||
def decode(self, data):
|
||||
"""Decode data part of the message.
|
||||
|
||||
:param data: The incoming data
|
||||
"""
|
||||
|
||||
async def execute(self, _context=None):
|
||||
"""Run a read exception status request against the store.
|
||||
|
||||
:returns: The populated response
|
||||
"""
|
||||
status = _MCB.Counter.Event
|
||||
return GetCommEventCounterResponse(status)
|
||||
|
||||
def __str__(self):
|
||||
"""Build a representation of the request.
|
||||
|
||||
:returns: The string representation of the request
|
||||
"""
|
||||
return f"GetCommEventCounterRequest({self.function_code})"
|
||||
|
||||
|
||||
class GetCommEventCounterResponse(ModbusResponse):
|
||||
"""Get comm event counter response.
|
||||
|
||||
The normal response contains a two-byte status word, and a two-byte
|
||||
event count. The status word will be all ones (FF FF hex) if a
|
||||
previously-issued program command is still being processed by the
|
||||
remote device (a busy condition exists). Otherwise, the status word
|
||||
will be all zeros.
|
||||
"""
|
||||
|
||||
function_code = 0x0B
|
||||
_rtu_frame_size = 8
|
||||
|
||||
def __init__(self, count=0x0000, slave=1, transaction=0, protocol=0, skip_encode=False):
|
||||
"""Initialize a new instance.
|
||||
|
||||
:param count: The current event counter value
|
||||
"""
|
||||
ModbusResponse.__init__(self, slave, transaction, protocol, skip_encode)
|
||||
self.count = count
|
||||
self.status = True # this means we are ready, not waiting
|
||||
|
||||
def encode(self):
|
||||
"""Encode the response.
|
||||
|
||||
:returns: The byte encoded message
|
||||
"""
|
||||
if self.status:
|
||||
ready = ModbusStatus.READY
|
||||
else:
|
||||
ready = ModbusStatus.WAITING
|
||||
return struct.pack(">HH", ready, self.count)
|
||||
|
||||
def decode(self, data):
|
||||
"""Decode a the response.
|
||||
|
||||
:param data: The packet data to decode
|
||||
"""
|
||||
ready, self.count = struct.unpack(">HH", data)
|
||||
self.status = ready == ModbusStatus.READY
|
||||
|
||||
def __str__(self):
|
||||
"""Build a representation of the response.
|
||||
|
||||
:returns: The string representation of the response
|
||||
"""
|
||||
arguments = (self.function_code, self.count, self.status)
|
||||
return (
|
||||
"GetCommEventCounterResponse(%d, %d, %d)" # pylint: disable=consider-using-f-string
|
||||
% arguments
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------#
|
||||
# TODO Make these only work on serial # pylint: disable=fixme
|
||||
# ---------------------------------------------------------------------------#
|
||||
class GetCommEventLogRequest(ModbusRequest):
|
||||
"""This function code is used to get a status word.
|
||||
|
||||
Event count, message count, and a field of event bytes from the remote device.
|
||||
|
||||
The status word and event counts are identical to that returned by
|
||||
the Get Communications Event Counter function (11, 0B hex).
|
||||
|
||||
The message counter contains the quantity of messages processed by the
|
||||
remote device since its last restart, clear counters operation, or
|
||||
power-up. This count is identical to that returned by the Diagnostic
|
||||
function (code 08), sub-function Return Bus Message Count (code 11,
|
||||
0B hex).
|
||||
|
||||
The event bytes field contains 0-64 bytes, with each byte corresponding
|
||||
to the status of one MODBUS send or receive operation for the remote
|
||||
device. The remote device enters the events into the field in
|
||||
chronological order. Byte 0 is the most recent event. Each new byte
|
||||
flushes the oldest byte from the field.
|
||||
"""
|
||||
|
||||
function_code = 0x0C
|
||||
function_code_name = "get_event_log"
|
||||
_rtu_frame_size = 4
|
||||
|
||||
def __init__(self, slave=1, transaction=0, protocol=0, skip_encode=False):
|
||||
"""Initialize a new instance."""
|
||||
ModbusRequest.__init__(self, slave, transaction, protocol, skip_encode)
|
||||
|
||||
def encode(self):
|
||||
"""Encode the message."""
|
||||
return b""
|
||||
|
||||
def decode(self, data):
|
||||
"""Decode data part of the message.
|
||||
|
||||
:param data: The incoming data
|
||||
"""
|
||||
|
||||
async def execute(self, _context=None):
|
||||
"""Run a read exception status request against the store.
|
||||
|
||||
:returns: The populated response
|
||||
"""
|
||||
results = {
|
||||
"status": True,
|
||||
"message_count": _MCB.Counter.BusMessage,
|
||||
"event_count": _MCB.Counter.Event,
|
||||
"events": _MCB.getEvents(),
|
||||
}
|
||||
return GetCommEventLogResponse(**results)
|
||||
|
||||
def __str__(self):
|
||||
"""Build a representation of the request.
|
||||
|
||||
:returns: The string representation of the request
|
||||
"""
|
||||
return f"GetCommEventLogRequest({self.function_code})"
|
||||
|
||||
|
||||
class GetCommEventLogResponse(ModbusResponse):
|
||||
"""Get Comm event log response.
|
||||
|
||||
The normal response contains a two-byte status word field,
|
||||
a two-byte event count field, a two-byte message count field,
|
||||
and a field containing 0-64 bytes of events. A byte count
|
||||
field defines the total length of the data in these four field
|
||||
"""
|
||||
|
||||
function_code = 0x0C
|
||||
_rtu_byte_count_pos = 2
|
||||
|
||||
def __init__(self, status=True, message_count=0, event_count=0, events=None, slave=1, transaction=0, protocol=0, skip_encode=False):
|
||||
"""Initialize a new instance.
|
||||
|
||||
:param status: The status response to report
|
||||
:param message_count: The current message count
|
||||
:param event_count: The current event count
|
||||
:param events: The collection of events to send
|
||||
"""
|
||||
ModbusResponse.__init__(self, slave, transaction, protocol, skip_encode)
|
||||
self.status = status
|
||||
self.message_count = message_count
|
||||
self.event_count = event_count
|
||||
self.events = events if events else []
|
||||
|
||||
def encode(self):
|
||||
"""Encode the response.
|
||||
|
||||
:returns: The byte encoded message
|
||||
"""
|
||||
if self.status:
|
||||
ready = ModbusStatus.READY
|
||||
else:
|
||||
ready = ModbusStatus.WAITING
|
||||
packet = struct.pack(">B", 6 + len(self.events))
|
||||
packet += struct.pack(">H", ready)
|
||||
packet += struct.pack(">HH", self.event_count, self.message_count)
|
||||
packet += b"".join(struct.pack(">B", e) for e in self.events)
|
||||
return packet
|
||||
|
||||
def decode(self, data):
|
||||
"""Decode a the response.
|
||||
|
||||
:param data: The packet data to decode
|
||||
"""
|
||||
length = int(data[0])
|
||||
status = struct.unpack(">H", data[1:3])[0]
|
||||
self.status = status == ModbusStatus.READY
|
||||
self.event_count = struct.unpack(">H", data[3:5])[0]
|
||||
self.message_count = struct.unpack(">H", data[5:7])[0]
|
||||
|
||||
self.events = []
|
||||
for i in range(7, length + 1):
|
||||
self.events.append(int(data[i]))
|
||||
|
||||
def __str__(self):
|
||||
"""Build a representation of the response.
|
||||
|
||||
:returns: The string representation of the response
|
||||
"""
|
||||
arguments = (
|
||||
self.function_code,
|
||||
self.status,
|
||||
self.message_count,
|
||||
self.event_count,
|
||||
)
|
||||
return (
|
||||
"GetCommEventLogResponse(%d, %d, %d, %d)" # pylint: disable=consider-using-f-string
|
||||
% arguments
|
||||
)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------#
|
||||
# TODO Make these only work on serial # pylint: disable=fixme
|
||||
# ---------------------------------------------------------------------------#
|
||||
class ReportSlaveIdRequest(ModbusRequest):
|
||||
"""This function code is used to read the description of the type.
|
||||
|
||||
The current status, and other information specific to a remote device.
|
||||
"""
|
||||
|
||||
function_code = 0x11
|
||||
function_code_name = "report_slave_id"
|
||||
_rtu_frame_size = 4
|
||||
|
||||
def __init__(self, slave=1, transaction=0, protocol=0, skip_encode=False):
|
||||
"""Initialize a new instance.
|
||||
|
||||
:param slave: Modbus slave slave ID
|
||||
|
||||
"""
|
||||
ModbusRequest.__init__(self, slave, transaction, protocol, skip_encode)
|
||||
|
||||
def encode(self):
|
||||
"""Encode the message."""
|
||||
return b""
|
||||
|
||||
def decode(self, data):
|
||||
"""Decode data part of the message.
|
||||
|
||||
:param data: The incoming data
|
||||
"""
|
||||
|
||||
async def execute(self, context=None):
|
||||
"""Run a report slave id request against the store.
|
||||
|
||||
:returns: The populated response
|
||||
"""
|
||||
report_slave_id_data = None
|
||||
if context:
|
||||
report_slave_id_data = getattr(context, "reportSlaveIdData", None)
|
||||
if not report_slave_id_data:
|
||||
information = DeviceInformationFactory.get(_MCB)
|
||||
|
||||
# Support identity values as bytes data and regular str data
|
||||
id_data = []
|
||||
for v_item in information.values():
|
||||
if isinstance(v_item, bytes):
|
||||
id_data.append(v_item)
|
||||
else:
|
||||
id_data.append(v_item.encode())
|
||||
|
||||
identifier = b"-".join(id_data)
|
||||
identifier = identifier or b"Pymodbus"
|
||||
report_slave_id_data = identifier
|
||||
return ReportSlaveIdResponse(report_slave_id_data)
|
||||
|
||||
def __str__(self):
|
||||
"""Build a representation of the request.
|
||||
|
||||
:returns: The string representation of the request
|
||||
"""
|
||||
return f"ReportSlaveIdRequest({self.function_code})"
|
||||
|
||||
|
||||
class ReportSlaveIdResponse(ModbusResponse):
|
||||
"""Show response.
|
||||
|
||||
The data contents are specific to each type of device.
|
||||
"""
|
||||
|
||||
function_code = 0x11
|
||||
_rtu_byte_count_pos = 2
|
||||
|
||||
def __init__(self, identifier=b"\x00", status=True, slave=1, transaction=0, protocol=0, skip_encode=False):
|
||||
"""Initialize a new instance.
|
||||
|
||||
:param identifier: The identifier of the slave
|
||||
:param status: The status response to report
|
||||
"""
|
||||
ModbusResponse.__init__(self, slave, transaction, protocol, skip_encode)
|
||||
self.identifier = identifier
|
||||
self.status = status
|
||||
self.byte_count = None
|
||||
|
||||
def encode(self):
|
||||
"""Encode the response.
|
||||
|
||||
:returns: The byte encoded message
|
||||
"""
|
||||
if self.status:
|
||||
status = ModbusStatus.SLAVE_ON
|
||||
else:
|
||||
status = ModbusStatus.SLAVE_OFF
|
||||
length = len(self.identifier) + 1
|
||||
packet = struct.pack(">B", length)
|
||||
packet += self.identifier # we assume it is already encoded
|
||||
packet += struct.pack(">B", status)
|
||||
return packet
|
||||
|
||||
def decode(self, data):
|
||||
"""Decode a the response.
|
||||
|
||||
Since the identifier is device dependent, we just return the
|
||||
raw value that a user can decode to whatever it should be.
|
||||
|
||||
:param data: The packet data to decode
|
||||
"""
|
||||
self.byte_count = int(data[0])
|
||||
self.identifier = data[1 : self.byte_count + 1]
|
||||
status = int(data[-1])
|
||||
self.status = status == ModbusStatus.SLAVE_ON
|
||||
|
||||
def __str__(self) -> str:
|
||||
"""Build a representation of the response.
|
||||
|
||||
:returns: The string representation of the response
|
||||
"""
|
||||
return f"ReportSlaveIdResponse({self.function_code}, {self.identifier}, {self.status})"
|
||||
Reference in New Issue
Block a user