Event-driven automation bridge between Timberborn's HTTP Adapters (sensors) and HTTP Levers (actuators).
- ✅ Event-driven webhook server — instant reaction to adapter state changes
- ✅ Polling fallback mode for simple setups
- ✅ Config-driven rules engine (YAML)
- ✅ AND/OR condition logic across multiple adapters
- ✅ State and event history API for dashboard integration
- ✅ Graceful handling when game isn't running
- ✅ Detailed logging of state changes and actions
- ✅ No crashes, just retry logic
The controller supports three operating modes:
Event-driven, instant reaction
The game pushes webhook calls to the controller when adapters change state. Zero polling delay.
In-game setup required: Configure each HTTP Adapter with webhook URLs:
- ON:
http://localhost:8081/on/{AdapterName} - OFF:
http://localhost:8081/off/{AdapterName}
Config:
mode: "webhook"
webhook_port: 8081Traditional polling, no in-game config needed
Controller polls /api/adapters periodically to check for state changes.
No in-game setup required — just run the controller.
Config:
mode: "polling"
polling_interval_seconds: 5Best of both worlds
Webhook server for instant events + periodic polling for state sync/recovery.
Config:
mode: "hybrid"
webhook_port: 8081
polling_interval_seconds: 10-
Install dependencies:
pip3 install -r requirements.txt
-
Create your config:
cp config.example.yaml config.yaml
-
Edit
config.yaml:- Set
mode(webhook / polling / hybrid) - Configure
webhook_portand/orpolling_interval_seconds - Define your automation rules (adapter/lever names must match in-game exactly)
- Set
-
Run:
python3 controller.py
For webhook/hybrid mode, the controller will print webhook URLs to configure in-game.
If using webhook or hybrid mode, configure your HTTP Adapters:
- Open each HTTP Adapter's configuration panel in-game
- Set "Call when switched on" to:
http://localhost:8081/on/{AdapterName} - Set "Call when switched off" to:
http://localhost:8081/off/{AdapterName} - Replace
{AdapterName}with the actual adapter name (e.g.,Weather Drought) - Choose GET or POST method (both supported)
The adapter name in the webhook URL must match the name used in your config.yaml rules.
mode: "webhook" # "webhook", "polling", or "hybrid"
webhook_port: 8081
game_api_url: http://localhost:8080
polling_interval_seconds: 5 # used in polling/hybrid mode
rules:
- name: "Rule Name"
conditions:
operator: AND # or OR (default)
checks:
- adapter: "Adapter Name"
state: true # or false
actions:
- lever: "Lever Name"
action: "on" # or "off"rules:
- name: "Drought Water Emergency"
conditions:
operator: AND
checks:
- adapter: "Weather Drought"
state: true
- adapter: "Water Depth Critical"
state: true
actions:
- lever: "Pump Station"
action: "on"
- lever: "Main Floodgate"
action: "off"
- name: "Crisis Resolved"
conditions:
operator: AND
checks:
- adapter: "Weather Drought"
state: false
- adapter: "Water Depth Critical"
state: false
actions:
- lever: "Pump Station"
action: "off"
- lever: "Floodgate Main"
action: "on"These rules react instantly (webhook mode) or within the polling interval to manage water during droughts.
The controller exposes an HTTP API on the webhook port for dashboard integration:
Returns current system state:
{
"adapters": {"Weather Drought": true, "Water Level": false},
"levers": {"Pump Station": true, "Floodgate": false},
"events": [...], // last 20 events
"timestamp": 1234567890.123
}Returns event history (default 50, configurable):
{
"events": [
{
"timestamp": 1234567890.123,
"type": "adapter",
"name": "Weather Drought",
"state": true,
"details": "Changed from False to True"
},
...
]
}Health check endpoint:
{
"status": "ok",
"mode": "webhook",
"adapters_count": 5,
"levers_count": 3
}GET|POST /on/{adapter_name}— Adapter switched ONGET|POST /off/{adapter_name}— Adapter switched OFF
These are called by the game when adapters change state.
python3 controller.pyOr specify a custom config:
python3 controller.py --config my-rules.yamlWebhook mode will:
- Start HTTP server on configured port
- Wait for adapter webhook calls from the game
- Update internal state when webhooks arrive
- Evaluate rules and trigger levers instantly
- Log all events to console +
controller.log
Polling mode will:
- Poll
/api/adaptersat the configured interval - Evaluate all rules against current adapter states
- Trigger lever actions when conditions match
- Log all state changes and actions
Hybrid mode does both.
Press Ctrl+C to stop.
- Exact names: Adapter and lever names must match exactly (case-sensitive)
- Webhook testing: Visit
http://localhost:8081/on/TestAdapterin a browser to simulate an adapter turning on - Dashboard integration: Point the dashboard to the controller's URL to see rich event history
- Polling interval: In hybrid mode, use a longer interval (10-30s) — webhooks handle instant reactions
- Logging: Check
controller.logfor detailed history - Game offline: Controller will keep retrying API calls until the game starts
Another process is using port 8081. Either:
- Stop the other process
- Change
webhook_portin config.yaml - Update in-game webhook URLs to match new port
- Check controller logs for incoming webhook calls
- Verify webhook URLs in-game match controller endpoint exactly
- Test manually:
curl http://localhost:8081/on/TestAdapter - Ensure adapter names match between webhook URL and config rules
- Make sure Timberborn is running
- Verify the HTTP API mod is enabled
- Check that
game_api_urlin config matches the game's API port (default: 8080) - Test:
curl http://localhost:8080/api/adapters
- Check adapter names match exactly (including spaces/capitalization)
- In webhook mode, ensure webhooks are configured in-game
- In polling mode, verify polling is active (check logs)
- Check logs for condition evaluation and rule firing
- Verify lever name is correct
- Check that the lever exists in-game
- Ensure the lever isn't controlled by in-game logic that overrides it
- Test manually:
curl -X POST http://localhost:8080/api/switch-on/{LeverName}
| Feature | Webhook | Polling | Hybrid |
|---|---|---|---|
| Reaction time | Instant | 5s (configurable) | Instant |
| In-game setup | Configure webhooks on each adapter | None | Configure webhooks |
| State sync | On startup only | Continuous | Both |
| Best for | Real-time automation | Simple setups, testing | Production (redundancy) |
| Dashboard events | ✅ Rich history | ✅ Rich history | ✅ Rich history |
The controller tracks three event types:
- adapter — Adapter state changed (on/off)
- lever — Lever toggled by automation
- rule — Automation rule triggered (conditions met)
All events include timestamp, name, state (where applicable), and details. View via /api/events or the dashboard.