Skip to content

thingworx-field-work/ThingWorx-Python-wrapper

Repository files navigation

thingworx-python

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.


Architecture

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

Prerequisites

  1. Python 3.7+
  2. The native ThingWorx C SDK shared library for your platform:
    • Windows: twCSdk.dll (+ its OpenSSL DLLs libcrypto-3-x64.dll, libssl-3-x64.dll)
    • Linux: libtwCSdk.so
    • macOS: libtwCSdk.dylib

The wrapper is not distributed with PTC's binaries. You build the C SDK yourself (or copy a build PTC has provided you).


Installation

You have three equivalent paths. Pick whichever fits your workflow.

Option A — One-shot installer scripts (recommended)

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\sdk

Linux / macOS (bash):

chmod +x install.sh
./install.sh --venv .venv --editable --extras dev,ml \
             --lib-path /opt/twx/sdk

All flags are optional. Run with no args to install into the current Python:

.\install.ps1
./install.sh

See install.ps1 -? / ./install.sh --help for the full flag list.

Option B — Plain pip from the source tree

# 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]"   # everything

Option C — Build a wheel and ship it

Useful 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.gz

Or use the repository helper scripts:

.\pack.ps1
./pack.sh

Then on the target machine:

pip install thingworx_python-1.0.0-py3-none-any.whl

Native library — where the wrapper looks for twCSdk

thingworx/_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' >> ~/.bashrc

Both install.ps1 -LibPath … and install.sh --lib-path … will do the persisted-set step for you.

Bundling the DLL into the wheel (for air-gapped deployments)

If you control a single platform/build, you can ship the native library inside the wheel:

  1. Drop your twCSdk.dll (or .so / .dylib) into thingworx/_bindings/.
  2. Uncomment the package-data line for thingworx._bindings in pyproject.toml.
  3. Uncomment the matching include line in MANIFEST.in.
  4. python -m build.

The loader's step #3 will then find it automatically — no env var required.


Quick start (example simple thing)

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.


Using it from another project

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()

API reference

ThingWorxClient

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

Thing

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

Types

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)

Low-level access

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")

Covered SDK modules

  • 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

Troubleshooting

OSError: Failed to load ThingWorx C SDK library 'twCSdk.dll' The loader couldn't find the shared library. Check, in order:

  1. echo $env:TWCSDK_LIB_PATH (PowerShell) / echo $TWCSDK_LIB_PATH (bash) — does it point to a directory containing the file?
  2. Is the file actually there (Test-Path C:\path\twCSdk.dll)?
  3. 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.
  4. On Linux, is LD_LIBRARY_PATH set if the SDK depends on other .so files?

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.

About

ThingWorx Python wrapper

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors