Toolkeez (1)

Download OpenAPI specification:

Serveur Toolkeez : broker MQTT 3.1.1 (port 1883, ou 8883 en TLS) + API HTTP locale (port 3443) pour piloter des modules ESP32 — sorties GPIO, émission Wiegand vers un lecteur de badge, et pont BLE central vers un équipement tiers (FAMA). La plupart des commandes sont publiées vers le module via MQTT ; le module applique la commande puis accuse réception (ACK binaire pour GPIO/Wiegand, ble/result JSON pour BLE).

Réponse HTTP 202 = publication seule. Toutes les routes de commande (PUT .../gpios/:gpio, POST .../wiegand/emit, POST .../ble/*) renvoient 202 dès que la commande est publiée sur MQTT — pas quand elle est réellement appliquée par le module. Suivre GET /api/commands/{commandId} (ou le flux SSE pour les notifications BLE) pour connaître le résultat réel.

⚠️ Le serveur écoute en HTTP en clair sur HTTP_PORT : le TLS public est terminé par nginx (deploy/nginx/toolkeez.conf), qui reparle en clair avec ce backend en local. Ne jamais exposer HTTP_PORT directement sans ce proxy — la clé API circule en clair (Bearer token, pas de mTLS).

Enveloppe binaire (GPIO / ACK / Wiegand)

Les payloads MQTT pour GPIO/ACK/Wiegand (pas BLE, en JSON) sont des buffers binaires bruts — jamais du JSON ni de l'hexadécimal texte — avec un en-tête commun de 40 octets (magic TK, version, type, flags, taille payload, séquence, timestamp, UUID de message). Détail complet octet par octet : PROTOCOL.md, codec de référence : src/protocol.js.

Déploiement FAMA (module → FAMA)

Sur ce déploiement, un module Toolkeez pilote 3 sorties GPIO reliées au FAMA. Binding fixé au niveau applicatif (pas dans le protocole Toolkeez lui-même — n'importe quel GPIO 0-255 reste utilisable), propriété de l'agent hopper pour les tests e2e (agents/hopper/tools/toolkeez/) :

Action GPIO Effet métier
USE 6 Passer le FAMA en mode "use"
SHUNT 5 Shunter le FAMA
WORKING 4 Passer le FAMA en mode "working"

Les 3 pins ne sont pas mutuellement exclusifs côté API : un scénario qui a besoin d'un seul état actif à la fois doit explicitement éteindre les autres pins avant/après. CLI internalisée : node agents/hopper/tools/toolkeez/toolkeez-cli.js action use on.

Système

Vérification de vie, sans authentification.

Vérification de vie

Nombre de clients MQTT connectés, uptime. Sans authentification.

Responses

Response samples

Content type
application/json
{
  • "status": "ok",
  • "secure": false,
  • "mqttClients": 1,
  • "uptimeSeconds": 165243
}

GPIO

Consigne persistante et retenue côté broker (QoS 1, retain: true) : acceptée même si le module est hors ligne, transmise automatiquement à sa prochaine connexion.

Lister les modules connus

Modules connectés ou déjà vus. État conservé uniquement en mémoire — redémarrer le serveur efface la liste. desiredState = dernière consigne envoyée par gpio · state = dernier état confirmé par le module (peut différer temporairement de desiredState pendant la propagation).

Authorizations:
bearerAuth

Responses

Response samples

Content type
application/json
[
  • {
    }
]

Détail d'un module

Authorizations:
bearerAuth
path Parameters
deviceId
required
string^[A-Za-z0-9_-]{1,64}$
Example: TK-001

Responses

Response samples

Content type
application/json
{
  • "deviceId": "TK-001",
  • "clientId": "toolkeez-TK-001",
  • "connected": true,
  • "connectedAt": "2019-08-24T14:15:22Z",
  • "disconnectedAt": "2019-08-24T14:15:22Z",
  • "lastSeenAt": "2019-08-24T14:15:22Z",
  • "status": {
    },
  • "desiredState": {
    },
  • "state": {
    },
  • "lastAck": {
    }
}

Publier une consigne GPIO ON/OFF

La consigne est persistante et retenue côté broker (QoS 1, retain: true) : acceptée même si le module est hors ligne, transmise automatiquement à sa prochaine connexion.

Authorizations:
bearerAuth
path Parameters
deviceId
required
string^[A-Za-z0-9_-]{1,64}$
Example: TK-001
gpio
required
integer [ 0 .. 255 ]
Request Body schema: application/json
required
required
string or boolean

"on" / "off" / true / false

Responses

Request samples

Content type
application/json
{
  • "state": "on"
}

Response samples

Content type
application/json
{
  • "protocolVersion": 1,
  • "commandId": "af774cbc-df78-4e79-9be1-f0d761b5753b",
  • "type": "gpio.set",
  • "deviceId": "TK-001",
  • "gpio": 4,
  • "state": "on",
  • "sequence": 43,
  • "issuedAt": "2026-09-15T09:46:44.988Z",
  • "status": "published",
  • "acknowledgedAt": null
}

Suivre l'exécution réelle d'une commande

Suit l'exécution d'une commande émise par n'importe laquelle des routes de ce document (GPIO, Wiegand, BLE). status passe de "published" à un statut d'ACK (GPIO/Wiegand) ou "completed"/"failed" (BLE, voir ble/result) une fois le module répondu. Les commandes sont purgées automatiquement 1h après émission.

Authorizations:
bearerAuth
path Parameters
commandId
required
string <uuid>

Responses

Response samples

Content type
application/json
{
  • "commandId": "af774cbc-df78-4e79-9be1-f0d761b5753b",
  • "deviceId": "TK-001",
  • "gpio": 4,
  • "state": "on",
  • "status": "applied",
  • "acknowledgedAt": "2026-09-15T09:46:45.201Z",
  • "ack": {
    }
}

Wiegand

Émission ponctuelle d'une trame Wiegand vers un lecteur de badge piloté par le module. Non persistante : contrairement au GPIO, si le module est hors ligne au moment de l'appel, la commande n'est pas rejouée à sa prochaine connexion (retain: false).

Émettre une trame Wiegand

Authorizations:
bearerAuth
path Parameters
deviceId
required
string^[A-Za-z0-9_-]{1,64}$
Example: TK-001
Request Body schema: application/json
required
format
integer
Default: 26
Enum: 26 36

26 = HID 26-bit, 36 = brut 36-bit

facilityCode
integer [ 0 .. 255 ]

Requis si format=26, ignoré sinon

cardNumber
required
integer

0..65535 si format=26, 0..68719476735 (36 bits) si format=36

Responses

Request samples

Content type
application/json
Example
{
  • "facilityCode": 12,
  • "cardNumber": 34567
}

Response samples

Content type
application/json
{
  • "protocolVersion": 1,
  • "commandId": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
  • "type": "wiegand.emit",
  • "deviceId": "TK-001",
  • "format": 26,
  • "facilityCode": 12,
  • "cardNumber": 34567,
  • "sequence": 7,
  • "issuedAt": "2026-09-15T09:50:00.000Z",
  • "status": "published",
  • "acknowledgedAt": null
}

BLE

Contrairement à GPIO/Wiegand, ce canal ne passe pas par l'enveloppe binaire — commandes et réponses en JSON brut, comme le channel status. Il pilote le rôle BLE central du module vers un équipement tiers qui expose un service GATT (le FAMA), sans configuration figée côté firmware : chaque commande transporte les UUID et valeurs cibles directement.

famaUid (UID 32 bits) est décodé par le module depuis les données constructeur (manufacturerData) de l'advertisement BLE de l'équipement — même layout que celui déjà décodé côté lhc-mobile/osha-list-mobile-app (ID constructeur Adveez, marqueur "ADV", octet de type, puis cet UID). Le module scanne en continu, décode les advertisements et se connecte au premier qui correspond s'il n'est pas déjà connecté, puis reste connecté en permanence — reconnexion automatique sauf après un ble/disconnect explicite.

Se connecter à l'équipement BLE (FAMA)

Authorizations:
bearerAuth
path Parameters
deviceId
required
string^[A-Za-z0-9_-]{1,64}$
Example: TK-001
Request Body schema: application/json
required
famaUid
required
integer <int64> [ 0 .. 4294967295 ]

UID 32 bits de l'équipement

password
required
string non-empty
connection_priority
integer
Enum: 0 1 2

0=balanced, 1=high, 2=low power (façon Android BluetoothGatt)

password_service_uuid
required
string (Uuid) ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]...
password_characteristic_uuid
required
string (Uuid) ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]...

Responses

Request samples

Content type
application/json
{
  • "famaUid": 305419896,
  • "password": "<secret>",
  • "connection_priority": 1,
  • "password_service_uuid": "ca340dd3-5e62-42d5-af47-8b4fd43b93e7",
  • "password_characteristic_uuid": "47182909-fb23-4324-a48e-37ba930d7911"
}

Response samples

Content type
application/json
{
  • "commandId": "9e2dd63c-3478-489f-86d3-8c292a65a0aa",
  • "type": "string",
  • "deviceId": "string",
  • "status": "string",
  • "issuedAt": "2019-08-24T14:15:22Z",
  • "acknowledgedAt": "2019-08-24T14:15:22Z"
}

Couper la liaison BLE en cours

Aucun champ requis. Termine la liaison BLE en cours et désactive la reconnexion automatique jusqu'au prochain ble/connect — utile pour laisser temporairement un autre appareil se connecter à l'équipement. Sans effet si rien n'est connecté (ble/result renvoie error: "ESP_ERR_INVALID_STATE").

Authorizations:
bearerAuth
path Parameters
deviceId
required
string^[A-Za-z0-9_-]{1,64}$
Example: TK-001

Responses

Response samples

Content type
application/json
{
  • "commandId": "9e2dd63c-3478-489f-86d3-8c292a65a0aa",
  • "type": "string",
  • "deviceId": "string",
  • "status": "string",
  • "issuedAt": "2019-08-24T14:15:22Z",
  • "acknowledgedAt": "2019-08-24T14:15:22Z"
}

Lire une caractéristique GATT

Résultat sur ble/resultvalue en hexadécimal si succès.

Authorizations:
bearerAuth
path Parameters
deviceId
required
string^[A-Za-z0-9_-]{1,64}$
Example: TK-001
Request Body schema: application/json
required
service_uuid
required
string (Uuid) ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]...
characteristic_uuid
required
string (Uuid) ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]...

Responses

Request samples

Content type
application/json
{
  • "service_uuid": "ca340dd3-5e62-42d5-af47-8b4fd43b93e7",
  • "characteristic_uuid": "ca340dd3-5e62-42d5-af47-8b4fd43b93e7"
}

Response samples

Content type
application/json
{
  • "commandId": "9e2dd63c-3478-489f-86d3-8c292a65a0aa",
  • "type": "string",
  • "deviceId": "string",
  • "status": "string",
  • "issuedAt": "2019-08-24T14:15:22Z",
  • "acknowledgedAt": "2019-08-24T14:15:22Z"
}

Écrire une caractéristique GATT

Authorizations:
bearerAuth
path Parameters
deviceId
required
string^[A-Za-z0-9_-]{1,64}$
Example: TK-001
Request Body schema: application/json
required
service_uuid
required
string (Uuid) ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]...
characteristic_uuid
required
string (Uuid) ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]...
value
required
string non-empty

Responses

Request samples

Content type
application/json
{
  • "service_uuid": "ca340dd3-5e62-42d5-af47-8b4fd43b93e7",
  • "characteristic_uuid": "ca340dd3-5e62-42d5-af47-8b4fd43b93e7",
  • "value": "string"
}

Response samples

Content type
application/json
{
  • "commandId": "9e2dd63c-3478-489f-86d3-8c292a65a0aa",
  • "type": "string",
  • "deviceId": "string",
  • "status": "string",
  • "issuedAt": "2019-08-24T14:15:22Z",
  • "acknowledgedAt": "2019-08-24T14:15:22Z"
}

S'abonner aux notifications d'une caractéristique

Active les notifications sur cette caractéristique (écriture du descripteur CCCD). Une seule souscription à la fois — une nouvelle commande remplace la précédente (désabonnement côté équipement avant réabonnement). Les valeurs notifiées arrivent en continu sur le flux SSE (GET .../ble/notifications/stream), indépendamment de cette commande ponctuelle.

Authorizations:
bearerAuth
path Parameters
deviceId
required
string^[A-Za-z0-9_-]{1,64}$
Example: TK-001
Request Body schema: application/json
required
service_uuid
required
string (Uuid) ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]...
characteristic_uuid
required
string (Uuid) ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]...

Responses

Request samples

Content type
application/json
{
  • "service_uuid": "ca340dd3-5e62-42d5-af47-8b4fd43b93e7",
  • "characteristic_uuid": "ca340dd3-5e62-42d5-af47-8b4fd43b93e7"
}

Response samples

Content type
application/json
{
  • "commandId": "9e2dd63c-3478-489f-86d3-8c292a65a0aa",
  • "type": "string",
  • "deviceId": "string",
  • "status": "string",
  • "issuedAt": "2019-08-24T14:15:22Z",
  • "acknowledgedAt": "2019-08-24T14:15:22Z"
}

Se désabonner des notifications

Aucun champ requis. Désactive la souscription en cours.

Authorizations:
bearerAuth
path Parameters
deviceId
required
string^[A-Za-z0-9_-]{1,64}$
Example: TK-001

Responses

Response samples

Content type
application/json
{
  • "commandId": "9e2dd63c-3478-489f-86d3-8c292a65a0aa",
  • "type": "string",
  • "deviceId": "string",
  • "status": "string",
  • "issuedAt": "2019-08-24T14:15:22Z",
  • "acknowledgedAt": "2019-08-24T14:15:22Z"
}

Flux temps réel des valeurs notifiées (SSE)

Flux text/event-stream des valeurs notifiées par la caractéristique actuellement souscrite ({ service_uuid, characteristic_uuid, value, receivedAt } par événement, value en hexadécimal). Indépendant de ble/notifications/subscribe : peut être ouvert avant, pendant ou après, et par plusieurs clients HTTP à la fois — le serveur republie chaque notification vers tous les flux ouverts pour ce module.

Authorizations:
bearerAuth
path Parameters
deviceId
required
string^[A-Za-z0-9_-]{1,64}$
Example: TK-001

Responses

Response samples

Content type
application/json
{
  • "error": "string"
}