Add ESP32-S3 + AG1171S project plan and firmware skeleton

This commit is contained in:
Clément SAILLANT
2026-02-13 14:15:51 +01:00
parent 304fed13bd
commit cd54b820af
5 changed files with 463 additions and 1 deletions
+20 -1
View File
@@ -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 dinterface (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.
+51
View File
@@ -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.
+189
View File
@@ -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 nutilises pas la ligne RJ11 dorigine: tu récupères seulement le crochet, le clavier, le micro et l’écouteur.
- Cest 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.
- Cest 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.
- LESP32 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 dimpulsions du cadran via GPIO + anti-rebond/filtrage.
- Souvent combiné avec lOption 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.
+15
View File
@@ -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
+188
View File
@@ -0,0 +1,188 @@
#include <Arduino.h>
/*
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<char>(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);
}