A complete, reusable Python wrapper for the ThingWorx C SDK
(twCSdk.dll on Windows, libtwCSdk.so on Linux, libtwCSdk.dylib on macOS).
It ships both:
- a high-level Pythonic API (
ThingWorxClient,Thing,DataShape,InfoTable, decorators), and - a low-level 1:1 ctypes binding for everything in the C SDK
(
twApi_*,twPrimitive_*,twInfoTable_*,twFileManager_*,twTunnelManager_*, …).
The wrapper itself has zero runtime pip dependencies — only the Python standard
library. Optional extras (ml, opc) pull in extra packages for the bundled
sample solutions.
thingworx/ <- High-level Pythonic API
|-- client.py <- ThingWorxClient (connect, TLS, proxy, callbacks)
|-- thing.py <- Thing (properties, services, events, decorators)
|-- types.py <- Primitive, InfoTable, DataShape, Location
|-- file_transfer.py <- FileTransferManager, TunnelManager
|-- exceptions.py <- Exception hierarchy mapped from C error codes
\-- _bindings/ <- Low-level 1:1 ctypes bindings
|-- api.py <- twApi_* (~80 functions)
|-- base_types.py <- twPrimitive_*, twStream_*
|-- infotable.py <- twInfoTable_*, twDataShape_*
|-- list.py <- twList_*, twMap_*, twDict_*
|-- extended.py <- twExt_*, twFileManager_*, twTunnelManager_*, twWs_*
|-- enums.py <- BaseType, EntityType, MsgCode, LogLevel, ...
|-- errors.py <- TW_OK, TW_INVALID_PARAM, ... (~100 codes)
|-- callbacks.py <- CFUNCTYPE definitions for all callback types
\-- loader.py <- Cross-platform shared-library loader
- Python 3.7+
- The native ThingWorx C SDK shared library for your platform:
- Windows:
twCSdk.dll(+ its OpenSSL DLLslibcrypto-3-x64.dll,libssl-3-x64.dll) - Linux:
libtwCSdk.so - macOS:
libtwCSdk.dylib
- Windows:
The wrapper is not distributed with PTC's binaries. You build the C SDK yourself (or copy a build PTC has provided you).
You have three equivalent paths. Pick whichever fits your workflow.
These wrap pip + venv + TWCSDK_LIB_PATH setup into a single command.
Windows (PowerShell):
# Fresh venv, editable install, dev + ML extras, configure DLL path
.\install.ps1 -Venv .venv -Editable -Extras dev,ml -LibPath C:\path\to\sdkLinux / macOS (bash):
chmod +x install.sh
./install.sh --venv .venv --editable --extras dev,ml \
--lib-path /opt/twx/sdkAll flags are optional. Run with no args to install into the current Python:
.\install.ps1./install.shSee install.ps1 -? / ./install.sh --help for the full flag list.
# In the directory that contains pyproject.toml
pip install .
# Or editable, for wrapper development
pip install -e .
# With optional extras
pip install ".[dev]" # pytest + build tooling
pip install ".[ml]" # numpy, pandas, pypmml, sklearn-pmml-model
pip install ".[opc]" # asyncua
pip install ".[dev,ml,opc]" # everythingUseful when you want to install on a machine that doesn't have the source tree.
pip install build
python -m build # produces dist/thingworx_python-1.0.0-*.whl
# and dist/thingworx_python-1.0.0.tar.gzOr use the repository helper scripts:
.\pack.ps1./pack.shThen on the target machine:
pip install thingworx_python-1.0.0-py3-none-any.whlthingworx/_bindings/loader.py searches in this order, stopping at the first hit:
| # | Location |
|---|---|
| 1 | $TWCSDK_LIB_PATH (directory containing the lib, or full path) |
| 2 | The current working directory |
| 3 | The thingworx/_bindings/ package directory |
| 4 | The OS loader path (PATH on Windows, LD_LIBRARY_PATH / DYLD_LIBRARY_PATH on Unix) |
Recommended: set the env var once and forget it.
PowerShell (current session):
$env:TWCSDK_LIB_PATH = "C:\path\to\sdk"PowerShell (persisted for your user):
[System.Environment]::SetEnvironmentVariable("TWCSDK_LIB_PATH", "C:\path\to\sdk", "User")Bash / Zsh:
echo 'export TWCSDK_LIB_PATH=/opt/twx/sdk' >> ~/.bashrcBoth
install.ps1 -LibPath …andinstall.sh --lib-path …will do the persisted-set step for you.
If you control a single platform/build, you can ship the native library inside the wheel:
- Drop your
twCSdk.dll(or.so/.dylib) intothingworx/_bindings/. - Uncomment the
package-dataline forthingworx._bindingsinpyproject.toml. - Uncomment the matching
includeline inMANIFEST.in. python -m build.
The loader's step #3 will then find it automatically — no env var required.
from thingworx import (
ThingWorxClient, Thing, DataShape, InfoTable,
BaseType, MsgCode, LogLevel,
)
with ThingWorxClient(
host="platform.example.com",
port=443,
app_key="your-app-key-here",
) as client:
client.set_self_signed_ok() # dev servers only
client.connect()
thing = Thing(client, "PythonThing")
thing.register_property("Temperature", BaseType.NUMBER)
thing.bind()
thing.set_subscribed_property("Temperature", 72.5)
thing.push_subscribed_properties()
value = thing.read_property("RemoteProperty")
thing.write_property("SetPoint", 68.0)
thing.register_event(
"Alert",
DataShape().add_entry("message", BaseType.STRING),
)
thing.fire_event("Alert", {"message": "Threshold exceeded"})A full runnable example lives in examples/simple_thing.py.
After pip install thingworx-python (or pointing pip at this directory),
your downstream project just imports it like any other package.
pyproject.toml of a downstream solution:
[project]
name = "my-edge-agent"
version = "0.1.0"
dependencies = [
"thingworx-python @ file:///C:/Dev/Python/thingworx-python",
# or, once you publish a wheel:
# "thingworx-python==1.0.0",
]agent.py:
from thingworx import ThingWorxClient, Thing, BaseType
with ThingWorxClient(host="...", port=443, app_key="...") as client:
client.connect()
Thing(client, "MyThing").bind()| Method | Description |
|---|---|
connect(timeout, retries) |
Connect to the platform |
disconnect(reason) |
Disconnect |
is_connected |
Connection status (property) |
set_self_signed_ok() |
Accept self-signed certs |
disable_cert_validation() |
Disable cert validation |
set_proxy(host, port, user, password) |
Configure HTTP proxy |
set_log_level(LogLevel) |
Set SDK log level |
on_connect(callback) |
Register connect callback |
on_disconnect(callback) |
Register disconnect callback |
on_authenticated(callback) |
Register auth callback |
send_ping(content) |
Send ping to server |
| Method | Description |
|---|---|
bind() / unbind() |
Bind/unbind from platform |
register_property(name, type, …) |
Register a property |
@property_handler(name, type) |
Decorator for property callbacks |
register_service(name, handler, …) |
Register a service |
@service_handler(name, inputs, …) |
Decorator for service callbacks |
register_event(name, datashape) |
Register an event |
fire_event(name, data) |
Fire an event |
read_property(name) |
Read remote property |
write_property(name, value) |
Write remote property |
set_subscribed_property(name, value) |
Set managed property |
push_subscribed_properties() |
Push all pending changes |
invoke_service(name, params) |
Call remote service |
| Class | Description |
|---|---|
Primitive |
Wraps twPrimitive* with auto Python ↔ C conversion |
InfoTable |
Wraps twInfoTable* with dict-like row access |
DataShape |
Builder for twDataShape (chainable .add_entry()) |
Location |
Named tuple (latitude, longitude, elevation) |
For anything not exposed in the high-level API, the raw ctypes handle is always available:
from thingworx._bindings import initialize
lib = initialize()
lib.twApi_SendPing(b"hello")- twApi — full lifecycle, properties, services, events, subscribed props
- twPrimitive / twStream — all type creation and conversion functions
- twInfoTable / twDataShape — table creation, row access, typed getters
- twList / twMap / twDict — collection operations
- twFileManager — file send/receive, virtual directories, callbacks
- twTunnelManager — tunnel lifecycle, callbacks, proxy
- twWebSocket — low-level WebSocket operations
- twExt (Shapes/Templates) — edge shape/template registration
- twLogger — log level and custom log function
- twOSPort — time, mutex, directory, tasker operations
OSError: Failed to load ThingWorx C SDK library 'twCSdk.dll'
The loader couldn't find the shared library. Check, in order:
echo $env:TWCSDK_LIB_PATH(PowerShell) /echo $TWCSDK_LIB_PATH(bash) — does it point to a directory containing the file?- Is the file actually there (
Test-Path C:\path\twCSdk.dll)? - On Windows, are the OpenSSL DLLs (
libcrypto-3-x64.dll,libssl-3-x64.dll) in the same directory? The DLL fails to load without them. - On Linux, is
LD_LIBRARY_PATHset if the SDK depends on other.sofiles?
ImportError: DLL load failed while importing _bindings
Almost always missing OpenSSL DLLs alongside twCSdk.dll. Copy them into the
same directory.
The wrapper imports but client.connect() hangs
Likely TLS / cert mismatch. For dev servers use client.set_self_signed_ok()
before connect(). For port 8016 use encryption=False in the constructor.