Skip to main content

Direct Methods

Direct methods let you invoke commands on connected devices in real time. The cloud sends a request, the device executes the command, and returns a response — all within a configurable timeout.

How It Works

Direct methods use a request-response pattern over MQTT with correlation IDs to match responses to requests:

┌────────────┐                           ┌────────────┐
│ Cloud │ │ Device │
│ (API) │ │ │
└─────┬──────┘ └─────┬──────┘
│ │
│ 1. POST /assets/{id}/commands/reboot │
│─────────────────────────┐ │
│ ▼ │
│ ┌──────────────────┐ │
│ │ MQTT Provider │ │
│ │ (generates │ │
│ │ correlationId) │ │
│ └────────┬─────────┘ │
│ │ │
│ 2. Publish to: │ │
│ devices/{id}/methods/reboot/invoke │
│ │───────────────>│
│ │ │
│ │ 3. Device │
│ │ executes │
│ │ │
│ 4. Publish to: │ │
│ devices/{id}/methods/reboot/response/{correlationId}
│ │<───────────────│
│ │ │
│ 5. Response │ │
│<──────────────────────┘ │
│ │

Invoking a Method (Cloud Side)

Methods are invoked through the Beacon Tower asset API:

curl -X POST https://api.beacontower.ai/assets/temp-sensor-001/commands/reboot \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"timeout": 30
}'

The timeout parameter (in seconds, default 30) controls how long the platform waits for a device response before returning an error.

Handling Methods (Device Side)

Subscribe to Method Invocations

The device subscribes to its method invocation topic using a wildcard:

devices/{deviceId}/methods/+/invoke    (QoS 1)

The + wildcard matches any method name, so the device receives all method invocations on a single subscription.

Invocation Payload

When a method is invoked, the device receives a message on devices/{deviceId}/methods/{methodName}/invoke:

{
"correlationId": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"responseTopic": "devices/temp-sensor-001/methods/reboot/response/a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"payload": {
"force": true
}
}
FieldDescription
correlationIdUnique ID for this invocation — must be included in the response
responseTopicThe exact topic to publish the response to
payloadThe command payload from the caller (may be null)

Publishing the Response

After executing the command, the device publishes the result to the responseTopic:

devices/{deviceId}/methods/{methodName}/response/{correlationId}    (QoS 1)

The response payload is any JSON value:

{
"status": "ok",
"uptime_before_reboot": 86400
}

Complete Device-Side Example

import paho.mqtt.client as mqtt
import json

DEVICE_ID = "temp-sensor-001"

def on_message(client, userdata, msg):
# Parse method name from topic
# Topic format: devices/{id}/methods/{name}/invoke
parts = msg.topic.split("/")
method_name = parts[3]

invocation = json.loads(msg.payload)
correlation_id = invocation["correlationId"]
response_topic = invocation["responseTopic"]
payload = invocation.get("payload")

# Execute the method
if method_name == "reboot":
result = {"status": "ok", "message": "Rebooting in 5 seconds"}
elif method_name == "get_diagnostics":
result = {"cpu_usage": 45.2, "memory_free": 1024}
else:
result = {"status": "error", "message": f"Unknown method: {method_name}"}

# Publish response
client.publish(response_topic, json.dumps(result), qos=1)

client = mqtt.Client(client_id=DEVICE_ID)
client.username_pw_set(DEVICE_ID, "device-primary-key")
client.on_message = on_message
client.connect("mqtt.example.com", 1883)

# Subscribe to all method invocations
client.subscribe(f"devices/{DEVICE_ID}/methods/+/invoke", qos=1)
client.loop_forever()

Timeouts and Errors

Timeout

If the device does not respond within the configured timeout (default 30 seconds), the caller receives:

{
"error": "MethodTimeout",
"message": "Device did not respond within the timeout period"
}

Device Offline

If the device is not connected to the broker when the method is invoked, the message is not retained (MQTT does not retain QoS 1 messages by default). The method will time out.

Error Handling

Any exception during method processing on the provider side returns an error response to the caller:

{
"error": "InternalError",
"message": "Description of what went wrong"
}

Supported Methods

Direct methods are not predefined — any method name is valid. The method name is simply the string in the topic path. It is up to the device firmware to recognize and handle the methods it supports.

Common patterns:

MethodTypical Purpose
rebootRestart the device
get_diagnosticsReturn diagnostic information
set_configApply configuration changes
update_firmwareTrigger firmware update
pingConnectivity check

Next Steps