--- share_link: https://share.note.sx/ziuyd353#P//B0nvVix4HFcZp0NAOVtbR3EXhPIYEtuv1VDkKkV4 share_updated: 2026-04-30T09:33:12+02:00 cssclasses: - full-width --- # CR technique — iGO STILL : fonctionnement et flux API + correspondance avec le module AGV EasyWMS > Compte-rendu technique simplifié du fleet manager **iGO easy** (alias **PACS Host API** côté KION/STILL) à partir des documents fournis dans le dossier STILL, suivi d'une table de correspondance complète avec le **module AGV EasyWMS** (cf. `CR_ModuleAGV.md`). > > Public : développeurs EasyWMS / intégration robotique. Date : 2026-04-28. Sources : > > - `2510_PACS-2.3-Host-Interface-Technical-Specifications_en-US--STILL-.pdf` (référence API la plus récente, 10/2025) > - `iGo easy 2.3 - Host Interface Specifications.pdf` (variante iGO easy — API identique au PACS 2.3) > - `IT requirements R1 20250929.pdf` (environnement MyMA — frontend Vue3 + backend .NET 8 + Postgres) > - `Technical specification EXV CB iGo.pdf` (datasheet véhicule — gerbeur EXV CB iGo) > - `Limagrain-LWM_Std_Interface_Compliance.xlsx` (matrice de compliance — _non lu automatiquement, format binaire ; sera abordé manuellement avec l'équipe Limagrain_) --- ## Sommaire 1. [Vue d'ensemble iGO / PACS](https://claude.ai/local_sessions/local_5e652410-ce93-46d4-bb6d-ec829a64d798#1-vue-densemble-igo--pacs) 2. [Stack technique et déploiement](https://claude.ai/local_sessions/local_5e652410-ce93-46d4-bb6d-ec829a64d798#2-stack-technique-et-d%C3%A9ploiement) 3. [Modèle de ressources](https://claude.ai/local_sessions/local_5e652410-ce93-46d4-bb6d-ec829a64d798#3-mod%C3%A8le-de-ressources) 4. [Flux API principaux](https://claude.ai/local_sessions/local_5e652410-ce93-46d4-bb6d-ec829a64d798#4-flux-api-principaux) 5. [Cycle de vie d'un Transport](https://claude.ai/local_sessions/local_5e652410-ce93-46d4-bb6d-ec829a64d798#5-cycle-de-vie-dun-transport) 6. [Sécurité et abonnements aux events](https://claude.ai/local_sessions/local_5e652410-ce93-46d4-bb6d-ec829a64d798#6-s%C3%A9curit%C3%A9-et-abonnements-aux-events) 7. [Table de correspondance EasyWMS AGV ↔ iGO](https://claude.ai/local_sessions/local_5e652410-ce93-46d4-bb6d-ec829a64d798#7-table-de-correspondance-easywms-agv--igo) 8. [Points d'attention pour l'intégration](https://claude.ai/local_sessions/local_5e652410-ce93-46d4-bb6d-ec829a64d798#8-points-dattention-pour-lint%C3%A9gration) 9. [FAQ STILL — réponses officielles](https://claude.ai/local_sessions/local_5e652410-ce93-46d4-bb6d-ec829a64d798#9-faq-still--r%C3%A9ponses-officielles) --- ## 1. Vue d'ensemble iGO / PACS **iGO easy** (et son grand frère **PACS** — _Productized Automated Concept Solutions_) est le **fleet manager AGV** de KION Group / STILL. Le moteur sous-jacent s'appelle `E'tricc` (visible dans la phrase de la doc PACS « _all transports that are still in the memory of E'tricc_ »). Les deux versions exposent **strictement la même API REST** en version 2.3 — le PACS est l'offre commerciale large, iGO easy est la déclinaison « _easy_ » destinée à des installations plus simples. ```mermaid flowchart LR subgraph WMS["Hôte (WMS / WES / ERP)"] direction TB EasyWMS["EasyWMS"] end subgraph FleetMgr["iGO easy / PACS Fleet Manager"] direction TB Etricc["Moteur E'tricc"] MyMA["MyMA - admin UI
Vue3 + .NET8 + Postgres"] Etricc <--> MyMA end subgraph Fleet["Flotte AGV"] EXV["EXV CB iGo
(gerbeur ~3.4m)"] Other["...autres modèles STILL"] end EasyWMS <-->|"HTTPS REST
port 7002
TLS 1.2 + Bearer"| Etricc Etricc -.->|"callback POST
vers WMS"| EasyWMS Etricc <--> Fleet ``` **Concepts clés à retenir :** - **Pas de PLC, pas de tables d'échange SQL** côté hôte. Tout passe par REST sur HTTPS. - **Modèle pull + push** : le WMS _pousse_ les ordres (POST /transports) ; iGO _pousse_ les changements d'état via webhook (callback vers une URL exposée par le WMS). - **Pas de notion de routes/segments** côté WMS : iGO ne demande qu'une `sourceLocation` et une `destinationLocation`. La trajectoire physique entre les deux est entièrement gérée par iGO. - **Décision tardive (group / decision point)** : si on ne sait pas encore _où exactement_ charger ou décharger au moment de la création du transport, on peut donner un `sourceGroupId` / `destinationGroupId`. iGO place alors le transport en `RequestSource` / `RequestDestination` et **interroge** le WMS au moment où l'AGV arrive au point de décision. - **Charge utile (Load)** = container EasyWMS. Existe comme ressource indépendante (catalogue) avec dimensions et type. --- ## 2. Stack technique et déploiement ### 2.1 Environnement (MyMA) D'après `IT requirements R1` : |Composant|Détail| |---|---| |Backend|.NET 8.0 (C#)| |Frontend|Vue 3.2| |Base de données|**Postgres 12+** par défaut, SQL Server 2019 ou MySQL 8.0 supportés| |OS serveur|Windows 11 Pro/Ent, Windows Server 2016/2019/2022, Ubuntu 18.04| |Navigateurs admin|Edge, Chrome, Firefox| |Hardware (low)|4 cores @2.26 GHz, 8 Go RAM, 500 Go RAID5, dual PSU| |Hardware (high)|8 cores, 16 Go RAM, 1 To, dual PSU| ### 2.2 Ports réseau |Service|Port| |---|---| |Front-end web (admin MyMA)|**82**| |Backend (REST interne)|**50005**| |API Host vers WMS (HTTPS REST)|**7002**| |Postgres|**5432**| ### 2.3 Wifi (pour terminaux opérateur si présents) Signal min `-70 dBm`, SNR min `20 dB`, débit min `24 Mbps`, ping moyen `≤ 50 ms`. ### 2.4 Véhicule type — STILL EXV CB iGo |Caractéristique|Valeur| |---|---| |Longueur totale (l1)|3 383 mm| |Longueur jusqu'au dosseret (l2)|2 083 mm| |Largeur tablier fourche (b3 / b1 / b2)|1 000 / 920 / 1 109 mm| |Fourche (s / e / l)|50 / 100 / **1 300 mm**| |Hauteur véhicule (arche / mât)|2 447 / 2 015 mm| > Le véhicule est un **gerbeur électrique automatisé** (EXV = Elektro-Vertikal) — il se déplace sur ses propres roues et lève la charge avec le mât. Il n'a pas de notion de couloir mécanique ni de canal compact à l'instar d'un Pallet Shuttle. --- ## 3. Modèle de ressources L'API expose **8 ressources** (chapitres 1-8 du PACS) : ```text ┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐ │ System │ │ Transport │ ─────▶│ Vehicle │ │ (état global + │ │ (l'ordre du │ │ (AGV physique) │ │ abonnements) │ │ WMS) │ └──────────────────┘ └──────────────────┘ └────────┬─────────┘ ▲ │ │ assignation ▼ │ ┌──────────────────┐ ┌──────────────────┐ │ Load │◀──────│ Location │ │ (charge physique │ │ (point géo + │ │ = container) │ │ actions) │ └────────┬─────────┘ └────────┬─────────┘ │ │ ▼ ▼ ┌──────────────────┐ ┌──────────────────┐ │ LoadType │ │ Group │ │ (catalogue de │ │ (ensemble de │ │ types) │ │ locations) │ └──────────────────┘ └──────────────────┘ ``` ### 3.1 Transport (l'ordre) C'est l'**équivalent direct de l'`AgvTask`** côté EasyWMS. |Champ|Type|Rôle| |---|---|---| |`id`|string|Id généré par iGO| |`transportHostId`|string|Id hôte (= `OrderExtId` côté EasyWMS)| |`sourceLocationId` _ou_ `sourceGroupId`|string|Source (un des deux requis)| |`destinationLocationId` _ou_ `destinationGroupId`|string|Destination (un des deux requis)| |`load`|Load|Charge embarquée| |`priority`|int 0-10|10 = max, 0 = min| |`suspended`|bool|Crée le transport mais sans l'exécuter| |`customMetaData`|dict (Key/Val)|Métadonnées libres| |`status`|enum|Voir § 5| ### 3.2 Vehicle (l'AGV) |Champ|Type|Rôle| |---|---|---| |`id`|string|Identifiant véhicule| |`mode`|enum|`Manual / Automatic / SemiAutomatic / Removed / Disabled`| |`status`|enum|`Idle / Executing / Charging / Faulted / Manual`| |`pose`|object (x, y, orientation)|Position physique en temps réel| |`batteryLevel`|int|% batterie| |`loadId` / `loadHostId`|string|Charge embarquée| |`locationStationId`|string|Station courante| |`errors`|array|Codes/labels d'erreur| ### 3.3 Load et LoadType `Load` = instance physique d'une charge (un container, une palette). Possède `loadHostId` (id côté WMS), `loadTypeId`, `locationId`, `dimensions` (W/D/H/Weight) et `customMetaData`. `LoadType` = catalogue (id + dimensions par défaut). Endpoint en lecture seule (`GET /api/load-types`). ### 3.4 Location & Group - **Location** : un point physique sur lequel un AGV peut faire des actions (`possibleActions`), avec types de véhicules et de charges autorisés et `actualLoads` courantes. - **Group** : un ensemble de Locations. Sert quand on veut différer le choix de la location finale jusqu'au point de décision (cas typique : zone de déchargement avec plusieurs alvéoles). Le WMS appelle alors `POST /api/transports/{id}/final-source` ou `/final-destination` pour fixer le choix. ### 3.5 System État global : projet courant, `isRunning`, abonnements actifs, timestamp de démarrage. --- ## 4. Flux API principaux ### 4.1 Inventaire des endpoints Tous sur `https://[IP]:7002/api/...` avec `X-API-Key` (header) et `Authorization: Bearer ` (header). |Verbe|URL|Effet| |---|---|---| |GET|`/api/system`|Status global + liste des subscriptions| |GET|`/api/transports`|Liste de tous les transports en mémoire| |POST|`/api/transports`|**Créer un nouveau transport**| |GET|`/api/transports/{id}`|Détail d'un transport| |POST|`/api/transports/{id}/final-destination`|Fixer la destination finale (group → location)| |POST|`/api/transports/{id}/final-source`|Fixer la source finale (group → location)| |POST|`/api/transports/{id}/suspend`|Mettre en pause| |POST|`/api/transports/{id}/release`|Relancer après suspend| |POST|`/api/transports/{id}/cancel`|Annuler| |POST|`/api/transports/{id}/priority?priority={0-10}`|Changer la priorité| |POST|`/api/transports/subscription?callbackUrl=…`|S'abonner aux events transport| |DELETE|`/api/transports/subscription?callbackUrl=…`|Se désabonner| |GET|`/api/groups` / `/api/groups/{id}`|Lecture des groupes| |GET|`/api/loads` / `/api/loads/{id}`|Lecture des loads| |POST|`/api/loads`|Créer une load à une location| |POST|`/api/loads/{id}/location`|Déplacer une load (manuellement)| |DELETE|`/api/loads/{id}`|Supprimer une load| |GET|`/api/load-types`|Catalogue des types| |GET|`/api/locations` / `/api/locations/{id}`|Lecture des locations| |GET|`/api/vehicles` / `/api/vehicles/{id}`|Lecture véhicules| |POST|`/api/vehicles/suspend`|Suspendre **toute la flotte**| |POST|`/api/vehicles/resume`|Relancer toute la flotte| |POST|`/api/vehicles/{id}/suspend` / `.../resume`|Suspend/resume un AGV donné| |POST|`/api/vehicles/restart`|Redémarrer toute la flotte| |POST|`/api/vehicles/subscription?callbackUrl=…`|S'abonner aux events vehicle| |DELETE|`/api/vehicles/subscription?callbackUrl=…`|Se désabonner| ### 4.2 Endpoints à implémenter **côté WMS** (callbacks) Spécifiés par le client (l'URL est passée à l'inscription). |URL (côté WMS)|Body reçu|Quand iGO l'appelle| |---|---|---| |`POST /api/transport/event`|objet `Transport` complet|À chaque changement d'état d'un transport| |`POST /api/vehicles/event`|objet `Vehicle` complet|À chaque changement d'état d'un véhicule| > ℹ️ Le contrat ne définit **pas** la fréquence ni le rate-limiting. À tester en charge — un transport qui passe par tous les états émet ~7 callbacks ; un véhicule qui se déplace peut en émettre beaucoup plus (pose updates). ### 4.3 Flux nominal — création et exécution d'un transport ```mermaid sequenceDiagram autonumber participant WMS as EasyWMS participant iGO as iGO easy participant V as Vehicle WMS->>iGO: POST /api/transports {sourceLocationId, destinationLocationId, load, priority, transportHostId} iGO-->>WMS: 200 OK Transport(id, status=Requested) iGO->>WMS: callback transport/event (status=Pending) iGO->>V: assigne le véhicule iGO->>WMS: callback transport/event (status=Assigned) Note over V: AGV se déplace
vers source V->>iGO: arrivé source iGO->>WMS: callback (status=Retrieving) Note over V: AGV charge V->>iGO: chargé iGO->>WMS: callback (status=Retrieved) Note over V: AGV se déplace
vers destination V->>iGO: arrivé destination iGO->>WMS: callback (status=Storing) Note over V: AGV décharge V->>iGO: déchargé iGO->>WMS: callback (status=Stored) iGO->>WMS: callback (status=Finished) ``` ### 4.4 Flux avec décision tardive (Group) C'est le cas où le WMS ne sait pas, à la création, _quelle alvéole exacte_ utiliser : ```mermaid sequenceDiagram autonumber participant WMS participant iGO participant V as Vehicle WMS->>iGO: POST /api/transports {destinationGroupId="DOCK_OUT", ...} iGO-->>WMS: 200 OK (status=Requested) iGO->>WMS: callback (status=Pending) iGO->>WMS: callback (status=Assigned) iGO->>WMS: callback (status=Retrieving → Retrieved) Note over V: AGV se déplace
vers le decision point
du groupe DOCK_OUT V->>iGO: arrivé au decision point iGO->>WMS: callback (status=RequestDestination) Note over WMS: WMS choisit une
alvéole précise dans
le groupe DOCK_OUT WMS->>iGO: POST /api/transports/{id}/final-destination
{destinationId: "DOCK_OUT_03"} iGO-->>WMS: 200 OK Note over V: AGV poursuit
vers DOCK_OUT_03 iGO->>WMS: callback (status=Storing → Stored → Finished) ``` > ⚠️ Si le WMS **ne répond pas assez vite**, iGO bascule de `RequestDestination` vers `WaitDestination` (l'AGV est arrivé physiquement et attend). Symétrique côté source : `RequestSource` → `WaitSource`. ### 4.5 Annulation et suspension ```text Action Endpoint Effet ───────────────────────────────────────────────────────────────────────────────────── Annuler POST /api/transports/{id}/cancel status=Cancelled (terminal) Suspendre POST /api/transports/{id}/suspend gel temporaire (peut être levé) Relancer POST /api/transports/{id}/release inverse de suspend Re-prioriser POST /api/transports/{id}/priority?p=N 0..10 Suspendre flotte POST /api/vehicles/suspend tous les AGV s'arrêtent Reprendre flotte POST /api/vehicles/resume Redémarrer flotte POST /api/vehicles/restart reset hard ``` > ⚠️ **Limite d'annulation confirmée par STILL** : un transport **ne peut pas être annulé après l'état `Retrieved`** (= AGV a déjà pris la palette) — cf. FAQ #6. > > **Conséquence côté EasyWMS** : la branche du `AgvTask_SetCancelledTask_PR` qui gérait l'annulation après chargement (et déclenchait la recherche de relocation) **n'a plus de sens dans le mapping iGO**. Si un cancel arrive côté WMS après `Retrieved`, il faut soit : > > 1. attendre la fin du transport (`Stored`) et faire alors une nouvelle tâche AGV de retour ; > 2. ou intervenir physiquement (intervention manuelle / fallback RFT) avant de cancel. > 💤 **Le champ `suspended`** (paramètre du POST de création) n'a pas d'usage métier identifié par STILL côté WMS classique (cf. FAQ #7). À utiliser uniquement si on veut pré-créer un transport avant que la palette soit physiquement disponible. --- ## 5. Cycle de vie d'un Transport État final possible : **`Finished`**, **`Cancelled`**, **`Aborted`**. ```mermaid flowchart TD New[New] --> Req[Requested] Req --> Pen[Pending] Pen --> Asg[Assigned] Asg -->|source = Group| RS[Request Source] Asg -->|source = Location| Ret[Retrieving] RS -->|final source set| Ret RS -->|AGV arrivé sans réponse| WS[Wait Source] WS -->|final source set| Ret Ret --> Rtd[Retrieved] Rtd -->|dest = Group| RD[Request Destination] Rtd -->|dest = Location| Sto[Storing] RD -->|final dest set| Sto RD -->|AGV arrivé sans réponse| WD[Wait Destination] WD -->|final dest set| Sto Sto --> Std[Stored] Std --> Fin[Finished] Asg -.cancel.-> Can[Cancelled] Pen -.cancel.-> Can Ret -.error.-> Abo[Aborted] Sto -.error.-> Abo ``` |État|Sens fonctionnel| |---|---| |`New`|État **interne instantané** — n'apparaît jamais dans les callbacks. À ignorer côté WMS. (cf. FAQ #4)| |`Requested`|**Premier état réellement observable** côté WMS, juste après le POST| |`Pending`|En file d'attente, en attente d'un AGV libre| |`Assigned`|Un AGV a été désigné| |`RequestSource` / `WaitSource`|Source = group ; iGO attend la décision finale du WMS| |`Retrieving`|AGV en route vers la source / en cours de chargement| |`Retrieved`|Charge prise| |`RequestDestination` / `WaitDestination`|Destination = group ; iGO attend la décision finale| |`Storing`|AGV en route vers destination / en cours de dépose| |`Stored`|Charge déposée| |`Finished`|Transport terminé proprement (état terminal)| |`Cancelled`|Annulé via `/cancel` (état terminal)| |`Aborted`|Erreur d'exécution irrécupérable (état terminal). ⚠ **Aucun code ni message d'erreur** dans le payload — seul le statut est transmis (cf. FAQ #2)| > 🔑 **Identifiant véhicule** : il n'apparaît dans le payload **qu'à partir de l'état `Retrieved`** (et plus, après donc). À l'état `Assigned`, le payload ne contient pas encore le `Vehicle.id` (cf. FAQ #1). Les workflows EasyWMS (typiquement `ProcessEvent_TaskAssigned_PR` qui faisait le lien Equipment ↔ Task) doivent donc **être recalés sur `Retrieved`** pour le mapping iGO. > ⏱️ **Pas de timestamp dans le payload** des callbacks (cf. FAQ #3). Si le WMS a besoin d'horodater, il doit le faire à réception (`DateTime.UtcNow`). --- ## 6. Sécurité et abonnements aux events ### 6.1 Sécurité - **Transport** : HTTPS avec **TLS 1.2** ; certificats **auto-signés** → le WMS doit les _truster_ explicitement (import dans le keystore). - **Authentification** : ✅ **C'est `X-API-Key` qui est utilisé** (confirmé par STILL — cf. FAQ #8). Le header `Authorization: Bearer ` mentionné dans certaines parties de la doc est obsolète / à ignorer. - La clé est **fixe** (pas de refresh automatique) → fournie par le PM STILL. ### 6.2 Modèle d'abonnement ```mermaid sequenceDiagram participant WMS participant iGO Note over WMS: au démarrage du WMS WMS->>iGO: POST /api/transports/subscription?callbackUrl=https://wms/agv/events/transport iGO-->>WMS: 204 No Content WMS->>iGO: POST /api/vehicles/subscription?callbackUrl=https://wms/agv/events/vehicle iGO-->>WMS: 204 No Content Note over iGO: en exploitation iGO->>WMS: POST https://wms/agv/events/transport (Transport JSON) WMS-->>iGO: 200 OK iGO->>WMS: POST https://wms/agv/events/vehicle (Vehicle JSON) WMS-->>iGO: 200 OK Note over WMS: à l'arrêt du WMS WMS->>iGO: DELETE /api/transports/subscription?callbackUrl=… WMS->>iGO: DELETE /api/vehicles/subscription?callbackUrl=… ``` ### 6.3 Bonnes pratiques côté EasyWMS - **Idempotence** : iGO peut retransmettre un event en cas de timeout côté WMS. Le handler côté EasyWMS doit gérer le doublon (par exemple via `transport.id` + `status`). - **Re-souscription** au boot : si iGO redémarre, les abonnements en mémoire peuvent être perdus. Le WMS doit toujours appeler `GET /api/system` au démarrage et vérifier la présence de la subscription, et la recréer sinon. - **Endpoint callback** : doit être en HTTPS (sinon iGO refuse), retourner **200 OK** rapidement (idéalement < 1s), traitement asynchrone derrière. --- ## 7. Table de correspondance EasyWMS AGV ↔ iGO ### 7.1 Concepts métier |EasyWMS (module AGV)|iGO easy / PACS|Commentaire| |---|---|---| |`AgvTask` (entité)|`Transport` (resource)|Cœur fonctionnel — l'ordre de transport| |`Container` / LPN|`Load`|La charge physique| |`ContainerType`|`LoadType`|Catalogue de types| |`Location` (`IRealLocation`)|`Location`|Point physique du warehouse| |`WorkingZone`|`Group`|Ensemble de locations à décision tardive| |AGV station (type 65)|`Vehicle`|Le véhicule lui-même| |`AgvLockType` (`AGV_Lock`)|`Location.isEnabled = false`|iGO n'a pas de typage de lock — juste un flag| |`ManualEquipment` (RFT fallback)|_(aucun équivalent)_|Concept WMS-uniquement| |`EagMessages` (table SQL)|API REST `POST /api/transports/...`|Tables ↔ HTTP| |`AgeMessages` (table SQL)|Webhook callback `POST /transport/event`|Tables ↔ HTTP| |`AgsMessages` (table SQL)|Webhook callback `POST /vehicles/event`|Status AGV| ### 7.2 Champs de l'ordre |EasyWMS `AgvTask`|iGO `Transport`|Conversion| |---|---|---| |`OrderExtId` (long, = `Task.TaskNumber`)|`transportHostId` (string)|`OrderExtId.ToString()`| |`Id` (Guid)|`id` (string)|iGO génère son propre `id`| |`LoadLocation`|`sourceLocationId`|mapping direct par code location| |`UnloadLocation`|`destinationLocationId`|id direct| |(groupe de couloirs / décision tardive)|`sourceGroupId` / `destinationGroupId`|Pour WorkingZones| |`LoadType` (0=Container, 1=PalletShuttle)|`Load.loadTypeId`|iGO ne gère pas nativement le PS| |`PalletId`|`Load.loadHostId`|id côté WMS| |`PalletType`|`Load.loadTypeId`|référence au catalogue LoadType| |`Priority` (0=Urgent ... 4=VeryLow)|`priority` (10=max, 0=min)|**Conversion inversée** — voir ci-dessous| |`HasTopper`|`customMetaData["HASTOPPER"]`|passe en metadata| |`CanPick`, `CanDrop`|_(pas d'équivalent natif)_|Voir § 8| |`UnloadAisleNumber/Side/X/Y/Depth`|_(porté par la `Location`)_|iGO gère la géométrie en interne| |`StationNumber` (AGV courant)|`Vehicle.id` (vu en callback)|id du véhicule assigné| |`PreviousOrderId` (chaînage)|_(pas d'équivalent natif)_|À encoder en customMetaData| |`Status` (enum AgvStatus)|`status` (enum Transport)|Voir § 7.3| |`Operation` (Create/Update/Delete)|endpoints REST distincts|POST / final-* / cancel| |`WarehouseNumber` / `WarehouseCode`|_(pas exposé)_|iGO suppose un seul site| **Conversion de priorité :** |EasyWMS|iGO|Suggestion| |---|---|---| |0 — Urgent|10 — Highest|mapping direct| |1 — High|8|| |2 — Normal|5|| |3 — Low|3|| |4 — VeryLow|1|| ### 7.3 États / phases |Phase AGV (EasyWMS)|EasyWMS `AgvStatus`|iGO `Transport.status`|Notes| |---|---|---|---| |(création)|`PendingToBeSend`|(pas encore envoyé)|côté WMS uniquement| |Envoi EAG|—|`New` → `Requested`|après `POST /api/transports`| |Phase 100 (Order accepted)|`Sent`|`Pending`|en file d'attente iGO| |Phase 103 (Vehicle assigned)|(Sent)|`Assigned`|véhicule affecté| |Phase 104 (Load permission)|`PendingToBeLoad`|`RequestSource` _(group only)_|iGO n'a ce comportement qu'en mode group| |(autorisation WMS load)|(Sent / re-export EAG)|`POST /final-source`|mais pas un _renvoi du même ordre_ — c'est un endpoint dédié| |Phase 106 (Load confirmed)|(Sent)|`Retrieving` → `Retrieved`|charge prise| |Phase 108 (Unload permission)|`PendingToBeUnload`|`RequestDestination` _(group only)_|idem auth load| |(autorisation WMS unload)|(Sent / re-export EAG)|`POST /final-destination`|endpoint dédié| |Phase 110 (Unload confirmed)|(Sent → purge)|`Storing` → `Stored` → `Finished`|terminé| |Phase 255 (Cancel by AGV)|`(Cancelled)`|`Cancelled` ou `Aborted`|aborted = erreur, cancelled = ordre annulé| > 🎯 **Différence sémantique majeure** : EasyWMS attend une **demande explicite d'autorisation** (phases 104 / 108) **à chaque ordre** quand `CanPick` / `CanDrop` sont à `false`. iGO ne demande l'autorisation qu'**au point de décision d'un Group**. Si la `sourceLocation` est connue dès la création, iGO ne demande **aucune autorisation** — elle exécute directement. > > Pour reproduire le comportement EasyWMS dans iGO, il faut **forcer** l'usage de Groups, même mono-location, là où EasyWMS aurait CanPick = false. ### 7.4 Erreurs |Code EasyWMS|Famille|Équivalent iGO|Remarque| |---|---|---|---| |1001-1014|Configuration (mauvaise station, ordre dupliqué…)|`HTTP 400 BadRequest` à la création|iGO refuse à la requête| |1003 (duplicate)||`HTTP 400` sur POST /transports si transportHostId déjà utilisé (à valider)|| |1009 (cancellation error)||`HTTP 400/404` sur POST /cancel|| |2003 (extraction error)|Exécution|`Transport.status = Aborted` + `Vehicle.errors[]`|erreur runtime| |2004 (putaway error)|Exécution|idem|| |2005 (manual cancel from AGV UI)|Exécution|`Transport.status = Cancelled` reçu en callback|| |2500-2503|Communication|erreurs **HTTP 5xx / timeouts**|au niveau réseau| |2700 (wrong/missing container)|Exécution|`Vehicle.errors[]` + `status = Faulted`|côté véhicule| > 💡 Côté EasyWMS, les codes 1001-2700 sont stockés dans `agvEvent.Flags` et routés par `ProcessErrors_PR`. **La logique côté EasyWMS doit donc être étendue** pour transformer une réponse HTTP / un callback iGO en un `agvEvent.Flags` numérique, qui ensuite ré-utilise toute la machinerie standard de notification (`ProcessError1001_PR`, etc.). ### 7.5 Verbe / opération |Action métier|EasyWMS (Operation + EAG)|iGO (REST)| |---|---|---| |Créer un ordre|`Operation = Create` + ligne EAG|`POST /api/transports`| |Modifier un ordre|`Operation = Update` + ligne EAG|(selon le cas) `POST /priority`, `POST /final-source`, `POST /final-destination`| |Annuler un ordre|`Operation = Delete` + ligne EAG|`POST /api/transports/{id}/cancel`| |Modifier priorité|`AgvTaskEditCommand` + `Operation = Update`|`POST /api/transports/{id}/priority?priority=N`| |Suspendre un ordre|(pas d'équivalent)|`POST /api/transports/{id}/suspend` ➕| |Reprendre un ordre|(pas d'équivalent)|`POST /api/transports/{id}/release` ➕| |Suspendre la flotte|(pas d'équivalent)|`POST /api/vehicles/suspend` ➕| |Demande d'auth load|EAG `Operation = Update` (CanPick=true)|`POST /api/transports/{id}/final-source`| |Demande d'auth unload|EAG `Operation = Update` (CanDrop=true)|`POST /api/transports/{id}/final-destination`| ➕ = capacité **nouvelle** offerte par iGO, sans contrepartie WMS — utile pour la maintenance. ### 7.6 Topologie / configuration |EasyWMS|iGO| |---|---| |AGV créé en EasyS dans un _AGV equipment group_ (type 65)|`Vehicle` configuré dans MyMA| |`Routes` configurées en EasyS entre stations|Layout iGO, géré dans MyMA / iGO designer| |`LoadAisle` / `UnloadAisle` (couloirs manuels)|`Location.possibleActions`| |`Allow loading / Allow unloading` per location|`Location.isEnabled` + `possibleActions`| |`Manual loading aisle`|(pas d'équivalent — iGO calcule la trajectoire)| |`LocationLockType` "For AGV"|`Location.isEnabled = false` (binaire)| |Fault notification group AGV|callback `POST /vehicles/event` (errors[])| ### 7.7 Workflows EasyWMS impactés par l'intégration iGO > 📖 **Vocabulaire** : dans la suite, l'expression **« Gateway iGO »** est utilisée comme raccourci pour désigner le **middleware côté flotte à développer pour iGO** (cf. § 8.4) — concrètement, **une pool IIS C# .NET 8** développée par Mecalux qui regroupe la pompe sortante (poll `AGV_OUTPUTQUEUE` → API iGO) et le webhook receiver (callbacks iGO → écrit `AGV_INPUTQUEUE`+`AGE`/`AGS`). Il **ne doit pas être confondu** avec la **Gateway AGV Mecalux**, qui elle existe déjà dans le module AGV core et joue un rôle différent (mediator côté Mecalux entre workflows et tables). > ✅ **Avec le pattern Gateway iGO + Gateway AGV Mecalux + tables EAG/AGE/AGS (cf. § 8.4) : aucun workflow EasyWMS, ni la Gateway AGV Mecalux, n'a besoin d'être modifié.** La spécificité iGO est **entièrement encapsulée** dans le Gateway iGO, qui se contente de traduire le contenu des tables vers/depuis l'API REST PACS. |Workflow EasyWMS|Comportement avec Gateway iGO| |---|---| |`MovementCreatedEventHandler_PR`|✅ Inchangé — toujours le déclencheur| |`AgvTask_CreateTaskFromMovement_PR`|✅ Inchangé — produit un `AgvTaskWF`| |`AgvTask_SetCreatedTask_PR`|✅ Inchangé — `Status = PendingToBeSend`| |`SerializeAgvTasks_PR` + `CreateMovTrackings_PR`|✅ Inchangé — écrit en table EAG. **Le Gateway iGO** lit cette ligne et exécute le `POST /api/transports`.| |`ProcessEvents_PR` + `ProcessEvent_*_PR`|✅ Inchangé — poll AGE comme d'habitude. **Le Gateway iGO** alimente AGE en traduisant les callbacks REST.| |`ProcessErrors_PR` + `ProcessError*_PR`|✅ Inchangé — réagit aux `Flags` dans AGE. **Le Gateway** est responsable d'inscrire un `Flags` cohérent (2003, 2004, etc.) à partir du `status=Aborted` + GET vehicles errors.| |`Agvtask_CanPick/CanDrop_PendingToBeSent_PR`|✅ Inchangé — réécrit une ligne EAG avec `CanPick=true`/`CanDrop=true`. **Le Gateway** reconnaît ce pattern et appelle `POST /transports/{id}/final-source` ou `/final-destination`.| |`TaskCanceledEventHandler_PR` + `AgvTask_SetCancelledTask_PR`|✅ Inchangé — écrit une ligne EAG `Operation=Delete`. **Le Gateway** appelle `POST /transports/{id}/cancel` (et signale impossibilité si statut iGO ≥ Retrieved).| |`MovementDestinationChanged_PR`|✅ Inchangé — émet un `Operation=Delete` puis `Operation=Create`. **Le Gateway** chaîne `cancel` puis nouveau `POST /transports`.| |Workflows RFT (`Equipment_AgvTask_*_UI`)|✅ Inchangés — fallback opérateur préservé si iGO indisponible| |`AGV_LocationLockType_Create_PR`|✅ Inchangé — init du LockType `AGV_Lock` côté EasyWMS. La pose effective du verrou n'a pas d'écho direct vers iGO (les locations iGO ne sont gérées que par MyMA).| |`Galileo_EventCreatedEventHandler_PR` (partial)|✅ Inchangé — non concerné par iGO (côté Galileo seulement)| > 📌 **Conséquence projet** : la livraison du custom `CstAGV` n'a **rien à voir** avec l'intégration iGO. Le custom AGV reste tel qu'il est, et c'est le Gateway iGO (livrable séparé, service Windows à part) qui porte toute la couche d'adaptation. C'est la bonne séparation des responsabilités. --- ## 8. Points d'attention pour l'intégration ### 8.1 Différences structurelles 1. **Pas de tables d'échange** : il faut un service HTTP listener côté EasyWMS pour recevoir les callbacks. Exposé typiquement sur le serveur WMS, sécurisé en HTTPS, avec un certificat trusté par MyMA. 2. **Pas de phases distinctes 100/103/104/106/108/110** dans iGO — tout est **état du Transport**. Le mapping en phases EasyWMS est un travail de traduction côté custom. 3. **Pas de `CanPick`/`CanDrop` natifs** : pour reproduire la demande d'autorisation, il faut **passer par les Groups**. Conséquence : le layout iGO doit déclarer un Group pour chaque location qui doit demander auth. 4. **Priorité 0-10** vs 0-4 : conversion bijective à fixer (cf. § 7.2). 5. **Pas de routing exposé** : iGO gère ses routes en interne. Donc pas d'équivalent à `Routes between stations` en EasyS, et pas d'erreur `Disabled route` côté iGO. ### 8.2 Capacités nouvelles iGO offre des capacités que l'AGV core EasyWMS n'expose pas : - **Suspend / Resume / Restart** d'une flotte ou d'un véhicule individuel sur demande WMS. - **Pose temps réel** de chaque véhicule (`x, y, orientation`) → utilisable pour un dashboard live côté EasyWMS. - **Battery level** → permet de déclencher des événements ERP/notifs à seuils. ### 8.3 Sujets levés avec STILL — état au 28/04/2026 Le retour FAQ STILL a clos plusieurs questions (cf. § 9). Récapitulatif : |#|Sujet|Statut| |---|---|---| |1|`X-API-Key` vs `Bearer token`|✅ **Résolu** : c'est `X-API-Key` (FAQ #8)| |2|Re-livraison des callbacks|🟡 **Partiel** : iGO retente, mais fréquence inconnue → à tester en charge (FAQ #9)| |3|Fréquence des `vehicle/event` (pose updates)|❌ Toujours ouvert| |4|Comportement queue saturée (transport `Pending` sans véhicule)|🟡 **Partiel** : on sait au moins que les transports survivent à un redémarrage iGO (FAQ #10)| |5|`customMetaData` (taille, caractères, ré-émis ?)|❌ Toujours ouvert| |6|Création/modification de `Location` via API|❌ Toujours ouvert (l'API n'expose que `GET`)| |7|Pallet Shuttle (LoadType = 1)|❌ Toujours ouvert| |8|Multi-warehouse|❌ Toujours ouvert| |9|HasTopper (attribut véhicule)|❌ Toujours ouvert| |10|`New` vs `Requested`|✅ **Résolu** : `New` est interne et instantané, traiter `Requested` comme premier état (FAQ #4)| |11|`Vehicle.id` disponible dès `Assigned` ?|✅ **Résolu** : non, seulement à partir de `Retrieved` (FAQ #1)| |12|Code/message d'erreur dans payload `Aborted`|✅ **Résolu** : aucun — juste le statut (FAQ #2)| |13|Timestamp dans les callbacks|✅ **Résolu** : aucun — le WMS doit horodater à réception (FAQ #3)| |14|Workflow `Load` : créer la palette avant ou avec le transport ?|✅ **Résolu** : ne pas créer — passer les infos directement dans le transport (FAQ #5)| |15|Annulation après chargement|✅ **Résolu** : non, impossible après `Retrieved` (FAQ #6)| |16|Cas d'usage du `suspended`|✅ **Résolu** : utile uniquement si pré-création d'un transport avant disponibilité de la palette (FAQ #7)| |17|Persistance après redémarrage iGO|✅ **Résolu** : oui, les données survivent (FAQ #10)| |18|Communication directe vs via `iGo Flow`|✅ **Résolu** : directement avec l'API PACS (FAQ #11)| ### 8.4 Architecture cible — Pattern à 4 composants (Gateway Mecalux + middleware pool IIS C#) > 🔑 **Principe directeur (vérifié dans la doc Mecalux `Interface_Communications_AGVs_EN.pdf` et le contrat technique `RT_AGVs_EN.pdf`)** : EasyWMS communique avec les fleet managers externes via une **base intermédiaire dédiée aux communications** (5 tables réelles). Côté Mecalux, un service **Gateway AGV (existant)** mediate entre les workflows EasyWMS et les tables. Côté flotte, un **middleware à fournir** (à développer **par Mecalux** pour iGO, sous forme de pool IIS C# .NET 8) mediate entre ces tables et l'API REST PACS. > > **Le `EasyWMSGateway2015` que l'on connaît pour Galileo ne joue PAS le rôle de la Gateway AGV Mecalux** — il joue le rôle du middleware côté flotte (médiateur entre tables et TCP frames). Pour iGO, il faut son équivalent fonctionnel mais en REST/HTTPS, sous forme de pool IIS C#. > > **Le custom `CstAGV` n'est pas modifié.** L'intégration iGO consiste uniquement à fournir le middleware pool IIS. #### 8.4.1 Schéma cible — 4 composants ```mermaid flowchart LR subgraph EasyWMS["Côté Mecalux EasyWMS (existant)"] Process[Process
Putaway/Picking/Shipping] Task[Task & Movement] AgvCore[Module AGV core
workflows CstAGV] GwMec[Gateway AGV Mecalux
service mediator
workflows ↔ tables] MonitorView[Vues SmartUI
AGV Tasks/Stations/
Messages] end subgraph DB["Intermediate database for communications"] direction TB OQ[(AGV_OUTPUTQUEUE
FIFO sortante)] EAG[(AGV_EAG
data ordres)] IQ[(AGV_INPUTQUEUE
FIFO entrante)] AGE[(AGV_AGE
data phases)] AGS[(AGV_AGS
data statuts AGV)] end subgraph FleetSide["Pool IIS C# .NET 8 — À DÉVELOPPER PAR MECALUX pour iGO"] direction TB Pump[Pompe sortante :
poll OUTPUTQUEUE
lit EAG via batchId
+ POST API iGO] Hook[Webhook receiver :
HTTPS endpoint
écrit INPUTQUEUE+AGE/AGS] end subgraph KION["iGO / PACS (existant chez STILL)"] iGO[API REST
port 7002] end Process --> Task --> AgvCore AgvCore -->|events workflow| GwMec GwMec -->|écrit OUTPUTQUEUE+EAG| OQ GwMec -->|écrit OUTPUTQUEUE+EAG| EAG GwMec -->|poll INPUTQUEUE+AGE/AGS| IQ GwMec -->|poll INPUTQUEUE+AGE/AGS| AGE GwMec -->|alimente| MonitorView Pump -->|poll| OQ Pump -->|lit data via batchId| EAG Pump -->|HTTPS REST
X-API-Key| iGO iGO -.webhook callback.-> Hook Hook -->|écrit| IQ Hook -->|écrit| AGE Hook -->|écrit| AGS ``` #### 8.4.2 Composants existants côté Mecalux — RIEN à développer |Composant|Rôle|Statut| |---|---|---| |`CstAGV` (workflows)|Logique métier AGV — création de tâches, gestion d'erreurs, fallback RFT, etc.|✅ Existant — non touché| |**Gateway AGV Mecalux**|Service mediator côté Mecalux : écoute events workflow → écrit `AGV_OUTPUTQUEUE` + `AGV_EAG` ; poll `AGV_INPUTQUEUE` → lit `AGV_AGE`/`AGV_AGS` → alimente vues SmartUI ; gère le `processedDate`|✅ Existant dans le module AGV — non touché| |Tables `AGV_INPUTQUEUE`, `AGV_OUTPUTQUEUE`, `AGV_EAG`, `AGV_AGE`, `AGV_AGS`|Intermediate database for communications|✅ Existantes| |Vues SmartUI (AGV Tasks/Stations/Messages)|Monitoring opérateur|✅ Existantes| #### 8.4.3 Middleware côté flotte — pool IIS C# à développer **par Mecalux** C'est **le seul livrable nouveau** de l'intégration. **Mecalux** (et non STILL) prend en charge ce développement, car le contrat avec les tables `AGV_*` est propriétaire Mecalux. Architecture cible : |Aspect|Description| |---|---| |**Forme**|Pool **IIS** dédiée hébergeant un service ASP.NET Core (C#, .NET 8.0)| |**Hébergement**|Serveur Mecalux — peut être co-localisé avec EasyWMS ou sur une VM séparée selon la topologie projet| |**Rôle**|Service unique multi-thread combinant pompe sortante ET webhook receiver| |**Accès BDD**|Connection chaîne vers la base intermédiaire (les 5 tables `AGV_*`) — typiquement la même base que le WMS, ou une base dédiée si l'architecture projet le décide| |**Sécurité**|Header `X-API-Key` sortant + endpoint HTTPS entrant (TLS 1.2, certificat trusté ou auto-signé selon politique)| ##### A. Pompe sortante (poll `AGV_OUTPUTQUEUE` → API iGO) |Aspect|Description| |---|---| |Mode|Background worker / hosted service ASP.NET Core — polling régulier (par ex. toutes les 1-5s) sur `AGV_OUTPUTQUEUE WHERE processedDate IS NULL ORDER BY creationDate ASC`| |Action|Pour chaque ligne queue : récupère le `id` (= `batchId`) → SELECT data correspondante dans `AGV_EAG WHERE batchId = ` → interprète l'`Operation` (`C`/`U`/`D`) → fait l'appel REST iGO adéquat| |Endpoints iGO appelés|`POST /api/transports` (Create), `POST /transports/{id}/cancel` (Delete), `POST /transports/{id}/priority`, `POST /transports/{id}/final-source`, `POST /transports/{id}/final-destination` (Update selon le pattern `CanPick`/`CanDrop`)| |Marquage|Après ack synchrone d'iGO (200 OK) : `UPDATE AGV_OUTPUTQUEUE SET processedDate = NOW() WHERE id = `| ##### B. Webhook receiver (callbacks iGO → écrit `AGV_INPUTQUEUE` + `AGV_AGE`/`AGS`) |Aspect|Description| |---|---| |Mode|Controller ASP.NET Core exposant deux endpoints HTTPS : `POST /agv/transport-event` et `POST /agv/vehicle-event` (URL configurable). Souscriptions iGO créées au boot via `POST /api/transports/subscription?callbackUrl=...` et `POST /api/vehicles/subscription?callbackUrl=...`| |Action|Pour chaque callback reçu : (1) `INSERT INTO AGV_INPUTQUEUE (message, creationDate) VALUES ('AGE'/'AGS', NOW())` → récupère le `id` généré → (2) `INSERT INTO AGV_AGE` (ou `AGV_AGS`) avec `batchId = `, `Phase` (selon mapping iGO `status` → 100/103/106/110/255), `ErrorType` (0 ou code 2003/2004/2700 selon contexte), et tous les autres champs du payload Transport/Vehicle iGO| |Idempotence|Déduplication sur `transport.id + status` pour éviter les doubles inserts en cas de retry iGO (cf. FAQ #9). Implémentée via cache local distribué (par ex. table de dedupe interne avec TTL)| |Horodatage|`creationDate = NOW()` UTC à la réception, car iGO ne fournit pas de timestamp (cf. FAQ #3)| |Réponse|200 OK rapidement (< 1s) après insertion en base — le traitement métier est différé à la Gateway AGV Mecalux qui poll `AGV_INPUTQUEUE`| ##### Pattern de boot du middleware À chaque démarrage de la pool IIS : 1. Vérifier la base intermédiaire accessible (connection string + ping `SELECT 1`) 2. Vérifier l'API iGO accessible : `GET /api/system` 3. Récupérer la liste des subscriptions actives via `GET /api/system` (champ `subscriptions`) → comparer avec ce qui est attendu → (re)créer les manquantes via `POST /api/transports/subscription` et `POST /api/vehicles/subscription` 4. Réconcilier les transports : `GET /api/transports` → comparer avec les `AGV_OUTPUTQUEUE` non encore acquittées → générer les lignes `AGV_INPUTQUEUE` + `AGV_AGE` manquantes pour les events perdus pendant la coupure 5. Démarrer le hosted service de polling sortant > 💡 **Une seule pool IIS** héberge les deux fonctions (pompe + webhook). C'est plus simple à exploiter (un seul service à monitorer, un seul recycling, un seul fichier de logs) et c'est le pattern recommandé pour iGO. #### 8.4.4 Mapping `Status` iGO → couple `(EventType, Flags)` AGE C'est le cœur de la traduction entrante côté webhook receiver : |iGO `Transport.status`|Inséré dans AGE comme| |---|---| |`Pending`|`EventType=100, Flags=0` (Order accepted)| |`Assigned`|`EventType=103, Flags=0` (Vehicle assigned) — mais cf. FAQ #1 : pas de `Vehicle.id` à ce moment, donc `StationNumber=null`| |`Retrieving`|(selon le mode group) `EventType=104, Flags=0` ou rien| |`Retrieved`|(selon le mode group) `EventType=106, Flags=0` (Load confirmed) — c'est ici que le `Vehicle.id` arrive| |`Storing`|`EventType=108, Flags=0` (Unload permission) si group, sinon avancement standard| |`Stored` / `Finished`|`EventType=110, Flags=0` (Unload confirmed)| |`Cancelled`|`EventType=255, Flags=0`| |`Aborted`|`Flags=2003` ou `2004` selon contexte (cf. FAQ #2 : à enrichir via `GET /api/vehicles/{id}` pour récupérer `errors[]`)| #### 8.4.5 Avantages du pattern ✅ **CstAGV livré tel quel, Gateway AGV Mecalux non modifiée**. L'intégration iGO ne touche à aucun code EasyWMS — toute la spécificité iGO est encapsulée dans le composant côté flotte. ✅ **RFT fallback préservé**, notifications préservées, recherche de relocation préservée — toute la machinerie AGV continue à fonctionner. ✅ **Découplage temporel** : si iGO est down, EAG s'accumule et sera pompé à la reprise. Si la pompe sortante crashe, EasyWMS n'est pas impacté. Si le webhook receiver est down, iGO retransmet (FAQ #9). ✅ **Pattern symétrique avec Galileo** : Galileo a son `EasyWMSGateway2015` côté flotte ; iGO aura son équivalent REST/HTTPS — même rôle, protocole différent. #### 8.4.6 Points de vigilance ⚠️ **Pas d'équivalent natif EAG du `final-source` / `final-destination`** : ces endpoints iGO sont consommés en réponse à un statut `RequestSource` / `RequestDestination`. Côté EAG, ils correspondent aux ré-exports `Operation=Update` avec `CanPick=true` / `CanDrop=true` → la pompe sortante doit reconnaître ce pattern et router vers le bon endpoint REST. ⚠️ **Annulation après `Retrieved`** (FAQ #6) : la pompe sortante doit, à la lecture d'un EAG `Operation=Delete`, vérifier le `status` iGO actuel (`GET /api/transports/{id}`). Si `≥ Retrieved` → ne pas appeler `/cancel` et écrire un Flags d'erreur dans AGE pour notifier le WMS. ⚠️ **Persistance** : les tables EAG/AGE/AGS persistent dans la base EasyWMS — pas de risque de perte si le composant côté flotte crashe. Le `BatchId` permet de reprendre proprement. #### 8.4.7 Comparaison avec les services Gateway côté flotte historiques Le **middleware iGO à développer** joue le même rôle que les services Gateway côté flotte que Mecalux a déjà développés pour d'autres protocoles. Comparaison côte à côte : |Aspect|`EasyWMSGateway2015` (Galileo TMS)|`EasyWMSGatewayRocla2015` (Rocla AGV)|Pool IIS iGO (à développer)| |---|---|---|---| |Côté logique|Flotte (TCP frames ↔ hardware)|Flotte (TCP frames ↔ AGV Rocla)|Flotte (REST ↔ iGO PACS)| |Forme|Service Windows|Service Windows|**Pool IIS C# .NET 8**| |Mode de communication aval|TCP socket binaire (port 3000)|TCP socket binaire (port 50011)|HTTPS REST (port 7002)| |Pattern d'échange|Long-polling Search/Event/End|Messages q/m/n/s/b|POST + webhook callback| |Format des messages|Frames GALILEO bas niveau|Frames Rocla propriétaires|JSON REST| |Authentification|`TokenUser` dans `MainObject.config`|(intégrée au protocole Rocla)|`X-API-Key`| |Tables/storage côté flotte|(Galileo a son propre stockage)|SQLite locale (`WCSROCLATASK`) pour mapping interne|(BDD partagée Mecalux uniquement)| |Liaison côté Mecalux|(autre architecture)|**Abonnement direct aux workflows** (`Galileo_SearchCreatedEventHandler_PR`, etc.) — héritage EasyB|**Tables `AGV_*`** (architecture moderne)| |Configuration|`MainObject.config`|`Communications.config` + JSON (Stations/Addresses/ContainerTypes/HeightTypes)|`appsettings.json` ASP.NET Core| |Logs|`C:\ProgramData\Mecalux\EasyWMS Gateway 2015\Logs\AllLog.log`|`C:\ProgramData\Mecalux\EasyWMS GatewayRocla 2015\Logs\`|Logging ASP.NET (Serilog/log4net selon standard projet)| |Architecture|Monolithique|Monolithique (Gateway Mecalux + middleware fusionnés)|**Découplée** via tables `AGV_*`| |Statut|Existant|Existant (historique)|À développer par Mecalux| > 💡 **Architecture moderne vs historique** : le pattern Rocla (`EasyWMSGatewayRocla2015`) **fusionnait** la Gateway Mecalux et le middleware côté flotte en un seul service Windows monolithique qui s'abonnait directement aux workflows EasyWMS et écrivait sa propre base SQLite locale. Le pattern iGO **respecte la séparation moderne** : la Gateway AGV Mecalux (existant côté Mecalux) et la pool IIS C# (côté flotte) communiquent uniquement via les tables `AGV_*`. C'est plus propre, plus testable, et permet de changer le fleet manager sans toucher à la Gateway Mecalux. > > 💡 **Recommandation projet** : ne PAS partir d'un fork de `EasyWMSGatewayRocla2015` (qui est dans l'ancienne architecture monolithique), mais bâtir la pool IIS iGO **from scratch** sur ASP.NET Core .NET 8, avec une dépendance unique vers la base intermédiaire (côté Mecalux) et une dépendance HTTP/REST vers iGO PACS (côté flotte). Cela donne un livrable plus simple, plus testable, et conforme aux standards Mecalux actuels. --- ## 9. FAQ STILL — réponses officielles > Réponses obtenues de STILL en avril 2026 sur les points clés d'intégration. Ces éléments **ont valeur contractuelle** et sont à intégrer aux workflows EasyWMS adaptés iGO. ### FAQ #1 — Identifiant véhicule au passage à `Assigned` **Q.** Lors du passage en état `Assigned`, le payload webhook contient-il l'identifiant du véhicule (sens iGO → EasyWMS) ? **R. STILL.** _Non, l'identifiant du véhicule n'est pas disponible au passage à `Assigned`. L'identifiant du véhicule fait partie du payload à partir du passage à l'état `Retrieved`._ **Impact EasyWMS.** Côté Gateway iGO : ne pas insérer la ligne AGE `EventType=103` avec un `StationNumber` au passage à `Assigned`. Insérer uniquement `EventType=103, Flags=0, StationNumber=null` (vehicle assigned mais inconnu), puis attendre le passage à `Retrieved` pour insérer `EventType=106` avec le `Vehicle.id` cette fois — ce qui déclenchera correctement `ProcessEvent_TaskAssigned_PR` côté core EasyWMS. ### FAQ #2 — Erreurs en cas d'`Aborted` **Q.** En cas d'`Aborted`, reçoit-on un code ou message d'erreur dans le payload ? **R. STILL.** _Non, nous recevons uniquement un POST avec l'état._ **Impact EasyWMS.** Le mapping vers les codes EasyWMS 2003 (extraction error) / 2004 (putaway error) / 2700 (wrong container) n'est **pas dérivable** du callback iGO seul. Côté Gateway iGO, à réception d'un `Aborted` : - soit faire un `GET /api/vehicles/{id}` complémentaire pour récupérer `errors[].errorCode` / `errorLabel` du véhicule, et **traduire** dans `Flags` de la ligne AGE ; - soit insérer un `Flags` générique (à définir, par ex. `2003`) et laisser une notification AGV « Aborted — investigation nécessaire » se déclencher. ### FAQ #3 — Timestamp des événements **Q.** Les événements webhook contiennent-ils un horodatage (timestamp) ? **R. STILL.** _Non._ **Impact EasyWMS.** Le Gateway iGO **doit horodater à la réception** (`DateTime.UtcNow` au moment du POST entrant) avant l'insertion en table `AgeMessages` (champ `CreationDate`). Sinon perte d'information pour le LMS / les KPI / l'audit. ### FAQ #4 — Statut `New` **Q.** Le statut `New` : quand apparaît-il et quelle est la différence avec `Requested` ? **R. STILL.** _Le statut `New` est un statut interne qui n'existe qu'un instant. Vous pouvez considérer que le premier statut est `Requested`._ **Impact EasyWMS.** Pas de gestion à prévoir pour `New`. Le mapping commence directement à `Requested` (= phase EasyWMS 100 / `AgvStatus.Sent`). ### FAQ #5 — Création préalable des palettes (`Load`) **Q.** Faut-il créer les palettes dans iGO (`POST /api/loads`) avant de créer un transport, ou peut-on inclure les infos palette directement dans la création du transport ? **R. STILL.** _Ce n'est pas nécessaire. Ni même souhaitable. Cela augmenterait la complexité de votre côté. Le seul cas d'usage que nous connaissons pour l'utilisation des `Loads`, ce serait dans le cas où le système qui reçoit les palettes est différent de celui qui crée le transport._ **Impact EasyWMS.** Le Gateway iGO **ne doit PAS** appeler `POST /api/loads` en amont du transport. Toutes les informations utiles de la palette (`loadHostId` = `PalletId`, dimensions, customMetaData reprenant `HasTopper`, `PalletType`, `PalletSide` etc.) sont passées **directement dans l'objet `load`** du payload `POST /api/transports`. Cela simplifie le Gateway et évite un point de défaillance supplémentaire. ### FAQ #6 — Annulation après chargement **Q.** Peut-on annuler un transport après que l'AGV a déjà pris la palette (état `Retrieved`) ? **R. STILL.** _Non._ **Impact EasyWMS.** Pas de modification du workflow EasyWMS `AgvTask_SetCancelledTask_PR` lui-même — il continue à écrire une ligne EAG `Operation=Delete` comme d'habitude. **C'est le Gateway iGO** qui, à la lecture de cette ligne, doit : ```text Status iGO courant du transport ? ├ Requested / Pending / Assigned / Retrieving │ → POST /api/transports/{id}/cancel ✅ │ → Insère AGE EventType=255 quand iGO confirme l'annulation │ ├ Retrieved / Storing / Stored │ → ❌ Cancel impossible côté iGO (limite STILL) │ → Le Gateway répond NotifyError dans AGE (Flags spécifique) │ → Le module AGV core notifie l'utilisateur via le notification group AGV │ → Workflow alternatif côté process (attendre Finished + tâche retour, ou RFT) │ └ Cancelled / Aborted / Finished → no-op (déjà terminal) ``` Cette logique est **interne au Gateway iGO** et n'impacte pas le custom EasyWMS. ### FAQ #7 — Cas d'usage du `suspended` **Q.** Le champ `suspended` : quel est son cas d'usage typique ? **R. STILL.** _Cela pourrait être utile si besoin de créer le transport avant que la palette ne soit disponible. Dans notre cas, je ne vois pas à quoi cela pourrait servir._ **Impact EasyWMS.** Champ à **mettre à `false`** par défaut dans tous les `POST /api/transports`. Pas de cas d'usage immédiat dans le mapping standard EasyWMS — pourrait éventuellement servir pour de la pré-réservation dans des scénarios spéciaux (e-commerce wave preparation, etc.) mais hors scope du custom AGV générique. ### FAQ #8 — Authentification **Q.** Authentification : faut-il utiliser `X-API-Key` ou `Bearer token` ? **R. STILL.** _`X-API-Key`._ **Impact EasyWMS.** Le Gateway iGO envoie systématiquement le header : ```http X-API-Key: ``` Le `Authorization: Bearer ` mentionné dans certaines parties de la doc PACS est à **ignorer**. La clé est stockée chiffrée dans la config locale du Gateway (analogie : `PasswordEncrypt.exe` côté `EasyWMSGateway2015`). ### FAQ #9 — Politique de retry des webhooks **Q.** En cas d'indisponibilité de notre serveur webhook, iGO retente-t-il l'envoi des événements ? Si oui, selon quelle politique ? **R. STILL.** _iGO retente l'envoi mais nous ne savons pas à quelle fréquence. À tester._ **Impact EasyWMS.** Le Listener du Gateway iGO **doit être idempotent** : si iGO renvoie le même event 2 fois, ne pas insérer deux lignes dans AGE. Idempotency-key suggérée : - `transport.id + transport.status` pour les events de transport ; - `vehicle.id + vehicle.status` pour les events véhicule (sans timestamp natif — cf. FAQ #3). À implémenter via une table de déduplication interne au Gateway (cache rolling de quelques minutes), ou un index unique sur (`OrderExtId`, `Phase`) côté `AgeMessages`. ⚠️ **Action de test à mener** : pendant la phase d'intégration, simuler un Gateway iGO en panne pendant 30 s / 1 min / 5 min et observer le comportement réel d'iGO (nombre de retries, intervalles, abandon). ### FAQ #10 — Persistance après redémarrage iGO **Q.** Les données de transport survivent-elles à un redémarrage iGO, ou sont-elles uniquement en mémoire vive ? **R. STILL.** _Oui, les données survivent à un redémarrage du système._ **Impact EasyWMS.** - Bonne nouvelle : pas besoin de re-pousser tous les transports en cours après un reboot iGO. - Cependant : les **subscriptions webhook** étaient marquées « _all transports that are still in the memory of E'tricc_ » dans la doc PACS § 2.2.1. Donc à clarifier : les **abonnements** survivent-ils aussi ? Si non, le Gateway doit ré-appeler `POST /api/transports/subscription` au redémarrage. - Recommandation : au boot du **Gateway iGO**, **toujours** : 1. Appeler `GET /api/system` pour voir si la subscription existe. 2. La (re)créer si absente. 3. Faire un `GET /api/transports` pour réconcilier — comparer l'état iGO avec les transports en cours côté tables EAG/AGE et générer les lignes AGE manquantes si nécessaire. ### FAQ #11 — Communication directe ou via iGo Flow **Q.** Communique-t-on directement avec l'API PACS ou via iGo Flow ? **R. STILL.** _Directement avec l'API PACS._ **Impact EasyWMS.** Pas de couche d'orchestration intermédiaire « iGo Flow » à intégrer. Le Gateway iGO appelle directement `https://[IP]:7002/api/...` en HTTPS. Architecture simplifiée : ```text EAG/AGE/AGS ──▶ Gateway iGO ──HTTPS REST──▶ PACS Host API ──▶ iGo / E'tricc ──▶ AGV ▲ │ (pas d'iGo Flow intermédiaire) ``` ### Synthèse FAQ — points-clés à intégrer dans le Gateway iGO |#|Règle dérivée| |---|---| |1|N'insérer le `StationNumber` (= Vehicle.id) dans AGE qu'à partir de `Retrieved` (pas dès `Assigned`)| |2|Pour les `Aborted`, enrichir via `GET /api/vehicles/{id}` (errors[]) avant d'insérer la ligne AGE| |3|Horodater (`CreationDate`) chaque insertion AGE à la **réception** du callback| |4|Ignorer `New`| |5|**Ne PAS** appeler `POST /api/loads` en amont — passer les infos palette dans le transport| |6|À la lecture d'un EAG `Operation=Delete`, vérifier le `status` iGO courant : refuser si ≥ `Retrieved` et générer un Flags d'erreur dans AGE| |7|`suspended = false` par défaut dans `POST /transports`| |8|Header `X-API-Key` (jamais `Bearer`)| |9|Listener **idempotent** (transport.id + status comme clé de déduplication)| |10|À chaque boot du Gateway : vérifier subscriptions + réconcilier transports via `GET /transports`| |11|Pas de couche iGo Flow — appel direct port 7002| --- ## Annexes ### A. Glossaire rapide |Sigle|Signification| |---|---| |**iGO easy**|Fleet manager AGV STILL (KION Group) — variante simple| |**PACS**|Productized Automated Concept Solutions — offre KION large couvrant iGO et au-delà| |**E'tricc**|Moteur interne du fleet manager (apparaît dans la doc PACS)| |**MyMA**|Suite logicielle KION : Vue3 + .NET8 + Postgres — héberge iGO côté admin| |**EXV CB iGo**|Modèle physique — gerbeur électrique automatisé STILL| |**TLS 1.2**|Niveau de chiffrement requis sur le port 7002| |**X-API-Key**|Authentification API officielle (FAQ #8)| |**iGo Flow**|Couche d'orchestration STILL — **non utilisée** dans l'intégration directe (FAQ #11)| ### B. Pointeurs sources |Document|Section utile| |---|---| |`2510_PACS-2.3-Host-Interface-Technical-Specifications_en-US--STILL-.pdf`|Toute l'API REST (chap. 1-8)| |`iGo easy 2.3 - Host Interface Specifications.pdf`|Identique à PACS — confirmant que iGO easy = produit dérivé du même moteur| |`IT requirements R1 20250929.pdf`|Stack, ports, hardware| |`Technical specification EXV CB iGo.pdf`|Datasheet véhicule| |`Limagrain-LWM_Std_Interface_Compliance.xlsx`|Matrice de compliance projet — **à exploiter manuellement** (binaire non lu)| ### C. Cross-référence avec le module AGV EasyWMS Pour le détail du module AGV EasyWMS qui sert de point de comparaison ici, voir le document compagnon `CR_ModuleAGV.md` dans le dossier `CstAGV/`.