Project Layout
scadable init linux my-project creates this directory:
my-project/
├── scadable.toml
├── fleet.toml
├── storage.py
├── routes.py
├── devices/
├── controllers/
└── models/Each file and folder has one job. Once you understand them, you understand the whole layout.
scadable.toml
The project manifest. Holds the project name, version, and target.
name = "my-project"
version = "0.1.0"
target = "linux"You bump the version when you cut a release. The compiler embeds these into manifest.json so the gateway knows what it is running.
fleet.toml
Maps gateways to the devices and controllers they should run. Most small projects have one gateway and one entry. Large factory deployments use this to ship different configs to different physical units.
[[gateway]]
id = "factory-floor-1"
target = "linux-arm64"
devices = ["devices/temp_sensor.py"]
controllers = ["controllers/temp_monitor.py"]
[gateway.env]
SENSOR_HOST = "192.168.1.50"Environment variables defined here are substituted into your devices at compile time, so you can use placeholders like host="${SENSOR_HOST}" in your Python and have the right value baked into each gateway's bundle.
storage.py
Local storage configuration for the gateway. Sets up data (time-series buffer), state (key-value store), and files (blob store) sized to the target. The defaults are sensible. You only edit this if you need to change retention or quotas.
routes.py
Cloud-side destinations. Declares the upload routes (S3 buckets, GCS, Azure Blob) and notification routes (Slack webhooks, email, PagerDuty) that controllers can refer to by name. Decoupling the route from the controller means you can change the destination without touching controller code.
devices/
One Python file per physical device. Each file declares a class subclassing Device with its connection, poll cadence, and registers. The CLI scaffolds these for you with scadable add device <protocol> <name>.
controllers/
One Python file per piece of business logic. Each file declares a class subclassing Controller with @on.* triggers that fire on intervals, thresholds, value changes, inbound messages, or device status changes. Scaffold with scadable add controller <name>.
models/
ONNX models you ship with your project. Each model gets a small Python wrapper declaring how to preprocess inputs and interpret outputs. Scaffold with scadable add model <name>.
What is not here
You will notice there is no Dockerfile, no requirements.txt for the gateway, no service definitions, no certificate config. That is the whole point. The gateway is a single binary you install once. Your project is just the description of what that binary should run.
Next steps
- Core Concepts: Device, Controller, Register vocabulary
- scadable init: creating a fresh project
- scadable add device: scaffolding device files
Updated 4 days ago
