feat: docs-as-code — générateur, literate-nav, badges, CI Gitea Actions
- PORTING_STATUS.yaml : source de vérité canal APT + placement nav - scripts/gen_device_reference.py : génération matrice + fiches + SUMMARY.md depuis integrationplugin*.json + meta.json ; nightly sans JSON = invisible - mkdocs.yml : plugin literate-nav, nav 6 sections, Appareils via SUMMARY.md - .gitea/workflows/docs.yml : CI complet — fetch JSON (branche auto-détectée), génération, build --strict, check idempotence, rsync deploy - Badges HTML (stable/testing/nightly + consumer/community + ok/part/road) - Fiches appareils : Eastron, ABB B2x, ABB Terra, Keba, Waveshare - requirements.txt : mkdocs-material, mkdocs-literate-nav, PyYAML Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
parent
394d8bc54a
commit
9eee067829
94
.gitea/workflows/docs.yml
Normal file
94
.gitea/workflows/docs.yml
Normal file
@ -0,0 +1,94 @@
|
||||
name: Build & Deploy docs
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
schedule:
|
||||
- cron: '0 3 * * *' # mise à jour nocturne (meta.json des repos plugins)
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
build-deploy:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Python
|
||||
uses: actions/setup-python@v5
|
||||
with:
|
||||
python-version: "3.11"
|
||||
|
||||
- name: Install dependencies
|
||||
run: pip install -r requirements.txt
|
||||
|
||||
# ── Récupération des JSON depuis les 5 repos drivers ─────────────────
|
||||
- name: Fetch plugin JSON files
|
||||
env:
|
||||
GITEA_TOKEN: ${{ secrets.MKDOCS_TOKEN }}
|
||||
run: |
|
||||
GITEA_BASE="https://git.etm-powersync.fr"
|
||||
AUTH_BASE="https://pakutz79:${GITEA_TOKEN}@git.etm-powersync.fr"
|
||||
mkdir -p .plugins-src
|
||||
|
||||
for repo in etm-powersync-plugins etm-powersync-plugins-modbus \
|
||||
nymea-plugins nymea-plugins-modbus nymea-generic; do
|
||||
|
||||
# Branche par défaut via API Gitea (pas de hardcoding main/master)
|
||||
BRANCH=$(curl -sf \
|
||||
-H "Authorization: token ${GITEA_TOKEN}" \
|
||||
"${GITEA_BASE}/api/v1/repos/ETM-Schurig/${repo}" \
|
||||
| python3 -c "import sys,json; d=json.load(sys.stdin); print(d.get('default_branch','main'))" \
|
||||
2>/dev/null) || BRANCH="main"
|
||||
|
||||
echo "→ ${repo} (branche: ${BRANCH})"
|
||||
git clone --depth 1 --branch "${BRANCH}" \
|
||||
"${AUTH_BASE}/ETM-Schurig/${repo}.git" \
|
||||
".plugins-src/${repo}" \
|
||||
|| echo "WARNING: ${repo} introuvable ou inaccessible — ignoré"
|
||||
done
|
||||
|
||||
# ── Génération de la doc ──────────────────────────────────────────────
|
||||
- name: Generate device reference + SUMMARY.md
|
||||
run: |
|
||||
python3 scripts/gen_device_reference.py \
|
||||
--src .plugins-src \
|
||||
--docs docs \
|
||||
--lang fr
|
||||
|
||||
# ── Build MkDocs ──────────────────────────────────────────────────────
|
||||
- name: MkDocs build --strict
|
||||
run: mkdocs build --strict
|
||||
|
||||
# ── Vérification idempotence ──────────────────────────────────────────
|
||||
- name: Check generated content is up-to-date
|
||||
run: |
|
||||
python3 scripts/gen_device_reference.py \
|
||||
--src .plugins-src \
|
||||
--docs docs \
|
||||
--lang fr \
|
||||
--check
|
||||
|
||||
# ── SSH ───────────────────────────────────────────────────────────────
|
||||
- name: Setup SSH deploy key
|
||||
env:
|
||||
SSH_KEY: ${{ secrets.DOCS_DEPLOY_SSH_KEY }}
|
||||
DEPLOY_HOST: ${{ secrets.DOCS_DEPLOY_HOST }}
|
||||
run: |
|
||||
mkdir -p ~/.ssh
|
||||
printf '%s\n' "${SSH_KEY}" > ~/.ssh/deploy_key
|
||||
chmod 600 ~/.ssh/deploy_key
|
||||
ssh-keyscan -H "${DEPLOY_HOST}" >> ~/.ssh/known_hosts
|
||||
|
||||
# ── Déploiement ───────────────────────────────────────────────────────
|
||||
- name: Deploy via rsync
|
||||
env:
|
||||
DEPLOY_USER: ${{ secrets.DOCS_DEPLOY_USER }}
|
||||
DEPLOY_HOST: ${{ secrets.DOCS_DEPLOY_HOST }}
|
||||
DEPLOY_PATH: ${{ secrets.DOCS_DEPLOY_PATH }}
|
||||
run: |
|
||||
rsync -az --delete \
|
||||
-e "ssh -i ~/.ssh/deploy_key -o StrictHostKeyChecking=yes" \
|
||||
site/ \
|
||||
"${DEPLOY_USER}@${DEPLOY_HOST}:${DEPLOY_PATH}"
|
||||
3
.gitignore
vendored
3
.gitignore
vendored
@ -1 +1,4 @@
|
||||
.venv/
|
||||
site/
|
||||
.plugins-src/
|
||||
.claude/
|
||||
|
||||
63
PORTING_STATUS.yaml
Normal file
63
PORTING_STATUS.yaml
Normal file
@ -0,0 +1,63 @@
|
||||
# Source de vérité : canal APT + placement nav.
|
||||
# title/tagline/stability/icon → meta.json du repo plugin.
|
||||
# slug : nom de fichier de la fiche (défaut = plugin).
|
||||
|
||||
- repo: etm-powersync-plugins-modbus
|
||||
plugin: eastron
|
||||
name: Eastron SDM
|
||||
channel: stable
|
||||
category: compteur
|
||||
|
||||
- repo: etm-powersync-plugins-modbus
|
||||
plugin: abbb2x
|
||||
slug: abb-b2x
|
||||
name: Compteur ABB B2x
|
||||
channel: testing
|
||||
category: compteur
|
||||
|
||||
- repo: etm-powersync-plugins-modbus
|
||||
plugin: waveshare-relay-d8
|
||||
slug: waveshare
|
||||
name: Waveshare relais
|
||||
channel: testing
|
||||
category: smartdevice
|
||||
|
||||
- repo: etm-powersync-plugins-modbus
|
||||
plugin: abbterra
|
||||
slug: abb-terra
|
||||
name: Borne ABB Terra AC
|
||||
channel: testing
|
||||
category: irve
|
||||
|
||||
- repo: nymea-plugins
|
||||
plugin: keba
|
||||
name: Keba
|
||||
channel: nightly
|
||||
category: irve
|
||||
|
||||
- repo: nymea-plugins
|
||||
plugin: fronius
|
||||
name: Fronius
|
||||
channel: nightly
|
||||
category: onduleur
|
||||
|
||||
- repo: nymea-plugins
|
||||
plugin: daikinairco
|
||||
name: Daikin
|
||||
channel: nightly
|
||||
category: hvac
|
||||
subcategory: climatisation
|
||||
|
||||
- repo: nymea-plugins
|
||||
plugin: sgready
|
||||
name: SG-Ready
|
||||
channel: nightly
|
||||
category: hvac
|
||||
subcategory: pac
|
||||
|
||||
- repo: nymea-plugins
|
||||
plugin: simpleheatpump
|
||||
name: SimpleHeatpump
|
||||
channel: nightly
|
||||
category: hvac
|
||||
subcategory: pac
|
||||
15
docs/appareils/SUMMARY.md
Normal file
15
docs/appareils/SUMMARY.md
Normal file
@ -0,0 +1,15 @@
|
||||
* [Compatibilité](compatibilite.md)
|
||||
* [Compteurs](compteurs/index.md)
|
||||
* [Eastron SDM](compteurs/eastron.md)
|
||||
* [Compteur ABB B2x](compteurs/abb-b2x.md)
|
||||
* [Bornes de recharge](bornes/index.md)
|
||||
* [Borne ABB Terra AC](bornes/abb-terra.md)
|
||||
* [Keba](bornes/keba.md)
|
||||
* [SmartDevices](smart/index.md)
|
||||
* [Waveshare relais](smart/waveshare.md)
|
||||
* [HVAC](hvac/index.md)
|
||||
* [Daikin](hvac/daikinairco.md)
|
||||
* [SG-Ready](hvac/sgready.md)
|
||||
* [SimpleHeatpump](hvac/simpleheatpump.md)
|
||||
* [Onduleurs / PV](onduleurs/index.md)
|
||||
* [Fronius](onduleurs/fronius.md)
|
||||
@ -1,3 +0,0 @@
|
||||
# Bornes de recharge
|
||||
|
||||
> Stub — détail des bornes supportées, registres Modbus, particularités d'intégration.
|
||||
104
docs/appareils/bornes/abb-terra.md
Normal file
104
docs/appareils/bornes/abb-terra.md
Normal file
@ -0,0 +1,104 @@
|
||||
# Borne ABB Terra AC
|
||||
|
||||
<span class="badge testing">TESTING</span> <span class="badge consumer">CONSUMER</span>
|
||||
|
||||
La borne de recharge ABB Terra AC existe en deux variantes de communication :
|
||||
**Modbus TCP** (réseau Ethernet/LAN) et **Modbus RTU** (bus RS485).
|
||||
|
||||
## 1. Choix de la variante
|
||||
|
||||
- **TCP** : la borne est sur le réseau local, repérée par son adresse IP /
|
||||
nom d'hôte. Ajout par découverte réseau.
|
||||
- **RTU** : la borne est sur un bus RS485, repérée par son adresse esclave.
|
||||
|
||||
## 2. Raccordement
|
||||
|
||||
- TCP : câble Ethernet vers le réseau du hub.
|
||||
- RTU : A↔A, B↔B, masse, terminaison 120 Ω.
|
||||
|
||||
## 3. Ajout dans PowerSync
|
||||
|
||||
Variante TCP : **découverte automatique** sur le réseau, ou ajout **manuel**
|
||||
(IP, port). Variante RTU : ajout via le maître RTU + adresse esclave.
|
||||
Voir [Ajouter un appareil](../../installation/application.md).
|
||||
|
||||
## 4. Vérification
|
||||
|
||||
`connected`, `pluggedIn` puis `charging` reflètent l'état de la session ;
|
||||
`maxChargingCurrent` reflète la consigne de courant.
|
||||
|
||||
---
|
||||
|
||||
## Référence
|
||||
|
||||
<!-- BEGIN GENERATED: integrationpluginabbterra.json -->
|
||||
**Fabricant :** ABB
|
||||
**Plugin :** `AbbTerra`
|
||||
|
||||
#### Modèles pris en charge
|
||||
| Modèle | Rôle | Transport | Ajout | Grandeurs |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| **Terra AC Charger (TCP)** | Borne de recharge | Modbus TCP | Découverte automatique / Ajout manuel | 17 |
|
||||
| **Terra AC Charger (RTU)** | Borne de recharge | Modbus RTU | Découverte automatique / Ajout manuel | 17 |
|
||||
|
||||
#### Détail par modèle
|
||||
??? abstract "Terra AC Charger (TCP) — `terraAcTcp`"
|
||||
_Réglages :_
|
||||
| Clé | Libellé | Type | Plage | Défaut | Lecture seule |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `macAddress` | MAC address | QString | — | — | oui |
|
||||
| `address` | Host address | QString | — | — | non |
|
||||
| `hostName` | Host name | QString | — | — | non |
|
||||
| `port` | Port | uint | — | `502` | non |
|
||||
| `slaveId` | Slave ID | uint | 1–255 | `1` | non |
|
||||
|
||||
_Grandeurs mesurées :_
|
||||
| Clé | Grandeur | Type | Unité |
|
||||
| --- | --- | --- | --- |
|
||||
| `connected` | Connected | bool | — |
|
||||
| `pluggedIn` | Plugged in | bool | — |
|
||||
| `charging` | Charging | bool | — |
|
||||
| `power` | Charging enabled | bool | — |
|
||||
| `maxChargingCurrent` | Maximum charging current | double | Ampere |
|
||||
| `phaseCount` | Phase count | uint | — |
|
||||
| `currentPower` | Active power | double | Watt |
|
||||
| `currentPhase1` | Current phase 1 | double | Ampere |
|
||||
| `currentPhase2` | Current phase 2 | double | Ampere |
|
||||
| `currentPhase3` | Current phase 3 | double | Ampere |
|
||||
| `voltagePhase1` | Voltage phase 1 | double | Volt |
|
||||
| `voltagePhase2` | Voltage phase 2 | double | Volt |
|
||||
| `voltagePhase3` | Voltage phase 3 | double | Volt |
|
||||
| `sessionEnergy` | Session energy | double | KiloWattHour |
|
||||
| `firmwareVersion` | Firmware version | QString | — |
|
||||
| `serialNumber` | Serial number | QString | — |
|
||||
| `errorCode` | Error code | uint | — |
|
||||
|
||||
??? abstract "Terra AC Charger (RTU) — `terraAcRtu`"
|
||||
_Réglages :_
|
||||
| Clé | Libellé | Type | Plage | Défaut | Lecture seule |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `rtuMaster` | Modbus RTU master | QString | — | — | non |
|
||||
| `slaveId` | Modbus slave ID | uint | 1–247 | `1` | non |
|
||||
|
||||
_Grandeurs mesurées :_
|
||||
| Clé | Grandeur | Type | Unité |
|
||||
| --- | --- | --- | --- |
|
||||
| `connected` | Connected | bool | — |
|
||||
| `pluggedIn` | Plugged in | bool | — |
|
||||
| `charging` | Charging | bool | — |
|
||||
| `power` | Charging enabled | bool | — |
|
||||
| `maxChargingCurrent` | Maximum charging current | double | Ampere |
|
||||
| `phaseCount` | Phase count | uint | — |
|
||||
| `currentPower` | Active power | double | Watt |
|
||||
| `currentPhase1` | Current phase 1 | double | Ampere |
|
||||
| `currentPhase2` | Current phase 2 | double | Ampere |
|
||||
| `currentPhase3` | Current phase 3 | double | Ampere |
|
||||
| `voltagePhase1` | Voltage phase 1 | double | Volt |
|
||||
| `voltagePhase2` | Voltage phase 2 | double | Volt |
|
||||
| `voltagePhase3` | Voltage phase 3 | double | Volt |
|
||||
| `sessionEnergy` | Session energy | double | KiloWattHour |
|
||||
| `firmwareVersion` | Firmware version | QString | — |
|
||||
| `serialNumber` | Serial number | QString | — |
|
||||
| `errorCode` | Error code | uint | — |
|
||||
|
||||
<!-- END GENERATED -->
|
||||
8
docs/appareils/bornes/index.md
Normal file
8
docs/appareils/bornes/index.md
Normal file
@ -0,0 +1,8 @@
|
||||
# Bornes de recharge
|
||||
|
||||
Bornes EVSE intégrées dans ETM PowerSync pour la recharge pilotée des véhicules électriques.
|
||||
|
||||
| Appareil | Protocole | Canal | Stabilité |
|
||||
|---|---|---|---|
|
||||
| [Borne ABB Terra AC](abb-terra.md) | Modbus TCP / RTU | <span class="badge testing">TESTING</span> | <span class="badge consumer">CONSUMER</span> |
|
||||
| [Keba](keba.md) | Modbus TCP | <span class="badge nightly">NIGHTLY</span> | <span class="badge community">COMMUNITY</span> |
|
||||
61
docs/appareils/bornes/keba.md
Normal file
61
docs/appareils/bornes/keba.md
Normal file
@ -0,0 +1,61 @@
|
||||
# Keba
|
||||
|
||||
<span class="badge nightly">NIGHTLY</span> <span class="badge community">COMMUNITY</span>
|
||||
|
||||
Bornes de recharge Keba (séries P30, P31), communication **Modbus TCP** via réseau local.
|
||||
|
||||
## 1. Matériel requis
|
||||
|
||||
- Borne Keba P30 ou P31
|
||||
- Connexion Ethernet vers le réseau du hub
|
||||
|
||||
## 2. Activation Modbus TCP
|
||||
|
||||
Modbus TCP est **désactivé par défaut** sur les bornes Keba.
|
||||
Activez-le dans l'interface web de la borne (port `502`).
|
||||
|
||||
!!! warning "Activation Modbus"
|
||||
Sans cette étape, la borne ne répondra pas à PowerSync.
|
||||
|
||||
## 3. Ajout dans PowerSync
|
||||
|
||||
Ajout par **découverte automatique** sur le réseau, ou **manuel** (IP, port 502).
|
||||
Voir [Ajouter un appareil](../../installation/application.md).
|
||||
|
||||
## 4. Vérification
|
||||
|
||||
`connected`, `pluggedIn` puis `charging` reflètent l'état de la session.
|
||||
|
||||
---
|
||||
|
||||
## Référence
|
||||
|
||||
<!-- BEGIN GENERATED: integrationpluginkeba.json -->
|
||||
**Fabricant :** Keba
|
||||
**Plugin :** `keba`
|
||||
|
||||
#### Modèles pris en charge
|
||||
| Modèle | Rôle | Transport | Ajout | Grandeurs |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| **Keba P30 / P31** | Borne de recharge | Modbus TCP | Découverte automatique / Ajout manuel | 6 |
|
||||
|
||||
#### Détail par modèle
|
||||
??? abstract "Keba P30 / P31 — `kebaEVCharger`"
|
||||
_Réglages :_
|
||||
| Clé | Libellé | Type | Plage | Défaut | Lecture seule |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `macAddress` | MAC address | QString | — | — | oui |
|
||||
| `address` | Host address | QString | — | — | non |
|
||||
| `port` | Port | uint | — | `502` | non |
|
||||
|
||||
_Grandeurs mesurées :_
|
||||
| Clé | Grandeur | Type | Unité |
|
||||
| --- | --- | --- | --- |
|
||||
| `connected` | Connected | bool | — |
|
||||
| `pluggedIn` | Plugged in | bool | — |
|
||||
| `charging` | Charging | bool | — |
|
||||
| `maxChargingCurrent` | Maximum charging current | double | Ampere |
|
||||
| `currentPower` | Active power | double | Watt |
|
||||
| `sessionEnergy` | Session energy | double | KiloWattHour |
|
||||
|
||||
<!-- END GENERATED -->
|
||||
@ -1,39 +1,47 @@
|
||||
# Compatibilité
|
||||
|
||||
Liste de référence des équipements. **Source de vérité** : générée à partir du suivi de
|
||||
portage (`PORTING_STATUS`). Statuts : [Supporté]{.badge .ok} ·
|
||||
[Partiel]{.badge .part} · [Roadmap]{.badge .road}.
|
||||
Liste de référence des équipements supportés par ETM PowerSync. Générée depuis
|
||||
`PORTING_STATUS.yaml` — ne pas modifier manuellement entre les marqueurs.
|
||||
|
||||
!!! warning "À automatiser"
|
||||
Cette page sera générée depuis `PORTING_STATUS` pour éviter la double saisie.
|
||||
Le tableau ci-dessous est un point de départ manuel.
|
||||
|
||||
## Bornes de recharge (EVSE)
|
||||
|
||||
| Marque / Modèle | Protocole | Statut |
|
||||
|---|---|---|
|
||||
| Keba | Modbus TCP | [Partiel]{.badge .part} |
|
||||
| Badge | Signification |
|
||||
|---|---|
|
||||
| <span class="badge stable">STABLE</span> | Disponible sur le dépôt APT **stable** — prêt pour la production |
|
||||
| <span class="badge testing">TESTING</span> | Disponible sur le dépôt APT **testing** — fonctionnel, en cours d'épreuve |
|
||||
| <span class="badge nightly">NIGHTLY</span> | Portage en cours — non disponible en production |
|
||||
|
||||
<!-- BEGIN GENERATED: __matrix__ -->
|
||||
## Compteurs
|
||||
|
||||
| Marque / Modèle | Protocole | Statut |
|
||||
|---|---|---|
|
||||
| Eastron SDM | Modbus RTU | [Supporté]{.badge .ok} |
|
||||
| Waveshare (relais) | Modbus | [Supporté]{.badge .ok} |
|
||||
| Marque / Modèle | Protocole | Canal | Stabilité |
|
||||
|---|---|---|---|
|
||||
| Eastron SDM | Modbus RTU | <span class="badge stable">STABLE</span> | <span class="badge consumer">CONSUMER</span> |
|
||||
| Compteur ABB B2x | Modbus RTU | <span class="badge testing">TESTING</span> | <span class="badge consumer">CONSUMER</span> |
|
||||
|
||||
## Bornes de recharge
|
||||
|
||||
| Marque / Modèle | Protocole | Canal | Stabilité |
|
||||
|---|---|---|---|
|
||||
| Borne ABB Terra AC | Modbus TCP | <span class="badge testing">TESTING</span> | <span class="badge consumer">CONSUMER</span> |
|
||||
| Keba | Modbus TCP | <span class="badge nightly">NIGHTLY</span> | <span class="badge consumer">CONSUMER</span> |
|
||||
|
||||
## SmartDevices
|
||||
|
||||
| Marque / Modèle | Protocole | Canal | Stabilité |
|
||||
|---|---|---|---|
|
||||
| Waveshare relais | Modbus RTU | <span class="badge testing">TESTING</span> | <span class="badge consumer">CONSUMER</span> |
|
||||
|
||||
## HVAC
|
||||
|
||||
| Marque / Modèle | Protocole | Canal | Stabilité |
|
||||
|---|---|---|---|
|
||||
| Daikin | — | <span class="badge nightly">NIGHTLY</span> | <span class="badge consumer">CONSUMER</span> |
|
||||
| SG-Ready | — | <span class="badge nightly">NIGHTLY</span> | <span class="badge consumer">CONSUMER</span> |
|
||||
| SimpleHeatpump | — | <span class="badge nightly">NIGHTLY</span> | <span class="badge consumer">CONSUMER</span> |
|
||||
|
||||
## Onduleurs / PV
|
||||
|
||||
| Marque / Modèle | Protocole | Statut |
|
||||
|---|---|---|
|
||||
| SMA | Modbus / SunSpec | [Partiel]{.badge .part} |
|
||||
| Fronius | Modbus / SunSpec | [Roadmap]{.badge .road} |
|
||||
| Huawei | Modbus | [Roadmap]{.badge .road} |
|
||||
| SolarEdge | Modbus | [Roadmap]{.badge .road} |
|
||||
| Marque / Modèle | Protocole | Canal | Stabilité |
|
||||
|---|---|---|---|
|
||||
| Fronius | Modbus TCP | <span class="badge nightly">NIGHTLY</span> | <span class="badge consumer">CONSUMER</span> |
|
||||
|
||||
## Batteries / ESS
|
||||
|
||||
| Marque / Modèle | Protocole | Statut |
|
||||
|---|---|---|
|
||||
| Victron | Modbus / MQTT | [Roadmap]{.badge .road} |
|
||||
|
||||
> Stub — compléter à partir du suivi de portage réel.
|
||||
<!-- END GENERATED -->
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
# Compteurs
|
||||
|
||||
> Stub — compteurs d'énergie supportés (Eastron SDM, etc.), câblage, configuration Modbus.
|
||||
71
docs/appareils/compteurs/abb-b2x.md
Normal file
71
docs/appareils/compteurs/abb-b2x.md
Normal file
@ -0,0 +1,71 @@
|
||||
# Compteur ABB B2x
|
||||
|
||||
<span class="badge testing">TESTING</span> <span class="badge consumer">CONSUMER</span>
|
||||
|
||||
Le compteur d'énergie ABB B2x communique en **Modbus RTU** sur le bus RS485 du
|
||||
hub. Mesure triphasée (tensions, courants et puissances par phase).
|
||||
|
||||
## 1. Matériel requis
|
||||
|
||||
- Compteur ABB B2x
|
||||
- Adaptateur USB↔RS485 côté hub
|
||||
- Câble bus 2 fils (A/B) + masse
|
||||
|
||||
## 2. Raccordement RS485
|
||||
|
||||
A↔A, B↔B, masse commune, terminaison **120 Ω** en bout de bus.
|
||||
|
||||
## 3. Adressage Modbus
|
||||
|
||||
Adresse esclave unique sur le bus (`1`–`254`, défaut `1`).
|
||||
|
||||
## 4. Ajout dans PowerSync
|
||||
|
||||
Ajout par **découverte automatique** ou **manuel** (saisie de l'adresse esclave).
|
||||
Voir [Ajouter un appareil](../../installation/application.md).
|
||||
|
||||
---
|
||||
|
||||
## Référence
|
||||
|
||||
<!-- BEGIN GENERATED: integrationpluginabbb2x.json -->
|
||||
**Fabricant :** ABB
|
||||
**Plugin :** `AbbB2x`
|
||||
|
||||
#### Modèles pris en charge
|
||||
| Modèle | Rôle | Transport | Ajout | Grandeurs |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| **ABB B2x energy meter** | Compteur d'énergie | Modbus RTU | Découverte automatique / Ajout manuel | 14 |
|
||||
|
||||
#### Détail par modèle
|
||||
??? abstract "ABB B2x energy meter — `abbB2x`"
|
||||
_Paramètres de découverte :_
|
||||
| Clé | Libellé | Type | Plage | Défaut |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `slaveAddress` | Modbus slave address | uint | 1–254 | `1` |
|
||||
|
||||
_Réglages :_
|
||||
| Clé | Libellé | Type | Plage | Défaut | Lecture seule |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `slaveAddress` | Modbus slave address | uint | 1–254 | `1` | oui |
|
||||
| `modbusMasterUuid` | Modbus RTU master | QString | — | — | oui |
|
||||
|
||||
_Grandeurs mesurées :_
|
||||
| Clé | Grandeur | Type | Unité |
|
||||
| --- | --- | --- | --- |
|
||||
| `connected` | Connected | bool | — |
|
||||
| `currentPower` | Current power | double | Watt |
|
||||
| `totalEnergyConsumed` | Total energy consumed | double | KiloWattHour |
|
||||
| `totalEnergyProduced` | Total energy produced | double | KiloWattHour |
|
||||
| `frequency` | Frequency | double | Hertz |
|
||||
| `voltagePhaseA` | Voltage phase A | double | Volt |
|
||||
| `voltagePhaseB` | Voltage phase B | double | Volt |
|
||||
| `voltagePhaseC` | Voltage phase C | double | Volt |
|
||||
| `currentPhaseA` | Current phase A | double | Ampere |
|
||||
| `currentPhaseB` | Current phase B | double | Ampere |
|
||||
| `currentPhaseC` | Current phase C | double | Ampere |
|
||||
| `currentPowerPhaseA` | Current power phase A | double | Watt |
|
||||
| `currentPowerPhaseB` | Current power phase B | double | Watt |
|
||||
| `currentPowerPhaseC` | Current power phase C | double | Watt |
|
||||
|
||||
<!-- END GENERATED -->
|
||||
407
docs/appareils/compteurs/eastron.md
Normal file
407
docs/appareils/compteurs/eastron.md
Normal file
@ -0,0 +1,407 @@
|
||||
# Compteurs Eastron (SDM)
|
||||
|
||||
<span class="badge stable">STABLE</span> <span class="badge consumer">CONSUMER</span>
|
||||
|
||||
Les compteurs Eastron de la série SDM (SDM72, SDM120, SDM220, SDM230, SDM630)
|
||||
communiquent en **Modbus RTU** sur le bus RS485 du hub. Selon le modèle, ils
|
||||
mesurent un raccordement monophasé ou triphasé et peuvent être affectés à trois
|
||||
rôles : compteur général, compteur de consommation ou compteur de production.
|
||||
|
||||
## 1. Matériel requis
|
||||
|
||||
- Le compteur Eastron (modèle selon le besoin de mesure)
|
||||
- Un adaptateur USB↔RS485 côté hub
|
||||
- Câble bus 2 fils torsadés (A/B) + masse
|
||||
|
||||
## 2. Raccordement RS485
|
||||
|
||||
Relier A↔A, B↔B entre l'adaptateur et le compteur, masse commune. Placer une
|
||||
résistance de terminaison **120 Ω** à chaque extrémité du bus.
|
||||
|
||||
!!! warning "À valider sur votre banc"
|
||||
Vitesse (baudrate) et parité par défaut du compteur : à confirmer dans le
|
||||
menu de l'appareil avant mise en service.
|
||||
|
||||
## 3. Adressage Modbus
|
||||
|
||||
Chaque appareil du bus doit avoir une **adresse esclave unique** (réglée via le
|
||||
menu du compteur). L'adresse par défaut est `1`. Si plusieurs Eastron partagent
|
||||
le bus, attribuez `1`, `2`, `3`, …
|
||||
|
||||
## 4. Ajout et configuration dans l'application
|
||||
|
||||
L'ajout se fait depuis l'application, en mode installateur — voir
|
||||
[Ajouter un appareil](../../installation/application.md). Pour l'Eastron :
|
||||
découverte sur le bus, sélection du modèle, puis choix du **rôle** (compteur
|
||||
général / consommation / production).
|
||||
|
||||
## 5. Vérification
|
||||
|
||||
Une fois ajouté, l'état `connected` passe à vrai et les grandeurs (`currentPower`,
|
||||
etc.) se mettent à jour. En cas d'absence de données : vérifier câblage A/B,
|
||||
adresse esclave et terminaison.
|
||||
|
||||
---
|
||||
|
||||
## Référence {#reference}
|
||||
|
||||
<!-- BEGIN GENERATED: integrationplugineastron.json -->
|
||||
**Fabricant :** Eastron
|
||||
**Plugin :** `eastron`
|
||||
|
||||
#### Modèles pris en charge
|
||||
| Modèle | Rôle | Transport | Ajout | Grandeurs |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| **SDM630 — Energy Meter** | Compteur d'énergie | Modbus RTU | Découverte automatique | 20 |
|
||||
| **SDM630 — Consumer Meter** | Compteur de consommation | Modbus RTU | Découverte automatique | 4 |
|
||||
| **SDM630 — Producer Meter** | Compteur de production | Modbus RTU | Découverte automatique | 4 |
|
||||
| **SDM72 — Energy Meter** | Compteur d'énergie | Modbus RTU | Découverte automatique | 14 |
|
||||
| **SDM72 — Consumer Meter** | Compteur de consommation | Modbus RTU | Découverte automatique | 4 |
|
||||
| **SDM72 — Producer Meter** | Compteur de production | Modbus RTU | Découverte automatique | 4 |
|
||||
| **SDM120 — Energy Meter** | Compteur d'énergie | Modbus RTU | Découverte automatique | 7 |
|
||||
| **SDM120 — Consumer Meter** | Compteur de consommation | Modbus RTU | Découverte automatique | 4 |
|
||||
| **SDM120 — Producer Meter** | Compteur de production | Modbus RTU | Découverte automatique | 4 |
|
||||
| **SDM220 — Energy Meter** | Compteur d'énergie | Modbus RTU | Découverte automatique | 7 |
|
||||
| **SDM220 — Consumer Meter** | Compteur de consommation | Modbus RTU | Découverte automatique | 4 |
|
||||
| **SDM220 — Producer Meter** | Compteur de production | Modbus RTU | Découverte automatique | 4 |
|
||||
| **SDM230 — Energy Meter** | Compteur d'énergie | Modbus RTU | Découverte automatique | 7 |
|
||||
| **SDM230 — Consumer Meter** | Compteur de consommation | Modbus RTU | Découverte automatique | 4 |
|
||||
| **SDM230 — Producer Meter** | Compteur de production | Modbus RTU | Découverte automatique | 4 |
|
||||
|
||||
#### Détail par modèle
|
||||
??? abstract "SDM630 — Energy Meter — `sdm630`"
|
||||
_Paramètres de découverte :_
|
||||
| Clé | Libellé | Type | Plage | Défaut |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `slaveAddress` | Slave address | int | — | `1` |
|
||||
|
||||
_Réglages :_
|
||||
| Clé | Libellé | Type | Plage | Défaut | Lecture seule |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `slaveAddress` | Modbus slave address | uint | — | `1` | non |
|
||||
| `modbusMasterUuid` | Modbus RTU master | QUuid | — | — | oui |
|
||||
|
||||
_Grandeurs mesurées :_
|
||||
| Clé | Grandeur | Type | Unité |
|
||||
| --- | --- | --- | --- |
|
||||
| `connected` | Connected | bool | — |
|
||||
| `voltagePhaseA` | Voltage phase A | double | Volt |
|
||||
| `voltagePhaseB` | Voltage phase B | double | Volt |
|
||||
| `voltagePhaseC` | Voltage phase C | double | Volt |
|
||||
| `currentPhaseA` | Current phase A | double | Ampere |
|
||||
| `currentPhaseB` | Current phase B | double | Ampere |
|
||||
| `currentPhaseC` | Current phase C | double | Ampere |
|
||||
| `currentPower` | Current power | double | Watt |
|
||||
| `currentPowerPhaseA` | Current power phase A | double | Watt |
|
||||
| `currentPowerPhaseB` | Current power phase B | double | Watt |
|
||||
| `currentPowerPhaseC` | Current power phase C | double | Watt |
|
||||
| `frequency` | Frequency | double | Hertz |
|
||||
| `totalEnergyConsumed` | Total energy consumed | double | KiloWattHour |
|
||||
| `totalEnergyProduced` | Total energy produced | double | KiloWattHour |
|
||||
| `energyConsumedPhaseA` | Energy consumed phase A | double | KiloWattHour |
|
||||
| `energyConsumedPhaseB` | Energy consumed phase B | double | KiloWattHour |
|
||||
| `energyConsumedPhaseC` | Energy consumed phase C | double | KiloWattHour |
|
||||
| `energyProducedPhaseA` | Energy produced phase A | double | KiloWattHour |
|
||||
| `energyProducedPhaseB` | Energy produced phase B | double | KiloWattHour |
|
||||
| `energyProducedPhaseC` | Energy produced phase C | double | KiloWattHour |
|
||||
|
||||
??? abstract "SDM630 — Consumer Meter — `sdm630Consumer`"
|
||||
_Paramètres de découverte :_
|
||||
| Clé | Libellé | Type | Plage | Défaut |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `slaveAddress` | Slave address | int | — | `1` |
|
||||
|
||||
_Réglages :_
|
||||
| Clé | Libellé | Type | Plage | Défaut | Lecture seule |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `slaveAddress` | Modbus slave address | uint | — | `1` | non |
|
||||
| `modbusMasterUuid` | Modbus RTU master | QUuid | — | — | oui |
|
||||
|
||||
_Grandeurs mesurées :_
|
||||
| Clé | Grandeur | Type | Unité |
|
||||
| --- | --- | --- | --- |
|
||||
| `connected` | Connected | bool | — |
|
||||
| `currentPower` | Current power | double | Watt |
|
||||
| `totalEnergyConsumed` | Total energy consumed | double | KiloWattHour |
|
||||
| `frequency` | Frequency | double | Hertz |
|
||||
|
||||
??? abstract "SDM630 — Producer Meter — `sdm630Producer`"
|
||||
_Paramètres de découverte :_
|
||||
| Clé | Libellé | Type | Plage | Défaut |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `slaveAddress` | Slave address | int | — | `1` |
|
||||
|
||||
_Réglages :_
|
||||
| Clé | Libellé | Type | Plage | Défaut | Lecture seule |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `slaveAddress` | Modbus slave address | uint | — | `1` | non |
|
||||
| `modbusMasterUuid` | Modbus RTU master | QUuid | — | — | oui |
|
||||
|
||||
_Grandeurs mesurées :_
|
||||
| Clé | Grandeur | Type | Unité |
|
||||
| --- | --- | --- | --- |
|
||||
| `connected` | Connected | bool | — |
|
||||
| `currentPower` | Current power | double | Watt |
|
||||
| `totalEnergyProduced` | Total energy produced | double | KiloWattHour |
|
||||
| `frequency` | Frequency | double | Hertz |
|
||||
|
||||
??? abstract "SDM72 — Energy Meter — `sdm72`"
|
||||
_Paramètres de découverte :_
|
||||
| Clé | Libellé | Type | Plage | Défaut |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `slaveAddress` | Slave address | int | — | `1` |
|
||||
|
||||
_Réglages :_
|
||||
| Clé | Libellé | Type | Plage | Défaut | Lecture seule |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `slaveAddress` | Modbus slave address | uint | — | `1` | non |
|
||||
| `modbusMasterUuid` | Modbus RTU master | QUuid | — | — | oui |
|
||||
|
||||
_Grandeurs mesurées :_
|
||||
| Clé | Grandeur | Type | Unité |
|
||||
| --- | --- | --- | --- |
|
||||
| `connected` | Connected | bool | — |
|
||||
| `voltagePhaseA` | Voltage phase A | double | Volt |
|
||||
| `voltagePhaseB` | Voltage phase B | double | Volt |
|
||||
| `voltagePhaseC` | Voltage phase C | double | Volt |
|
||||
| `currentPhaseA` | Current phase A | double | Ampere |
|
||||
| `currentPhaseB` | Current phase B | double | Ampere |
|
||||
| `currentPhaseC` | Current phase C | double | Ampere |
|
||||
| `currentPower` | Current power | double | Watt |
|
||||
| `currentPowerPhaseA` | Current power phase A | double | Watt |
|
||||
| `currentPowerPhaseB` | Current power phase B | double | Watt |
|
||||
| `currentPowerPhaseC` | Current power phase C | double | Watt |
|
||||
| `frequency` | Frequency | double | Hertz |
|
||||
| `totalEnergyConsumed` | Total energy consumed | double | KiloWattHour |
|
||||
| `totalEnergyProduced` | Total energy produced | double | KiloWattHour |
|
||||
|
||||
??? abstract "SDM72 — Consumer Meter — `sdm72Consumer`"
|
||||
_Paramètres de découverte :_
|
||||
| Clé | Libellé | Type | Plage | Défaut |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `slaveAddress` | Slave address | int | — | `1` |
|
||||
|
||||
_Réglages :_
|
||||
| Clé | Libellé | Type | Plage | Défaut | Lecture seule |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `slaveAddress` | Modbus slave address | uint | — | `1` | non |
|
||||
| `modbusMasterUuid` | Modbus RTU master | QUuid | — | — | oui |
|
||||
|
||||
_Grandeurs mesurées :_
|
||||
| Clé | Grandeur | Type | Unité |
|
||||
| --- | --- | --- | --- |
|
||||
| `connected` | Connected | bool | — |
|
||||
| `currentPower` | Current power | double | Watt |
|
||||
| `totalEnergyConsumed` | Total energy consumed | double | KiloWattHour |
|
||||
| `frequency` | Frequency | double | Hertz |
|
||||
|
||||
??? abstract "SDM72 — Producer Meter — `sdm72Producer`"
|
||||
_Paramètres de découverte :_
|
||||
| Clé | Libellé | Type | Plage | Défaut |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `slaveAddress` | Slave address | int | — | `1` |
|
||||
|
||||
_Réglages :_
|
||||
| Clé | Libellé | Type | Plage | Défaut | Lecture seule |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `slaveAddress` | Modbus slave address | uint | — | `1` | non |
|
||||
| `modbusMasterUuid` | Modbus RTU master | QUuid | — | — | oui |
|
||||
|
||||
_Grandeurs mesurées :_
|
||||
| Clé | Grandeur | Type | Unité |
|
||||
| --- | --- | --- | --- |
|
||||
| `connected` | Connected | bool | — |
|
||||
| `currentPower` | Current power | double | Watt |
|
||||
| `totalEnergyProduced` | Total energy produced | double | KiloWattHour |
|
||||
| `frequency` | Frequency | double | Hertz |
|
||||
|
||||
??? abstract "SDM120 — Energy Meter — `sdm120`"
|
||||
_Paramètres de découverte :_
|
||||
| Clé | Libellé | Type | Plage | Défaut |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `slaveAddress` | Slave address | int | — | `1` |
|
||||
|
||||
_Réglages :_
|
||||
| Clé | Libellé | Type | Plage | Défaut | Lecture seule |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `slaveAddress` | Modbus slave address | uint | — | `1` | non |
|
||||
| `modbusMasterUuid` | Modbus RTU master | QUuid | — | — | oui |
|
||||
|
||||
_Grandeurs mesurées :_
|
||||
| Clé | Grandeur | Type | Unité |
|
||||
| --- | --- | --- | --- |
|
||||
| `connected` | Connected | bool | — |
|
||||
| `voltagePhaseA` | Voltage | double | Volt |
|
||||
| `currentPhaseA` | Current | double | Ampere |
|
||||
| `currentPower` | Current power | double | Watt |
|
||||
| `frequency` | Frequency | double | Hertz |
|
||||
| `totalEnergyConsumed` | Total energy consumed | double | KiloWattHour |
|
||||
| `totalEnergyProduced` | Total energy produced | double | KiloWattHour |
|
||||
|
||||
??? abstract "SDM120 — Consumer Meter — `sdm120Consumer`"
|
||||
_Paramètres de découverte :_
|
||||
| Clé | Libellé | Type | Plage | Défaut |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `slaveAddress` | Slave address | int | — | `1` |
|
||||
|
||||
_Réglages :_
|
||||
| Clé | Libellé | Type | Plage | Défaut | Lecture seule |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `slaveAddress` | Modbus slave address | uint | — | `1` | non |
|
||||
| `modbusMasterUuid` | Modbus RTU master | QUuid | — | — | oui |
|
||||
|
||||
_Grandeurs mesurées :_
|
||||
| Clé | Grandeur | Type | Unité |
|
||||
| --- | --- | --- | --- |
|
||||
| `connected` | Connected | bool | — |
|
||||
| `currentPower` | Current power | double | Watt |
|
||||
| `totalEnergyConsumed` | Total energy consumed | double | KiloWattHour |
|
||||
| `frequency` | Frequency | double | Hertz |
|
||||
|
||||
??? abstract "SDM120 — Producer Meter — `sdm120Producer`"
|
||||
_Paramètres de découverte :_
|
||||
| Clé | Libellé | Type | Plage | Défaut |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `slaveAddress` | Slave address | int | — | `1` |
|
||||
|
||||
_Réglages :_
|
||||
| Clé | Libellé | Type | Plage | Défaut | Lecture seule |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `slaveAddress` | Modbus slave address | uint | — | `1` | non |
|
||||
| `modbusMasterUuid` | Modbus RTU master | QUuid | — | — | oui |
|
||||
|
||||
_Grandeurs mesurées :_
|
||||
| Clé | Grandeur | Type | Unité |
|
||||
| --- | --- | --- | --- |
|
||||
| `connected` | Connected | bool | — |
|
||||
| `currentPower` | Current power | double | Watt |
|
||||
| `totalEnergyProduced` | Total energy produced | double | KiloWattHour |
|
||||
| `frequency` | Frequency | double | Hertz |
|
||||
|
||||
??? abstract "SDM220 — Energy Meter — `sdm220`"
|
||||
_Paramètres de découverte :_
|
||||
| Clé | Libellé | Type | Plage | Défaut |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `slaveAddress` | Slave address | int | — | `1` |
|
||||
|
||||
_Réglages :_
|
||||
| Clé | Libellé | Type | Plage | Défaut | Lecture seule |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `slaveAddress` | Modbus slave address | uint | — | `1` | non |
|
||||
| `modbusMasterUuid` | Modbus RTU master | QUuid | — | — | oui |
|
||||
|
||||
_Grandeurs mesurées :_
|
||||
| Clé | Grandeur | Type | Unité |
|
||||
| --- | --- | --- | --- |
|
||||
| `connected` | Connected | bool | — |
|
||||
| `voltagePhaseA` | Voltage | double | Volt |
|
||||
| `currentPhaseA` | Current | double | Ampere |
|
||||
| `currentPower` | Current power | double | Watt |
|
||||
| `frequency` | Frequency | double | Hertz |
|
||||
| `totalEnergyConsumed` | Total energy consumed | double | KiloWattHour |
|
||||
| `totalEnergyProduced` | Total energy produced | double | KiloWattHour |
|
||||
|
||||
??? abstract "SDM220 — Consumer Meter — `sdm220Consumer`"
|
||||
_Paramètres de découverte :_
|
||||
| Clé | Libellé | Type | Plage | Défaut |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `slaveAddress` | Slave address | int | — | `1` |
|
||||
|
||||
_Réglages :_
|
||||
| Clé | Libellé | Type | Plage | Défaut | Lecture seule |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `slaveAddress` | Modbus slave address | uint | — | `1` | non |
|
||||
| `modbusMasterUuid` | Modbus RTU master | QUuid | — | — | oui |
|
||||
|
||||
_Grandeurs mesurées :_
|
||||
| Clé | Grandeur | Type | Unité |
|
||||
| --- | --- | --- | --- |
|
||||
| `connected` | Connected | bool | — |
|
||||
| `currentPower` | Current power | double | Watt |
|
||||
| `totalEnergyConsumed` | Total energy consumed | double | KiloWattHour |
|
||||
| `frequency` | Frequency | double | Hertz |
|
||||
|
||||
??? abstract "SDM220 — Producer Meter — `sdm220Producer`"
|
||||
_Paramètres de découverte :_
|
||||
| Clé | Libellé | Type | Plage | Défaut |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `slaveAddress` | Slave address | int | — | `1` |
|
||||
|
||||
_Réglages :_
|
||||
| Clé | Libellé | Type | Plage | Défaut | Lecture seule |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `slaveAddress` | Modbus slave address | uint | — | `1` | non |
|
||||
| `modbusMasterUuid` | Modbus RTU master | QUuid | — | — | oui |
|
||||
|
||||
_Grandeurs mesurées :_
|
||||
| Clé | Grandeur | Type | Unité |
|
||||
| --- | --- | --- | --- |
|
||||
| `connected` | Connected | bool | — |
|
||||
| `currentPower` | Current power | double | Watt |
|
||||
| `totalEnergyProduced` | Total energy produced | double | KiloWattHour |
|
||||
| `frequency` | Frequency | double | Hertz |
|
||||
|
||||
??? abstract "SDM230 — Energy Meter — `sdm230`"
|
||||
_Paramètres de découverte :_
|
||||
| Clé | Libellé | Type | Plage | Défaut |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `slaveAddress` | Slave address | int | — | `1` |
|
||||
|
||||
_Réglages :_
|
||||
| Clé | Libellé | Type | Plage | Défaut | Lecture seule |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `slaveAddress` | Modbus slave address | uint | — | `1` | non |
|
||||
| `modbusMasterUuid` | Modbus RTU master | QUuid | — | — | oui |
|
||||
|
||||
_Grandeurs mesurées :_
|
||||
| Clé | Grandeur | Type | Unité |
|
||||
| --- | --- | --- | --- |
|
||||
| `connected` | Connected | bool | — |
|
||||
| `voltagePhaseA` | Voltage | double | Volt |
|
||||
| `currentPhaseA` | Current | double | Ampere |
|
||||
| `currentPower` | Current power | double | Watt |
|
||||
| `frequency` | Frequency | double | Hertz |
|
||||
| `totalEnergyConsumed` | Total energy consumed | double | KiloWattHour |
|
||||
| `totalEnergyProduced` | Total energy produced | double | KiloWattHour |
|
||||
|
||||
??? abstract "SDM230 — Consumer Meter — `sdm230Consumer`"
|
||||
_Paramètres de découverte :_
|
||||
| Clé | Libellé | Type | Plage | Défaut |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `slaveAddress` | Slave address | int | — | `1` |
|
||||
|
||||
_Réglages :_
|
||||
| Clé | Libellé | Type | Plage | Défaut | Lecture seule |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `slaveAddress` | Modbus slave address | uint | — | `1` | non |
|
||||
| `modbusMasterUuid` | Modbus RTU master | QUuid | — | — | oui |
|
||||
|
||||
_Grandeurs mesurées :_
|
||||
| Clé | Grandeur | Type | Unité |
|
||||
| --- | --- | --- | --- |
|
||||
| `connected` | Connected | bool | — |
|
||||
| `currentPower` | Current power | double | Watt |
|
||||
| `totalEnergyConsumed` | Total energy consumed | double | KiloWattHour |
|
||||
| `frequency` | Frequency | double | Hertz |
|
||||
|
||||
??? abstract "SDM230 — Producer Meter — `sdm230Producer`"
|
||||
_Paramètres de découverte :_
|
||||
| Clé | Libellé | Type | Plage | Défaut |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| `slaveAddress` | Slave address | int | — | `1` |
|
||||
|
||||
_Réglages :_
|
||||
| Clé | Libellé | Type | Plage | Défaut | Lecture seule |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `slaveAddress` | Modbus slave address | uint | — | `1` | non |
|
||||
| `modbusMasterUuid` | Modbus RTU master | QUuid | — | — | oui |
|
||||
|
||||
_Grandeurs mesurées :_
|
||||
| Clé | Grandeur | Type | Unité |
|
||||
| --- | --- | --- | --- |
|
||||
| `connected` | Connected | bool | — |
|
||||
| `currentPower` | Current power | double | Watt |
|
||||
| `totalEnergyProduced` | Total energy produced | double | KiloWattHour |
|
||||
| `frequency` | Frequency | double | Hertz |
|
||||
|
||||
<!-- END GENERATED -->
|
||||
8
docs/appareils/compteurs/index.md
Normal file
8
docs/appareils/compteurs/index.md
Normal file
@ -0,0 +1,8 @@
|
||||
# Compteurs
|
||||
|
||||
Compteurs d'énergie supportés par ETM PowerSync via Modbus RTU.
|
||||
|
||||
| Appareil | Protocole | Canal | Stabilité |
|
||||
|---|---|---|---|
|
||||
| [Eastron SDM](eastron.md) | Modbus RTU | <span class="badge stable">STABLE</span> | <span class="badge consumer">CONSUMER</span> |
|
||||
| [Compteur ABB B2x](abb-b2x.md) | Modbus RTU | <span class="badge testing">TESTING</span> | <span class="badge consumer">CONSUMER</span> |
|
||||
@ -1,10 +1,9 @@
|
||||
# Appareils
|
||||
|
||||
ETM PowerSync communique avec les équipements via Modbus (TCP/RTU), MQTT et protocoles
|
||||
propriétaires, grâce aux plugins du dépôt
|
||||
[powersync-plugins](https://github.com/etmschurig/powersync-plugins).
|
||||
ETM PowerSync communique avec les équipements via Modbus (TCP/RTU) et protocoles
|
||||
propriétaires, grâce aux plugins embarqués.
|
||||
|
||||
- [Compatibilité](compatibilite.md) — liste de référence filtrable
|
||||
- [Bornes de recharge](bornes.md)
|
||||
- [Compteurs](compteurs.md)
|
||||
- [Onduleurs / PV](onduleurs.md)
|
||||
- [Compatibilité](compatibilite.md) — matrice complète avec canaux APT
|
||||
- [Compteurs](compteurs/index.md) — Eastron SDM, ABB B2x
|
||||
- [Bornes de recharge](bornes/index.md) — ABB Terra AC, Keba
|
||||
- [SmartDevices](smart/index.md) — Waveshare
|
||||
|
||||
@ -1,3 +0,0 @@
|
||||
# Onduleurs / PV
|
||||
|
||||
> Stub — onduleurs et données PV (SunSpec/Modbus), lecture de production.
|
||||
7
docs/appareils/smart/index.md
Normal file
7
docs/appareils/smart/index.md
Normal file
@ -0,0 +1,7 @@
|
||||
# SmartDevices
|
||||
|
||||
Modules de pilotage de charges supportés par ETM PowerSync.
|
||||
|
||||
| Appareil | Protocole | Canal | Stabilité |
|
||||
|---|---|---|---|
|
||||
| [Waveshare relais](waveshare.md) | Modbus RTU | <span class="badge testing">TESTING</span> | <span class="badge consumer">CONSUMER</span> |
|
||||
64
docs/appareils/smart/waveshare.md
Normal file
64
docs/appareils/smart/waveshare.md
Normal file
@ -0,0 +1,64 @@
|
||||
# Waveshare relais
|
||||
|
||||
<span class="badge testing">TESTING</span> <span class="badge consumer">CONSUMER</span>
|
||||
|
||||
Module de relais Waveshare (modèle 8 canaux RS485), pilotage via **Modbus RTU**.
|
||||
|
||||
## 1. Matériel requis
|
||||
|
||||
- Module Waveshare 8-Channel Relay (RS485)
|
||||
- Adaptateur USB↔RS485 côté hub
|
||||
- Alimentation 12 V DC + câble bus (A/B)
|
||||
|
||||
## 2. Raccordement RS485
|
||||
|
||||
A↔A, B↔B, masse commune, terminaison **120 Ω** en bout de bus.
|
||||
Alimentation 12 V DC sur les bornes VCC/GND du module.
|
||||
|
||||
## 3. Adressage Modbus
|
||||
|
||||
Adresse par défaut : **1**. Configurable via l'utilitaire Waveshare ou par
|
||||
commande Modbus de changement d'adresse.
|
||||
|
||||
Paramètres : **9600 bps, 8N1**.
|
||||
|
||||
## 4. Ajout dans PowerSync
|
||||
|
||||
Ajout manuel (port série, adresse esclave).
|
||||
Voir [Ajouter un appareil](../../installation/application.md).
|
||||
|
||||
---
|
||||
|
||||
## Référence
|
||||
|
||||
<!-- BEGIN GENERATED: integrationpluginwaveshare-relay-d8.json -->
|
||||
**Fabricant :** Waveshare
|
||||
**Plugin :** `waveshare-relay-d8`
|
||||
|
||||
#### Modèles pris en charge
|
||||
| Modèle | Rôle | Transport | Ajout | Grandeurs |
|
||||
| --- | --- | --- | --- | --- |
|
||||
| **Waveshare 8-Channel Relay (RS485)** | — | Modbus RTU | Ajout manuel | 9 |
|
||||
|
||||
#### Détail par modèle
|
||||
??? abstract "Waveshare 8-Channel Relay (RS485) — `waveshareRelayD8`"
|
||||
_Réglages :_
|
||||
| Clé | Libellé | Type | Plage | Défaut | Lecture seule |
|
||||
| --- | --- | --- | --- | --- | --- |
|
||||
| `modbusMasterUuid` | Modbus RTU master | QUuid | — | — | oui |
|
||||
| `slaveAddress` | Slave address | uint | 1–247 | `1` | non |
|
||||
|
||||
_Grandeurs mesurées :_
|
||||
| Clé | Grandeur | Type | Unité |
|
||||
| --- | --- | --- | --- |
|
||||
| `connected` | Connected | bool | — |
|
||||
| `relay1` | Relay 1 | bool | — |
|
||||
| `relay2` | Relay 2 | bool | — |
|
||||
| `relay3` | Relay 3 | bool | — |
|
||||
| `relay4` | Relay 4 | bool | — |
|
||||
| `relay5` | Relay 5 | bool | — |
|
||||
| `relay6` | Relay 6 | bool | — |
|
||||
| `relay7` | Relay 7 | bool | — |
|
||||
| `relay8` | Relay 8 | bool | — |
|
||||
|
||||
<!-- END GENERATED -->
|
||||
@ -1,8 +0,0 @@
|
||||
# API REST / MQTT [Supporté]{.badge .ok}
|
||||
|
||||
ETM PowerSync expose l'API JSON-RPC de nymea, permettant l'intégration domotique
|
||||
(Home Assistant, etc.). Vos données restent accessibles, en local.
|
||||
|
||||
Voir [Intégrations](../integrations/rest-api.md) pour les détails.
|
||||
|
||||
> Stub — documenter les endpoints principaux.
|
||||
@ -4,14 +4,14 @@ Vue d'ensemble des fonctions du HEMS et de leur état réel.
|
||||
|
||||
| Fonction | État |
|
||||
|---|---|
|
||||
| [Surplus solaire](surplus-solaire.md) | [Partiel]{.badge .part} |
|
||||
| [Délestage / Load management](delestage.md) | [Partiel]{.badge .part} |
|
||||
| [Gestion batterie](gestion-batterie.md) | [Partiel]{.badge .part} |
|
||||
| [API REST / MQTT](api.md) | [Supporté]{.badge .ok} |
|
||||
| Tarifs dynamiques (FR) | [Roadmap]{.badge .road} |
|
||||
| Optimisation CO₂ (RTE) | [Roadmap]{.badge .road} |
|
||||
| Planificateur de charge | [Roadmap]{.badge .road} |
|
||||
| Pompe à chaleur | [Roadmap]{.badge .road} |
|
||||
| [Surplus solaire](surplus-solaire.md) | <span class="badge testing">EN COURS</span> |
|
||||
| [Délestage / Load management](delestage.md) | <span class="badge testing">EN COURS</span> |
|
||||
| [Gestion batterie](gestion-batterie.md) | <span class="badge testing">EN COURS</span> |
|
||||
| [API REST](../integrations/rest-api.md) / [MQTT](../integrations/mqtt.md) | <span class="badge stable">DISPONIBLE</span> |
|
||||
| Tarifs dynamiques (FR) | <span class="badge nightly">ROADMAP</span> |
|
||||
| Optimisation CO₂ (RTE) | <span class="badge nightly">ROADMAP</span> |
|
||||
| Planificateur de charge | <span class="badge nightly">ROADMAP</span> |
|
||||
| Pompe à chaleur | <span class="badge nightly">ROADMAP</span> |
|
||||
|
||||
!!! note
|
||||
Les fonctions en *Roadmap* ne sont pas encore disponibles. Elles sont listées par
|
||||
|
||||
@ -8,9 +8,9 @@ Bâti sur [nymea.io](https://nymea.io), selon une architecture **Open Core** : u
|
||||
libre (GPL-3.0) et une couche d'optimisation propriétaire.
|
||||
|
||||
!!! info "Statuts honnêtes"
|
||||
Chaque fonction affiche son état réel : [:material-circle:{.ok} **Supporté**]{.badge .ok}
|
||||
en production · [:material-circle:{.part} **Partiel**]{.badge .part} en industrialisation ·
|
||||
[:material-circle:{.road} **Roadmap**]{.badge .road} planifié. On ne documente pas une promesse.
|
||||
Chaque fonction affiche son état réel : <span class="badge stable">STABLE</span>
|
||||
en production · <span class="badge testing">EN COURS</span> en industrialisation ·
|
||||
<span class="badge nightly">ROADMAP</span> planifié. On ne documente pas une promesse.
|
||||
|
||||
## Par où commencer
|
||||
|
||||
|
||||
33
docs/installation/application.md
Normal file
33
docs/installation/application.md
Normal file
@ -0,0 +1,33 @@
|
||||
# L'application PowerSync
|
||||
|
||||
Guide d'utilisation de l'application ETM PowerSync pour ajouter et configurer des appareils.
|
||||
|
||||
## Accéder à l'interface
|
||||
|
||||
L'interface est accessible depuis un navigateur sur le réseau local :
|
||||
|
||||
```
|
||||
http://<ip-du-hub>
|
||||
```
|
||||
|
||||
!!! note "Capture"
|
||||
*Placeholder — capture du menu principal de l'application à ajouter.*
|
||||
|
||||
## Ajouter un appareil
|
||||
|
||||
1. Ouvrir l'application et naviguer vers **Appareils** → **Ajouter un appareil**
|
||||
2. Sélectionner le type d'appareil dans la liste
|
||||
3. Renseigner les paramètres de connexion (adresse IP ou port série, adresse Modbus)
|
||||
4. Valider — l'appareil apparaît dans le tableau de bord si la connexion est établie
|
||||
|
||||
!!! note "Capture"
|
||||
*Placeholder — capture de l'écran de configuration d'un appareil
|
||||
(`app-config-thing.png`) à remplacer quand l'app sera prête.*
|
||||
|
||||
## Tableau de bord
|
||||
|
||||
Le tableau de bord affiche en temps réel les puissances, l'état des bornes et le bilan
|
||||
énergétique du site.
|
||||
|
||||
!!! note "Capture"
|
||||
*Placeholder — capture du tableau de bord à ajouter.*
|
||||
@ -11,9 +11,21 @@
|
||||
}
|
||||
[data-md-color-scheme="slate"] .md-typeset a { color: var(--md-primary-fg-color); }
|
||||
|
||||
/* badges de statut : {.badge .ok} / {.badge .part} / {.badge .road} */
|
||||
/* badges — 3 familles : canal APT · stabilité plugin · maturité fonctionnalité */
|
||||
.badge{font-family:"IBM Plex Mono",monospace;font-size:.7rem;letter-spacing:.06em;
|
||||
text-transform:uppercase;padding:2px 8px;border-radius:20px;font-weight:600;white-space:nowrap}
|
||||
.badge.ok{color:#3fd18a;background:rgba(63,209,138,.12);border:1px solid rgba(63,209,138,.3)}
|
||||
.badge.part{color:#fec113;background:rgba(254,193,19,.1);border:1px solid rgba(254,193,19,.3)}
|
||||
.badge.road{color:#8fa9b5;background:rgba(143,169,181,.1);border:1px solid rgba(143,169,181,.3)}
|
||||
text-transform:uppercase;padding:2px 8px;border-radius:20px;font-weight:600;white-space:nowrap;
|
||||
display:inline-block;vertical-align:middle;line-height:1.4}
|
||||
|
||||
/* canal APT */
|
||||
.badge.stable {color:#3fd18a;background:rgba(63,209,138,.12);border:1px solid rgba(63,209,138,.3)}
|
||||
.badge.testing {color:#fec113;background:rgba(254,193,19,.1);border:1px solid rgba(254,193,19,.3)}
|
||||
.badge.nightly {color:#8fa9b5;background:rgba(143,169,181,.1);border:1px solid rgba(143,169,181,.3)}
|
||||
|
||||
/* stabilité plugin (meta.json) */
|
||||
.badge.consumer {color:#31a3dd;background:rgba(49,163,221,.1);border:1px solid rgba(49,163,221,.3)}
|
||||
.badge.community {color:#a78bfa;background:rgba(167,139,250,.1);border:1px solid rgba(167,139,250,.3)}
|
||||
|
||||
/* maturité fonctionnalités (à la main) */
|
||||
.badge.ok {color:#3fd18a;background:rgba(63,209,138,.12);border:1px solid rgba(63,209,138,.3)}
|
||||
.badge.part {color:#fec113;background:rgba(254,193,19,.1);border:1px solid rgba(254,193,19,.3)}
|
||||
.badge.road {color:#8fa9b5;background:rgba(143,169,181,.1);border:1px solid rgba(143,169,181,.3)}
|
||||
|
||||
24
mkdocs.yml
24
mkdocs.yml
@ -22,8 +22,7 @@ theme:
|
||||
primary: custom # couleurs réelles définies dans stylesheets/extra.css
|
||||
accent: custom
|
||||
features:
|
||||
- navigation.sections
|
||||
- navigation.tabs
|
||||
- navigation.indexes
|
||||
- navigation.top
|
||||
- navigation.instant
|
||||
- navigation.footer
|
||||
@ -47,6 +46,7 @@ markdown_extensions:
|
||||
- pymdownx.highlight:
|
||||
anchor_linenums: true
|
||||
- pymdownx.superfences
|
||||
- pymdownx.details
|
||||
- pymdownx.inlinehilite
|
||||
- pymdownx.tabbed:
|
||||
alternate_style: true
|
||||
@ -57,6 +57,8 @@ markdown_extensions:
|
||||
plugins:
|
||||
- search:
|
||||
lang: fr
|
||||
- literate-nav:
|
||||
nav_file: SUMMARY.md
|
||||
|
||||
nav:
|
||||
- Accueil: index.md
|
||||
@ -64,22 +66,18 @@ nav:
|
||||
- installation/index.md
|
||||
- Dépôt APT: installation/depot-apt.md
|
||||
- Configuration: installation/configuration.md
|
||||
- L'application: installation/application.md
|
||||
- Appareils: appareils/
|
||||
- Fonctionnalités:
|
||||
- fonctionnalites/index.md
|
||||
- Surplus solaire: fonctionnalites/surplus-solaire.md
|
||||
- Délestage / Load management: fonctionnalites/delestage.md
|
||||
- Délestage: fonctionnalites/delestage.md
|
||||
- Gestion batterie: fonctionnalites/gestion-batterie.md
|
||||
- API REST / MQTT: fonctionnalites/api.md
|
||||
- Appareils:
|
||||
- appareils/index.md
|
||||
- Compatibilité: appareils/compatibilite.md
|
||||
- Bornes de recharge: appareils/bornes.md
|
||||
- Compteurs: appareils/compteurs.md
|
||||
- Onduleurs / PV: appareils/onduleurs.md
|
||||
- Intégrations:
|
||||
- Tarifs dynamiques: tarifs.md
|
||||
- Référence:
|
||||
- reference.md
|
||||
- API REST: integrations/rest-api.md
|
||||
- MQTT: integrations/mqtt.md
|
||||
- Tarifs: tarifs.md
|
||||
- Référence: reference.md
|
||||
- Aide:
|
||||
- Dépannage: depannage.md
|
||||
- FAQ: faq.md
|
||||
|
||||
3
requirements.txt
Normal file
3
requirements.txt
Normal file
@ -0,0 +1,3 @@
|
||||
mkdocs-material>=9.5
|
||||
mkdocs-literate-nav>=0.6
|
||||
PyYAML>=6.0
|
||||
409
scripts/gen_device_reference.py
Normal file
409
scripts/gen_device_reference.py
Normal file
@ -0,0 +1,409 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
gen_device_reference.py — génère la matrice de compatibilité, les sections de
|
||||
référence des appareils et le fichier de nav literate-nav (SUMMARY.md) depuis
|
||||
PORTING_STATUS.yaml + integrationplugin*.json + meta.json.
|
||||
|
||||
Principe docs-as-code : ne remplace que le contenu entre marqueurs existants.
|
||||
|
||||
<!-- BEGIN GENERATED: integrationplugineastron.json -->
|
||||
... contenu régénéré ...
|
||||
<!-- END GENERATED -->
|
||||
|
||||
Marqueur spécial pour la matrice de compatibilité :
|
||||
<!-- BEGIN GENERATED: __matrix__ -->
|
||||
|
||||
Usage :
|
||||
python3 scripts/gen_device_reference.py --src .plugins-src --docs docs --lang fr
|
||||
python3 scripts/gen_device_reference.py --src .plugins-src --docs docs --lang fr --check
|
||||
"""
|
||||
from __future__ import annotations
|
||||
import argparse
|
||||
import json
|
||||
import re
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
try:
|
||||
import yaml
|
||||
except ImportError:
|
||||
sys.exit("PyYAML est requis : pip install PyYAML")
|
||||
|
||||
INTERFACE_ROLE = {
|
||||
"energymeter": "Compteur d'énergie",
|
||||
"smartmeterconsumer": "Compteur de consommation",
|
||||
"smartmeterproducer": "Compteur de production",
|
||||
"evcharger": "Borne de recharge",
|
||||
"heatpump": "Pompe à chaleur",
|
||||
"smartmeter": "Compteur intelligent",
|
||||
}
|
||||
TECH_INTERFACES = {"connectable", "networkdevice"}
|
||||
|
||||
CREATE_METHOD = {
|
||||
"discovery": "Découverte automatique",
|
||||
"user": "Ajout manuel",
|
||||
"auto": "Automatique",
|
||||
}
|
||||
|
||||
CATEGORY_LABELS = {
|
||||
"compteur": "Compteurs",
|
||||
"irve": "Bornes de recharge",
|
||||
"smartdevice": "SmartDevices",
|
||||
"hvac": "HVAC",
|
||||
"onduleur": "Onduleurs / PV",
|
||||
"batterie": "Batteries / ESS",
|
||||
"tarif": "Tarifs & prévisions",
|
||||
}
|
||||
|
||||
CATEGORY_FOLDER = {
|
||||
"compteur": "compteurs",
|
||||
"irve": "bornes",
|
||||
"smartdevice": "smart",
|
||||
"hvac": "hvac",
|
||||
"onduleur": "onduleurs",
|
||||
"batterie": "batteries",
|
||||
"tarif": "tarifs",
|
||||
}
|
||||
|
||||
CATEGORY_ORDER = ["compteur", "irve", "smartdevice", "hvac", "onduleur", "batterie", "tarif"]
|
||||
|
||||
CHANNEL_BADGES = {
|
||||
"stable": '<span class="badge stable">STABLE</span>',
|
||||
"testing": '<span class="badge testing">TESTING</span>',
|
||||
"nightly": '<span class="badge nightly">NIGHTLY</span>',
|
||||
}
|
||||
|
||||
STABILITY_BADGES = {
|
||||
"consumer": '<span class="badge consumer">CONSUMER</span>',
|
||||
"community": '<span class="badge community">COMMUNITY</span>',
|
||||
}
|
||||
|
||||
MARKER_RE = re.compile(
|
||||
r"(<!-- BEGIN GENERATED: (?P<key>[^\s]+) -->)(?P<body>.*?)(<!-- END GENERATED -->)",
|
||||
re.DOTALL,
|
||||
)
|
||||
|
||||
|
||||
# ── Chargement ────────────────────────────────────────────────────────────────
|
||||
|
||||
def load_porting_status(root: Path) -> list:
|
||||
path = root / "PORTING_STATUS.yaml"
|
||||
if not path.exists():
|
||||
sys.exit(f"ERREUR : PORTING_STATUS.yaml introuvable à {path}")
|
||||
with open(path) as f:
|
||||
return yaml.safe_load(f)
|
||||
|
||||
|
||||
def load_plugins(src: Path) -> dict:
|
||||
"""Charge tous les integrationplugin*.json trouvés (récursivement)."""
|
||||
plugins: dict = {}
|
||||
for f in sorted(src.rglob("integrationplugin*.json")):
|
||||
if f.name not in plugins:
|
||||
plugins[f.name] = json.loads(f.read_text(encoding="utf-8"))
|
||||
return plugins
|
||||
|
||||
|
||||
def load_meta(src: Path, plugin: str) -> dict:
|
||||
"""Charge meta.json depuis le même dossier que integrationplugin<plugin>.json."""
|
||||
for f in sorted(src.rglob(f"integrationplugin{plugin}.json")):
|
||||
meta_path = f.parent / "meta.json"
|
||||
if meta_path.exists():
|
||||
return json.loads(meta_path.read_text(encoding="utf-8"))
|
||||
return {}
|
||||
return {}
|
||||
|
||||
|
||||
# ── Libellé d'un appareil ────────────────────────────────────────────────────
|
||||
|
||||
def entry_name(e: dict, meta: dict) -> str:
|
||||
"""Titre : PORTING_STATUS.name > meta.json.title > plugin (fallback dernier recours)."""
|
||||
return e.get("name") or meta.get("title") or e.get("plugin", "?")
|
||||
|
||||
|
||||
# ── Helpers JSON nymea ────────────────────────────────────────────────────────
|
||||
|
||||
def transport_of(tc: dict) -> str:
|
||||
params = {p["name"] for p in tc.get("paramTypes", [])} | \
|
||||
{p["name"] for p in tc.get("discoveryParamTypes", [])}
|
||||
ifaces = set(tc.get("interfaces", []))
|
||||
if "networkdevice" in ifaces or {"hostName", "address", "port", "macAddress"} & params:
|
||||
return "Modbus TCP"
|
||||
if {"modbusMasterUuid", "rtuMaster"} & params:
|
||||
return "Modbus RTU"
|
||||
return "—"
|
||||
|
||||
|
||||
def roles(tc: dict) -> str:
|
||||
r = [INTERFACE_ROLE.get(i, i) for i in tc.get("interfaces", []) if i not in TECH_INTERFACES]
|
||||
return ", ".join(r) if r else "—"
|
||||
|
||||
|
||||
def add_method(tc: dict) -> str:
|
||||
return " / ".join(CREATE_METHOD.get(m, m) for m in tc.get("createMethods", [])) or "—"
|
||||
|
||||
|
||||
def resolve_protocol(plugin_data: dict | None) -> str:
|
||||
if not plugin_data:
|
||||
return "—"
|
||||
for v in plugin_data.get("vendors", []):
|
||||
for tc in v.get("thingClasses", []):
|
||||
t = transport_of(tc)
|
||||
if t != "—":
|
||||
return t
|
||||
return "—"
|
||||
|
||||
|
||||
# ── Rendu Markdown ────────────────────────────────────────────────────────────
|
||||
|
||||
def fmt_range(p: dict) -> str:
|
||||
lo, hi = p.get("minValue"), p.get("maxValue")
|
||||
if lo is not None and hi is not None:
|
||||
return f"{lo}–{hi}"
|
||||
return "—"
|
||||
|
||||
|
||||
def fmt_default(p: dict) -> str:
|
||||
d = p.get("defaultValue", "")
|
||||
if d == "" or d is None:
|
||||
return "—"
|
||||
return f"`{d}`"
|
||||
|
||||
|
||||
def md_table(headers: list, rows: list) -> str:
|
||||
out = ["| " + " | ".join(headers) + " |",
|
||||
"| " + " | ".join("---" for _ in headers) + " |"]
|
||||
for r in rows:
|
||||
out.append("| " + " | ".join(str(c) for c in r) + " |")
|
||||
return "\n".join(out)
|
||||
|
||||
|
||||
def render_params(tc: dict) -> list:
|
||||
lines = []
|
||||
disc = tc.get("discoveryParamTypes", [])
|
||||
if disc:
|
||||
rows = [[f"`{p['name']}`", p.get("displayName", ""), p.get("type", ""),
|
||||
fmt_range(p), fmt_default(p)] for p in disc]
|
||||
lines.append("_Paramètres de découverte :_")
|
||||
lines.append(md_table(["Clé", "Libellé", "Type", "Plage", "Défaut"], rows))
|
||||
lines.append("")
|
||||
settings = tc.get("paramTypes", [])
|
||||
if settings:
|
||||
rows = [[f"`{p['name']}`", p.get("displayName", ""), p.get("type", ""),
|
||||
fmt_range(p), fmt_default(p),
|
||||
"oui" if p.get("readOnly") else "non"] for p in settings]
|
||||
lines.append("_Réglages :_")
|
||||
lines.append(md_table(["Clé", "Libellé", "Type", "Plage", "Défaut", "Lecture seule"], rows))
|
||||
lines.append("")
|
||||
return lines
|
||||
|
||||
|
||||
def render_states(tc: dict) -> list:
|
||||
states = tc.get("stateTypes", [])
|
||||
if not states:
|
||||
return []
|
||||
rows = [[f"`{s['name']}`", s.get("displayName", ""), s.get("type", ""),
|
||||
s.get("unit") or "—"] for s in states]
|
||||
return [md_table(["Clé", "Grandeur", "Type", "Unité"], rows), ""]
|
||||
|
||||
|
||||
def render_plugin(plugin: dict) -> str:
|
||||
out = []
|
||||
vendors = plugin.get("vendors", [])
|
||||
vname = ", ".join(v.get("displayName", v.get("name", "")) for v in vendors)
|
||||
out.append(f"**Fabricant :** {vname} ")
|
||||
out.append(f"**Plugin :** `{plugin.get('name', '')}`")
|
||||
out.append("")
|
||||
|
||||
tcs = [(v, tc) for v in vendors for tc in v.get("thingClasses", [])]
|
||||
rows = [[f"**{tc.get('displayName', tc.get('name'))}**",
|
||||
roles(tc), transport_of(tc), add_method(tc),
|
||||
str(len(tc.get("stateTypes", [])))]
|
||||
for _, tc in tcs]
|
||||
out.append("#### Modèles pris en charge")
|
||||
out.append(md_table(["Modèle", "Rôle", "Transport", "Ajout", "Grandeurs"], rows))
|
||||
out.append("")
|
||||
|
||||
out.append("#### Détail par modèle")
|
||||
for _, tc in tcs:
|
||||
title = tc.get("displayName", tc.get("name"))
|
||||
out.append(f'??? abstract "{title} — `{tc.get("name")}`"')
|
||||
body = []
|
||||
body += render_params(tc)
|
||||
if tc.get("stateTypes"):
|
||||
body.append("_Grandeurs mesurées :_")
|
||||
body += render_states(tc)
|
||||
for ln in ("\n".join(body)).splitlines():
|
||||
out.append(" " + ln if ln else "")
|
||||
out.append("")
|
||||
return "\n".join(out).rstrip() + "\n"
|
||||
|
||||
|
||||
def render_matrix(entries: list, plugins: dict, src: Path) -> str:
|
||||
by_cat: dict = {}
|
||||
for e in entries:
|
||||
by_cat.setdefault(e.get("category", "autre"), []).append(e)
|
||||
|
||||
lines = []
|
||||
ordered_cats = [c for c in CATEGORY_ORDER if c in by_cat]
|
||||
ordered_cats += [c for c in by_cat if c not in CATEGORY_ORDER]
|
||||
|
||||
for cat in ordered_cats:
|
||||
label = CATEGORY_LABELS.get(cat, cat.capitalize())
|
||||
cat_rows = []
|
||||
for e in by_cat[cat]:
|
||||
fname = f"integrationplugin{e['plugin']}.json" if e.get("plugin") else None
|
||||
plugin_data = plugins.get(fname) if fname else None
|
||||
# nightly sans JSON → absent de la matrice et du nav
|
||||
if e["channel"] == "nightly" and (not fname or fname not in plugins):
|
||||
continue
|
||||
meta = load_meta(src, e["plugin"]) if e.get("plugin") else {}
|
||||
name = entry_name(e, meta)
|
||||
protocol = resolve_protocol(plugin_data)
|
||||
channel_badge = CHANNEL_BADGES.get(e["channel"], e["channel"])
|
||||
stability = meta.get("stability", "")
|
||||
stability_badge = STABILITY_BADGES.get(stability, "—") if stability else "—"
|
||||
cat_rows.append(f"| {name} | {protocol} | {channel_badge} | {stability_badge} |")
|
||||
if not cat_rows:
|
||||
continue
|
||||
lines.append(f"## {label}\n")
|
||||
lines.append("| Marque / Modèle | Protocole | Canal | Stabilité |")
|
||||
lines.append("|---|---|---|---|")
|
||||
lines.extend(cat_rows)
|
||||
lines.append("")
|
||||
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
# ── SUMMARY.md pour mkdocs-literate-nav ──────────────────────────────────────
|
||||
|
||||
def generate_summary(entries: list, docs: Path, src: Path, plugins: dict) -> None:
|
||||
"""Écrit docs/appareils/SUMMARY.md (nav literate-nav)."""
|
||||
by_cat: dict = {}
|
||||
for e in entries:
|
||||
by_cat.setdefault(e.get("category", "autre"), []).append(e)
|
||||
|
||||
lines = ["* [Compatibilité](compatibilite.md)"]
|
||||
|
||||
ordered_cats = [c for c in CATEGORY_ORDER if c in by_cat]
|
||||
ordered_cats += [c for c in by_cat if c not in CATEGORY_ORDER]
|
||||
|
||||
for cat in ordered_cats:
|
||||
label = CATEGORY_LABELS.get(cat, cat.capitalize())
|
||||
folder = CATEGORY_FOLDER.get(cat, cat)
|
||||
cat_entries = []
|
||||
for e in by_cat[cat]:
|
||||
if not e.get("plugin"):
|
||||
continue
|
||||
fname = f"integrationplugin{e['plugin']}.json"
|
||||
# nightly sans JSON → pas de fiche, pas d'entrée nav
|
||||
if e["channel"] == "nightly" and fname not in plugins:
|
||||
continue
|
||||
meta = load_meta(src, e["plugin"])
|
||||
name = entry_name(e, meta)
|
||||
slug = e.get("slug") or e["plugin"]
|
||||
cat_entries.append(f" * [{name}]({folder}/{slug}.md)")
|
||||
if cat_entries:
|
||||
lines.append(f"* [{label}]({folder}/index.md)")
|
||||
lines.extend(cat_entries)
|
||||
|
||||
summary_path = docs / "appareils" / "SUMMARY.md"
|
||||
summary_path.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
||||
print(f"SUMMARY.md → {summary_path.relative_to(docs.parent)}")
|
||||
|
||||
|
||||
# ── Validation ────────────────────────────────────────────────────────────────
|
||||
|
||||
def validate_entries(entries: list, plugins: dict, src: Path) -> None:
|
||||
errors = []
|
||||
for e in entries:
|
||||
if not e.get("plugin"):
|
||||
continue
|
||||
fname = f"integrationplugin{e['plugin']}.json"
|
||||
|
||||
if e["channel"] != "nightly":
|
||||
# JSON obligatoire pour stable / testing
|
||||
if fname not in plugins:
|
||||
errors.append(
|
||||
f" BLOQUANT : {fname} introuvable dans --src "
|
||||
f"(channel={e['channel']}, plugin={e['plugin']})"
|
||||
)
|
||||
# Libellé obligatoire
|
||||
meta = load_meta(src, e["plugin"])
|
||||
if not e.get("name") and not meta.get("title"):
|
||||
errors.append(
|
||||
f" BLOQUANT : libellé manquant pour plugin={e['plugin']} "
|
||||
f"(ni PORTING_STATUS.name ni meta.json.title)"
|
||||
)
|
||||
|
||||
if errors:
|
||||
sys.exit("ERREURS BLOQUANTES :\n" + "\n".join(errors))
|
||||
|
||||
|
||||
# ── Traitement des fichiers MD ────────────────────────────────────────────────
|
||||
|
||||
def process(docs: Path, entries: list, plugins: dict, src: Path, check: bool) -> int:
|
||||
entry_by_plugin = {e["plugin"]: e for e in entries if e.get("plugin")}
|
||||
changed = []
|
||||
|
||||
for md in sorted(docs.rglob("*.md")):
|
||||
text = md.read_text(encoding="utf-8")
|
||||
if "<!-- BEGIN GENERATED:" not in text:
|
||||
continue
|
||||
|
||||
def repl(m: re.Match) -> str:
|
||||
key = m.group("key")
|
||||
if key == "__matrix__":
|
||||
gen = render_matrix(entries, plugins, src)
|
||||
elif key in plugins:
|
||||
gen = render_plugin(plugins[key])
|
||||
else:
|
||||
print(f" ! {md.name}: clé '{key}' absente de --src", file=sys.stderr)
|
||||
return m.group(0)
|
||||
return f"{m.group(1)}\n{gen}\n{m.group(4)}"
|
||||
|
||||
new = MARKER_RE.sub(repl, text)
|
||||
if new != text:
|
||||
changed.append(md)
|
||||
if not check:
|
||||
md.write_text(new, encoding="utf-8")
|
||||
|
||||
if check:
|
||||
if changed:
|
||||
print("Doc PAS à jour :", ", ".join(str(c) for c in changed))
|
||||
return 1
|
||||
print("Doc à jour.")
|
||||
return 0
|
||||
print(f"Régénéré : {len(changed)} page(s).")
|
||||
for c in changed:
|
||||
print(f" - {c.relative_to(docs)}")
|
||||
return 0
|
||||
|
||||
|
||||
# ── Point d'entrée ────────────────────────────────────────────────────────────
|
||||
|
||||
def main() -> int:
|
||||
ap = argparse.ArgumentParser(description=__doc__)
|
||||
ap.add_argument("--src", default=".plugins-src", type=Path,
|
||||
help="Dossier source des JSON (plat ou avec sous-dossiers repos)")
|
||||
ap.add_argument("--docs", default="docs", type=Path)
|
||||
ap.add_argument("--lang", default="fr", help="Conservé pour compatibilité CI")
|
||||
ap.add_argument("--check", action="store_true",
|
||||
help="CI : exit 1 si la doc n'est pas à jour")
|
||||
a = ap.parse_args()
|
||||
|
||||
src = a.src
|
||||
entries = load_porting_status(Path.cwd())
|
||||
plugins = load_plugins(src)
|
||||
|
||||
if not plugins:
|
||||
print(f"Aucun integrationplugin*.json trouvé dans {src}", file=sys.stderr)
|
||||
return 2
|
||||
print(f"{len(plugins)} plugin(s) chargé(s) : {', '.join(plugins)}")
|
||||
|
||||
validate_entries(entries, plugins, src)
|
||||
generate_summary(entries, a.docs, src, plugins)
|
||||
return process(a.docs, entries, plugins, src, a.check)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
raise SystemExit(main())
|
||||
Loading…
x
Reference in New Issue
Block a user