Skip to content

Communication protocol

The pypalmsens.CommProtocol class provides an interface to exchange messages with your device using the communication protocol. You can use the Communication Protocol to directly query/manipulate the state of your device, e.g. setting registers, file operations, and sending scripts. It supports various connection types, such as serial ports, USB, and Bluetooth.

The Communication Protocol is supported by all MethodSCRIPT-capable instruments:

Connecting to the device

To communicate with a PalmSens instrument you need an active connection. CommProtocol supports the context manager protocol, so you can pass a pypalmsens.Instrument instance. In this case, it opens and manages the connection:

>>> import pypalmsens as ps
>>> instrument, *_ = ps.discover()
>>> with ps.CommProtocol(instrument) as comm:
...     print(comm.query('t'))
es4_lr1500#Mar 12 2026 14:28:01
R*

Alternatively, you can manage the connection yourself. The repr shows the state of the connection:

>>> comm = ps.CommProtocol(instrument)
>>> comm.open()
>>> comm
CommProtocol('EmStat4 LR [1]', connected=True)
>>> comm.close()
>>> comm
CommProtocol('EmStat4 LR [1]', connected=False)

Sending commands

The primary method for interactive communication is .query. It sends a command to the device, waits for completion, reads the full response, strips the prefix, and returns it as a string:

>>> comm.query('i')  # Serial number
'ES4LR20B0008'
>>> comm.query('v')  # MethodSCRIPT version
'01.09.00'
>>> comm.query('t')  # Firmware version
'es4_lr1500#Mar 12 2026 14:28:01\nR*'

For commands that run for a long time (e.g., scripts), this method will block until the script completes or times out. For more commands, see the Communication Protocol documentation for your device.

Running MethodSCRIPTs

.run_methodscript is a helper method that loads and executes a MethodSCRIPT on the instrument:

>>> script = 'send_string "Hello world!"'
>>> comm.run_methodscript(script)
'THello world!\n'

This returns the string prepended by a T, which is the text packet identifier.

Capabilities

You can query which features are available on the connected instrument through capability detection:

>>> comm.get_methodscript_capabilities()
('abort', 'add_var', ..., 'var', 'wait')
>>> comm.get_communication_capabilities()
('CC', 'CM', ..., 't', 'v')

These are helper functions that parse the hexadecimal bit fields returned by the underlying commands CC and CM:

>>> comm.query('CC')
'000000000000000000000000000000000000002F0000003FFFFF98FF00000002'
>>> comm.query('CM')
'000000000000000000000000000003FFFFBFE8FFFFFFFFFFFFFFFFFFFFBFFFFE'

Configuration

The interface exposes configuration attributes for controlling timeouts and read delays:

  • CommProtocol.timeout: Maximum time (in seconds) to wait for a response before timing out. Defaults to 10s.
  • CommProtocol.delay: Pause (in seconds) between writing a command and reading subsequent responses. Adjust based on your specific hardware and connection type.
>>> comm.timeout = 30.0  #(1)!
>>> comm.delay = 0.5     #(2)!
  1. extend timeout for slow measurements
  2. increase delay for slower connections

Error handling

Communication errors raise [MethodScriptRuntimeError][pypalmsens.MethodScriptRuntimeError] (a subclass of ConnectionError) when the device returns an error response. The error includes an error code that can be looked up in the MethodSCRIPT manual:

>>> comm.run_methodscript('invalid_command\n')
Traceback (most recent call last):
...
pypalmsens._instruments.comm_protocol.CommProtocolError: [4001] The script command is unknown (Line 1, Col 16)

Aborting measurements

Use .abort to abort any currently running script or measurement and wait for completion. Note that this could take a while, depending on the measurement that was running:

>>> comm.abort()

Low-level communication

For more control over individual reads and writes, use the following methods:

  • .write: Write a command or data to the instrument. To submit a command for execution, append a newline character ('\n') to the end of the string.
  • .read: Read the next available chunk from the buffer without blocking. Returns an empty string ('') if no data are available.
  • .lines: Generator that yields response chunks as they arrive, stopping when a timeout occurs between responses.
  • .wait_until: Wait until a response line starting with a given prefix arrives (useful for waiting on command echoes).
  • .read_until: Read lines from the device until a termination sequence is found.

Response history

The interface maintains a history of recent responses for debugging and inspection via CommProtocol.history. By default, it stores the last 100 responses:

>>> comm.history
deque(['iES4LR20B0008\n', 'v01.09.00\n', ...], maxlen=100)

Async Comm protocol

For async workflows, use pypalmsens.DeviceFileSystemAsync:

>>> import asyncio
>>> import pypalmsens as ps

>>> async def main():
...     instrument, *_ = await ps.discover_async()
...     comm = ps.CommProtocolAsync(instrument)
...     await comm.open()
...
...     print(repr(await comm.query('i')))
...     print(repr(await comm.query('v')))
...     print(repr(await comm.query('t')))
...
...     script = 'send_string "Hello world!"'
...     output = await comm.run_methodscript(script)
...     print(repr(output))

>>> asyncio.run(main())
'ES4LR20B0008'
'01.09.00'
'es4_lr1500#Mar 12 2026 14:28:01\nR*'
'THello world!\n'