Includes: - 3 Python actions (hello, http_example, read_counter) - 1 counter trigger type - 1 counter sensor (Python, keystore-backed, per-rule state) - 1 example rule (count_and_log) - requirements.txt with requests and pika - README with full usage documentation
7.3 KiB
Python Example Pack for Attune
A complete example pack demonstrating Python actions, a stateful counter sensor with keystore integration, and HTTP requests using the requests library.
Purpose
This pack exercises as many parts of the Attune SDLC as possible:
- Python actions with the wrapper-based execution model
- Python sensor with RabbitMQ rule lifecycle integration
- Trigger types with structured payload schemas
- Rules connecting triggers to actions with parameter mapping
- Keystore integration for persistent sensor state across restarts
- External Python dependencies (
requests,pika) - Per-rule scoped state — each rule subscription gets its own counter
Components
Actions
| Ref | Description |
|---|---|
python_example.hello |
Returns "Hello, Python" — minimal action |
python_example.http_example |
Uses requests to GET https://example.com |
python_example.read_counter |
Consumes a counter value and returns a formatted message |
Triggers
| Ref | Description |
|---|---|
python_example.counter |
Fires periodically with an incrementing counter per rule |
Sensors
| Ref | Description |
|---|---|
python_example.counter_sensor |
Manages per-rule counters stored in the Attune keystore |
Rules
| Ref | Description |
|---|---|
python_example.count_and_log |
Wires the counter trigger to the read_counter action |
Installation
As a Git Pack (recommended)
# Install via the Attune CLI from a git repository
attune pack install https://github.com/attune-automation/pack-python-example.git
# Or via the API
curl -X POST "http://localhost:8080/api/v1/packs/install" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{"source": "git", "url": "https://github.com/attune-automation/pack-python-example.git"}'
Local Development (submodule)
If you're developing against the Attune repository:
cd attune
# Add as a git submodule in packs.examples/
git submodule add <your-repo-url> packs.examples/python_example
# Or if you already have the directory, initialize it:
cd packs.examples/python_example
git init
git remote add origin <your-repo-url>
Manual / Volume Mount
Copy or symlink the pack into your Attune packs directory:
cp -r python_example /opt/attune/packs/python_example
# Then restart services to pick it up, or use the dev packs volume
Dependencies
Declared in requirements.txt:
requests>=2.28.0— HTTP client for thehttp_exampleaction and sensor API callspika>=1.3.0— RabbitMQ client for the counter sensor
These are installed automatically when the pack is loaded by a Python worker with dependency management enabled.
How It Works
Counter Sensor Flow
┌──────────────────────────────────────────────────────────┐
│ counter_sensor.py │
│ │
│ 1. Startup: fetch active rules from GET /api/v1/rules │
│ 2. Listen: RabbitMQ queue sensor.python_example.* │
│ for rule.created / rule.enabled / rule.disabled / │
│ rule.deleted messages │
│ 3. Per active rule, spawn a timer thread: │
│ │
│ ┌────────────────────────────────────────┐ │
│ │ Timer Thread (1 tick/sec per rule) │ │
│ │ │ │
│ │ GET /api/v1/keys/{key} → read counter │ │
│ │ counter += 1 │ │
│ │ PUT /api/v1/keys/{key} → write back │ │
│ │ POST /api/v1/events → emit event │ │
│ └────────────────────────────────────────┘ │
│ │
│ 4. On shutdown: stop all timer threads gracefully │
└──────────────────────────────────────────────────────────┘
Keystore Key Naming
Each rule gets its own counter key:
python_example.counter.<rule_ref_with_dots_replaced_by_underscores>
For example, a rule with ref python_example.count_and_log stores its counter at:
python_example.counter.python_example_count_and_log
Event Payload
Each emitted event has this structure:
{
"counter": 42,
"rule_ref": "python_example.count_and_log",
"sensor_ref": "python_example.counter_sensor",
"fired_at": "2025-01-15T12:00:00.000000+00:00"
}
Rule Parameter Mapping
The included count_and_log rule maps trigger payload fields to action parameters:
action_params:
counter: "{{ trigger.payload.counter }}"
rule_ref: "{{ trigger.payload.rule_ref }}"
The read_counter action then returns:
{
"message": "Counter value is 42 (from rule: python_example.count_and_log)",
"counter": 42,
"rule_ref": "python_example.count_and_log"
}
Testing Individual Components
Test the hello action
attune action execute python_example.hello
# Output: {"message": "Hello, Python"}
Test the HTTP action
attune action execute python_example.http_example
# Output: {"status_code": 200, "url": "https://example.com", ...}
Test the read_counter action directly
attune action execute python_example.read_counter --param counter=99 --param rule_ref=test
# Output: {"message": "Counter value is 99 (from rule: test)", ...}
Enable the rule to start the counter sensor loop
# The rule is enabled by default when the pack is loaded.
# To manually enable/disable:
attune rule enable python_example.count_and_log
attune rule disable python_example.count_and_log
# Monitor executions produced by the rule:
attune execution list --action python_example.read_counter
Configuration
The pack supports the following configuration in pack.yaml:
| Setting | Default | Description |
|---|---|---|
counter_key_prefix |
python_example.counter |
Prefix for keystore keys |
The sensor supports these parameters:
| Parameter | Default | Description |
|---|---|---|
default_interval_seconds |
1 |
Default tick interval per rule |
key_prefix |
python_example.counter |
Keystore key prefix |
The trigger supports per-rule configuration:
| Parameter | Default | Description |
|---|---|---|
interval_seconds |
1 |
Seconds between counter ticks |
Development
# Run the sensor manually for testing
export ATTUNE_API_URL=http://localhost:8080
export ATTUNE_API_TOKEN=<your-token>
export ATTUNE_MQ_URL=amqp://guest:guest@localhost:5672/
python3 sensors/counter_sensor.py
# Run an action manually
echo '{"parameters": {"name": "World"}}' | python3 actions/hello.py
License
MIT