diff --git a/Module_00_Installation.odt b/Module_00_Installation.odt deleted file mode 100644 index f9d7b58..0000000 Binary files a/Module_00_Installation.odt and /dev/null differ diff --git a/Module_01_Architecture.odt b/Module_01_Architecture.odt deleted file mode 100644 index c6c3283..0000000 Binary files a/Module_01_Architecture.odt and /dev/null differ diff --git a/Module_02_GPIO_NeoPixel.odt b/Module_02_GPIO_NeoPixel.odt deleted file mode 100644 index c60a816..0000000 Binary files a/Module_02_GPIO_NeoPixel.odt and /dev/null differ diff --git a/Module_03_PWM_ADC.odt b/Module_03_PWM_ADC.odt deleted file mode 100644 index 28400af..0000000 Binary files a/Module_03_PWM_ADC.odt and /dev/null differ diff --git a/Module_04_Serie_Debug.odt b/Module_04_Serie_Debug.odt deleted file mode 100644 index a768e79..0000000 Binary files a/Module_04_Serie_Debug.odt and /dev/null differ diff --git a/Module_05_I2C_SPI.odt b/Module_05_I2C_SPI.odt deleted file mode 100644 index 843a291..0000000 Binary files a/Module_05_I2C_SPI.odt and /dev/null differ diff --git a/Module_06_Interruptions_Timers.odt b/Module_06_Interruptions_Timers.odt deleted file mode 100644 index 1737ad6..0000000 Binary files a/Module_06_Interruptions_Timers.odt and /dev/null differ diff --git a/Module_07_WiFi.odt b/Module_07_WiFi.odt deleted file mode 100644 index 40421c0..0000000 Binary files a/Module_07_WiFi.odt and /dev/null differ diff --git a/Module_08_ServeurWeb.odt b/Module_08_ServeurWeb.odt deleted file mode 100644 index c85c01f..0000000 Binary files a/Module_08_ServeurWeb.odt and /dev/null differ diff --git a/Module_09_BLE.odt b/Module_09_BLE.odt deleted file mode 100644 index cc52ac3..0000000 Binary files a/Module_09_BLE.odt and /dev/null differ diff --git a/Module_10_Energie.odt b/Module_10_Energie.odt deleted file mode 100644 index e6657dc..0000000 Binary files a/Module_10_Energie.odt and /dev/null differ diff --git a/Module_11_MQTT.odt b/Module_11_MQTT.odt deleted file mode 100644 index 1471583..0000000 Binary files a/Module_11_MQTT.odt and /dev/null differ diff --git a/Module_12_ProjetFinal.odt b/Module_12_ProjetFinal.odt deleted file mode 100644 index 2eab2b7..0000000 Binary files a/Module_12_ProjetFinal.odt and /dev/null differ diff --git a/README.md b/README.md index c2d8ce2..9eed0fb 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,63 @@ -# Formation Arduino (ESP32) +# Formation Arduino (ESP32-S3) -Support de formation en 13 modules (00 à 12) plus une synthèse du matériel, au format OpenDocument (.odt). +Support de formation en 13 modules (00 à 12) plus une synthèse du matériel. +Les sources sont en Markdown [Quarto](https://quarto.org) (`modules/*.qmd`) et produisent des PDF. | Fichier | Sujet | |---|---| -| Module_00_Installation | Installation de l'environnement | -| Module_01_Architecture | Architecture | -| Module_02_GPIO_NeoPixel | GPIO et NeoPixel | -| Module_03_PWM_ADC | PWM et ADC | -| Module_04_Serie_Debug | Liaison série et débogage | -| Module_05_I2C_SPI | I2C et SPI | -| Module_06_Interruptions_Timers | Interruptions et timers | -| Module_07_WiFi | WiFi | -| Module_08_ServeurWeb | Serveur web | -| Module_09_BLE | Bluetooth Low Energy | -| Module_10_Energie | Gestion de l'énergie | -| Module_11_MQTT | MQTT | -| Module_12_ProjetFinal | Projet final | -| Synthese_Formation_Materiel | Synthèse du matériel | +| `00-installation` | Installation de l'environnement | +| `01-architecture` | Découverte du microcontrôleur ESP32-S3 | +| `02-gpio-neopixel` | Entrées/sorties numériques et LED NeoPixel | +| `03-pwm-adc` | Signaux analogiques : PWM et ADC | +| `04-serie-debug` | Communication série et débogage | +| `05-i2c-spi` | Bus I2C et SPI | +| `06-interruptions-timers` | Interruptions matérielles et timers | +| `07-wifi` | Wi-Fi : station, point d'accès, client HTTP | +| `08-serveurweb` | Serveur web embarqué | +| `09-ble` | Bluetooth Low Energy | +| `10-energie` | Gestion de l'énergie | +| `11-mqtt` | IoT et MQTT | +| `12-projetfinal` | Projet final | +| `synthese-materiel` | Synthèse et liste de matériel | + +## Organisation + +``` +modules/ sources des supports (.qmd) +modele/ gabarit PDF (Typst) et thème de coloration du code +schemas/ schémas décrits en Python (schemdraw + matplotlib), rendus en svg/ et png/ +_quarto.yml configuration du projet +_output/ PDF générés (non versionnés) +``` + +## Produire les PDF + +Prérequis : [Quarto](https://quarto.org/docs/get-started/) (inclut Pandoc et Typst). + +``` +quarto render # tous les supports +quarto render modules/03-pwm-adc.qmd # un seul support +``` + +Les PDF sont créés dans `_output/modules/`. +Pour obtenir aussi du Word ou de l'ODT, ajouter `docx:` ou `odt:` sous `format:` dans `_quarto.yml`. + +## Modifier ou ajouter un schéma + +Les images de `schemas/svg/` sont versionnées : il n'est nécessaire de les régénérer que si l'on modifie un schéma. + +``` +python -m venv .venv +.venv\Scripts\python -m pip install -r schemas/requirements.txt +.venv\Scripts\python schemas\generer.py # ou : generer.py m03 +``` + +Un schéma est une fonction Python déclarée dans `schemas/mXX_*.py` (liste `FIGURES`), puis appelée dans le `.qmd` : + +```markdown +![Légende de la figure](../schemas/svg/m03-servo-50hz.svg){#fig-m03-servo-50hz} +``` + +## Historique + +Les supports étaient à l'origine au format `.odt` ; ils restent récupérables via le tag `avant-quarto`. diff --git a/Synthese_Formation_Materiel.odt b/Synthese_Formation_Materiel.odt deleted file mode 100644 index ef8dacb..0000000 Binary files a/Synthese_Formation_Materiel.odt and /dev/null differ diff --git a/schemas/generer.py b/schemas/generer.py index 9bf2c07..34d385b 100644 --- a/schemas/generer.py +++ b/schemas/generer.py @@ -29,7 +29,7 @@ def modules_figures(filtres=()): def enregistrer(fig, id_): if hasattr(fig, "fig"): # dessin schemdraw (backend matplotlib) fig = fig.fig - fig.savefig(DOSSIER_SVG / f"{id_}.svg") + fig.savefig(DOSSIER_SVG / f"{id_}.svg", metadata={"Date": None}) # pas de date : diff git stable fig.savefig(DOSSIER_PNG / f"{id_}.png", dpi=200) plt.close(fig) diff --git a/schemas/inserer.py b/schemas/inserer.py deleted file mode 100644 index c9a11e9..0000000 --- a/schemas/inserer.py +++ /dev/null @@ -1,172 +0,0 @@ -"""Insère les schémas générés dans les supports .odt. - -Usage : python schemas/inserer.py [Module_03_PWM_ADC.odt ...] -Sans argument : traite chaque support pour lequel un fichier mXX_*.py existe. - -Idempotent : les figures déjà insérées (cadres « schema-* ») sont retirées puis réinsérées. -""" -import os -import re -import struct -import sys -import tempfile -import zipfile -from pathlib import Path - -from lxml import etree - -from generer import DOSSIER_PNG, DOSSIER_SVG, modules_figures - -RACINE = Path(__file__).resolve().parent.parent - -NS = { - "office": "urn:oasis:names:tc:opendocument:xmlns:office:1.0", - "text": "urn:oasis:names:tc:opendocument:xmlns:text:1.0", - "draw": "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0", - "style": "urn:oasis:names:tc:opendocument:xmlns:style:1.0", - "fo": "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0", - "svg": "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0", - "xlink": "http://www.w3.org/1999/xlink", - "manifest": "urn:oasis:names:tc:opendocument:xmlns:manifest:1.0", -} -STYLE_IMAGE = "Schema_Image" -STYLE_LEGENDE = "Schema_Legende" -STYLE_CADRE = "Schema_Cadre" - - -def q(nom): - prefixe, local = nom.split(":") - return f"{{{NS[prefixe]}}}{local}" - - -def normaliser(texte): - return re.sub(r"\s+", " ", texte.replace("’", "'")).strip() - - -def taille_png(chemin): - with open(chemin, "rb") as f: - entete = f.read(24) - return struct.unpack(">II", entete[16:24]) - - -def ajouter_styles(racine): - auto = racine.find(q("office:automatic-styles")) - existants = {s.get(q("style:name")) for s in auto} - if STYLE_IMAGE not in existants: - s = etree.SubElement(auto, q("style:style"), {q("style:name"): STYLE_IMAGE, q("style:family"): "paragraph"}) - etree.SubElement(s, q("style:paragraph-properties"), { - q("fo:text-align"): "center", q("fo:margin-top"): "0.3cm", - q("fo:margin-bottom"): "0.1cm", q("fo:keep-with-next"): "always"}) - if STYLE_LEGENDE not in existants: - s = etree.SubElement(auto, q("style:style"), {q("style:name"): STYLE_LEGENDE, q("style:family"): "paragraph"}) - etree.SubElement(s, q("style:paragraph-properties"), { - q("fo:text-align"): "center", q("fo:margin-top"): "0cm", q("fo:margin-bottom"): "0.4cm"}) - etree.SubElement(s, q("style:text-properties"), { - q("fo:font-style"): "italic", q("fo:font-size"): "9pt", q("fo:color"): "#4b5563"}) - if STYLE_CADRE not in existants: - s = etree.SubElement(auto, q("style:style"), {q("style:name"): STYLE_CADRE, q("style:family"): "graphic"}) - etree.SubElement(s, q("style:graphic-properties"), { - q("style:vertical-pos"): "top", q("style:vertical-rel"): "baseline", - q("fo:border"): "none", q("fo:padding"): "0cm"}) - - -def retirer_figures(corps): - styles = (STYLE_IMAGE, STYLE_LEGENDE) - for p in list(corps.iter(q("text:p"))): - if p.get(q("text:style-name")) in styles: - p.getparent().remove(p) - - -def trouver_point_insertion(corps, ancre): - """Renvoie l'élément après lequel insérer : le paragraphe d'introduction qui suit le titre.""" - cible = normaliser(ancre) - for p in corps.iter(q("text:p"), q("text:h")): - if normaliser("".join(p.itertext())) == cible: - suivant = p.getnext() - while suivant is not None and suivant.tag == q("text:p") and not "".join(suivant.itertext()).strip(): - suivant = suivant.getnext() - if suivant is not None and suivant.tag == q("text:p"): - return suivant - return p - raise ValueError(f"ancre introuvable : {ancre!r}") - - -def construire_figure(f, numero): - largeur, hauteur = taille_png(DOSSIER_PNG / f"{f.id}.png") - h_cm = f.largeur_cm * hauteur / largeur - p_image = etree.Element(q("text:p"), {q("text:style-name"): STYLE_IMAGE}) - cadre = etree.SubElement(p_image, q("draw:frame"), { - q("draw:style-name"): STYLE_CADRE, q("draw:name"): f"schema-{f.id}", - q("text:anchor-type"): "as-char", q("svg:width"): f"{f.largeur_cm:.2f}cm", - q("svg:height"): f"{h_cm:.2f}cm", q("draw:z-index"): "0"}) - for ext, mime in (("svg", "image/svg+xml"), ("png", "image/png")): - etree.SubElement(cadre, q("draw:image"), { - q("xlink:href"): f"Pictures/{f.id}.{ext}", q("xlink:type"): "simple", - q("xlink:show"): "embed", q("xlink:actuate"): "onLoad", q("draw:mime-type"): mime}) - etree.SubElement(cadre, q("svg:title")).text = f.legende - p_legende = etree.Element(q("text:p"), {q("text:style-name"): STYLE_LEGENDE}) - p_legende.text = f"Figure {numero} — {f.legende}" - return p_image, p_legende - - -def maj_manifest(xml, figures): - racine = etree.fromstring(xml) - for e in list(racine): - if e.get(q("manifest:full-path"), "").startswith("Pictures/schema-") or \ - re.match(r"Pictures/m\d\d-", e.get(q("manifest:full-path"), "")): - racine.remove(e) - for f in figures: - for ext, mime in (("svg", "image/svg+xml"), ("png", "image/png")): - etree.SubElement(racine, q("manifest:file-entry"), { - q("manifest:full-path"): f"Pictures/{f.id}.{ext}", q("manifest:media-type"): mime}) - return etree.tostring(racine, xml_declaration=True, encoding="UTF-8") - - -def traiter(odt, figures): - num_module = int(figures[0].id[1:3]) - with zipfile.ZipFile(odt) as z: - entrees = {i.filename: z.read(i.filename) for i in z.infolist()} - ordre = [i.filename for i in z.infolist()] - racine = etree.fromstring(entrees["content.xml"]) - corps = racine.find(f"{q('office:body')}/{q('office:text')}") - ajouter_styles(racine) - retirer_figures(corps) - for n, f in enumerate(figures, 1): - point = trouver_point_insertion(corps, f.ancre) - p_image, p_legende = construire_figure(f, f"{num_module}.{n}") - point.addnext(p_image) - p_image.addnext(p_legende) - entrees["content.xml"] = etree.tostring(racine, xml_declaration=True, encoding="UTF-8") - entrees["META-INF/manifest.xml"] = maj_manifest(entrees["META-INF/manifest.xml"], figures) - # Images : on retire les anciennes versions puis on ajoute les nouvelles - ordre = [n for n in ordre if not re.match(r"Pictures/m\d\d-", n)] - for f in figures: - entrees[f"Pictures/{f.id}.svg"] = (DOSSIER_SVG / f"{f.id}.svg").read_bytes() - entrees[f"Pictures/{f.id}.png"] = (DOSSIER_PNG / f"{f.id}.png").read_bytes() - ordre += [f"Pictures/{f.id}.svg", f"Pictures/{f.id}.png"] - # Réécriture : mimetype en premier et non compressé (exigence ODF) - fd, temp = tempfile.mkstemp(suffix=".odt", dir=odt.parent) - os.close(fd) - with zipfile.ZipFile(temp, "w") as z: - z.writestr(zipfile.ZipInfo("mimetype"), entrees["mimetype"], compress_type=zipfile.ZIP_STORED) - for nom in ordre: - if nom != "mimetype": - z.writestr(nom, entrees[nom], compress_type=zipfile.ZIP_DEFLATED) - os.replace(temp, odt) - print(f"{odt.name} : {len(figures)} figure(s) insérée(s)") - - -def main(): - par_module = modules_figures() - cibles = [RACINE / a for a in sys.argv[1:]] or \ - [p for p in sorted(RACINE.glob("Module_*.odt")) if f"m{p.name[7:9]}" in par_module] - for odt in cibles: - prefixe = f"m{odt.name[7:9]}" - if prefixe not in par_module: - print(f"{odt.name} : aucune figure déclarée, ignoré") - continue - traiter(odt, par_module[prefixe]) - - -if __name__ == "__main__": - main() diff --git a/schemas/m03_pwm_adc.py b/schemas/m03_pwm_adc.py index 7799da0..922d77c 100644 --- a/schemas/m03_pwm_adc.py +++ b/schemas/m03_pwm_adc.py @@ -138,16 +138,8 @@ def adc_quantification(): FIGURES = [ - Figure("m03-pwm-rapport-cyclique", - "Le rapport cyclique fixe la tension moyenne perçue par la charge (LED, moteur)", - "1. Qu'est-ce que le PWM ?", pwm_rapport_cyclique), - Figure("m03-servo-50hz", - "Commande d'un servomoteur : la largeur de l'impulsion (1 à 2 ms) fixe l'angle", - "2.2 Approche explicite : API LEDC (contrôle fin)", servo_50hz, largeur_cm=15), - Figure("m03-montage-variateur", - "Câblage de l'exercice : potentiomètre sur GPIO1 (ADC1), LED sur GPIO4 (PWM)", - "3. Exercice : variateur de luminosité avec potentiomètre", montage_variateur, largeur_cm=14), - Figure("m03-adc-quantification", - "Conversion analogique-numérique puis mise à l'échelle avec map()", - "4. Le convertisseur analogique-numérique (ADC)", adc_quantification), + Figure("m03-pwm-rapport-cyclique", pwm_rapport_cyclique), + Figure("m03-servo-50hz", servo_50hz), + Figure("m03-montage-variateur", montage_variateur), + Figure("m03-adc-quantification", adc_quantification), ] diff --git a/schemas/style.py b/schemas/style.py index e2200bb..ace6262 100644 --- a/schemas/style.py +++ b/schemas/style.py @@ -35,6 +35,7 @@ plt.rcParams.update({ "ytick.color": GRIS, "lines.linewidth": 2, "svg.fonttype": "path", # texte vectorisé : rendu identique partout + "svg.hashsalt": "formation-esp32", # identifiants SVG stables d'une génération à l'autre "savefig.bbox": "tight", "savefig.pad_inches": 0.1, "savefig.facecolor": "white", @@ -43,9 +44,10 @@ plt.rcParams.update({ @dataclass class Figure: - """Déclaration d'une figure à générer puis insérer dans un support.""" + """Déclaration d'une figure à générer. + + La légende et l'emplacement sont dans le .qmd : + ![Légende](../schemas/svg/.svg){#fig-} + """ id: str # ex. "m03-pwm-duty" ; le préfixe mXX donne le module - legende: str # texte de la légende (sans « Figure X.Y — ») - ancre: str # texte exact du titre de section concerné dessiner: Callable # renvoie une figure matplotlib ou un dessin schemdraw - largeur_cm: float = 16.0 diff --git a/schemas/svg/m03-adc-quantification.svg b/schemas/svg/m03-adc-quantification.svg index e932dcc..3878703 100644 --- a/schemas/svg/m03-adc-quantification.svg +++ b/schemas/svg/m03-adc-quantification.svg @@ -6,7 +6,6 @@ - 2026-10-18T14:38:22.443124 image/svg+xml @@ -42,16 +41,16 @@ z +" clip-path="url(#p4e42c2ff59)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - - + @@ -88,11 +87,11 @@ z +" clip-path="url(#p4e42c2ff59)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -122,11 +121,11 @@ z +" clip-path="url(#p4e42c2ff59)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -166,11 +165,11 @@ z +" clip-path="url(#p4e42c2ff59)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -495,16 +494,16 @@ z +" clip-path="url(#p4e42c2ff59)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - - + @@ -518,11 +517,11 @@ L -3.5 0 +" clip-path="url(#p4e42c2ff59)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -536,11 +535,11 @@ L 164.919024 143.414568 +" clip-path="url(#p4e42c2ff59)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -554,11 +553,11 @@ L 164.919024 126.215762 +" clip-path="url(#p4e42c2ff59)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -572,11 +571,11 @@ L 164.919024 109.016956 +" clip-path="url(#p4e42c2ff59)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -611,11 +610,11 @@ z +" clip-path="url(#p4e42c2ff59)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -656,11 +655,11 @@ z +" clip-path="url(#p4e42c2ff59)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -706,11 +705,11 @@ z +" clip-path="url(#p4e42c2ff59)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -826,7 +825,7 @@ z +" clip-path="url(#p4e42c2ff59)" style="fill: none; stroke-dasharray: 1.3,2.145; stroke-dashoffset: 0; stroke: #6b7280; stroke-width: 1.3"/> +" clip-path="url(#p4e42c2ff59)" style="fill: none; stroke: #1f5fa8; stroke-width: 2; stroke-linecap: square"/> +" clip-path="url(#pb446d379c4)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - - + @@ -1748,11 +1747,11 @@ L 3.5 0 +" clip-path="url(#pb446d379c4)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -1767,11 +1766,11 @@ L 397.941901 122.489354 +" clip-path="url(#pb446d379c4)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -1787,11 +1786,11 @@ L 397.941901 78.345751 +" clip-path="url(#pb446d379c4)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -1878,11 +1877,11 @@ L 397.941901 34.202148 +" clip-path="url(#pb34704d88d)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -1896,11 +1895,11 @@ L 234.997222 34.202148 +" clip-path="url(#pb34704d88d)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -1914,11 +1913,11 @@ L 284.374398 34.202148 +" clip-path="url(#pb34704d88d)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -1932,11 +1931,11 @@ L 333.751573 34.202148 +" clip-path="url(#pb34704d88d)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -1977,11 +1976,11 @@ L 383.128748 34.202148 +" clip-path="url(#pb34704d88d)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -1995,11 +1994,11 @@ L 397.941901 166.632956 +" clip-path="url(#pb34704d88d)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -2016,11 +2015,11 @@ L 397.941901 133.51717 +" clip-path="url(#pb34704d88d)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -2037,11 +2036,11 @@ L 397.941901 100.401383 +" clip-path="url(#pb34704d88d)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -2058,11 +2057,11 @@ L 397.941901 67.285596 +" clip-path="url(#pb34704d88d)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -2160,17 +2159,17 @@ z +" clip-path="url(#pb34704d88d)" style="fill: none; stroke: #1f5fa8; stroke-width: 2; stroke-linecap: square"/> +" clip-path="url(#pb34704d88d)" style="fill: none; stroke-dasharray: 4.44,1.92; stroke-dashoffset: 0; stroke: #e07a1f; stroke-width: 1.2"/> - - - + + @@ -2622,13 +2621,13 @@ z - + - + - + diff --git a/schemas/svg/m03-montage-variateur.svg b/schemas/svg/m03-montage-variateur.svg index db7dd37..efb5854 100644 --- a/schemas/svg/m03-montage-variateur.svg +++ b/schemas/svg/m03-montage-variateur.svg @@ -6,7 +6,6 @@ - 2026-10-18T14:38:22.285543 image/svg+xml @@ -35,7 +34,7 @@ L 437.451525 174.665381 L 430.108684 164.385404 L 444.794366 164.385404 z -" clip-path="url(#p34353fba05)" style="fill: none; stroke: #e07a1f; stroke-width: 2; stroke-linecap: round"/> +" clip-path="url(#p4639aee0bc)" style="fill: none; stroke: #e07a1f; stroke-width: 2; stroke-linecap: round"/> +" clip-path="url(#p4639aee0bc)" style="fill: none; stroke: #1f5fa8; stroke-width: 2; stroke-linecap: round"/> +" clip-path="url(#p4639aee0bc)" style="fill: none; stroke: #1f5fa8; stroke-width: 2; stroke-linecap: round"/> +" clip-path="url(#p4639aee0bc)" style="fill: none; stroke: #1f5fa8; stroke-width: 2; stroke-linecap: round"/> +" clip-path="url(#p4639aee0bc)" style="fill: none; stroke: #1f5fa8; stroke-width: 2; stroke-linecap: round"/> +" clip-path="url(#p4639aee0bc)" style="fill: none; stroke: #1f5fa8; stroke-width: 2; stroke-linecap: round"/> +" clip-path="url(#p4639aee0bc)" style="fill: none; stroke: #1f2937; stroke-width: 2; stroke-linecap: round"/> +" clip-path="url(#p4639aee0bc)" style="fill: none; stroke: #1f2937; stroke-width: 2; stroke-linecap: round"/> +" clip-path="url(#p4639aee0bc)" style="fill: none; stroke: #2e8b57; stroke-width: 2; stroke-linecap: round"/> +" clip-path="url(#p4639aee0bc)" style="fill: none; stroke: #2e8b57; stroke-width: 2; stroke-linecap: round"/> +" clip-path="url(#p4639aee0bc)" style="fill: #2e8b57"/> +" clip-path="url(#p4639aee0bc)" style="fill: none; stroke: #2e8b57; stroke-width: 2; stroke-linecap: round"/> +" clip-path="url(#p4639aee0bc)" style="fill: none; stroke: #1f2937; stroke-width: 2; stroke-linecap: round"/> +" clip-path="url(#p4639aee0bc)" style="fill: none; stroke: #1f2937; stroke-width: 2; stroke-linecap: round"/> +" clip-path="url(#p4639aee0bc)" style="fill: none; stroke: #e07a1f; stroke-width: 2; stroke-linecap: round"/> +" clip-path="url(#p4639aee0bc)" style="fill: none; stroke: #e07a1f; stroke-width: 2; stroke-linecap: round"/> +" clip-path="url(#p4639aee0bc)" style="fill: none; stroke: #e07a1f; stroke-width: 2; stroke-linecap: round"/> +" clip-path="url(#p4639aee0bc)" style="fill: #e07a1f"/> +" clip-path="url(#p4639aee0bc)" style="fill: none; stroke: #e07a1f; stroke-width: 2; stroke-linecap: round"/> +" clip-path="url(#p4639aee0bc)" style="fill: #e07a1f"/> +" clip-path="url(#p4639aee0bc)" style="fill: none; stroke: #1f2937; stroke-width: 2; stroke-linecap: round"/> @@ -713,7 +712,7 @@ z - + diff --git a/schemas/svg/m03-pwm-rapport-cyclique.svg b/schemas/svg/m03-pwm-rapport-cyclique.svg index 2bb124b..68f074c 100644 --- a/schemas/svg/m03-pwm-rapport-cyclique.svg +++ b/schemas/svg/m03-pwm-rapport-cyclique.svg @@ -6,7 +6,6 @@ - 2026-10-18T14:38:21.884270 image/svg+xml @@ -39,7 +38,7 @@ z - - - + + - - + - + - + - + @@ -4088,16 +4087,16 @@ L 0 3.5 +" clip-path="url(#p1988a58d21)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - - + @@ -4147,11 +4146,11 @@ z +" clip-path="url(#p1988a58d21)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -4223,12 +4222,12 @@ L 303.599124 41.618357 L 303.763905 86.250527 L 385.989833 86.250527 L 385.989833 86.250527 -" clip-path="url(#pb27fd7aba9)" style="fill: none; stroke: #1f5fa8; stroke-width: 2; stroke-linecap: square"/> +" clip-path="url(#p1988a58d21)" style="fill: none; stroke: #1f5fa8; stroke-width: 2; stroke-linecap: square"/> +" clip-path="url(#p1988a58d21)" style="fill: none; stroke-dasharray: 6.66,2.88; stroke-dashoffset: 0; stroke: #e07a1f; stroke-width: 1.8"/> - - - + + - + - + - + - + @@ -9343,11 +9342,11 @@ z +" clip-path="url(#paaff85ab5e)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -9363,11 +9362,11 @@ L 402.459735 173.980087 +" clip-path="url(#paaff85ab5e)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -9396,12 +9395,12 @@ L 331.11762 129.347917 L 331.282402 173.980087 L 385.989833 173.980087 L 385.989833 173.980087 -" clip-path="url(#p0a19abac77)" style="fill: none; stroke: #1f5fa8; stroke-width: 2; stroke-linecap: square"/> +" clip-path="url(#paaff85ab5e)" style="fill: none; stroke: #1f5fa8; stroke-width: 2; stroke-linecap: square"/> +" clip-path="url(#paaff85ab5e)" style="fill: none; stroke-dasharray: 6.66,2.88; stroke-dashoffset: 0; stroke: #e07a1f; stroke-width: 1.8"/> - - - + + - + @@ -13540,7 +13539,7 @@ z - + @@ -13553,7 +13552,7 @@ z - + @@ -13593,7 +13592,7 @@ z - + @@ -13875,11 +13874,11 @@ z +" clip-path="url(#p8d88850880)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -13895,11 +13894,11 @@ L 402.459735 261.709647 +" clip-path="url(#p8d88850880)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -13928,12 +13927,12 @@ L 358.636117 217.077477 L 358.800899 261.709647 L 385.989833 261.709647 L 385.989833 261.709647 -" clip-path="url(#p83c9427cba)" style="fill: none; stroke: #1f5fa8; stroke-width: 2; stroke-linecap: square"/> +" clip-path="url(#p8d88850880)" style="fill: none; stroke: #1f5fa8; stroke-width: 2; stroke-linecap: square"/> +" clip-path="url(#p8d88850880)" style="fill: none; stroke-dasharray: 6.66,2.88; stroke-dashoffset: 0; stroke: #e07a1f; stroke-width: 1.8"/> + - + - + diff --git a/schemas/svg/m03-servo-50hz.svg b/schemas/svg/m03-servo-50hz.svg index c90cb28..9b998ba 100644 --- a/schemas/svg/m03-servo-50hz.svg +++ b/schemas/svg/m03-servo-50hz.svg @@ -6,7 +6,6 @@ - 2026-10-18T14:38:22.123535 image/svg+xml @@ -39,7 +38,7 @@ z - - - + + - - + - + - + - + - + - + - + - + - + @@ -8123,16 +8122,16 @@ L 0 3.5 +" clip-path="url(#p542e91d944)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - - + @@ -8182,11 +8181,11 @@ z +" clip-path="url(#p542e91d944)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -8254,7 +8253,7 @@ L 248.269569 25.18249 L 248.450649 68.954639 L 420.296197 68.954639 L 420.296197 68.954639 -" clip-path="url(#pc2960f74f9)" style="fill: none; stroke: #1f5fa8; stroke-width: 1.8; stroke-linecap: square"/> +" clip-path="url(#p542e91d944)" style="fill: none; stroke: #1f5fa8; stroke-width: 1.8; stroke-linecap: square"/> - - - + + - + - + - + - + - + - + - + - + - + @@ -17129,11 +17128,11 @@ z +" clip-path="url(#pd7fc223f79)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -17149,11 +17148,11 @@ L 438.399736 144.270361 +" clip-path="url(#pd7fc223f79)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -17178,7 +17177,7 @@ L 252.796585 100.498213 L 252.977666 144.270361 L 420.296197 144.270361 L 420.296197 144.270361 -" clip-path="url(#pfd1aaeace0)" style="fill: none; stroke: #1f5fa8; stroke-width: 1.8; stroke-linecap: square"/> +" clip-path="url(#pd7fc223f79)" style="fill: none; stroke: #1f5fa8; stroke-width: 1.8; stroke-linecap: square"/> - - - + + - + @@ -25321,7 +25320,7 @@ z - + @@ -25334,7 +25333,7 @@ z - + @@ -25348,7 +25347,7 @@ z - + @@ -25362,7 +25361,7 @@ z - + @@ -25402,7 +25401,7 @@ z - + @@ -25416,7 +25415,7 @@ z - + @@ -25430,7 +25429,7 @@ z - + @@ -25444,7 +25443,7 @@ z - + @@ -25571,11 +25570,11 @@ z +" clip-path="url(#p3b8cd38529)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -25591,11 +25590,11 @@ L 438.399736 219.586084 +" clip-path="url(#p3b8cd38529)" style="fill: none; stroke: #e5e7eb; stroke-width: 0.8; stroke-linecap: square"/> - + @@ -25620,7 +25619,7 @@ L 257.323602 175.813935 L 257.504682 219.586084 L 420.296197 219.586084 L 420.296197 219.586084 -" clip-path="url(#peefe64885e)" style="fill: none; stroke: #1f5fa8; stroke-width: 1.8; stroke-linecap: square"/> +" clip-path="url(#p3b8cd38529)" style="fill: none; stroke: #1f5fa8; stroke-width: 1.8; stroke-linecap: square"/> + - + - +