Cookwala / SDK and scenarios / 006

List the demo devices, the operation vocabulary and the recipes a hub can plan

Three catalog calls give you everything a dry run works with: capability documents by id, the fifty-seven operations with their envelopes and sensor ladders, and the recipe ids the hub holds.

Audience: developer · Goal: Robots for people · Level: beginner

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

Steps

  1. Six capability documents: the example arm and the five presets of the home-page demo. getDevices

  2. The operation vocabulary. Deep frying has a one-rung ladder; simmering is water at 85 to 96 degC. getOps

  3. The nine example recipes, sorted by id. listRecipes

Outcome

You can look up any operation envelope by index or id and any device by its file name. Next: scenario 009 asks the sensor ladder which rung a device can satisfy.

Command line

curl -s http://localhost:7878/v1/tools/devices
curl -s http://localhost:7878/v1/tools/vocab/ops
curl -s http://localhost:7878/v1/tools/recipes

Recorded output

Status: ok

[1] getDevices: {"devices": {"demo-arm": {"cookwala": "0.1.0", "actor": {"kind": "robot", "id": "demo:arm", "vendor": "Cookwala demo presets", "model": "Counter robot arm (cuts, cracks, mixes, moves)"}, "roles": ["executor"], "location": {"zone": "kitchen", "mobile": false}, "capabilities": {"ops": [{"op": "cw.op.cut"}, {"op": "cw.op.crack"}, {"op": "cw.op.transfer"}, {"op": "cw.op.mix"}, {"op": "cw.op.whisk"}, {"op": "cw.op.wash"}, {"op": "cw.op.drain"}, {"op": "cw.op.crush"}, {"op": "cw.op.grate"}, {"op": "cw.op.layer"}, {"op": "cw.op.garnish"}, {"op": "cw.op.form"}], "sensors": [{"sensor": "cw.sense.vision…
[2] getOps: {"name": "ops", "version": "0.2.0", "entries": [{"id": "cw.op.dispense", "label": {"en": "Dispense / measure", "ar": "قياس وإضافة"}, "definition": "Measure an ingredient by mass, volume or count and add it to a target.", "classes": ["cw.opfamily.handle"], "paramsSchema": {"type": "object", "properties": {"precision": {"type": "number"}}}, "sensors": ["cw.sense.mass"], "links": {"ieee1872": "IEEE 1872.1-2024 Task (to be mapped)"}}, {"id": "cw.op.transfer", "label": {"en": "Transfer", "ar": "نقل"}, "definition": "Move food or a vessel's contents from one place to another.", "classes": ["cw.opfam…
[3] listRecipes: {"recipes": ["basbousa", "ful-medames", "kofta-oven", "koshari", "lentil-soup", "molokhia", "rice-vermicelli", "salata-baladi", "shakshuka"]}

Code

Run: python scenarios/out/006-list-devices-and-ops/python.py

# Scenario 006: List the demo devices, the operation vocabulary and the recipes a hub can plan
# Three catalog calls give you everything a dry run works with: capability documents by id, the fifty-seven operations with their envelopes and sensor ladders, and the recipe ids the hub holds.
# 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: Six capability documents: the example arm and the five presets of the home-page demo.
devices = c.get_devices()
assert pick(devices, "devices.demo-oven.actor.kind") == "appliance", pick(devices, "devices.demo-oven.actor.kind")
print("ok", "devices.demo-oven.actor.kind", "=", "appliance")
assert pick(devices, "devices.robot-arm.capabilities.ops.length") == 3, pick(devices, "devices.robot-arm.capabilities.ops.length")
print("ok", "devices.robot-arm.capabilities.ops.length", "=", 3)
assert pick(devices, "devices.demo-fryer-robot.capabilities.sensors.length") == 6, pick(devices, "devices.demo-fryer-robot.capabilities.sensors.length")
print("ok", "devices.demo-fryer-robot.capabilities.sensors.length", "=", 6)
assert pick(devices, "devices.demo-hob-robot-basic.capabilities.sensors.length") == 1, pick(devices, "devices.demo-hob-robot-basic.capabilities.sensors.length")
print("ok", "devices.demo-hob-robot-basic.capabilities.sensors.length", "=", 1)

# Step 2: The operation vocabulary. Deep frying has a one-rung ladder; simmering is water at 85 to 96 degC.
ops = c.get_ops()
assert pick(ops, "name") == "ops", pick(ops, "name")
print("ok", "name", "=", "ops")
assert pick(ops, "version") == "0.2.0", pick(ops, "version")
print("ok", "version", "=", "0.2.0")
assert pick(ops, "entries.length") == 57, pick(ops, "entries.length")
print("ok", "entries.length", "=", 57)
assert pick(ops, "entries[30].id") == "cw.op.deep_fry", pick(ops, "entries[30].id")
print("ok", "entries[30].id", "=", "cw.op.deep_fry")
assert pick(ops, "entries[30].envelope.sensorLadder.length") == 1, pick(ops, "entries[30].envelope.sensorLadder.length")
print("ok", "entries[30].envelope.sensorLadder.length", "=", 1)
assert pick(ops, "entries[32].id") == "cw.op.simmer", pick(ops, "entries[32].id")
print("ok", "entries[32].id", "=", "cw.op.simmer")
assert pick(ops, "entries[32].envelope.tempC.min") == 85, pick(ops, "entries[32].envelope.tempC.min")
print("ok", "entries[32].envelope.tempC.min", "=", 85)
assert pick(ops, "entries[32].envelope.tempC.max") == 96, pick(ops, "entries[32].envelope.tempC.max")
print("ok", "entries[32].envelope.tempC.max", "=", 96)

# Step 3: The nine example recipes, sorted by id.
recipes = c.list_recipes()
assert pick(recipes, "recipes.length") == 9, pick(recipes, "recipes.length")
print("ok", "recipes.length", "=", 9)
assert pick(recipes, "recipes[0]") == "basbousa", pick(recipes, "recipes[0]")
print("ok", "recipes[0]", "=", "basbousa")
assert pick(recipes, "recipes[8]") == "shakshuka", pick(recipes, "recipes[8]")
print("ok", "recipes[8]", "=", "shakshuka")

print("scenario complete")

scenarios/006-list-devices-and-ops.json

Previous: 005 Next: 007