Official Python SDK for the Scadable IoT platform.
Project description
Scadable Python SDK
Scadable is the first fully container-native SCADA platform—built on Kubernetes & NATS and delivered with Python + React SDKs. Forget rigid vendor UIs: craft your own dashboards, deploy in any cloud, and scale to millions of tags in minutes.
Table of Contents
Overview
The Scadable Python SDK provides a simple, pythonic interface to interact with the Scadable SCADA platform. Key features include:
- Live Telemetry Streaming: Subscribe to real-time device data via WebSocket connections
- Device Management: Create and manage multiple devices within a facility
- Flexible Connection Handling: Built-in WebSocket support with extensible connection factory pattern
- Async-First Design: Fully asynchronous API using Python's
asyncio - Type-Safe: Full type hints for better IDE support and code quality
Access & Deployment
- PyPI Package: Available at pypi.org/project/scadable
- Installation:
pip install scadable - Source Code: github.com/scadable/library-python
- Platform: Requires Python 3.10 or higher
- Dependencies: Minimal dependencies (websockets >= 13.0)
Installation
Requirements
- Python 3.10 or higher
- pip package manager
Install from PyPI
pip install scadable
Install for Development
For contributing to the project, see the CONTRIBUTING.md guide.
Quick Start
Here's a minimal example to get started with Scadable:
import asyncio
from scadable import Facility
from scadable.connection import WebsocketConnectionFactory
# Initialize a facility with your API key
facility = Facility(
api_key="your-api-key-here",
connection_factory=WebsocketConnectionFactory(dest_uri="your-scadable-host.com")
)
# Create devices with live connections
devices = facility.create_many_devices(
device_ids=["device-1", "device-2"],
create_connection=True
)
# Subscribe to live telemetry for specific devices
@facility.live_telemetry(["device-1", "device-2"])
async def handle_telemetry(data: str):
print(f"Received data: {data}")
# Process your telemetry data here
# Start listening for telemetry
async def main():
await asyncio.gather(*[device.start_live_telemetry() for device in devices])
if __name__ == "__main__":
asyncio.run(main())
Core Concepts
Facility
The Facility class is your main entry point. It represents a physical or logical facility containing multiple devices.
from scadable import Facility
facility = Facility(api_key="your-api-key")
Devices
Devices represent individual data sources (PLCs, sensors, controllers, etc.) within your facility.
# Create a single device
device = facility.create_device("device-id-123")
# Create multiple devices
devices = facility.create_many_devices(["device-1", "device-2", "device-3"])
Connections
Connections manage the communication channel between your application and the Scadable platform. The SDK provides WebSocket connections out of the box:
from scadable.connection import WebsocketConnectionFactory
# Create a connection factory
factory = WebsocketConnectionFactory(
dest_uri="scadable.example.com",
connection_type="wss" # or "ws" for non-secure
)
facility = Facility(api_key="your-key", connection_factory=factory)
Live Telemetry
Subscribe to real-time data streams using decorators:
# Subscribe to a single device
@facility.live_telemetry("device-1")
async def handler(data: str):
print(data)
# Subscribe to multiple devices
@facility.live_telemetry(["device-1", "device-2"])
async def multi_handler(data: str):
# This handler will receive data from both devices
process_data(data)
Usage Examples
Example 1: Basic Telemetry Monitoring
import asyncio
from scadable import Facility
from scadable.connection import WebsocketConnectionFactory
async def monitor_devices():
# Setup
facility = Facility(
api_key="your-api-key",
connection_factory=WebsocketConnectionFactory("your-host.com")
)
# Create devices with connections
device = facility.create_device("sensor-001", create_connection=True)
# Subscribe to telemetry
@facility.live_telemetry("sensor-001")
async def log_data(data: str):
print(f"Sensor reading: {data}")
# Start monitoring
await device.start_live_telemetry()
asyncio.run(monitor_devices())
Example 2: Multiple Device Management
import asyncio
from scadable import Facility
from scadable.connection import WebsocketConnectionFactory
async def monitor_facility():
facility = Facility(
api_key="your-api-key",
connection_factory=WebsocketConnectionFactory("your-host.com")
)
# Create multiple devices
device_ids = ["plc-1", "plc-2", "sensor-1", "sensor-2"]
devices = facility.create_many_devices(device_ids, create_connection=True)
# Different handlers for different device groups
@facility.live_telemetry(["plc-1", "plc-2"])
async def handle_plc_data(data: str):
print(f"PLC Data: {data}")
@facility.live_telemetry(["sensor-1", "sensor-2"])
async def handle_sensor_data(data: str):
print(f"Sensor Data: {data}")
# Start all connections
await asyncio.gather(*[dev.start_live_telemetry() for dev in devices])
asyncio.run(monitor_facility())
Example 3: Raw Data Processing
For advanced use cases where you need access to raw, unparsed data:
device = facility.create_device("device-1", create_connection=True)
@device.raw_live_telemetry
async def handle_raw(raw_data: str):
# Process raw data before parsing
print(f"Raw: {raw_data}")
await device.start_live_telemetry()
Architecture
Component Overview
┌─────────────────────────────────────────────────────────┐
│ Facility │
│ - Manages API authentication │
│ - Coordinates devices and connections │
└────────────────┬───────────────────┬────────────────────┘
│ │
┌────────▼────────┐ ┌───────▼──────────┐
│ DeviceManager │ │ ConnectionFactory │
│ - Device CRUD │ │ - Creates conns │
└────────┬────────┘ └───────┬───────────┘
│ │
┌────────▼────────┐ ┌───────▼───────────┐
│ Device │ │ Connection │
│ - Telemetry bus │◄─┤ - WebSocket │
│ - Event routing │ │ - Send/Receive │
└─────────────────┘ └───────────────────┘
Key Design Patterns
- Factory Pattern:
ConnectionFactoryallows for different connection types (WebSocket, HTTP, custom) - Observer Pattern: Devices use a pub-sub bus for telemetry data distribution
- Async/Await: Fully asynchronous for efficient I/O operations
- Decorator Pattern: Clean syntax for subscribing to telemetry streams
Tech Stack
- Language: Python 3.10+
- Async Framework: asyncio (standard library)
- WebSocket Library: websockets 13.0+
- Type System: Full type hints with Python's typing module
Package Structure
scadable/
├── __init__.py # Public API exports
├── facility.py # Facility class
├── device.py # Device and DeviceManager classes
└── connection.py # Connection abstractions and WebSocket implementation
Contributing
We welcome contributions! Please see CONTRIBUTING.md for:
- Development environment setup
- Code style guidelines
- Testing requirements
- Pull request process
Support
- Issues: Report bugs at github.com/scadable/library-python/issues
- Discussions: Ask questions in GitHub Discussions
- Documentation: Full docs at the repository
License
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file scadable-2.0.0.tar.gz.
File metadata
- Download URL: scadable-2.0.0.tar.gz
- Upload date:
- Size: 20.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
84e673e27a8df02705e8309530e30952fc8128f9ec8e1f9ac5eca4d96da1c5e7
|
|
| MD5 |
173de28805e06151d037485a11d2f8b6
|
|
| BLAKE2b-256 |
7bea110e53367f26e69b844137905f5eeae724f92df4c267a6ee6121f1a9ba31
|
Provenance
The following attestation bundles were made for scadable-2.0.0.tar.gz:
Publisher:
python-publish.yml on scadable/library-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
scadable-2.0.0.tar.gz -
Subject digest:
84e673e27a8df02705e8309530e30952fc8128f9ec8e1f9ac5eca4d96da1c5e7 - Sigstore transparency entry: 1168259878
- Sigstore integration time:
-
Permalink:
scadable/library-python@36afa21a0a2501b88fa75f4660a36ad597655586 -
Branch / Tag:
refs/tags/2.0.0 - Owner: https://github.com/scadable
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@36afa21a0a2501b88fa75f4660a36ad597655586 -
Trigger Event:
release
-
Statement type:
File details
Details for the file scadable-2.0.0-py3-none-any.whl.
File metadata
- Download URL: scadable-2.0.0-py3-none-any.whl
- Upload date:
- Size: 18.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.7
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
ec2a52e06ca6d62184f3ebcbcf9248c4fc35fdab8614b86eec6f3b421a2fe1aa
|
|
| MD5 |
183ece8920a6aae175a9bafb785dbd12
|
|
| BLAKE2b-256 |
386c01ec2b766f9728f2cfe21a5d9916496e47a76c9a4aeb884eb08366069ffb
|
Provenance
The following attestation bundles were made for scadable-2.0.0-py3-none-any.whl:
Publisher:
python-publish.yml on scadable/library-python
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
scadable-2.0.0-py3-none-any.whl -
Subject digest:
ec2a52e06ca6d62184f3ebcbcf9248c4fc35fdab8614b86eec6f3b421a2fe1aa - Sigstore transparency entry: 1168260121
- Sigstore integration time:
-
Permalink:
scadable/library-python@36afa21a0a2501b88fa75f4660a36ad597655586 -
Branch / Tag:
refs/tags/2.0.0 - Owner: https://github.com/scadable
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
python-publish.yml@36afa21a0a2501b88fa75f4660a36ad597655586 -
Trigger Event:
release
-
Statement type: