Cookwala / SDK and scenarios / 005

Read what a device says about itself: capabilities, safety limits, conformance, recalls

The four GET endpoints of the Core API answer before any cooking: what the device can do, which limits it enforces locally, what it claims to conform to, and which recipe revisions are recalled.

Audience: appliance maker · Goal: Robots for people · Level: beginner

Read first: /docs/CORE/ /docs/QUICKSTART/

Steps

  1. The reference hub simulates the example robot arm: three operations and one vision sensor. capabilities

  2. The draft default limits pack: fourteen limits, the first one cuts heat when frying oil passes 200 degC. safetyLimits

  3. The hub declares the executor class itself; it has no third-party report, and says so. conformance

  4. No recall is in force for the hub. recalls

Outcome

You know the shape of a capability document and a SafetyLimits pack, and that the disclaimer in the pack asks makers to replace it with limits from their own safety case. Next: scenario 006 lists the demo devices and the operation vocabulary.

Command line

curl -s http://localhost:7878/v1/capabilities
curl -s http://localhost:7878/v1/safety-limits
curl -s http://localhost:7878/v1/conformance
curl -s http://localhost:7878/v1/recalls

Recorded output

Status: ok

[1] capabilities: {"cookwala": "0.1.0", "actor": {"kind": "robot", "id": "robot:arm-1", "vendor": "Example Robotics", "model": "CounterArm 2"}, "roles": ["executor"], "location": {"zone": "counter-left", "mobile": false}, "capabilities": {"ops": [{"op": "cw.op.cut", "params": {"shape": ["dice", "slice", "mince", "julienne"]}, "ingredientClasses": ["cw.ing.class.vegetable_firm", "cw.ing.class.herb"], "reliability": 0.97}, {"op": "cw.op.crack", "reliability": 0.95}, {"op": "cw.op.transfer", "maxMassG": 3000}], "sensors": [{"sensor": "cw.sense.vision", "visionCues": ["cw.sense.translucent", "cw.sense.egg_whites_se…
[2] safetyLimits: {"core": "0.2.0", "kind": "SafetyLimits", "id": "cookwala-default", "version": "0.2.0", "status": "draft", "limits": [{"id": "oil.max_temp", "kind": "max_temp", "action": "cut_heat", "message": "Cut heat above 200 °C: most cooking oils smoke and fire risk rises.", "source": "Common frying-oil smoke points; fire-safety practice", "appliesTo": {"medium": "oil", "ops": ["cw.op.fry", "cw.op.deep_fry"]}, "max": 200, "unit": "degC"}, {"id": "pan.max_surface", "kind": "max_temp", "action": "cut_heat", "message": "Cut heat above 280 °C pan surface (coatings degrade, oil ignites).", "source": "Cookware…
[3] conformance: {"claims": ["executor"], "report": null, "note": "reference hub, self-declared; run tools/run_conformance.py --report"}
[4] recalls: []

Code

Run: python scenarios/out/005-read-capabilities-and-safety-limits/python.py

# Scenario 005: Read what a device says about itself: capabilities, safety limits, conformance, recalls
# The four GET endpoints of the Core API answer before any cooking: what the device can do, which limits it enforces locally, what it claims to conform to, and which recipe revisions are recalled.
# Run a hub first: python hub/cookwala_hub.py --recipes examples
import json, os
from cookwala.client import CookwalaClient, CookwalaProblem

def load(path):
    with open(path, encoding="utf-8") as f:
        return json.load(f)

def pick(obj, path):
    for part in path.replace("]", "").replace("[", ".").split("."):
        obj = obj[int(part)] if part.isdigit() else (len(obj) if part == "length" else obj.get(part))
    return obj

c = CookwalaClient(os.environ.get("COOKWALA_HUB", "http://localhost:7878"))


# Step 1: The reference hub simulates the example robot arm: three operations and one vision sensor.
caps = c.capabilities()
assert pick(caps, "actor.id") == "robot:arm-1", pick(caps, "actor.id")
print("ok", "actor.id", "=", "robot:arm-1")
assert pick(caps, "actor.kind") == "robot", pick(caps, "actor.kind")
print("ok", "actor.kind", "=", "robot")
assert pick(caps, "roles[0]") == "executor", pick(caps, "roles[0]")
print("ok", "roles[0]", "=", "executor")
assert pick(caps, "capabilities.ops.length") == 3, pick(caps, "capabilities.ops.length")
print("ok", "capabilities.ops.length", "=", 3)
assert pick(caps, "capabilities.sensors.length") == 1, pick(caps, "capabilities.sensors.length")
print("ok", "capabilities.sensors.length", "=", 1)

# Step 2: The draft default limits pack: fourteen limits, the first one cuts heat when frying oil passes 200 degC.
limits = c.safety_limits()
assert pick(limits, "id") == "cookwala-default", pick(limits, "id")
print("ok", "id", "=", "cookwala-default")
assert pick(limits, "status") == "draft", pick(limits, "status")
print("ok", "status", "=", "draft")
assert pick(limits, "limits.length") == 14, pick(limits, "limits.length")
print("ok", "limits.length", "=", 14)
assert pick(limits, "limits[0].id") == "oil.max_temp", pick(limits, "limits[0].id")
print("ok", "limits[0].id", "=", "oil.max_temp")
assert pick(limits, "limits[0].max") == 200, pick(limits, "limits[0].max")
print("ok", "limits[0].max", "=", 200)
assert pick(limits, "limits[0].action") == "cut_heat", pick(limits, "limits[0].action")
print("ok", "limits[0].action", "=", "cut_heat")

# Step 3: The hub declares the executor class itself; it has no third-party report, and says so.
conf = c.conformance()
assert pick(conf, "claims[0]") == "executor", pick(conf, "claims[0]")
print("ok", "claims[0]", "=", "executor")
assert pick(conf, "report") == None, pick(conf, "report")
print("ok", "report", "=", None)

# Step 4: No recall is in force for the hub.
recalls = c.recalls()
assert pick(recalls, "length") == 0, pick(recalls, "length")
print("ok", "length", "=", 0)

print("scenario complete")

scenarios/005-read-capabilities-and-safety-limits.json

Previous: 004 Next: 006