Using Interactive Mode Programmatically
Since the interactive mode uses the serial port, it can also be operated programmatically.
In production processes, there may be situations where you want to use interactive mode automatically. Here, we introduce an example of reading configuration values using Python.
Mechanism of Interactive Mode
In its initial state, the RX
port of TWELITE operates at 115200bps 8N1. To transition into interactive mode, input +
three times at intervals of approximately 200 to 1000ms. Since interactive mode accepts only ASCII characters as input, once entered, it can be freely controlled programmatically.
Implementation Example
Reading Configuration Values Using Python
Below is a script that reads the serial ID and configuration values from a TWELITE device programmed with the serial communication app App_Uart
, via TWELITE R2/R3.
The tweliter
module is used to identify TWELITE R2/R3, retrieve the serial port, and control the reset pin of TWELITE R2/R3.
pip install tweliter
Script
Using Python 3.12.
The get_serial_id_and_settings()
function can be reused for user scripts.
# -*- coding: utf-8 -*-
import time
import re
from tweliter import Tweliter # Mono Wireless module for TWELITE R devices
def get_serial_id_and_settings() -> tuple[str, dict[str, str]] | None:
"""
Get the serial ID and settings from the interactive mode of a TWELITE R device.
Returns:
tuple[str, dict[str, str]] | None:
A tuple containing:
- str: the serial ID (e.g., "0x82010079")
- dict[str, str]: the settings dictionary (e.g., {'a': '0x67720103', ...})
Returns None if the device cannot be accessed or the output is invalid.
Notes:
Example output from the interactive mode of an App_Uart device:
--- CONFIG/TWE UART APP V1-04-6/SID=0x82010079/LID=0x78 -- ---
a: set Application ID (0x67720103)
i: set Device ID (120=0x78)
c: set Channels (18)
x: set RF Conf (3)
r: set Role (0x0)
l: set Layer (0x1)
b: set UART baud (38400)
B: set UART option (8N1)
m: set UART mode (E)
k: set Tx Trigger (sep=0x0d0a, min_bytes=0 dly=0[ms])
h: set header format [;U;%t;%i;0x%A;%q;%s;<*;%X;\n]
C: set crypt mode (0)
o: set option bits (0x00000100)
---
S: save Configuration
R: reset to Defaults
"""
try:
with Tweliter(
type_filter=Tweliter.Type.TWELITE_R2 | Tweliter.Type.TWELITE_R3
) as liter:
# Reset the device
liter.reset_device()
# Get the serial port instance (pyserial)
ser = liter.get_serial_instance()
ser.timeout = 1.0
# Enter to the interactive mode
for _ in range(3):
ser.write("+")
time.sleep(0.3)
# Read the output
raw_output = ser.read_until(b"S:").decode("utf-8")
# Reset the device (Exit interactive mode)
liter.reset_device()
except IOError as e:
print(f"Couldn't open the device {e}")
return None
# Find the settings block in the output
filter_output = re.search(r"---(.*?)---(.*?)---", raw_output, re.DOTALL)
if filter_output:
information_line = filter_output.group(1)
settings_block = filter_output.group(2)
else:
print("No settings block found.")
return None
# Extract serial id from the information line
serial_id_match = re.search(r"SID=0x([0-9A-Fa-f]+)", information_line)
if serial_id_match:
serial_id = f"0x{serial_id_match.group(1)}"
else:
print("Serial ID not found.")
return None
# Extract key-value pairs (str,str) from the settings block
settings_dict = dict(
re.findall(r"^\s*(\w):.*?\(([^()]*)\)", settings_block, re.MULTILINE)
)
return serial_id, settings_dict
def main() -> None:
# Get the serial ID and settings from the device
result = get_serial_id_and_settings()
if result is None:
print("Failed to retrieve serial ID and settings.")
return
serial_id, settings = result
# Show the results
print(f"Serial ID: {serial_id}")
for id, value in settings.items():
match id:
case "a":
print(f"Application ID: {value}")
# case "i":
# print(f"Logical ID: {value}")
# case "c":
# print(f"Channel: {value}")
if __name__ == "__main__":
main()
Explanation
Flow of Reading Output from Interactive Mode
- Reset the TWELITE
- Resetting brings the device back to its initial state for entering interactive mode. This reset is performed by controlling the reset pin on TWELITE R2/R3.
- Obtain the serial port instance
- Using
pyserial
, obtain an instance for accessing serial I/O of TWELITE from the PC. Through this instance, you can send commands and read data.
- Using
- Input
+
three times- By sending
+
three times at fixed intervals (200–1000ms), TWELITE transitions into interactive mode. This method is the same as manual operation by the user.
- By sending
- Read output up to the line starting with
S:
- In interactive mode, the line
S:
appears after a series of configuration items. Reading up to this point ensures that all configuration contents are retrieved.
- In interactive mode, the line
- Reset the TWELITE
- After reading, reset again to return from interactive mode to normal operation.
with Tweliter(
type_filter=Tweliter.Type.TWELITE_R2 | Tweliter.Type.TWELITE_R3
) as liter:
# Reset the device
liter.reset_device()
# Get the serial port instance (pyserial)
ser = liter.get_serial_instance()
ser.timeout = 1.0
# Enter to the interactive mode
for _ in range(3):
ser.write("+")
time.sleep(0.3)
# Read the output
raw_output = ser.read_until(b"S:").decode("utf-8")
# Reset the device (Exit interactive mode)
liter.reset_device()
Flow of Interpreting Output from Interactive Mode
- Extract the line and the block enclosed by
---
- Use
re.search(r"---(.*?)---(.*?)---", raw_output, re.DOTALL)
to retrieve the full configuration info from the interactive mode output, divided into two parts:information_line
(containing serial ID etc.), andsettings_block
(listing configuration items).re.DOTALL
enables matching across multiple lines.
- Use
- Extract the serial ID from the first line
- Use
re.search(r"SID=0x([0-9A-Fa-f]+)", information_line)
to obtain the hexadecimal ID followingSID=0x
, format it as a string like0x82010079
. Both uppercase and lowercase hex digits are matched.
- Use
- Extract command ID and value pairs from the block
- Use
re.findall(r"^\s*(\w):.*?\(([^()]*)\)", settings_block, re.MULTILINE)
to extract lines in the format likea: ... (value)
, retrieving the one-letter command ID and the value inside parentheses. Leading spaces and any characters after the colon are ignored.re.MULTILINE
enables matching across multiple lines.
- Use
# Find the settings block in the output
filter_output = re.search(r"---(.*?)---(.*?)---", raw_output, re.DOTALL)
if filter_output:
information_line = filter_output.group(1)
settings_block = filter_output.group(2)
else:
print("No settings block found.")
return None
# Extract serial id from the information line
serial_id_match = re.search(r"SID=0x([0-9A-Fa-f]+)", information_line)
if serial_id_match:
serial_id = f"0x{serial_id_match.group(1)}"
else:
print("Serial ID not found.")
return None
# Extract key-value pairs (str,str) from the settings block
settings_dict = dict(
re.findall(r"^\s*(\w):.*?\(([^()]*)\)", settings_block, re.MULTILINE)
)
return serial_id, settings_dict