{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# What to do if the raspberry Pi manufacturing process goes bad\n",
    "\n",
    "Shows an example of an API that can be called by the raspberry pi if something goes wrong during the manufacturing process.\n",
    "\n",
    "This example assumes there are jobs available in the \"AwaitingManufacture\" state."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from dotenv import dotenv_values\n",
    "config = dotenv_values(\".test.env\")\n",
    "\n",
    "# The auth server is used for authentication and account management\n",
    "authApiUrl = config['BIGSCREEN_API_URL']\n",
    "\n",
    "# The admin server has the fabricator endpoints\n",
    "adminApiUrl = config['BIGSCREEN_ADMIN_API_URL']\n",
    "\n",
    "# Each http request needs a bearer token. This is a revokable token which is assigned to each external application that\n",
    "# uses the Bigscreen APIs (e.g. this script is an external application).\n",
    "apiBearerToken = config['BIGSCREEN_API_KEY']\n",
    "\n",
    "cncApiBearerToken = config['BIGSCREEN_CNC_API_KEY']\n",
    "\n",
    "# Finally, we need an account.  The account is necessary for us to identify who is using the various APIs. The account \n",
    "# must have access to the \"Fabricator\" endpoints to work.\n",
    "email = config['ADMIN_ACCOUNT_EMAIL']\n",
    "password = config['ADMIN_ACCOUNT_PASSWORD']"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Login the CNC user"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import requests\n",
    "\n",
    "# CNC machine account\n",
    "payload = {\n",
    "    \"email\": \"qa+cnc@bigscreenvr.com\",\n",
    "    \"password\": \"TQDnMGe2tod26B2JgeWBi3W86oPkph9H\",\n",
    "}\n",
    "\n",
    "headers = {\n",
    "    \"Content-Type\": \"application/json\",\n",
    "    \"Authorization\": f\"Bearer {apiBearerToken}\"\n",
    "}\n",
    "\n",
    "cncUser = {\n",
    "    \"refreshToken\": \"\",\n",
    "    \"accessToken\": \"\"\n",
    "}\n",
    "\n",
    "r = requests.post(f\"{authApiUrl}/auth/login\", headers=headers, json=payload)\n",
    "assert r.status_code == 200, f\"status code should be 200 (actual: {r.status_code})\"\n",
    "cncUser[\"refreshToken\"] = r.headers[\"x-refresh-token\"]\n",
    "cncUser[\"accessToken\"] = r.headers[\"x-access-token\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# You may need to run this on Jupyter\n",
    "# !pip install requests\n",
    "\n",
    "import requests\n",
    "\n",
    "headers = {\n",
    "    \"Content-Type\": \"application/json\",\n",
    "    \"Authorization\": f\"Bearer {apiBearerToken}\"\n",
    "}\n",
    "\n",
    "payload = {\n",
    "    \"email\": email,\n",
    "    \"password\": password\n",
    "}\n",
    "\n",
    "r = requests.post(f\"{authApiUrl}/auth/login\", headers=headers, json=payload)\n",
    "print(r.status_code)\n",
    "refreshToken = r.headers[\"x-refresh-token\"]\n",
    "accessToken = r.headers[\"x-access-token\"]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def getAdminHeaders():\n",
    "    return {\n",
    "        \"Content-Type\": \"application/json\",\n",
    "        \"Authorization\": f\"Bearer {apiBearerToken}\",\n",
    "        \"x-access-token\": accessToken\n",
    "    }\n",
    "    \n",
    "r = requests.get(f\"{authApiUrl}/auth/verify\", headers=getAdminHeaders())\n",
    "r.status_code"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from enum import Enum\n",
    "\n",
    "r = requests.get(f\"{adminApiUrl}/admin/fabricator/schemas\", headers=getAdminHeaders())\n",
    "assert r.status_code == 200, f\"status code should be 200 (actual: {r.status_code})\"\n",
    "\n",
    "schemas = r.json()\n",
    "JobStates = Enum(\"JobStates\", dict([(v, int(k)) for k, v in schemas[\"JobStates\"].items()]))\n",
    "JobActions = Enum(\"JobActions\", dict([(v, int(k)) for k, v in schemas[\"JobActions\"].items()]))\n",
    "\n",
    "JobActions, JobStates"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Get the next available toolpath:"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def getCncAdminHeaders():\n",
    "    return {\n",
    "        \"Content-Type\": \"application/json\",\n",
    "        \"Authorization\": f\"Bearer {apiBearerToken}\",\n",
    "        \"x-access-token\": cncUser[\"accessToken\"]\n",
    "    }\n",
    "\n",
    "r = requests.get(f\"{adminApiUrl}/cnc\", headers=getCncAdminHeaders())\n",
    "assert r.status_code == 200, f\"status code should be 200 (actual: {r.status_code})\""
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "payload = {\n",
    "    \"metaData\": {\n",
    "        \"machineId\": \"python_notebook\",\n",
    "    }\n",
    "}\n",
    "\n",
    "r = requests.put(f\"{adminApiUrl}/cnc/next\", headers=getCncAdminHeaders(), json=payload)\n",
    "assert r.status_code == 200, f\"status code should be 200 (actual: {r.status_code})\"\n",
    "\n",
    "data = r.json()\n",
    "cncId = data[\"id\"]\n",
    "toolPathData = data[\"toolPathData\"]\n",
    "print(cncId)"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "If manufacturing failed, the CNC user can send an action and additional meta data back to the servers."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "payload = {\n",
    "    \"action\" : JobActions.ManufacturingFailed.value,\n",
    "    \"metaData\": {\n",
    "        \"machineId\": \"python_notebook\"\n",
    "    }\n",
    "}\n",
    "\n",
    "r = requests.put(f\"{adminApiUrl}/cnc/{cncId}\", headers=getCncAdminHeaders(), json=payload)\n",
    "assert r.status_code == 200, f\"status code should be 200 (actual: {r.status_code})\""
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "After this, the job can be reset by the fabricator admin to prep it for another CNC attempt. \n",
    "\n",
    "After this, the job will be put back into the queue again.\n",
    "\n",
    "This step should be completed on the `fabricator` web app."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "query = {\n",
    "    \"state\": JobStates.ManufacturingFailed.value\n",
    "}\n",
    "\n",
    "r = requests.post(f\"{adminApiUrl}/admin/fabricator/jobs\", headers=getAdminHeaders(), json=query)\n",
    "assert r.status_code == 200, f\"status code should be 200 (actual: {r.status_code})\"\n",
    "\n",
    "jobs = r.json().get(\"jobs\", [])\n",
    "jobId = jobs[0][\"id\"]\n",
    "\n",
    "payload = { \"action\": JobActions.ResetManufacturing.value }\n",
    "r = requests.put(f\"{adminApiUrl}/admin/fabricator/job/{jobId}\", headers=getAdminHeaders(), json=payload)\n",
    "assert r.status_code == 200, f\"status code should be 200 (actual: {r.status_code})\""
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.10.11"
  },
  "orig_nbformat": 4,
  "vscode": {
   "interpreter": {
    "hash": "369f2c481f4da34e4445cda3fffd2e751bd1c4d706f27375911949ba6bb62e1c"
   }
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
