python-cybro
Asynchronous Python client for the Cybrotech scgi server. Use it to read and write variables of Cybro / HIQ PLCs through the scgi server's HTTP interface.
Requirements
- Python 3.11 or newer
- A running Cybrotech scgi server v3.2.6 or newer (tested with v3.2.6 and v3.3.1;
earlier versions are not supported).
You can install the server natively, or run it as a Docker container:
Installation
pip install cybro
Usage
import asyncio
from cybro import Cybro
async def main() -> None:
nad = 10000 # network address (NAD) of the PLC
prefix = f"c{nad}."
async with Cybro("192.168.1.100", port=4000, nad=nad) as cybro:
# The first update reads server and PLC information.
# It must run before variables can be added, read or written.
device = await cybro.update()
print("Server version:", device.server_info.server_version)
print("Controllers:", device.server_info.nad_list)
print("PLC status:", device.plc_info.plc_status)
# Register variables that every following update() should refresh.
cybro.add_var(f"{prefix}scan_time")
cybro.add_var(f"{prefix}sys.response_time")
device = await cybro.update()
for name in device.user_vars:
print(name, "->", device.vars[name].value)
# Read and write single variables.
print(await cybro.read_var(f"{prefix}lc00_qx00"))
await cybro.write_var(f"{prefix}lc00_qx00", "1")
asyncio.run(main())
A longer example lives in examples/control.py.
Connecting
Cybro(host_str, port=4000, nad=0, session=None)
host_strcan be a plain host name or IP address, or a URL with a path, e.g.http://example.com/scgi. The scheme is ignored; requests always use HTTP.nadis the network address of the PLC. It is needed for PLC information and foradd_var(). Withnad=0(the default), only server information is read. See Server only (nad=0).sessionlets you pass your ownaiohttp.ClientSession; you stay responsible for closing it. Otherwise one is created on the first request and closed when leavingasync with Cybro(...)or callingawait cybro.disconnect().
Reading data
await cybro.update(full_update=False, plc_nad=0, device_type=0) returns a Device:
| Attribute | Content |
|---|---|
device.server_info |
Server data: version, uptime, request counters, active NADs (nad_list) |
device.plc_info |
PLC data: IP/port, status, response time, ALC file, available variables |
device.vars |
All read variables by name (Var objects) |
device.user_vars |
Variables registered with add_var() |
- The first call (or
full_update=True) reads server and PLC information. Later calls only refresh the variables registered withadd_var(). - Set
device_type=1for HIQ controllers to also read their HIQ-specific variables. plc_nadsets the PLC address if none was given toCybro(). It only takes effect on the very firstupdate()call.
Server only (nad=0)
Without a NAD, update() reads only the server information. Use this to check that the
server is reachable, or to list the controllers it knows (device.server_info.nad_list).
In this mode:
device.plc_infoisNone.cybro.add_var(name)only accepts system variables (c<nad>.sys.*). Passallow_all=Trueto register other variables.read_var()andwrite_var()work with full variable names, e.g.c10000.scan_time.
To work with a PLC, create the Cybro object with its NAD.
Variables
cybro.add_var(name)registers a variable forupdate(). Only variables listed in the PLC's ALC file and system variables (c<nad>.sys.*) are accepted; passallow_all=Trueto add any name.cybro.remove_var(name)removes it again.await cybro.read_var(name)andawait cybro.write_var(name, value)read or write a single variable immediately.
Values are returned as strings. Each Var in device.vars has helpers to convert them:
value_int(), value_float() and value_bool().
Errors
All exceptions derive from CybroError, so catching it is enough:
| Exception | Raised when |
|---|---|
CybroConnectionError |
The scgi server cannot be reached |
CybroConnectionTimeoutError |
The scgi server does not answer in time |
CybroEmptyResponseError |
The scgi server returns an empty response |
CybroPlcNotFoundError |
The PLC information for the NAD is missing |
CybroError |
Any other error, e.g. add_var() or read_var() before update() |
Connection errors, timeouts and server errors (HTTP 5xx) are retried up to three times before an exception is raised. Client errors (HTTP 4xx) are raised immediately. Writes are retried too, so after a timeout a write may reach the PLC twice.
Development
The project uses Poetry. A ready-to-use dev container is included for VS Code.
poetry install
poetry run pytest
poetry run pre-commit install # run Ruff, prettier and the tests before every commit
Contributing
Contributions are welcome! Please read the contribution guidelines first.
License
Metadata
Release files for cybro 0.4.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| cybro-0.4.0.tar.gz | 15.6 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| cybro-0.4.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 29.4 kB
Release files / cybro-0.4.0.tar.gz
| Download URL | cybro-0.4.0.tar.gz |
|---|---|
| Size | 15.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
739d9b3d8e52051d4c166cd9bef0658054368fd7f15e4a2212260702a47c514d
|
|
BLAKE2b-256 checksum How to use checksums |
0a0fdb40508eb1c24913e0d8bd5b9a9d44de3d35e3b435c720f937ac5e18e807
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Release files / cybro-0.4.0-py3-none-any.whl
| Download URL | cybro-0.4.0-py3-none-any.whl |
|---|---|
| Size | 13.7 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
5b6703a086fd77c5d69d5c9e855432bf669f49303aa327525f8739e396504a34
|
|
BLAKE2b-256 checksum How to use checksums |
20dd0420bd88963bbb00b5558ef62ab8acf519b7cb900af780e0f62b888df920
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|