# OCPP

> Référence du pilote OCPP : le système central intégré, les certificats des bornes, les tags de connecteur et la règle de nommage Meter, Status et Transaction.

Le pilote OCPP fait de Ganter Lab le **système central** des bornes de recharge de véhicules
qui parlent l'Open Charge Point Protocol. Comme pour LoRaWAN, le sens est
inversé : la station ne se connecte pas à la borne, c'est la **borne qui se connecte
à Ganter Lab** par un WebSocket, s'enregistre, et y pousse sa télémétrie.

Le système central intégré démarre quand le premier équipement OCPP activé est chargé
dans le connector en service, et s'arrête quand le dernier est retiré ou désactivé : sans
aucune borne configurée, rien n'écoute sur le port. En ajouter une le fait
revenir, sans redémarrer l'application. Chaque équipement que vous configurez représente **une
borne**, identifiée par l'ID sous lequel elle se connecte.

## Préparer la borne {#prepare-the-charge-point}

C'est la borne qui appelle cette station et, en sortie d'usine, elle ne sait pas où
la station se trouve. La page de chaque équipement OCPP porte la carte **Préparer la
borne**, avec ce qu'il faut saisir dans les réglages OCPP de la borne, écrit pour
cette station :

| Ce qu'il faut configurer sur la borne | Ce que donne la carte |
|---|---|
| Adresse du système central | `wss://<adresse>:19521/<id-de-la-borne>`, d'abord avec l'adresse par le nom de cette station (le « Nom réseau » de la configuration du serveur OPC UA intégré, ou le nom de l'ordinateur tant qu'il est vide), puis une fois pour chaque adresse IPv4 que cette station a sur un réseau, chacune avec un bouton de copie. Une borne qui vérifie le nom du serveur a besoin de l'adresse par le nom ; une borne qui ne le vérifie pas accepte n'importe laquelle, et celle de son propre réseau suffit alors. |
| Identité de la borne | L'**Identifiant** de l'équipement ou, tant qu'il est vide, le nom que la station donne à l'équipement. Beaucoup de bornes ajoutent elles-mêmes leur identité à l'adresse : sur celles-ci, saisissez l'adresse jusqu'au port seulement, et l'identité dans son propre champ. |
| Sécurité | TLS avec certificat client, ce qu'OCPP appelle le profil de sécurité 3. Les profils 1 et 2, qui n'ont pas de certificat client, ne sont pas acceptés. Le certificat de la borne porte son identité dans son nom commun ou dans un nom alternatif DNS (voir [Certificats](#certificates)). |
| Certificat racine du système central | Le chemin complet de `GanterLabConnector-<station>.pem`, le certificat racine de cette station, que la borne installe pour faire confiance au système central, avec le bouton **Ouvrir le dossier**, qui montre le fichier dans l'explorateur de fichiers de Windows. Le bouton agit dans la fenêtre de la station elle-même ; dans un navigateur sur un autre appareil, il reste grisé et dit pourquoi. |

La carte est ouverte tant que la borne ne s'est pas connectée depuis l'ouverture de
la station, et se replie une fois qu'elle s'est connectée : elle reste sur la page
pour la prochaine fois que la borne sera configurée. Une borne dont aucune racine
installée dans Windows ne garantit le certificat est refusée à sa première connexion
et attend dans [Accès des équipements](#equipment-access).

Le fichier est écrit au premier démarrage du système central, dès qu'une borne est
enregistrée, et jusque-là la carte le dit. C'est le même fichier pour toutes les bornes de
cette station, et il ne change pas quand le nom ou les adresses de la station changent
(voir [Le certificat racine de la station](#the-stations-root-certificate)).

**Toute borne qui a reçu un fichier d'une version antérieure a besoin de celui-ci,
installé une fois.** Au premier démarrage de cette version, une station dont les bornes
peuvent détenir un fichier antérieur affiche sur la carte un avis, **Le fichier de cette
station a changé**, dans cette exécution seulement. L'avis est un rappel, pas la
consigne : installez le nouveau fichier une fois sur chaque borne d'une station qui avait
déjà des bornes, que la carte affiche l'avis ou non. Une borne qui vérifie le nom du
serveur accepte ensuite la station.

## Système central et ports {#central-system-and-ports}

| Quoi | Valeur |
|---|---|
| Versions du protocole | OCPP **1.6**, **2.0**, **2.0.1** et **2.1** (négociation de sous-protocole WebSocket ; JSON) |
| Écoute | Toutes les interfaces, port TCP **19521**, TLS seulement |
| Adresse de la borne | `wss://<adresse-de-la-station>:19521/<id-de-la-borne>` |
| Identité | La dernière partie du chemin WebSocket est l'ID de la borne |

L'écoute est toujours en TLS ; une écoute en HTTP simple est refusée partout sauf sur la
boucle locale, qui n'existe que pour les essais internes au processus. Une borne s'enregistre
avec sa BootNotification (à laquelle on répond par un intervalle de battement de 60 secondes), et chaque
badge présenté pour autorisation est accepté : Ganter Lab observe la recharge, il
ne gère ni tarifs ni accès.

## Certificats {#certificates}

Le côté serveur de la poignée de main TLS présente un certificat signé par la racine propre
à cette station (voir [Le certificat racine de la station](#the-stations-root-certificate)).
Chaque borne doit présenter un **certificat client** :

1. Il doit être digne de confiance de l'une de deux façons : il construit une chaîne valide
   sur cette machine Windows, jusqu'à une racine qui y est installée, sans erreur de
   politique TLS ; ou vous avez approuvé ce certificat précis sous **Accès des équipements**
   sur la page de ce pilote (plus bas). Dans les deux cas, il doit être dans ses dates de
   validité. Une vérification en échec refuse la connexion et le journal enregistre laquelle
   a échoué.
2. Son nom commun de sujet ou un autre nom de sujet DNS doit **nommer l'ID de la borne**
   sous lequel elle se connecte. Un certificat qui nomme une autre borne que
   celle du chemin de connexion est refusé, même approuvé.

Une poignée de main sans certificat client est abandonnée avant qu'aucune donnée ne circule.

### Le certificat racine de la station {#the-stations-root-certificate}

| Quoi | Valeur |
|---|---|
| La racine | Créée une fois par profil, au premier démarrage du système central ou du serveur réseau LoRaWAN. Son sujet est `Ganter Lab Connector (<station>)`, où `<station>` est le nom réseau ce jour-là. Elle n'expire jamais et n'est jamais remplacée d'elle-même : renommer l'ordinateur, changer le nom réseau ou changer les adresses de la station la laisse telle quelle. |
| Le fichier | `GanterLabConnector-<station>.pem`, la partie publique seulement, dans le dossier de données sous `ua\pki\station`. C'est le même fichier pour une borne et pour une passerelle LoRaWAN, qui l'installe comme `tc.trust`. |
| Le certificat que présente le système central | Signé par cette racine. Il nomme le nom réseau de la station (le « Nom réseau » de la configuration du serveur OPC UA intégré ; le nom de l'ordinateur tant qu'il est vide), `localhost` et chaque adresse IPv4 de la station, si bien qu'une borne qui vérifie le nom du serveur (profil de sécurité 3) l'accepte. Quand le nom réseau ou une adresse change, seul ce certificat est émis de nouveau, de lui-même, sans rien à faire sur la borne. |
| Le certificat du serveur OPC UA | Pas utilisé ici. Le serveur OPC UA intégré garde son propre certificat pour les clients OPC UA. |

Une racine enregistrée qui ne peut plus être ouverte, par exemple parce qu'elle a été écrite
par un autre compte Windows, est remplacée par une nouvelle. Chaque borne a alors besoin du
nouveau fichier, une fois, et la carte le dit.

### Accès des équipements {#equipment-access}

Une borne dont aucune racine installée dans Windows ne garantit le certificat, parce qu'il
est auto-signé ou émis par l'autorité du fabricant lui-même, n'a pas besoin que cette racine
soit installée sur cet ordinateur. Sa première connexion est refusée, et son certificat
attend sous **Accès des équipements**, à la fin de la page du pilote OCPP, la même carte que
celle de la page du pilote OPC UA, jusqu'à ce que vous décidiez :

| Groupe | Ce qu'il montre | Ce que vous pouvez faire |
|---|---|---|
| En attente d'approbation | Chaque certificat refusé, sous l'ID de la borne avec lequel elle s'est connectée : son empreinte SHA-256, sa dernière tentative et leur nombre, et ses détails (sujet, émetteur, noms de domaine, dates de validité). | **Approuver** admet le certificat dès la prochaine connexion de la borne. **Bloquer** continue de le refuser sans le relister ici. **Écarter tous les certificats en attente** vide la liste sans rien approuver ni bloquer. |
| Équipements approuvés | Les certificats que vous avez approuvés ou importés, avec qui a décidé et quand. | **Retirer l'approbation** ferme la connexion de la borne et remet son certificat dans la liste. **Importer un certificat** approuve le certificat public d'une borne avant sa première connexion. |
| Équipements bloqués | Les certificats que vous avez bloqués. Un certificat bloqué est refusé même si Windows lui fait confiance. | **Débloquer** remet le certificat dans la liste, sans l'approuver. |

Chaque certificat est approuvé pour lui-même, jamais l'autorité qui l'a signé : une deuxième
borne du même fabricant attend donc sa propre approbation. Comparez l'empreinte avec celle
qu'indique la borne avant de l'approuver. L'approbation ne change pas la borne que le
certificat désigne : il reste admis uniquement sous l'ID de la borne qu'il nomme, et
uniquement dans ses dates de validité. Un certificat auquel Windows fait déjà confiance est
admis comme avant et n'apparaît jamais ici ; rien n'est approuvé automatiquement.

Les décisions sont gardées dans le dossier de données de la station, sous `ua\pki\ocpp`, et
survivent à un redémarrage. Seul un rôle qui peut configurer le Connector reçoit les
commandes, et elles n'agissent que dans la fenêtre de la station elle-même : un navigateur sur
un autre appareil lit la carte sans la modifier, et aucun outil d'agent n'approuve un
certificat. La liste garde jusqu'à 100 certificats en attente d'approbation ; une fois
pleine, un nouveau certificat reste refusé mais n'est pas listé, et la carte le dit.

## Champs de connexion {#connection-fields}

| Champ | Ce que c'est | Format | Défaut |
|---|---|---|---|
| Identifiant | L'**ID de la borne** que cet équipement représente : le même ID que la borne place au bout de son URL de connexion et porte dans son certificat. | Texte libre, comparé sans tenir compte de la casse. Vide retombe sur le nom d'équipement assaini. | vide |

Il n'y a ni champ d'hôte, ni de port, ni d'identifiants : la borne détient les détails de
connexion, et cette station a seulement besoin de savoir quelle borne l'équipement désigne.
Il n'y a pas non plus de champ de période de scrutation. OCPP est fondé sur la poussée : la borne envoie
des messages MeterValues et StatusNotification à sa propre cadence, et les tags
se rafraîchissent depuis les dernières données reçues sur un cycle fixe d'une seconde.

Une borne qui ne s'est pas encore connectée, ou un connecteur qui n'a pas encore rapporté,
n'a donc **aucune lecture**, et non une lecture en échec. Ses tags restent vides et aucun
échec n'est journalisé : une valeur que la borne n'a pas encore envoyée, c'est le protocole
qui fonctionne.

### L'état de santé de la borne {#the-charge-points-health}

Comme une borne envoie ses valeurs quand elle en a, le silence de ses tags ne peut pas
distinguer une borne qui n'a pas encore rapporté d'une borne qui n'est plus là. Son état de
santé, le point sur sa ligne dans l'arborescence et la colonne **État de santé** sur la page
du pilote, suit plutôt sa connexion au système central de cette station :

| Situation | État de santé |
|---|---|
| Configurée, et pas connectée depuis l'ouverture de la station | **Hors ligne** |
| Connectée, rien envoyé encore | **En ligne** |
| Connectée et qui envoie | **En ligne**, ou **Partiellement en ligne** quand certaines des valeurs qu'elle a envoyées ne se lisent pas |
| Tombée : arrêtée, débranchée ou coupée du réseau | **Hors ligne**, jusqu'à ce qu'elle se reconnecte |
| Le système central n'écoute pas | **Hors ligne** |
| Désactivé | **Désactivé** |

Tant que la borne est connectée, un connecteur qui n'a pas encore rapporté ne compte pas
contre elle. Pendant au plus dix secondes après l'enregistrement d'une modification de la
borne, ou le démarrage du Connector, elle se lit **Pas encore connu** : remettre
l'équipement en place peut redémarrer le système central, et la borne met un moment à se
reconnecter.

## Tags {#tags}

Un tag OCPP lit un **connecteur** de la borne (connecteur au sens OCPP :
une position de prise, numérotée à partir de 1). En OCPP 2.0, 2.0.1 et 2.1, le numéro est celui de l'**EVSE**,
car les connecteurs y sont numérotés de nouveau à partir de 1 dans chaque EVSE. Trois sortes de tags existent, distinguées par
le **suffixe du nom du tag**, qui est validé :

| Le nom du tag se termine par | Ce qu'il lit | Type sensé |
|---|---|---|
| `Meter` | La dernière valeur de compteur échantillonnée que le connecteur a rapportée (MeterValues OCPP ; en OCPP 2.x, aussi les valeurs qu'un TransactionEvent apporte pendant une recharge). L'unité est ce que la borne envoie, typiquement le Wh. Le serveur garde les 10 derniers échantillons et le tag lit le plus récent. Un connecteur qui n'a jamais rapporté se lit comme une valeur vide, pas comme zéro. | Float ou Double |
| `Status` | Le texte d'état du connecteur, tiré de la dernière StatusNotification (par exemple `Available`, `Faulted`). En OCPP 2.x, un EVSE à plusieurs connecteurs se lit comme le plus parlant d'entre eux : `Faulted` l'emporte sur `Occupied`, `Occupied` sur `Reserved`, `Reserved` sur `Available`, et `Available` sur `Unavailable`. Un EVSE qui n'a encore rapporté aucun état se lit comme une valeur vide. | String |
| `Transaction` | Le numéro de la transaction en cours sur le connecteur, celui que demandent les commandes RemoteStopTransaction et GetTransactionStatus : en OCPP 1.6, le numéro que cette station a donné à la transaction à son début ; en OCPP 2.x, l'identifiant propre de la borne, tel qu'elle l'a envoyé. Il est rempli quand une transaction commence et vidé quand elle se termine : sans transaction en cours, le tag lit un texte vide. Tant qu'aucune transaction n'a commencé ni fini depuis que la borne s'est connectée, il se lit comme une valeur vide, car une transaction pouvait déjà être en cours. | String |

Un nom sans l'un de ces suffixes est refusé par la validation : nommez les tags
`Connector1Meter`, `Connector1Status` et `Connector1Transaction`.

| Champ | Ce qu'il fait | Valeurs | Défaut |
|---|---|---|---|
| Connecteur | Le numéro que ce tag lit : celui du connecteur en OCPP 1.6, celui de l'EVSE en OCPP 2.x. | 1 ou plus | 1 |
| Type de donnée | Le type OPC UA sous lequel la valeur est exposée. | Int32, Float, Double, String | Float |

Les tags OCPP sont en **lecture seule** : le champ d'accès ne propose aucun choix inscriptible, et une
écriture est refusée plutôt que feinte. Commander une borne est une commande à part
entière, décrite juste après, pas une valeur écrite dans un tag.

## Commandes {#commands}

Une borne se commande autant qu'elle se lit. Chaque équipement OCPP porte les commandes
ci-dessous en **méthodes sur l'équipement** dans l'espace d'adressage OPC UA propre à cette station, si bien que
un client OPC UA connecté à cette station en envoie une en appelant la méthode.

Chaque commande prend l'**ID de la borne** en premier argument, et rend la
réponse propre de la borne en résultat.

| Commande | Autres arguments | Ce qu'elle fait |
| --- | --- | --- |
| ChangeAvailability | ConnectorId, Type (`Operative` ou `Inoperative`) | Met un connecteur en service ou hors service. |
| ChangeConfiguration | Key, Value | Pose une clé de configuration sur la borne (OCPP 1.6). |
| ClearCache | aucun | Vide le cache d'autorisation de la borne. |
| GetConfiguration | Key | Lit une clé de configuration (OCPP 1.6). |
| RemoteStartTransaction | IdTag | Démarre une session de recharge pour un jeton. |
| RemoteStopTransaction | TransactionId | Arrête une session en cours. |
| GetTransactionStatus | TransactionId | Demande si une transaction tourne encore (OCPP 2.x). |
| Reset | aucun | Redémarre la borne. |
| UnlockConnector | ConnectorId | Libère le câble d'un connecteur. |
| SetChargingProfile | ConnectorId, Limit, NumberOfPhases | Pose une limite de puissance de recharge, en watts. ConnectorId 0 limite la borne entière ; un autre numéro pose la limite par défaut des sessions que ce connecteur recharge. |
| SetVariables | ComponentName, VariableName, AttributeType, AttributeValue | Pose une variable d'un composant (OCPP 2.x). |
| GetVariables | ComponentName, VariableName, AttributeType | Lit une variable d'un composant (OCPP 2.x). |

`AttributeType` vaut `Actual`, `Target`, `MinSet` ou `MaxSet`.

**D'où vient le TransactionId.** RemoteStopTransaction et GetTransactionStatus agissent sur une transaction, désignée par son numéro. Lisez-le dans le tag `Transaction` du connecteur sur lequel la session charge (l'EVSE en OCPP 2.x), par exemple `Connector1Transaction`, et transmettez-le tel qu'il se lit. Un texte vide à cet endroit signifie qu'aucune transaction n'est en cours sur ce connecteur.

**Un catalogue pour toutes les versions.** Les commandes gardent les noms ci-dessus quelle que
soit la version que parle la borne, et la station envoie chacune dans la forme que cette version
définit. En OCPP 2.0, 2.0.1 et 2.1, les connecteurs sont regroupés sous des EVSE, et le numéro
passé comme ConnectorId désigne l'EVSE.

| Commande | En OCPP 1.6 | En OCPP 2.0, 2.0.1 et 2.1 |
| --- | --- | --- |
| ChangeAvailability | Agit sur le connecteur indiqué ; 0 est la borne entière. | Agit sur l'EVSE indiqué ; 0 est la borne entière. |
| RemoteStartTransaction | Envoie l'IdTag, et la borne choisit le connecteur. | Part comme RequestStartTransaction, avec l'IdTag comme jeton central et un identifiant de démarrage propre ; la borne choisit l'EVSE. |
| RemoteStopTransaction | Le TransactionId est le numéro que cette station a donné à la session à son début. | Part comme RequestStopTransaction ; le TransactionId est l'identifiant propre de la borne, transmis comme texte. |
| Reset | Un redémarrage complet. | Un redémarrage immédiat. |
| UnlockConnector | Libère le connecteur indiqué. | Libère le premier connecteur de l'EVSE indiqué. |
| SetChargingProfile | 0 pose le profil maximal de la borne ; un autre connecteur reçoit un profil par défaut. | 0 pose le profil maximal de la borne ; un autre EVSE reçoit un profil par défaut. |
| ChangeConfiguration, GetConfiguration | Comme dans le tableau ci-dessus. | Absentes de ces versions : la borne répond par une erreur, et la commande échoue. |
| GetTransactionStatus, SetVariables, GetVariables | Absentes de cette version : la borne répond par une erreur, et la commande échoue. | Comme dans le tableau ci-dessus. |

**Attendre la réponse.** Une commande n'est pas finie quand la station l'a envoyée.
La station tient l'appel ouvert jusqu'à ce que la borne réponde à l'ordre même qu'elle
a envoyé, apparié par l'identifiant de corrélation qui voyage avec lui, et alors seulement
rapporte le succès et rend la réponse. Trois choses y mettent fin autrement, chacune
rapportée comme un échec avec sa raison :

- La borne n'est pas connectée, ou sa connexion n'est pas ouverte. Rien n'est envoyé.
- La borne répond par une erreur OCPP, par exemple pour une commande qu'elle n'implémente
  pas. Le code d'erreur est la raison.
- **30 secondes** passent sans aucune réponse. Une commande à laquelle personne n'a répondu est un échec,
  jamais un succès.

Une commande envoyée pour une borne qu'un équipement ne porte pas, ou qui n'est pas
connectée, est refusée tout de suite plutôt que mise en file.

## Découverte {#discovery}

**Découvrir** sur le pilote OCPP liste les bornes **actuellement connectées** au
système central, et lire les voies d'un candidat propose un tag `Meter`, un tag
`Status` et un tag `Transaction` par connecteur que la borne a rapporté jusqu'ici.

La **première borne se configure toujours à la main**. Rien ne peut se connecter avant que
le système central n'écoute, et il n'écoute qu'une fois qu'un équipement OCPP existe ici, si bien qu'un
balayage sur une installation sans borne configurée ne trouve rien et le dit.
Ajoutez ce premier équipement avec l'ID sous lequel la borne se connectera ; après cela, une
borne qui s'est connectée peut être découverte. Le déroulement général de la découverte est décrit
sur la page [Connector](connector).

L'ID est comparé **sans tenir compte de la casse**, dans le certificat, dans le chemin de
connexion et face à l'équipement : une borne qui se connecte comme `cp-a` avec un certificat
qui nomme `CP-A` est la même borne qu'un équipement dont l'identifiant indique `CP-A`.

Une borne que vous avez déjà relit ses connecteurs depuis sa propre page : **Découvrir les tags**, dans l'en-tête de sa carte **Tags**, propose les tags `Meter`, `Status` et `Transaction` de chaque connecteur qu'elle a rapporté pendant qu'elle était connectée et pour lequel l'équipement n'a pas encore de tag (voir [Découvrir les tags d'un équipement](connector-discovery#discovering-a-devices-tags)).
