User Guide: TOYOPUC Computer Link Python
This page explains the high-level Python API only.
Use it when you want to read and write TOYOPUC devices by device string such as P1-D0000, P1-M0000, ES0000, or FR000000.
Installation
pip install .
Choose an API
Use one of these two styles:
ToyopucDeviceClientBest for scripts, tools, and desktop applications that want simple synchronous calls.ToyopucConnectionOptionsplusopen_and_connect(...)and helper functions such asread_typed,read_named, andpollBest for asyncio applications.
Quick start
Synchronous workflow
from toyopuc import ToyopucDeviceClient
with ToyopucDeviceClient("192.168.250.100", 1025) as plc:
word_value = plc.read("P1-D0000")
print(f"P1-D0000 = {word_value}")
plc.write("P1-D0001", 1234)
plc.write("P1-M0000", 1)
snapshot = plc.read_many(["P1-D0000", "P1-D0001", "P1-M0000"])
print(snapshot)
Asynchronous workflow
import asyncio
from toyopuc import ToyopucConnectionOptions, open_and_connect, read_named, read_typed, write_typed
async def main() -> None:
options = ToyopucConnectionOptions(host="192.168.250.100", port=1025, timeout=3.0, retries=0)
async with await open_and_connect(options) as plc:
speed = await read_typed(plc, "P1-D0100", "F")
print(f"speed = {speed}")
await write_typed(plc, "P1-D0200", "L", -500)
values = await read_named(plc, ["P1-D0000", "P1-D0100:F", "P1-D0000.0"])
print(values)
asyncio.run(main())
Device addressing
Address format
[Program]-[AreaType][Address]
ProgramP1,P2, orP3AreaTypedevice family such asD,M,ES,FRAddressdecimal or hexadecimal device number
When a profile is in use, basic families P/K/V/T/C/L/X/Y/M/S/N/R/D should be written as P1-*, P2-*, or P3-*.
Normalize device text
from toyopuc import normalize_address
assert normalize_address("p1-d0000", profile="TOYOPUC-Plus:Plus Standard mode") == "P1-D0000"
Common device families
| Area | Type | Example |
|---|---|---|
D |
Data register (word) | P1-D0100 |
S |
Special register (word) | P1-S0000 |
N |
File register (word) | P1-N0100 |
M |
Internal relay (bit) | P1-M0100 |
P |
Shared relay (bit) | P1-P0000 |
X |
Input relay (bit) | P1-X0000 |
Y |
Output relay (bit) | P1-Y0000 |
T |
Timer (bit) | P1-T0000 |
C |
Counter (bit) | P1-C0000 |
ES |
Extended special register (word) | ES0000 |
EN |
Extended file register (word) | EN0000 |
U |
Extended word area | U00000 |
EB |
Extended block word area | EB00000 |
FR |
File register flash area | FR000000 |
Extended areas such as ES, EN, H, U, EB, and FR do not require a program prefix.
Byte and packed-word suffixes
Append L, H, or W to bit-area addresses for byte or packed-word access:
plc.read("P1-M0010W") # M0010 as a packed 16-bit word
plc.read("P1-M0010L") # low byte of the packed word
plc.read("P1-M0010H") # high byte of the packed word
Common tasks
Read and write a single device
value = plc.read("P1-D0000")
plc.write("P1-D0001", 1234)
plc.write("P1-M0000", 1)
Read and write several devices together
snapshot = plc.read_many(["P1-D0000", "P1-D0001", "P1-M0000"])
print(snapshot)
plc.write_many(
{
"P1-D0000": 10,
"P1-D0001": 20,
"P1-M0000": 0,
}
)
Read 32-bit and float values
Use ToyopucDeviceClient when you prefer synchronous methods:
counter = plc.read_dword("P1-D0200")
temperature = plc.read_float32("P1-D0300")
values = plc.read_dwords("P1-D0200", 4)
Use async helper functions when you prefer explicit type codes:
| dtype | Type | Size |
|---|---|---|
"U" |
unsigned 16-bit int | 1 word |
"S" |
signed 16-bit int | 1 word |
"D" |
unsigned 32-bit int | 2 words |
"L" |
signed 32-bit int | 2 words |
"F" |
float32 | 2 words |
float_value = await read_typed(plc, "P1-D0100", "F")
signed_value = await read_typed(plc, "P1-D0200", "L")
await write_typed(plc, "P1-D0100", "F", 3.14)
await write_typed(plc, "P1-D0200", "S", -100)
Read contiguous blocks
from toyopuc import (
read_dwords_chunked,
read_dwords_single_request,
read_words_chunked,
read_words_single_request,
)
words = await read_words_single_request(plc, "P1-D0000", 10)
dwords = await read_dwords_single_request(plc, "P1-D0000", 4)
large_words = await read_words_chunked(plc, "P1-D1000", 1000)
large_dwords = await read_dwords_chunked(plc, "P1-D2000", 120)
Use *_single_request when the transfer must stay on the high-level contiguous path.
Use *_chunked only when the caller explicitly accepts multi-request chunking.
Change one bit inside a word
from toyopuc import write_bit_in_word
await write_bit_in_word(plc, "P1-D0100", bit_index=3, value=True)
Read a typed snapshot by name
Address notation:
| Format | Meaning |
|---|---|
"P1-D0100" |
unsigned 16-bit word |
"P1-D0100:F" |
float32 |
"P1-D0100:S" |
signed 16-bit word |
"P1-D0100:D" |
unsigned 32-bit value |
"P1-D0100:L" |
signed 32-bit value |
"P1-D0100.3" |
bit 3 inside the word |
from toyopuc import read_named
result = await read_named(
plc,
["P1-D0100", "P1-D0101:F", "P1-D0102:S", "P1-D0100.3"],
)
print(result)
Poll values repeatedly
poll yields a snapshot dictionary every interval.
import asyncio
from toyopuc import ToyopucConnectionOptions, open_and_connect, poll
async def main() -> None:
options = ToyopucConnectionOptions(host="192.168.250.100", port=1025, timeout=3.0, retries=0)
async with await open_and_connect(options) as plc:
count = 0
async for snapshot in poll(plc, ["P1-D0100", "P1-D0101:F"], interval=1.0):
print(snapshot)
count += 1
if count >= 3:
break
asyncio.run(main())
FR file register access
Use FR helpers when you need non-volatile file-register data.
current_value = plc.read_fr("FR000000")
plc.write_fr("FR000000", 0x1234, commit=False)
plc.commit_fr("FR000000", wait=True)
Use commit=True only when you intentionally want to persist the modified FR block to flash.
Relay access
Relay helpers are also available from ToyopucDeviceClient.
status = plc.relay_read_cpu_status("P1-L2:N2")
word_value = plc.relay_read_words("P1-L2:N2", "P1-D0000", count=1)
plc.relay_write_words("P1-L2:N2", "P1-D0000", 0x1234)
Error handling
| Exception | Condition |
|---|---|
ToyopucError |
PLC returned an error response |
ToyopucProtocolError |
Malformed or unexpected protocol data |
ToyopucTimeoutError |
Communication timeout |
from toyopuc import ToyopucError, ToyopucProtocolError, ToyopucTimeoutError
try:
value = await plc.read("P1-D0000")
except ToyopucTimeoutError:
print("Timeout: check IP address and Computer Link port.")
except ToyopucProtocolError as exc:
print(f"Protocol error: {exc}")
except ToyopucError as exc:
print(f"PLC error: {exc}")
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
ToyopucTimeoutError |
Wrong IP or port | Default port is 1025. Confirm the Computer Link network settings. |
ToyopucProtocolError |
Invalid address format | Check the program prefix and the device family. |
| Wrong values | Word / byte mismatch | Recheck W, L, and H suffix usage. |
Sample programs
Open these files when you want a complete working example:
samples/high_level_minimal.pySmallest possible read / write workflowsamples/high_level_basic.pySingle reads,read_many, andW/H/Lpacked accesssamples/high_level_all_sync.pySync cookbook forToyopucDeviceClientsamples/high_level_all_async.pyAsync cookbook foropen_and_connect,read_typed,read_named,poll, and related helperssamples/high_level_udp.pyUDP connection with--local-portsamples/fr_basic.pyFR read, write, and optional commitsamples/relay_basic.pyRelay CPU status, clock, word, and FR examplessamples/clock_and_status.pyPLC clock and CPU status decode Desktop monitor UI