From cd54b820af98b274f631243da0611f1e45b1ed7b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20SAILLANT?= <108685187+electron-rare@users.noreply.github.com> Date: Fri, 13 Feb 2026 14:15:51 +0100 Subject: [PATCH] Add ESP32-S3 + AG1171S project plan and firmware skeleton --- README.md | 21 ++- docs/plan_chef_projet_esp32s3_ag1171s.md | 51 ++++++ docs/solutions_rtc_phone_esp32.md | 189 +++++++++++++++++++++++ platformio.ini | 15 ++ src/main.cpp | 188 ++++++++++++++++++++++ 5 files changed, 463 insertions(+), 1 deletion(-) create mode 100644 docs/plan_chef_projet_esp32s3_ag1171s.md create mode 100644 docs/solutions_rtc_phone_esp32.md create mode 100644 platformio.ini create mode 100644 src/main.cpp diff --git a/README.md b/README.md index 1704e4a..b766a6d 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,21 @@ # RTC_BL_PHONE -esp32 bluetooth audio to rtc phone + +Projet PlatformIO ESP32 pour recycler un téléphone RTC ancien (combiné, clavier, hook). + +## Démarrage rapide +1. Ouvrir le dossier dans PlatformIO. +2. Compiler et flasher l'environnement `esp32-s3-devkitc-1` (par défaut). +3. Ouvrir le moniteur série à 115200 bauds. +4. Utiliser les commandes série (`h`, `r`, `o`, `d`, `c`) pour piloter la machine d'états. + +## Choix de cartes ESP32 +Voir `docs/solutions_rtc_phone_esp32.md` pour la shortlist des DevKit utilisables (ESP32-DevKitC, ESP32-S3-DevKitC-1, NodeMCU-32S, LOLIN32), les liens de référence web, et les solutions d’interface (direct combiné/clavier, SLIC/FXS, ATA externe), dont une variante AG1171S (Silvertel). + +## Plan projet (chef de projet) +Voir `docs/plan_chef_projet_esp32s3_ag1171s.md` pour le planning en phases, les risques, les critères d'acceptation et les livrables de la version ESP32-S3 + AG1171S. + +## Contenu +- `platformio.ini`: configuration multi-env (ESP32-S3 par défaut + ESP32 legacy). +- `src/main.cpp`: squelette firmware machine d'états pour intégration AG1171S. +- `docs/solutions_rtc_phone_esp32.md`: comparaison des architectures et recommandations. +- `docs/plan_chef_projet_esp32s3_ag1171s.md`: plan d'exécution projet version V0.1. diff --git a/docs/plan_chef_projet_esp32s3_ag1171s.md b/docs/plan_chef_projet_esp32s3_ag1171s.md new file mode 100644 index 0000000..1aebdcc --- /dev/null +++ b/docs/plan_chef_projet_esp32s3_ag1171s.md @@ -0,0 +1,51 @@ +# Plan chef de projet — ESP32-S3 + AG1171S (Silvertel) + +## 1) Objectif projet +Livrer un prototype fonctionnel "téléphone analogique ancien" piloté par ESP32-S3, avec interface 2 fils privée via AG1171S, sans connexion PSTN publique. + +## 2) Périmètre (version V0.1) +- Détection hook (on/off hook). +- Commande d'activation ligne (line enable). +- Commande de sonnerie (ring command/cadence côté analogique). +- Journal série + machine d'états téléphonie basique. +- Cible matérielle principale: **ESP32-S3-DevKitC-1**. + +## 3) Planning macro +### Phase A — Cadrage & schéma (Semaine 1) +- Valider broches AG1171S retenues (hook detect, ring control, line feed control). +- Produire schéma de câblage V0.1 (alims, masses, protections, découplage). +- Sortie: checklist sécurité + BOM V0.1. + +### Phase B — Firmware fondation (Semaine 2) +- Mettre en place environnement PlatformIO `esp32-s3-devkitc-1`. +- Implémenter machine d'états: `ON_HOOK`, `OFF_HOOK`, `DIALING`, `IN_CALL`, `RINGING`. +- Ajouter commandes série pour tests rapides (`r/o/d/c`). +- Sortie: build firmware de base + logs validés. + +### Phase C — Intégration hardware (Semaine 3) +- Câblage réel ESP32-S3 ↔ AG1171S. +- Test de robustesse hook (anti-rebond + stabilité). +- Test commande ring/line sans charge puis avec téléphone analogique. +- Sortie: matrice de tests V0.1 avec résultats. + +### Phase D — Validation système (Semaine 4) +- Campagne tests end-to-end: raccroché/décroché, sonnerie, transitions d'état. +- Vérifier alimentation et thermique. +- Corriger pinout/temporisations selon résultats. +- Sortie: release candidate V0.1. + +## 4) Risques & mitigation +- **Risque analogique (niveaux/impédance):** prévoir test progressif et instrumentation (oscillo, multimètre). +- **Risque sécurité téléphonie:** rester hors PSTN publique tant que conformité non traitée. +- **Risque planning:** découper firmware et hardware en jalons testables hebdomadaires. + +## 5) Critères d'acceptation V0.1 +- Boot stable sur ESP32-S3. +- Hook detect stable (> 100 transitions sans faux positif en test de banc). +- Commande `RINGING` active le signal de commande attendu. +- Retour `ON_HOOK` coupe ligne et ring command. + +## 6) Suite (V0.2+) +- Ajout décodage numérotation (DTMF/pulse). +- Ajout audio (codec I2S) et scénarios d'appel avancés. +- Option passerelle SIP locale. diff --git a/docs/solutions_rtc_phone_esp32.md b/docs/solutions_rtc_phone_esp32.md new file mode 100644 index 0000000..0b2efdc --- /dev/null +++ b/docs/solutions_rtc_phone_esp32.md @@ -0,0 +1,189 @@ +# Solutions recommandées: ESP32 + téléphone RTC ancien + +## Objectif +Créer un projet PlatformIO sur ESP32 pour réutiliser un ancien téléphone analogique RTC (combiné, clavier, crochet) avec une architecture moderne. + +## Contraintes importantes +- **Ne jamais connecter directement** l'ESP32 à une ligne téléphonique publique (PSTN) sans isolation/éléments homologués. +- Les tensions de sonnerie peuvent être élevées; prévoir isolation galvanique si interface ligne 2 fils. +- La qualité audio dépend fortement du front-end analogique (adaptation d'impédance, gain, anti-larsen). + +## Option A — Réutiliser uniquement le combiné + clavier (recommandé MVP) +### Principe +- Débrancher l'électronique ligne d'origine. +- Lire en hard: + - hook switch (décroché/raccroché) + - clavier (matrice) +- Audio: + - micro du combiné vers préampli + ADC/codec I2S + - écouteur via DAC/codec + ampli + +### Avantages +- La plus simple pour un premier prototype. +- Sécurité électrique plus facile à maîtriser. +- Excellente maîtrise logicielle côté ESP32 (Bluetooth, Wi-Fi, SIP, intercom local). + +### Inconvénients +- Nécessite un peu d'analogique audio (préamp, filtre, gain). +- Le clavier ancien peut demander reverse engineering. + +## Option B — Interface 2 fils complète type "ligne RTC privée" (SLIC/DAA) +### Principe +- Conserver le téléphone quasiment tel quel (port RJ11/2 fils). +- Générer alimentation de boucle, tonalité, éventuellement sonnerie via circuit spécialisé (SLIC). + +### Avantages +- Expérience "téléphone d'origine" la plus fidèle. +- Compatible avec plusieurs postes analogiques. + +### Inconvénients +- Plus complexe et coûteux. +- Design analogique + sécurité plus exigeants. +- Debug plus long. + +### Variante concrète: module **Silvertel AG1171S** +Si tu veux garder un ancien téléphone tel quel (2 fils TIP/RING) avec une carte ESP32, l'AG1171S est une piste concrète côté **FXS/SLIC**. + +#### Ce que ça apporte +- Génération de la boucle analogique pour alimenter un poste RTC ancien. +- Interface pensée pour créer une "ligne privée" locale (pas une connexion directe PSTN brute). +- Réduction de la complexité analogique par rapport à un design SLIC discret from-scratch. + +#### Comment l'intégrer proprement avec ESP32 +1. **AG1171S = étage ligne analogique** (alimentation de boucle, interface 2 fils). +2. **ESP32 = logique et signalisation** (états off-hook/on-hook, numérotation, scénarios). +3. **Chemin audio**: + - soit via codec audio externe (I2S) + adaptation vers l'étage ligne, + - soit via une architecture où l'audio analogique reste majoritairement côté téléphonie, et l'ESP32 pilote surtout la logique. +4. **Détection d'événements**: exposer vers GPIO les états utiles (hook, ring detect selon schéma d'application). + +#### Points d'attention (importants) +- Respecter strictement les notes d'application Silvertel (DC feed, protection, découplage, routage). +- Ne pas connecter à une ligne publique sans conformité réglementaire et schéma adapté. +- Prévoir protections (surintensité/surtension) et isolation selon l'usage final. +- Valider impédance et niveau audio pour éviter faible volume, saturation, écho/larsen. + +#### Recommandation projet +- **MVP rapide**: continuer Option A (combiné + clavier en hard) pour avancer sur firmware. +- **Version "vraie ligne 2 fils"**: passer en Option B avec AG1171S quand la logique applicative est stable. + + +### Proposition de mapping initial (ESP32-S3-DevKitC-1) +- `GPIO4` : Hook sense (entrée, `INPUT_PULLUP`, actif bas selon câblage). +- `GPIO5` : Ring command (sortie logique vers étage de commande sonnerie). +- `GPIO6` : Line enable (sortie logique vers activation ligne AG1171S). +- `GPIO48`: LED debug état firmware. + +> Ce mapping est un **point de départ firmware** et doit être validé/ajusté selon le schéma AG1171S final. + +## Option C — Passerelle hybride (ATA/FXS externe + ESP32 contrôle) +### Principe +- L'audio et la boucle téléphonique sont gérés par un matériel externe (ATA/box FXS). +- ESP32 gère logique applicative (boutons, scénario d'appel, domotique, BLE/Wi-Fi). + +### Avantages +- Déploiement rapide avec qualité voix stable. +- Risque analogique réduit. + +### Inconvénients +- Dépendance à un boîtier externe. +- Moins "DIY full stack". + +## Dev kits ESP32 utilisables (vérifiés web) +> Recherche croisée faite sur la doc officielle Espressif (`esp-dev-kits`) et la liste des cartes PlatformIO (`espressif32`). + +### Recommandés pour TON projet (RTC + combiné + clavier + audio) +1. **ESP32-DevKitC (WROOM-32)** + - Très compatible avec exemples existants. + - Wi-Fi + Bluetooth Classic/BLE utile si tu vises audio BT/HFP plus tard. + - Mapping PlatformIO simple: `board = esp32dev`. + +2. **ESP32-S3-DevKitC-1** + - Plus récent, bon support I/O et USB natif. + - Très bon choix pour version long terme (UI, USB CDC, plus de marge CPU/RAM selon variantes). + - Mapping PlatformIO: `board = esp32-s3-devkitc-1`. + +3. **NodeMCU-32S / LOLIN32** + - Faciles à trouver et souvent moins chers. + - Bons pour prototypage hook + clavier + logique de numérotation. + - Mapping PlatformIO: `board = nodemcu-32s` ou `board = lolin32`. + +### Utilisables mais moins adaptés à ton besoin immédiat +- **ESP32-C3-DevKitC-02** + - Très bien pour projets IoT BLE/Wi-Fi. + - Mais pas de Bluetooth Classic, donc moins idéal si objectif audio BT "téléphone" avancé. + +## Recommandation pratique +1. **Phase 1 (MVP): Option A + ESP32-DevKitC** + - Hook + clavier + audio local simple. + - Validation UX (décroché, composition, feedback audio). +2. **Phase 2:** ajout Bluetooth/Wi-Fi (SIP/WebRTC passerelle). +3. **Phase 3:** si besoin d'un vrai port 2 fils: migration vers Option B. + +## Matériel conseillé (MVP) +- ESP32-WROOM / ESP32-S3. +- Codec audio I2S simple (ou carte audio ESP32 dédiée). +- Petit ampli casque/écouteur + préampli micro électret/carbone selon combiné. +- Optocoupleur ou transistors pour lecture fiable hook/clavier si tensions atypiques. +- Alimentation propre 5V + 3.3V, masse analogique soignée. + +## Notes logiciel PlatformIO +- Démarrer avec un squelette Arduino + machine d'états: + - `IDLE` (raccroché) + - `OFF_HOOK` + - `DIALING` + - `IN_CALL` +- Ajouter journal série détaillé dès le début. +- Écrire des tests de mapping clavier (table de correspondance). + + +## Solutions existantes pour interfacer un ancien téléphone à un microcontrôleur + +Oui, il existe plusieurs familles de solutions déjà utilisées en pratique: + +1. **Interface combiné “en direct” (hook + clavier + audio séparé)** + - Tu n’utilises pas la ligne RJ11 d’origine: tu récupères seulement le crochet, le clavier, le micro et l’écouteur. + - C’est la méthode la plus simple pour ESP32 et la plus sûre pour un prototype. + - Très bien pour interphone, SIP local, Bluetooth, domotique vocale. + +2. **Interface FXS/SLIC (émuler une vraie ligne analogique privée)** + - Le microcontrôleur pilote un front-end téléphonique spécialisé qui fournit tension de ligne, courant de boucle et sonnerie. + - C’est la solution “propre téléphonie” si tu veux brancher un poste analogique sur 2 fils comme à l’époque. + - Plus complexe en électronique et en sécurité CEM/isolement. + +3. **Interface FXO/DAA (recevoir ou analyser une ligne analogique existante)** + - Utilisée quand on veut interfacer une ligne analogique côté “réseau”. + - Demande encore plus de prudence réglementaire/sécurité selon le pays. + +4. **Passerelle ATA externe (FXS déjà intégrée)** + - Exemple courant: un ATA SIP/FXS fait tout le travail téléphonique analogique. + - L’ESP32 ne gère que la logique (capteurs, scénarios, UI, automation). + - Super choix pour aller vite avec une bonne qualité audio. + +5. **Décodage DTMF / cadran impulsionnel dédié** + - Si ton téléphone est à cadran ou clavier ancien, tu peux ajouter un étage dédié: + - décodage DTMF matériel, + - ou capture d’impulsions du cadran via GPIO + anti-rebond/filtrage. + - Souvent combiné avec l’Option A. + +### Ce qui marche le mieux pour ton cas +- Vu ton besoin ("combiné + clavier en hard"), la meilleure approche reste: + - **MVP: interface directe (Option A)**, + - puis migration vers **ATA externe** ou **SLIC/FXS** si tu veux une expérience “ligne RTC” complète. + +## Sources web utiles +- Espressif DevKitC: https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32/esp32-devkitc/index.html +- Espressif S3 DevKitC-1: https://docs.espressif.com/projects/esp-dev-kits/en/latest/esp32s3/esp32-s3-devkitc-1/index.html +- PlatformIO `esp32dev`: https://docs.platformio.org/en/latest/boards/espressif32/esp32dev.html +- PlatformIO `esp32-s3-devkitc-1`: https://docs.platformio.org/en/latest/boards/espressif32/esp32-s3-devkitc-1.html +- PlatformIO `nodemcu-32s`: https://docs.platformio.org/en/latest/boards/espressif32/nodemcu-32s.html +- PlatformIO `lolin32`: https://docs.platformio.org/en/latest/boards/espressif32/lolin32.html +- PlatformIO `esp32-c3-devkitc-02`: https://docs.platformio.org/en/latest/boards/espressif32/esp32-c3-devkitc-02.html +- Asterisk documentation (PBX/VoIP): https://docs.asterisk.org/ +- Exemple ATA FXS (Grandstream HT801): https://www.grandstream.com/products/gateways-and-atas/analog-telephone-adaptors/product/ht801 +- Silvertel (catalogue modules téléphonie): https://www.silvertel.com/ + +## Décision proposée +Pour ton besoin immédiat (PLIP / combiné + clavier en hard), la **meilleure balance risque/temps** est: +- **Option A en premier** avec **ESP32-DevKitC**. +- Puis extension progressive vers ESP32-S3 ou interface ligne complète si nécessaire. diff --git a/platformio.ini b/platformio.ini new file mode 100644 index 0000000..bf01ce5 --- /dev/null +++ b/platformio.ini @@ -0,0 +1,15 @@ +[platformio] +default_envs = esp32-s3-devkitc-1 + +[env] +platform = espressif32 +framework = arduino +monitor_speed = 115200 +build_flags = + -DCORE_DEBUG_LEVEL=1 + +[env:esp32-s3-devkitc-1] +board = esp32-s3-devkitc-1 + +[env:esp32dev] +board = esp32dev diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..fa66a11 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,188 @@ +#include + +/* + RTC_BL_PHONE - ESP32-S3 + AG1171S control skeleton + + Goal: + - Provide a practical firmware base for a private analog line project. + - Keep telephony analog front-end on AG1171S side. + - Let ESP32 manage call-state logic and debug observability. + + Notes: + - Pin mapping must be validated against your AG1171S application schematic. + - Never connect to PSTN without compliant isolation/protection design. +*/ + +enum class PhoneState : uint8_t { + ON_HOOK, + OFF_HOOK, + DIALING, + IN_CALL, + RINGING +}; + +struct PhonePins { + uint8_t pinHookSense; + uint8_t pinRingCmd; + uint8_t pinLineEnable; + uint8_t pinLed; +}; + +#if CONFIG_IDF_TARGET_ESP32S3 +constexpr PhonePins PINS{ + .pinHookSense = 4, // AG1171S hook/off-hook indication input to ESP32-S3 + .pinRingCmd = 5, // ESP32-S3 output: request ring cadence generator/enable + .pinLineEnable = 6, // ESP32-S3 output: line feed enable (through safe driver) + .pinLed = 48 // ESP32-S3 DevKitC-1 RGB/Status-compatible GPIO +}; +#else +constexpr PhonePins PINS{ + .pinHookSense = 27, + .pinRingCmd = 26, + .pinLineEnable = 25, + .pinLed = 2 +}; +#endif + +constexpr uint32_t SERIAL_BAUD = 115200; +constexpr uint32_t DEBOUNCE_MS = 25; + +PhoneState g_state = PhoneState::ON_HOOK; +bool g_hookOffHook = false; +uint32_t g_lastHookEdgeMs = 0; + +const char* stateToString(PhoneState state) { + switch (state) { + case PhoneState::ON_HOOK: return "ON_HOOK"; + case PhoneState::OFF_HOOK: return "OFF_HOOK"; + case PhoneState::DIALING: return "DIALING"; + case PhoneState::IN_CALL: return "IN_CALL"; + case PhoneState::RINGING: return "RINGING"; + } + + return "UNKNOWN"; +} + +void setState(PhoneState newState) { + if (newState == g_state) { + return; + } + + g_state = newState; + Serial.printf("[RTC_PHONE] state=%s\n", stateToString(g_state)); + + switch (g_state) { + case PhoneState::ON_HOOK: + digitalWrite(PINS.pinLineEnable, LOW); + digitalWrite(PINS.pinRingCmd, LOW); + digitalWrite(PINS.pinLed, LOW); + break; + + case PhoneState::OFF_HOOK: + digitalWrite(PINS.pinLineEnable, HIGH); + digitalWrite(PINS.pinRingCmd, LOW); + digitalWrite(PINS.pinLed, HIGH); + break; + + case PhoneState::DIALING: + digitalWrite(PINS.pinLineEnable, HIGH); + digitalWrite(PINS.pinRingCmd, LOW); + digitalWrite(PINS.pinLed, HIGH); + break; + + case PhoneState::IN_CALL: + digitalWrite(PINS.pinLineEnable, HIGH); + digitalWrite(PINS.pinRingCmd, LOW); + digitalWrite(PINS.pinLed, HIGH); + break; + + case PhoneState::RINGING: + digitalWrite(PINS.pinLineEnable, HIGH); + digitalWrite(PINS.pinRingCmd, HIGH); + digitalWrite(PINS.pinLed, HIGH); + break; + } +} + +void printHelp() { + Serial.println("[RTC_PHONE] Commands:"); + Serial.println(" h -> help"); + Serial.println(" r -> enter RINGING"); + Serial.println(" o -> force ON_HOOK"); + Serial.println(" d -> force DIALING"); + Serial.println(" c -> force IN_CALL"); +} + +void handleSerialCommands() { + while (Serial.available() > 0) { + const char cmd = static_cast(Serial.read()); + + switch (cmd) { + case 'h': + printHelp(); + break; + case 'r': + setState(PhoneState::RINGING); + break; + case 'o': + setState(PhoneState::ON_HOOK); + break; + case 'd': + setState(PhoneState::DIALING); + break; + case 'c': + setState(PhoneState::IN_CALL); + break; + default: + break; + } + } +} + +void updateHookState() { + const bool rawOffHook = (digitalRead(PINS.pinHookSense) == LOW); + const uint32_t nowMs = millis(); + + if (rawOffHook != g_hookOffHook && (nowMs - g_lastHookEdgeMs) > DEBOUNCE_MS) { + g_lastHookEdgeMs = nowMs; + g_hookOffHook = rawOffHook; + + Serial.printf("[RTC_PHONE] hook=%s\n", g_hookOffHook ? "OFF_HOOK" : "ON_HOOK"); + + if (g_hookOffHook) { + setState(PhoneState::OFF_HOOK); + } else { + setState(PhoneState::ON_HOOK); + } + } +} + +void setup() { + Serial.begin(SERIAL_BAUD); + + pinMode(PINS.pinHookSense, INPUT_PULLUP); + pinMode(PINS.pinRingCmd, OUTPUT); + pinMode(PINS.pinLineEnable, OUTPUT); + pinMode(PINS.pinLed, OUTPUT); + + digitalWrite(PINS.pinRingCmd, LOW); + digitalWrite(PINS.pinLineEnable, LOW); + digitalWrite(PINS.pinLed, LOW); + + Serial.println("\n[RTC_PHONE] Boot OK"); +#if CONFIG_IDF_TARGET_ESP32S3 + Serial.println("[RTC_PHONE] Target: ESP32-S3"); +#else + Serial.println("[RTC_PHONE] Target: ESP32 (legacy mapping)"); +#endif + Serial.println("[RTC_PHONE] Profile: AG1171S control skeleton"); + printHelp(); + + setState(PhoneState::ON_HOOK); +} + +void loop() { + updateHookState(); + handleSerialCommands(); + delay(10); +}