# Onboard Discovered Devices

import { Badge } from "zudoku/ui/Badge";

<div className="flex flex-wrap gap-2 not-prose mb-4">
  <Badge variant="outline">Inventory</Badge>
  <Badge variant="secondary" className="font-mono text-xs">
    GET /v1/discoveredDevices
  </Badge>
  <Badge variant="secondary" className="font-mono text-xs">
    POST /v1/tasks
  </Badge>
</div>

Onboard the discovered devices that are ready to onboard, and track the task to completion.

:::tip

You can adjust the script to your needs. Change the conditions, variables, and values to
produce the output you want.

:::

<Recipe
  language={["python", "javascript"]}
  steps={[
    {
      title: "Set up the request",
      body: "Use the access token returned by the [Authenticate](/recipes/authentication) recipe.",
      code: {
        python:
          'import json\nimport time\n\nimport requests\n\nBASE = "https://api.securithings.com"\nheaders = {"Authorization": f"Bearer {access_token}"}',
        javascript:
          'const BASE = "https://api.securithings.com";\nconst headers = {\n  Authorization: `Bearer ${accessToken}`,\n};\nconst sleep = (ms) =>\n  new Promise((resolve) => setTimeout(resolve, ms));',
      },
    },
    {
      title: "Select target devices",
      body: "Filter discovered devices on `onboardingStatus`.",
      code: {
        python:
          'discovered = requests.get(\n    f"{BASE}/v1/discoveredDevices",\n    params={\n        "onboardingStatus": "readyToOnboard",\n        "limit": 100,\n    },\n    headers=headers,\n).json()["discoveredDevices"]\n\ntargets = [device["id"] for device in discovered]',
        javascript:
          'const query = new URLSearchParams({\n  onboardingStatus: "readyToOnboard",\n  limit: "100",\n});\nconst discoveredResponse = await fetch(\n  `${BASE}/v1/discoveredDevices?${query}`,\n  { headers },\n);\nconst discovered = await discoveredResponse.json();\n\nconst targets = discovered.discoveredDevices.map(\n  (device) => device.id,\n);',
      },
    },
    {
      title: "Execute the task",
      body: "`onboardDevice` requires no configuration, so no payload is sent.",
      code: {
        python:
          'response = requests.post(\n    f"{BASE}/v1/tasks",\n    json={\n        "taskType": "onboardDevice",\n        "devices": [\n            {"deviceId": device_id}\n            for device_id in targets\n        ],\n    },\n    headers=headers,\n)\ntask_id = response.json()["taskId"]',
        javascript:
          'const taskResponse = await fetch(`${BASE}/v1/tasks`, {\n  method: "POST",\n  headers: {\n    ...headers,\n    "Content-Type": "application/json",\n  },\n  body: JSON.stringify({\n    taskType: "onboardDevice",\n    devices: targets.map((deviceId) => ({\n      deviceId,\n    })),\n  }),\n});\nconst { taskId } = await taskResponse.json();',
      },
    },
    {
      title: "Poll for completion",
      body: "The task is done once every device task reaches `completed`.",
      code: {
        python:
          'while True:\n    task = requests.get(\n        f"{BASE}/v1/tasks/{task_id}",\n        headers=headers,\n    ).json()\n    pending = [\n        device_task\n        for device_task in task["deviceTasks"]\n        if device_task["status"] != "completed"\n    ]\n    if not pending:\n        break\n    time.sleep(30)',
        javascript:
          'let task;\nwhile (true) {\n  const statusResponse = await fetch(\n    `${BASE}/v1/tasks/${taskId}`,\n    { headers },\n  );\n  task = await statusResponse.json();\n  const pending = task.deviceTasks.filter(\n    (deviceTask) => deviceTask.status !== "completed",\n  );\n  if (pending.length === 0) break;\n  await sleep(30000);\n}',
      },
    },
    {
      title: "Build the result",
      body: "A device task is `completed` whether or not it succeeded, so read `result`.",
      code: {
        python:
          'result = {\n    "taskId": task_id,\n    "succeeded": [\n        {\n            "deviceId": device_task["deviceId"],\n            "deviceName": device_task["deviceName"],\n        }\n        for device_task in task["deviceTasks"]\n        if device_task["result"] == "succeeded"\n    ],\n    "failed": [\n        {\n            "deviceId": device_task["deviceId"],\n            "deviceName": device_task["deviceName"],\n            "result": device_task["result"],\n        }\n        for device_task in task["deviceTasks"]\n        if device_task["result"] != "succeeded"\n    ],\n}\n\nprint(json.dumps(result, indent=2))',
        javascript:
          'const succeeded = [];\nconst failed = [];\n\nfor (const deviceTask of task.deviceTasks) {\n  const entry = {\n    deviceId: deviceTask.deviceId,\n    deviceName: deviceTask.deviceName,\n  };\n  if (deviceTask.result === "succeeded") {\n    succeeded.push(entry);\n  } else {\n    failed.push({\n      ...entry,\n      result: deviceTask.result,\n    });\n  }\n}\n\nconst result = { taskId, succeeded, failed };\n\nconsole.log(JSON.stringify(result, null, 2));',
      },
    },
  ]}
  response={`{
  "taskId": "23bpozz1mpjjedtr",
  "succeeded": [
    {
      "deviceId": "9ff559ee-38b6-11f1-81cb-465864a35d0a",
      "deviceName": "Lobby camera 12"
    }
  ],
  "failed": [
    {
      "deviceId": "dc7d4ef1-6bf9-11f1-b083-d27bafcacdf8",
      "deviceName": "Lobby camera 13",
      "result": "failed"
    }
  ]
}`}
/>
