feat(v2.0): Auto-discovery, correzione bug critici, e documentazione completa
Build Docker Image for Raspberry Pi / build-and-push (push) Failing after 4m42s

🆕 Funzionalità Auto-Discovery
- Aggiunto metodo AutoDiscoverBufferSizes() per rilevamento automatico QPIGS/QPIRI/QMOD/QPIWS
- Supporto variabili d'ambiente (INVERTER_DEVICE, MQTT_SERVER, etc.)
- Caching persistente buffer sizes in /cache/inverter.conf.cache
- Flag -a/--auto-discover per modalità auto-detection

🐛 Bug Fixes Critici
- **Parsing interi**: Aggiunta attemptAddSettingInt() con stoi() invece di stof()
  - Fix: stof('98') = 98.0f → 97 (int), ora stoi('98') = 98 direttamente
  - Applicato a: qpiri, qpiws, qmod, qpigs
- **Thread sync**: Aggiunto ups_qpiws_changed a main loop e condizione exit poll()
  - Fix: loop principale controllava solo 3 flag su 4, causava hang
  - Fix: thread poll() non usciva in runOnce perché mancava controllo QPIWS
- **Config accuracy**: Corretti buffer sizes (qpiri: 98→103, qpiws: 36→40)
  - Rimosso sources/inverter-cli/inverter.conf che sovrascriveva config globale
  - Validato con test: inverter_poller -1 completa in 6s con JSON completo

📚 Documentazione Completa
- Creato documentation/CODE_ARCHITECTURE.md (38KB)
  - Mappa logica variabili globali
  - Flusso esecuzione main() con diagrammi ASCII
  - Sequence diagram classe cInverter (poll, query, auto-discovery)
  - Thread synchronization diagrams
  - MQTT integration bash scripts flow
  - Mappa concettuale 5-layer system architecture
  - Error handling e performance optimizations
- Organizzati file .md in documentation/ (AUTO_DISCOVERY, IMPLEMENTATION, QUICKSTART, DEBUG)
- Aggiornato README.md con sezione v2.0 e indice documentazione
- Aggiornato .github/copilot-instructions.md con novità v2.0

🔧 Miglioramenti Build & CI/CD
- Gitea Actions per build multi-arch (arm/v6, arm/v7, arm64, amd64, 386)
- Configurazione VS Code completa (tasks, launch, debug GDB)
- Script test-autodiscovery.sh e test-device.sh

 Testing Validato
- inverter_poller -1 completa in 6 secondi
- Output JSON completo con tutte le metriche
- Exit pulito senza timeout (exit code 0)
- Tutte le 4 query QMOD/QPIGS/QPIRI/QPIWS funzionanti
This commit is contained in:
Pi Developer
2026-01-25 15:00:48 +01:00
parent ac2642639f
commit 6af9fcad7e
30 changed files with 4503 additions and 139 deletions
+392
View File
@@ -0,0 +1,392 @@
# Auto-Discovery Feature
Il sistema di auto-discovery rileva automaticamente i parametri di comunicazione corretti del tuo inverter all'avvio del container.
## Come Funziona
All'avvio, il container:
1. **Controlla** se esiste già una configurazione salvata (`.discovery_done`)
2. **Testa** la comunicazione con l'inverter inviando i 4 comandi principali
3. **Rileva** le dimensioni corrette del buffer per ogni comando
4. **Salva** i parametri scoperti in `/etc/inverter/.discovery_done`
5. **Aggiorna** `/etc/inverter/inverter.conf` con i valori corretti
6. **Avvia** i servizi MQTT normalmente
## Variabili d'Ambiente
### `INVERTER_DEVICE`
Specifica il device seriale dell'inverter.
**Default:** `/dev/ttyUSB0`
**Esempi:**
```yaml
environment:
- INVERTER_DEVICE=/dev/ttyUSB1 # USB-to-Serial adapter
- INVERTER_DEVICE=/dev/ttyS0 # Built-in serial port
- INVERTER_DEVICE=/dev/hidraw0 # USB HID device
```
### `FORCE_DISCOVERY`
Forza l'auto-discovery ad ogni avvio, anche se esistono già parametri salvati.
**Default:** `false`
**Quando usarlo:**
- Dopo aver cambiato inverter
- Se sospetti che i parametri salvati siano errati
- Per debug o testing
**Esempio:**
```yaml
environment:
- FORCE_DISCOVERY=true
```
### `SKIP_DISCOVERY`
Salta completamente l'auto-discovery e usa solo i valori da `inverter.conf`.
**Default:** `false`
**Quando usarlo:**
- Quando conosci già i parametri corretti
- Per velocizzare l'avvio (risparmia ~10 secondi)
- In ambienti di produzione stabili
**Esempio:**
```yaml
environment:
- SKIP_DISCOVERY=true
```
## Scenari d'Uso
### Scenario 1: Primo Avvio (Default)
```yaml
services:
voltronic-mqtt:
environment:
- INVERTER_DEVICE=/dev/ttyUSB1
```
**Cosa succede:**
- ✓ Container rileva che non esiste `.discovery_done`
- ✓ Esegue auto-discovery (~10-15 secondi)
- ✓ Salva i parametri trovati
- ✓ Avvia i servizi MQTT
**Log:**
```
=== Voltronic MQTT Bridge Starting ===
Configuration:
Device: /dev/ttyUSB1
Force Discovery: false
Skip Discovery: false
No previous discovery found, will run auto-discovery
=== Running Auto-Discovery ===
This will take about 10-15 seconds...
Testing QMOD command (buffer 5-100)...
✓ QMOD: found response at 5 bytes
...
✓ Auto-discovery completed successfully!
device=/dev/ttyUSB1
qmod=5
qpigs=110
qpiri=103
qpiws=40
```
### Scenario 2: Avvii Successivi (Cached)
```yaml
services:
voltronic-mqtt:
environment:
- INVERTER_DEVICE=/dev/ttyUSB1
```
**Cosa succede:**
- ✓ Container trova `.discovery_done` esistente
- ✓ Verifica che il device non sia cambiato
- ✓ Carica i parametri salvati
- ✓ Avvia immediatamente i servizi (nessun ritardo)
**Log:**
```
=== Voltronic MQTT Bridge Starting ===
Configuration:
Device: /dev/ttyUSB1
Force Discovery: false
Skip Discovery: false
✓ Using previous discovery results
Current configuration:
device=/dev/ttyUSB1
qmod=5
qpigs=110
qpiri=103
qpiws=40
=== Starting MQTT Bridge Services ===
```
### Scenario 3: Cambio Device
```yaml
services:
voltronic-mqtt:
environment:
- INVERTER_DEVICE=/dev/ttyUSB0 # Cambiato da ttyUSB1
```
**Cosa succede:**
- ✓ Container rileva che il device è cambiato
- ✓ Elimina `.discovery_done` esistente
- ✓ Esegue nuovamente l'auto-discovery
- ✓ Salva i nuovi parametri
**Log:**
```
⚠ Device changed from /dev/ttyUSB1 to /dev/ttyUSB0
Running new discovery...
=== Running Auto-Discovery ===
...
```
### Scenario 4: Force Discovery
```yaml
services:
voltronic-mqtt:
environment:
- INVERTER_DEVICE=/dev/ttyUSB1
- FORCE_DISCOVERY=true
```
**Cosa succede:**
- ✓ Ignora `.discovery_done` esistente
- ✓ Esegue sempre auto-discovery
- ✓ Aggiorna parametri salvati
**Quando usarlo:** Dopo aggiornamento firmware inverter, troubleshooting.
### Scenario 5: Skip Discovery
```yaml
services:
voltronic-mqtt:
environment:
- INVERTER_DEVICE=/dev/ttyUSB1
- SKIP_DISCOVERY=true
```
**Cosa succede:**
- ✓ Non esegue mai auto-discovery
- ✓ Usa solo valori da `config/inverter.conf`
- ✓ Avvio istantaneo
**Quando usarlo:** Parametri già noti e stabili, avvio rapido richiesto.
## File Generati
### `/etc/inverter/.discovery_done`
Contiene i parametri scoperti con timestamp:
```bash
device=/dev/ttyUSB1
qmod=5
qpigs=110
qpiri=103
qpiws=40
timestamp=2024-01-15T10:30:00+01:00
```
Questo file è **persistente** nel volume `./config/` e sopravvive ai restart del container.
### `/etc/inverter/inverter.conf.backup`
Backup automatico della configurazione originale prima dell'auto-discovery.
## Troubleshooting
### Discovery Fallisce
**Log:**
```
✗ Auto-discovery failed!
Please check:
1. Inverter is powered on
2. Cable is properly connected
3. Device path is correct: /dev/ttyUSB1
Falling back to default configuration...
```
**Soluzioni:**
1. Verifica che l'inverter sia acceso
2. Controlla il cablaggio RS232/USB
3. Verifica il device corretto: `ls -la /dev/tty*`
4. Testa manualmente:
```bash
docker exec -it voltronic-mqtt /opt/inverter-cli/bin/inverter_poller -a
```
### Device Non Trovato
**Errore:**
```
Unable to open device file
```
**Soluzioni:**
1. Verifica mapping in docker-compose.yml:
```yaml
devices:
- /dev/ttyUSB1:/dev/ttyUSB1:rwm
```
2. Controlla permessi: `sudo chmod 666 /dev/ttyUSB1`
3. Verifica che il device esista: `ls -la /dev/ttyUSB1`
### Valori Scoperti Errati
**Soluzione 1 - Force Discovery:**
```yaml
environment:
- FORCE_DISCOVERY=true
```
**Soluzione 2 - Configurazione Manuale:**
```yaml
environment:
- SKIP_DISCOVERY=true
```
E modifica manualmente `config/inverter.conf`:
```bash
device=/dev/ttyUSB1
qmod=5
qpigs=110
qpiri=103
qpiws=40
```
## Test Manuale
Puoi testare l'auto-discovery manualmente senza riavviare il container:
```bash
# Test base
docker exec -it voltronic-mqtt /opt/inverter-cli/bin/inverter_poller -a
# Test con debug
docker exec -it voltronic-mqtt /opt/inverter-cli/bin/inverter_poller -d -a
# Test singolo comando
docker exec -it voltronic-mqtt /opt/inverter-cli/bin/inverter_poller -r QPIGS
```
## Best Practices
1. **Primo Setup:** Lascia auto-discovery attivo (default)
2. **Produzione:** Dopo aver verificato che funzioni, considera `SKIP_DISCOVERY=true` per avvio rapido
3. **Multi-Inverter:** Usa container separati con `INVERTER_DEVICE` diversi
4. **Backup:** Salva `config/.discovery_done` dopo il primo successo
5. **Logging:** Monitora i log del primo avvio per verificare discovery:
```bash
docker logs voltronic-mqtt
```
## Esempio Completo docker-compose.yml
```yaml
version: '3'
services:
# Inverter primario su ttyUSB1
voltronic-mqtt-primary:
image: bushrangers/ha-voltronic-mqtt
container_name: voltronic-mqtt-primary
privileged: true
restart: always
environment:
- INVERTER_DEVICE=/dev/ttyUSB1
- FORCE_DISCOVERY=false
- SKIP_DISCOVERY=false
volumes:
- ./config-primary/:/etc/inverter/
devices:
- /dev/ttyUSB1:/dev/ttyUSB1:rwm
# Inverter secondario su ttyUSB0 (discovery skippato)
voltronic-mqtt-secondary:
image: bushrangers/ha-voltronic-mqtt
container_name: voltronic-mqtt-secondary
privileged: true
restart: always
environment:
- INVERTER_DEVICE=/dev/ttyUSB0
- SKIP_DISCOVERY=true # Parametri già noti
volumes:
- ./config-secondary/:/etc/inverter/
devices:
- /dev/ttyUSB0:/dev/ttyUSB0:rwm
```
## Migrazione da Versione Precedente
Se stai aggiornando da una versione senza auto-discovery:
1. **Backup configurazione esistente:**
```bash
cp config/inverter.conf config/inverter.conf.old
```
2. **Aggiungi variabili d'ambiente al docker-compose.yml:**
```yaml
environment:
- INVERTER_DEVICE=/dev/ttyUSB1 # Il tuo device attuale
```
3. **Primo avvio con auto-discovery:**
```bash
docker-compose down
docker-compose up -d
docker logs -f voltronic-mqtt
```
4. **Verifica risultati:**
```bash
cat config/.discovery_done
```
5. **Se tutto OK, abilita skip per avvio rapido:**
```yaml
environment:
- INVERTER_DEVICE=/dev/ttyUSB1
- SKIP_DISCOVERY=true # Usa parametri scoperti
```
## FAQ
**Q: Quanto tempo impiega l'auto-discovery?**
A: Circa 10-15 secondi al primo avvio. Gli avvii successivi sono istantanei.
**Q: Posso usare auto-discovery con più inverter?**
A: Sì! Usa container separati con `INVERTER_DEVICE` diversi e directory config separate.
**Q: Cosa succede se l'inverter è spento durante discovery?**
A: Il container fallisce gracefully e usa i parametri di default da `inverter.conf`.
**Q: Devo eliminare `.discovery_done` manualmente?**
A: No, il container lo fa automaticamente quando cambi `INVERTER_DEVICE` o usi `FORCE_DISCOVERY=true`.
**Q: Posso disabilitare completamente auto-discovery?**
A: Sì, usa `SKIP_DISCOVERY=true`.
**Q: I parametri scoperti sono persistenti?**
A: Sì, sono salvati nel volume `./config/` e sopravvivono ai restart.
+893
View File
@@ -0,0 +1,893 @@
# Architettura del Codice - Mappa Logica e Flusso di Esecuzione
## Panoramica Generale
Il progetto è composto da due componenti principali:
1. **inverter-cli** (C++): Applicazione che comunica con l'inverter via RS232/USB
2. **inverter-mqtt** (Bash): Script che gestiscono l'integrazione MQTT con Home Assistant
```
┌──────────────────────────────────────────────────────────────┐
│ CONTAINER DOCKER │
│ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ entrypoint.sh │ │
│ │ 1. Auto-Discovery (prima esecuzione) │ │
│ │ 2. Caricamento configurazione │ │
│ │ 3. Avvio servizi MQTT │ │
│ └──────┬─────────────┬─────────────┬─────────────────────┘ │
│ │ │ │ │
│ ┌────▼────┐ ┌────▼────┐ ┌────▼────────┐ │
│ │mqtt-init│ │mqtt-push│ │mqtt-subscriber│ │
│ │ .sh │ │ .sh │ │ .sh │ │
│ └────┬────┘ └────┬────┘ └────┬────────┘ │
│ │ │ │ │
│ │ ┌────▼─────────────▼────┐ │
│ │ │ inverter_poller │ │
│ │ │ (binario C++) │ │
│ │ └────┬──────────────────┘ │
│ │ │ │
│ └─────────────┴──────┐ │
│ │ │
│ ┌────▼────┐ │
│ │ MQTT │ │
│ │ Broker │ │
│ └─────────┘ │
└──────────────────────────────────────────────────────────────┘
┌─────▼──────┐
│ Home │
│ Assistant │
└────────────┘
```
---
## Componente 1: inverter-cli (C++)
### 1.1 Mappa delle Variabili Globali
#### File: main.cpp
```cpp
// Configurazione
string devicename = "/dev/ttyUSB0"; // Device seriale
float runinterval = 0; // Intervallo polling (120 = ogni 30s)
float ampfactor = 1; // Fattore correzione amperaggio
float wattfactor = 1; // Fattore correzione wattaggio
int qpiri = 0, qpiws = 0; // Buffer sizes comandi
int qmod = 0, qpigs = 0;
// Flag di controllo
bool debugFlag = false; // Debug mode
bool runOnce = false; // Esegui una volta e esci
// Flag atomici per sincronizzazione thread
atomic_bool ups_status_changed(false);
atomic_bool ups_qmod_changed(false); // Mode query completata
atomic_bool ups_qpiri_changed(false); // QPIRI query completata
atomic_bool ups_qpigs_changed(false); // QPIGS query completata
atomic_bool ups_qpiws_changed(false); // QPIWS query completata
// Oggetto inverter
cInverter *ups = nullptr;
```
### 1.2 Flusso di Esecuzione: main()
```
START main(argc, argv)
├─> Parse argomenti CLI (InputParser)
│ ├─> -d/--debug → debugFlag = true
│ ├─> -1/--run-once → runOnce = true
│ ├─> -r <command> → rawcmd = command
│ └─> -a/--auto-discover → modalità auto-discovery
├─> Carica configurazione
│ ├─> Cerca ./inverter.conf
│ └─> Altrimenti /etc/inverter/inverter.conf
│ ├─> devicename (es: /dev/ttyUSB1)
│ ├─> run_interval
│ ├─> amperage_factor, watt_factor
│ └─> qpiri, qpiws, qmod, qpigs (buffer sizes)
├─> Crea oggetto cInverter
│ ups = new cInverter(devicename, qpiri, qpiws, qmod, qpigs)
├─> BRANCH: Modalità auto-discovery?
│ YES ├─> ups->AutoDiscoverBufferSizes()
│ ├─> Stampa DISCOVERY_QMOD=X
│ ├─> Stampa DISCOVERY_QPIGS=X
│ ├─> Stampa DISCOVERY_QPIRI=X
│ ├─> Stampa DISCOVERY_QPIWS=X
│ ├─> Stampa DISCOVERY_SUCCESS=true/false
│ └─> exit(0)
├─> BRANCH: Comando raw specificato?
│ YES ├─> ups->ExecuteCmd(rawcmd)
│ ├─> Stampa risposta
│ └─> exit(0)
├─> Modalità polling normale
│ ├─> ups->runMultiThread()
│ │ └─> Avvia thread: poll()
│ │
│ └─> LOOP PRINCIPALE while(true)
│ │
│ ├─> WAIT: ups_qmod_changed && ups_qpiri_changed &&
│ │ ups_qpigs_changed && ups_qpiws_changed
│ │
│ ├─> Quando tutti i flag sono true:
│ │ ├─> Reset flag a false
│ │ ├─> Leggi dati con GetQpigsStatus(), GetQpiriStatus()
│ │ ├─> Parse valori con sscanf()
│ │ ├─> Calcola PV watts, watthour
│ │ ├─> Stampa JSON completo su stdout
│ │ └─> IF runOnce: exit(0)
│ │
│ └─> sleep(1) e ripeti
└─> END
```
### 1.3 Classe cInverter
#### Variabili Membro (inverter.h)
```cpp
class cInverter {
private:
// Configurazione
int fd; // File descriptor device seriale
string device; // Path device (es: /dev/ttyUSB1)
int buf_qpiri, buf_qpiws; // Buffer sizes configurati
int buf_qmod, buf_qpigs;
// Mutex per thread-safety
mutex m;
// Dati letti dall'inverter
char status1[512]; // Risposta QPIGS
char status2[512]; // Risposta QPIRI
char warnings[512]; // Risposta QPIWS
int mode; // Mode corrente (1-6)
// Buffer comunicazione seriale
uint8_t buf[2048];
public:
// Costruttore
cInverter(string devicename, int qpiri, int qpiws, int qmod, int qpigs);
// Metodi polling
void poll(); // Thread principale polling
void runMultiThread(); // Avvia poll() in thread separato
// Metodi query
bool query(const char *cmd, int replysize);
int query_auto(const char *cmd, int max_size);
// Getter
string *GetQpigsStatus();
string *GetQpiriStatus();
string *GetWarnings();
int GetMode();
// Utility
void ExecuteCmd(const string cmd);
void AutoDiscoverBufferSizes();
};
```
#### Flusso di Esecuzione: poll() Thread
```
START poll() [Thread separato]
├─> fprintf: "Thread started, runOnce=X"
└─> LOOP while(true)
├─> IF !ups_qmod_changed
│ ├─> query("QMOD", buf_qmod)
│ │ ├─> Costruisci comando con CRC
│ │ ├─> write() su device seriale
│ │ ├─> read() risposta
│ │ ├─> Verifica CRC
│ │ └─> return true se OK
│ ├─> SetMode(buf[1])
│ └─> ups_qmod_changed = true
├─> IF !ups_qpigs_changed
│ ├─> query("QPIGS", buf_qpigs)
│ ├─> Copia in status1
│ └─> ups_qpigs_changed = true
├─> IF !ups_qpiri_changed
│ ├─> query("QPIRI", buf_qpiri)
│ ├─> Copia in status2
│ └─> ups_qpiri_changed = true
├─> IF !ups_qpiws_changed
│ ├─> query("QPIWS", buf_qpiws)
│ ├─> Copia in warnings
│ └─> ups_qpiws_changed = true
├─> IF runOnce && tutti_i_flag_true
│ ├─> fprintf: "All data collected"
│ └─> return (termina thread)
├─> fprintf: "Flags: QMOD=X QPIGS=X ..."
└─> sleep(2) e ripeti
```
#### Flusso di Esecuzione: query()
```
START query(cmd, replysize)
├─> Apri device se non già aperto
│ ├─> open(device, O_RDWR | O_NOCTTY | O_NDELAY)
│ ├─> Configura termios (2400 baud, 8N1)
│ └─> tcsetattr()
├─> Flush buffer I/O
│ ├─> tcflush(fd, TCIOFLUSH)
│ └─> usleep(100000) // 100ms delay
├─> Costruisci comando con CRC
│ ├─> Comando base (es: "QPIGS")
│ ├─> Calcola CRC con cal_crc_half()
│ ├─> Aggiungi CRC bytes
│ └─> Aggiungi CR (\r)
├─> Invia comando
│ └─> write(fd, comando, lunghezza)
├─> Leggi risposta (loop incrementale)
│ ├─> FOR i=0 to replysize
│ │ ├─> read(fd, buf+i, replysize-i)
│ │ ├─> IF byte letto == CR: break
│ │ └─> continue
│ │
│ ├─> IF debug: stampa hex dump
│ │
│ └─> Verifica formato risposta
│ ├─> Primo byte deve essere '('
│ ├─> Ultimo byte deve essere CR
│ └─> Verifica CRC
└─> RETURN true se OK, false se errore
```
#### Flusso di Esecuzione: AutoDiscoverBufferSizes()
```
START AutoDiscoverBufferSizes()
├─> Stampa intestazione "AUTO-DISCOVERY MODE"
├─> Test QMOD (5-100 bytes)
│ ├─> query_auto("QMOD", 100)
│ │ ├─> Invia comando
│ │ ├─> Leggi byte fino a CR
│ │ └─> return numero_bytes
│ └─> Stampa "✓ QMOD buffer size: X"
├─> Test QPIGS (5-200 bytes)
│ ├─> query_auto("QPIGS", 200)
│ └─> Stampa "✓ QPIGS buffer size: X"
├─> Test QPIRI (5-200 bytes)
│ ├─> query_auto("QPIRI", 200)
│ └─> Stampa "✓ QPIRI buffer size: X"
├─> Test QPIWS (5-100 bytes)
│ ├─> query_auto("QPIWS", 100)
│ └─> Stampa "✓ QPIWS buffer size: X"
└─> Output risultati (parsabile)
├─> DISCOVERY_QMOD=X
├─> DISCOVERY_QPIGS=X
├─> DISCOVERY_QPIRI=X
├─> DISCOVERY_QPIWS=X
└─> DISCOVERY_SUCCESS=true
```
### 1.4 Funzioni di Utilità
#### getSettingsFile()
```
Legge /etc/inverter/inverter.conf
├─> Parse linee formato: chiave=valore
├─> Ignora righe con # (commenti)
└─> Popola variabili globali:
├─> devicename
├─> runinterval
├─> amperage_factor, watt_factor
└─> qpiri, qpiws, qmod, qpigs
```
#### attemptAddSettingInt() / attemptAddSetting()
```
Parse stringhe in int/float
├─> stoi() per interi (qpiri, qpiws, qmod, qpigs)
└─> stof() per float (amperage_factor, watt_factor)
```
#### cal_crc_half()
```
Calcola CRC-16 custom per protocollo inverter
├─> Input: buffer, lunghezza
├─> Algoritmo polinomiale custom
└─> Return: uint16_t CRC
```
---
## Componente 2: inverter-mqtt (Bash Scripts)
### 2.1 entrypoint.sh - Orchestrator Principale
```
START Container
├─> Carica variabili d'ambiente
│ ├─> INVERTER_DEVICE (default: /dev/ttyUSB0)
│ ├─> FORCE_DISCOVERY (default: false)
│ └─> SKIP_DISCOVERY (default: false)
├─> DECISIONE: Eseguire auto-discovery?
│ │
│ ├─> IF FORCE_DISCOVERY=true
│ │ ├─> rm .discovery_done
│ │ └─> NEED_DISCOVERY=true
│ │
│ ├─> ELSE IF SKIP_DISCOVERY=true
│ │ ├─> Aggiorna solo device in config
│ │ └─> NEED_DISCOVERY=false
│ │
│ ├─> ELSE IF .discovery_done non esiste
│ │ └─> NEED_DISCOVERY=true
│ │
│ └─> ELSE
│ ├─> Leggi device salvato
│ ├─> IF device cambiato
│ │ └─> NEED_DISCOVERY=true
│ └─> ELSE
│ ├─> Carica parametri salvati
│ └─> NEED_DISCOVERY=false
├─> IF NEED_DISCOVERY
│ └─> run_discovery()
│ ├─> Esegue: inverter_poller -d -a
│ ├─> Parse output DISCOVERY_*
│ ├─> IF SUCCESS=true
│ │ ├─> update_config_with_discovery()
│ │ │ ├─> sed device, qmod, qpigs, qpiri, qpiws
│ │ │ └─> cp inverter.conf.backup
│ │ └─> Salva in .discovery_done
│ └─> ELSE
│ └─> Usa config di default
├─> Avvia servizi MQTT
│ │
│ ├─> BACKGROUND: watch -n 300 mqtt-init.sh
│ │ └─> Ogni 5 minuti: re-init sensori HA
│ │
│ ├─> BACKGROUND: mqtt-subscriber.sh
│ │ └─> Ascolta comandi da Home Assistant
│ │
│ └─> FOREGROUND: watch -n 30 mqtt-push.sh
│ └─> Ogni 30s: push dati MQTT
└─> END (rimane in loop con mqtt-push.sh)
```
### 2.2 mqtt-push.sh - Pubblicazione Dati
```
START mqtt-push.sh
├─> Carica configurazione MQTT
│ └─> cat mqtt.json | jq
│ ├─> MQTT_SERVER
│ ├─> MQTT_PORT
│ ├─> MQTT_TOPIC (base)
│ ├─> DEVICENAME
│ └─> Credenziali
├─> Esegui polling inverter
│ └─> inverter_poller -1 > output.json
├─> Parse JSON e pubblica ogni metrica
│ └─> FOR each campo in JSON
│ ├─> Estrai valore con jq
│ └─> mosquitto_pub
│ ├─> Topic: homeassistant/sensor/${DEVICENAME}_${metric}
│ ├─> Payload: valore
│ └─> Retain: true
├─> OPZIONALE: Push su InfluxDB
│ └─> IF influx.enabled=true
│ └─> curl POST a InfluxDB API
└─> END
```
### 2.3 mqtt-subscriber.sh - Ricezione Comandi
```
START mqtt-subscriber.sh (loop infinito)
├─> Subscribe a topic comandi
│ └─> mosquitto_sub -t homeassistant/sensor/${DEVICENAME}/command
└─> LOOP: Per ogni messaggio ricevuto
├─> Valida comando con regex
│ └─> Match contro lista comandi validi
│ ├─> POP0[0-2]
│ ├─> PCP0[0-3]
│ ├─> PBDV*, PBCV*, PBFT*, PCVV*
│ └─> PE*/PD* (enable/disable)
├─> IF comando valido
│ ├─> Esegui: inverter_poller -r COMANDO
│ └─> Log risultato
└─> ELSE
└─> Log: comando non valido
```
### 2.4 mqtt-init.sh - Auto-Discovery Home Assistant
```
START mqtt-init.sh
├─> Carica config MQTT
└─> FOR each sensor (mode, voltage, current, watt, etc)
├─> Costruisci JSON config
│ ├─> name: "Voltronic Battery Voltage"
│ ├─> state_topic: homeassistant/sensor/voltronic_Battery_voltage
│ ├─> unit_of_measurement: "V"
│ ├─> device_class: "voltage"
│ └─> unique_id, icon, ecc.
└─> Pubblica su config topic
└─> mosquitto_pub -t homeassistant/sensor/${DEVICENAME}_${sensor}/config
└─> Payload: JSON config
└─> Retain: true
└─> END (Home Assistant auto-scopre tutti i sensori)
```
---
## Mappa Concettuale del Sistema
```
┌─────────────────────────────────────────────────────────────────┐
│ LIVELLO FISICO │
│ ┌──────────────┐ │
│ │ Inverter │ ←──── RS232/USB (2400 baud, 8N1) │
│ │ Hardware │ │
│ └──────┬───────┘ │
└─────────┼─────────────────────────────────────────────────────┬─┘
│ │
┌─────────▼─────────────────────────────────────────────────────▼─┐
│ LIVELLO COMUNICAZIONE │
│ │
│ ┌────────────────────────────────────────────────────────┐ │
│ │ cInverter::query() / query_auto() │ │
│ │ • Costruzione comandi con CRC │ │
│ │ • Gestione protocollo RS232 │ │
│ │ • Parsing risposte │ │
│ │ • Validazione CRC │ │
│ └────────┬───────────────────────────────────────────────┘ │
└───────────┼──────────────────────────────────────────────────┬─┘
│ │
┌───────────▼──────────────────────────────────────────────────▼─┐
│ LIVELLO APPLICAZIONE │
│ │
│ ┌──────────────────┐ ┌─────────────────────┐ │
│ │ cInverter::poll │◄───────┤ Thread Polling │ │
│ │ (Thread) │ │ • QMOD │ │
│ │ │ │ • QPIGS │ │
│ │ Ciclo continuo │ │ • QPIRI │ │
│ │ lettura dati │ │ • QPIWS │ │
│ └────────┬─────────┘ └─────────────────────┘ │
│ │ │
│ │ Atomic flags │
│ │ (ups_qmod_changed, ups_qpigs_changed, ...) │
│ │ │
│ ┌────────▼─────────┐ │
│ │ main() loop │ │
│ │ • Attende flag │ │
│ │ • Parse dati │ │
│ │ • Output JSON │ │
│ └────────┬─────────┘ │
└───────────┼──────────────────────────────────────────────────┬─┘
│ │
│ JSON stdout │
│ │
┌───────────▼──────────────────────────────────────────────────▼─┐
│ LIVELLO INTEGRAZIONE │
│ │
│ ┌──────────────────┐ ┌──────────────────┐ ┌──────────────┐ │
│ │ mqtt-push.sh │ │mqtt-subscriber.sh│ │ mqtt-init.sh │ │
│ │ • Esegue poller │ │ • Riceve comandi │ │ • Auto- │ │
│ │ • Parse JSON │ │ • Valida │ │ discovery │ │
│ │ • Pubblica MQTT │ │ • Esegue │ │ • Config HA │ │
│ └────────┬─────────┘ └────────┬─────────┘ └──────┬───────┘ │
└───────────┼──────────────────────┼────────────────────┼───────┬─┘
│ │ │ │
│ MQTT Protocol │ │ │
│ │ │ │
┌───────────▼──────────────────────▼────────────────────▼───────▼─┐
│ LIVELLO PRESENTAZIONE │
│ │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ MQTT Broker │ │
│ │ Topics: │ │
│ │ • homeassistant/sensor/voltronic_Battery_voltage │ │
│ │ • homeassistant/sensor/voltronic_PV_in_watts │ │
│ │ • homeassistant/sensor/voltronic_Load_watt │ │
│ │ • ... │ │
│ │ • homeassistant/sensor/voltronic/command (subscribe) │ │
│ └─────────────────────────────┬─────────────────────────────┘ │
└────────────────────────────────┼───────────────────────────────┘
┌──────────▼──────────┐
│ Home Assistant │
│ • Sensori │
│ • Grafici │
│ • Automazioni │
│ • Comandi │
└─────────────────────┘
```
---
## Sincronizzazione Multi-Thread
### Schema di Comunicazione Thread
```
┌─────────────────────────────────────────────────────────────┐
│ THREAD PRINCIPALE │
│ main() │
│ │
│ while(true) { │
│ ┌────────────────────────────────────────────────┐ │
│ │ WAIT per flag atomici: │ │
│ │ ups_qmod_changed == true ◄────┐ │ │
│ │ ups_qpigs_changed == true ◄────┤ │ │
│ │ ups_qpiri_changed == true ◄────┤ │ │
│ │ ups_qpiws_changed == true ◄────┤ │ │
│ └────────────────────────────────────┼───────────┘ │
│ │ │
│ Quando TUTTI true: │ │
│ ├─> Reset flag a false │ │
│ ├─> GetQpigsStatus() ────────────────┼──────┐ │
│ ├─> GetQpiriStatus() ────────────────┼──┐ │ │
│ ├─> GetWarnings() ────────────────┼┐ │ │ │
│ ├─> Parse e calcolo ││ │ │ │
│ ├─> Output JSON ││ │ │ │
│ └─> IF runOnce: exit(0) ││ │ │ │
│ ││ │ │ │
│ sleep(1) ││ │ │ │
│ } ││ │ │ │
└──────────────────────────────────────────┼┼─┼───┼──────────┘
││ │ │
Mutex protected ────────┼┼─┼───┼──────────┐
││ │ │ │
┌──────────────────────────────────────────▼▼─▼───▼──────────▼─┐
│ THREAD POLL │
│ cInverter::poll() │
│ │
│ while(true) { │
│ IF !ups_qmod_changed { │
│ query("QMOD") ──> status1[512] │
│ ups_qmod_changed = true ─────────────────┐ │
│ } │ │
│ │ │
│ IF !ups_qpigs_changed { │ │
│ query("QPIGS") ─┬─> LOCK(mutex) │ │
│ └─> status1 = buf │ │
│ ups_qpigs_changed = true ────────────────┤ │
│ } │ │
│ │ │
│ IF !ups_qpiri_changed { │ │
│ query("QPIRI") ─┬─> LOCK(mutex) │ │
│ └─> status2 = buf │ │
│ ups_qpiri_changed = true ────────────────┤ │
│ } │ │
│ │ │
│ IF !ups_qpiws_changed { │ │
│ query("QPIWS") ─┬─> LOCK(mutex) │ │
│ └─> warnings = buf │ │
│ ups_qpiws_changed = true ────────────────┘ │
│ } │
│ │
│ IF runOnce && all_flags_true { │
│ return; // Termina thread │
│ } │
│ │
│ sleep(2) │
│ } │
└───────────────────────────────────────────────────────────────┘
```
### Protezione Dati Condivisi
```cpp
// Dati protetti da mutex
mutex m;
// Scrittura (thread poll)
m.lock();
strcpy(status1, buffer);
m.unlock();
// Lettura (thread main)
string *GetQpigsStatus() {
m.lock();
string *result = new string(status1);
m.unlock();
return result;
}
// Flag atomici (non necessitano mutex)
atomic_bool ups_qmod_changed; // Lettura/scrittura atomica garantita
```
---
## Gestione Errori e Retry
### Strategia di Resilienza
```
query() failure
├─> CRC error
│ ├─> Log errore
│ ├─> Return false
│ └─> Thread poll riprova al ciclo successivo (2s)
├─> Device non aperto
│ ├─> Tentativo apertura device
│ ├─> IF fallisce: sleep(1) e retry
│ └─> MAX 3 tentativi prima di abort
├─> Timeout lettura
│ ├─> read() con timeout implicito
│ ├─> Return false
│ └─> Retry al prossimo ciclo
└─> Formato risposta errato
├─> Log hex dump (se debug)
├─> Return false
└─> Retry al prossimo ciclo
```
### Auto-Recovery Container
```
entrypoint.sh
├─> IF discovery fallisce
│ ├─> Log errore
│ ├─> Usa config di default
│ └─> Continua con servizi MQTT
└─> IF inverter_poller crash
└─> watch riavvia automaticamente ogni 30s
```
---
## Ottimizzazioni Prestazioni
### Frequency di Polling
```
Configurabile via run_interval:
├─> 120 = ogni 30 secondi (default)
├─> 60 = ogni minuto
└─> 30 = ogni 2 minuti
Thread poll interno:
├─> Query sequenziali (non parallele)
├─> Sleep 2s tra cicli
└─> Immediate exit se runOnce mode
```
### Buffer Management
```
Buffer sizes ottimizzati per ogni comando:
├─> QMOD: 5 bytes (fisso)
├─> QPIGS: 110 bytes (varia per modello)
├─> QPIRI: 103 bytes (varia per modello)
└─> QPIWS: 40 bytes (varia per modello)
Auto-discovery determina sizes esatti:
└─> Evita letture incomplete o overhead
```
### Caching MQTT
```
entrypoint.sh:
├─> .discovery_done persiste parametri
├─> Evita re-discovery ad ogni restart
└─> Re-discovery solo se:
├─> FORCE_DISCOVERY=true
├─> Device cambiato
└─> File cache non esiste
```
---
## Debugging e Logging
### Livelli di Debug
```
inverter_poller -d:
├─> Abilita lprintf() output
├─> Stampa parametri configurazione
├─> Hex dump buffer seriali
├─> Log apertura/chiusura device
└─> Timestamps su ogni operazione
entrypoint.sh:
├─> Echo ogni step esecuzione
├─> Simboli visual: ✓ ✗ ⚠
└─> Log risultati discovery
mqtt-push.sh:
└─> Silenzioso (output su /dev/null)
```
### File di Log
```
/var/log/inverter.log:
└─> lprintf() scrive qui (se debugFlag=true)
Container logs:
└─> docker logs voltronic-mqtt
├─> Output entrypoint.sh
├─> Errori servizi MQTT
└─> Messaggi discovery
```
---
## Variabili d'Ambiente Docker
```
INVERTER_DEVICE:
├─> Default: /dev/ttyUSB0
├─> Usato da: entrypoint.sh
└─> Scritto in: /etc/inverter/inverter.conf
FORCE_DISCOVERY:
├─> Default: false
├─> Se true: rm .discovery_done e riesegui
└─> Usato da: entrypoint.sh
SKIP_DISCOVERY:
├─> Default: false
├─> Se true: usa solo inverter.conf
└─> Usato da: entrypoint.sh
```
---
## Sequence Diagram: Primo Avvio Container
```
Container Start
├─> entrypoint.sh
│ │
│ ├─> Check .discovery_done: NOT FOUND
│ │
│ ├─> run_discovery()
│ │ │
│ │ ├─> inverter_poller -d -a
│ │ │ │
│ │ │ ├─> cInverter::AutoDiscoverBufferSizes()
│ │ │ │ ├─> query_auto("QMOD")
│ │ │ │ │ └─> Serial: QMOD + CRC
│ │ │ │ │ Inverter ──> (L<CR>
│ │ │ │ │ └─> Return: 5
│ │ │ │ │
│ │ │ │ ├─> query_auto("QPIGS")
│ │ │ │ │ └─> Return: 110
│ │ │ │ │
│ │ │ │ ├─> query_auto("QPIRI")
│ │ │ │ │ └─> Return: 103
│ │ │ │ │
│ │ │ │ └─> query_auto("QPIWS")
│ │ │ │ └─> Return: 40
│ │ │ │
│ │ │ └─> Output:
│ │ │ DISCOVERY_QMOD=5
│ │ │ DISCOVERY_QPIGS=110
│ │ │ DISCOVERY_QPIRI=103
│ │ │ DISCOVERY_QPIWS=40
│ │ │ DISCOVERY_SUCCESS=true
│ │ │
│ │ ├─> Parse output (grep + cut)
│ │ │
│ │ ├─> update_config_with_discovery()
│ │ │ ├─> sed -i "s/^qmod=.*/qmod=5/"
│ │ │ ├─> sed -i "s/^qpigs=.*/qpigs=110/"
│ │ │ ├─> sed -i "s/^qpiri=.*/qpiri=103/"
│ │ │ └─> sed -i "s/^qpiws=.*/qpiws=40/"
│ │ │
│ │ └─> echo "device=..." > .discovery_done
│ │
│ ├─> Start MQTT services
│ │ │
│ │ ├─> watch -n 300 mqtt-init.sh &
│ │ │ └─> Auto-discovery HA sensors
│ │ │
│ │ ├─> mqtt-subscriber.sh &
│ │ │ └─> mosquitto_sub -t .../command
│ │ │
│ │ └─> watch -n 30 mqtt-push.sh (foreground)
│ │ │
│ │ └─> LOOP ogni 30s:
│ │ ├─> inverter_poller -1
│ │ │ │
│ │ │ ├─> Thread poll()
│ │ │ ├─> Wait flags
│ │ │ └─> Output JSON
│ │ │
│ │ └─> mosquitto_pub (ogni metrica)
│ │
│ └─> Container running...
└─> Home Assistant riceve dati MQTT
```
---
## Summary: Punti Chiave dell'Architettura
### 1. Separazione Responsabilità
- **C++**: Comunicazione hardware, parsing protocollo, performance
- **Bash**: Orchestrazione, integrazione MQTT, configurazione
### 2. Thread Safety
- Atomic flags per sincronizzazione
- Mutex per protezione dati condivisi
- Pattern producer-consumer (poll → main)
### 3. Resilienza
- Auto-discovery automatica
- Retry automatico su errori
- Graceful degradation (fallback a config default)
- Container auto-restart
### 4. Configurabilità
- Buffer sizes auto-detected
- Device configurabile via ENV
- Fattori correzione calibrabili
- Intervallo polling personalizzabile
### 5. Estensibilità
- Facile aggiungere nuovi comandi inverter
- Template MQTT per nuovi sensori
- Supporto multi-inverter (container separati)
- Plugin InfluxDB opzionale
+367
View File
@@ -0,0 +1,367 @@
# Debug Configuration - inverter-cli
Questa directory contiene le configurazioni per il debug dell'applicazione `inverter-cli` in VS Code.
## Prerequisiti
### Software Richiesto
```bash
# Installa gli strumenti di build e debug
sudo apt-get update
sudo apt-get install -y build-essential cmake gdb
# Verifica installazione
gdb --version
cmake --version
g++ --version
```
### Estensioni VS Code Consigliate
- **C/C++** (ms-vscode.cpptools) - IntelliSense, debugging, browsing
- **CMake** (twxs.cmake) - Syntax highlighting per CMakeLists.txt
- **CMake Tools** (ms-vscode.cmake-tools) - Integrazione CMake avanzata
## Configurazioni di Debug Disponibili
### 1. Debug inverter_poller (Release Build)
**Nome:** `(gdb) Debug inverter_poller`
- Build in modalità Release con ottimizzazioni
- Esegue con flag `-d -1` (debug + run-once)
- Utile per debug rapido senza simboli completi
### 2. Debug inverter_poller - Run Once with Debug
**Nome:** `(gdb) Debug inverter_poller - Run Once with Debug`
- Build in modalità Debug con simboli completi
- Esegue con flag `-d -1`
- Include tutti i simboli di debug per analisi dettagliata
- **Consigliato per debug approfondito**
### 3. Debug inverter_poller - Loop Mode
**Nome:** `(gdb) Debug inverter_poller - Loop Mode`
- Build in modalità Debug
- Esegue in modalità loop continuo con debug `-d`
- Utile per debug di problemi intermittenti o di threading
### 4. Debug inverter_poller - Raw Command
**Nome:** `(gdb) Debug inverter_poller - Raw Command`
- Build in modalità Debug
- Esegue comando raw specifico: `-r QPIGS`
- Modifica l'argomento in launch.json per testare altri comandi
### 5. Attach to running inverter_poller
**Nome:** `(gdb) Attach to running inverter_poller`
- Attach a processo già in esecuzione
- Utile per debug di container o processi daemon
- Richiede permessi adeguati (potrebbe richiedere sudo)
## Tasks di Build
### Build Tasks
#### build-inverter-cli (Default)
```bash
Ctrl+Shift+B
```
Build in modalità Release con ottimizzazioni (-O2).
#### build-inverter-cli-debug
Build in modalità Debug con simboli completi (-O0 -g).
#### clean-inverter-cli
Pulisce tutti i file di build generati.
#### rebuild-inverter-cli
Pulisce e ricompila completamente il progetto.
### Run Tasks
#### run-inverter-cli-once
```bash
Tasks: Run Task → run-inverter-cli-once
```
Compila ed esegue il poller una volta con debug abilitato.
#### run-inverter-cli-loop
Compila ed esegue il poller in modalità loop continuo.
### Docker Tasks
#### docker-build
Build dell'immagine Docker locale per development.
#### docker-run
Avvia il container con docker-compose.
#### docker-logs
Mostra i log del container in tempo reale.
#### docker-stop
Ferma il container docker-compose.
## Workflow di Debug Tipici
### Debug Locale (senza device fisico)
Il programma proverà ad aprire il device seriale. Se non è disponibile, otterrai errori ma puoi comunque:
1. **Debug della logica di parsing:**
```bash
# Modifica temporaneamente main.cpp per usare dati mock
# Oppure esegui con un device virtuale
```
2. **Debug con socat (porta seriale virtuale):**
```bash
# Installa socat
sudo apt-get install socat
# Crea coppia di porte virtuali
socat -d -d pty,raw,echo=0 pty,raw,echo=0
# Output: PTY is /dev/pts/2 e /dev/pts/3
# Modifica config/inverter.conf
device=/dev/pts/2
# In un altro terminale, simula risposte inverter su /dev/pts/3
```
### Debug con Device Reale
1. **Identifica il device:**
```bash
ls -la /dev/ttyUSB* /dev/ttyS* /dev/hidraw*
dmesg | grep tty # Per vedere device USB
```
2. **Verifica permessi:**
```bash
sudo chmod 666 /dev/ttyUSB0 # O il tuo device
# OPPURE aggiungi utente al gruppo
sudo usermod -a -G dialout $USER
# Logout e login necessari
```
3. **Aggiorna configurazione:**
```bash
# Modifica config/inverter.conf
device=/dev/ttyUSB0
```
4. **Avvia debug:**
- Imposta breakpoint dove necessario
- Premi F5 o seleziona configurazione dal menu Debug
- Step through con F10 (step over), F11 (step into)
### Debug Problemi Comuni
#### CRC Errors
**Breakpoint:** `inverter.cpp` → funzione `CheckCRC()`
- Verifica calcolo CRC
- Controlla dati ricevuti in `buf[]`
#### Device Communication Issues
**Breakpoint:** `inverter.cpp` → funzione `query()`
- Verifica apertura device (errno)
- Controlla configurazione seriale (baud rate, etc.)
- Monitora `write()` e `read()` operations
#### Threading Issues
**Breakpoint:** `inverter.cpp` → `poll()` e `main.cpp` → main loop
- Verifica sincronizzazione mutex
- Controlla `atomic_bool` flags
- Watch variables: `ups_status_changed`, ecc.
#### JSON Parsing Issues
**Breakpoint:** `main.cpp` → dopo `sscanf()` calls
- Verifica parsing corretto delle risposte
- Controlla valori delle variabili dopo sscanf
- Debug calcoli (ampfactor, wattfactor)
## Debugging con Watchpoints
### Variabili Chiave da Monitorare
In VS Code Debug View → Watch, aggiungi:
```
voltage_grid
voltage_batt
pv_input_watts
mode
ups_qpigs_changed
device_status
```
### GDB Commands Utili
Nel Debug Console (Ctrl+Shift+Y):
```gdb
# Print strutture dati
-exec p voltage_grid
-exec p device_status
# Backtrace
-exec bt
# Info threads
-exec info threads
# Print tutti i local vars
-exec info locals
# Watch memory
-exec x/100c buf
```
## Configurazione IntelliSense
Il file `.vscode/c_cpp_properties.json` viene auto-generato. Se necessario, puoi personalizzarlo:
```json
{
"configurations": [
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"/usr/include"
],
"defines": [],
"compilerPath": "/usr/bin/g++",
"cStandard": "c11",
"cppStandard": "c++11",
"intelliSenseMode": "linux-gcc-arm"
}
],
"version": 4
}
```
## Debug Container Docker
### Attach a Container in Esecuzione
```bash
# Trova il processo nel container
docker exec -it voltronic-mqtt ps aux | grep inverter
# Installa gdbserver nel container (se necessario)
docker exec -it voltronic-mqtt apt-get install -y gdbserver
# Avvia gdbserver nel container
docker exec -it voltronic-mqtt gdbserver :2345 /opt/inverter-cli/bin/inverter_poller -d -1
# Nella configurazione launch.json, aggiungi:
{
"name": "(gdb) Remote Debug",
"type": "cppdbg",
"request": "launch",
"program": "${workspaceFolder}/sources/inverter-cli/bin/inverter_poller",
"miDebuggerServerAddress": "localhost:2345",
"miDebuggerPath": "/usr/bin/gdb",
"MIMode": "gdb"
}
```
### Debug Logs
```bash
# Tail logs in tempo reale
docker logs -f voltronic-mqtt
# Exec nel container per debug manuale
docker exec -it voltronic-mqtt bash
cd /opt/inverter-cli/bin
./inverter_poller -d -1
```
## Performance Profiling
### Con valgrind
```bash
# Installa valgrind
sudo apt-get install valgrind
# Memory leak detection
valgrind --leak-check=full --show-leak-kinds=all \
./sources/inverter-cli/bin/inverter_poller -1
# Profiling
valgrind --tool=callgrind ./sources/inverter-cli/bin/inverter_poller -1
```
### Con gprof
```bash
# Compila con profiling
cd sources/inverter-cli
cmake -DCMAKE_CXX_FLAGS="-pg" .
make
# Esegui
./bin/inverter_poller -1
# Analizza
gprof bin/inverter_poller gmon.out > analysis.txt
```
## Tips & Tricks
1. **Conditional Breakpoints:**
- Click destro su breakpoint → Edit Breakpoint
- Aggiungi condizione, es: `voltage_batt < 24.0`
2. **Logpoints:**
- Invece di breakpoint, logpoint stampa senza fermare
- Click destro → Add Logpoint
- Esempio: `Voltage: {voltage_grid}V`
3. **Debug con file di log:**
- Il programma scrive su `/tmp/inverter.log` (vedi LOG_FILE in tools.h)
- Usa `tail -f /tmp/inverter.log` in terminale separato
4. **Quick Debug:**
```bash
# Build e run rapido senza VS Code
cd sources/inverter-cli
cmake -DCMAKE_BUILD_TYPE=Debug . && make && gdb --args bin/inverter_poller -d -1
```
## Troubleshooting Debug Setup
### GDB non trova simboli
```bash
# Verifica che binary abbia simboli debug
file sources/inverter-cli/bin/inverter_poller
# Output dovrebbe contenere: "not stripped"
# Se stripped, rebuilda in debug mode
cd sources/inverter-cli && cmake -DCMAKE_BUILD_TYPE=Debug . && make
```
### Permission denied su /dev/ttyUSB0
```bash
sudo chmod 666 /dev/ttyUSB0
# O permanentemente:
sudo usermod -a -G dialout $USER
```
### VS Code non trova GDB
```bash
# Installa gdb
sudo apt-get install gdb
# Verifica path in launch.json
which gdb # Usa questo path in miDebuggerPath
```
## Risorse Aggiuntive
- [VS Code C++ Debugging](https://code.visualstudio.com/docs/cpp/cpp-debug)
- [GDB Documentation](https://sourceware.org/gdb/documentation/)
- [CMake Tutorial](https://cmake.org/cmake/help/latest/guide/tutorial/)
- [Protocol Manual](../../manual/) - Documentazione protocollo inverter
+374
View File
@@ -0,0 +1,374 @@
# 🎉 Auto-Discovery Implementation Complete!
## ✅ What's Been Added
### 1. Auto-Discovery Feature in C++ Binary
**File:** [sources/inverter-cli/inverter.cpp](sources/inverter-cli/inverter.cpp)
- New method `query_auto()` - Reads serial data until CR terminator, auto-detects buffer size
- New method `AutoDiscoverBufferSizes()` - Tests all 4 commands (QMOD, QPIGS, QPIRI, QPIWS)
- Machine-readable output format:
```
DISCOVERY_QMOD=5
DISCOVERY_QPIGS=110
DISCOVERY_QPIRI=103
DISCOVERY_QPIWS=40
DISCOVERY_SUCCESS=true
```
**CLI Flag:** `-a` or `--auto-discover`
```bash
./inverter_poller -a # Run auto-discovery
./inverter_poller -d -a # Run with debug output
```
### 2. Smart Container Entrypoint
**File:** [sources/inverter-mqtt/entrypoint.sh](sources/inverter-mqtt/entrypoint.sh)
**Features:**
- ✅ Automatic buffer size detection at first startup
- ✅ Persistent cache in `/etc/inverter/.discovery_done`
- ✅ Re-runs discovery when device changes
- ✅ Environment variable configuration
- ✅ Force/Skip discovery options
- ✅ Graceful fallback on failure
- ✅ Detailed logging with icons (✓, ✗, ⚠, )
**Workflow:**
```
Container Start
Check FORCE_DISCOVERY=true?
Yes → Run Discovery
No ↓
Check SKIP_DISCOVERY=true?
Yes → Use inverter.conf
No ↓
Check .discovery_done exists?
No → Run Discovery
Yes ↓
Check device changed?
Yes → Run Discovery
No → Use cached results
Start MQTT Services
```
### 3. Docker Compose Configuration
**File:** [docker-compose.yml](docker-compose.yml)
**Added Environment Variables:**
```yaml
environment:
- INVERTER_DEVICE=/dev/ttyUSB1 # Your serial device
- FORCE_DISCOVERY=false # Re-run every time
- SKIP_DISCOVERY=false # Never run discovery
```
### 4. Comprehensive Documentation
**Files Created:**
- **[AUTO_DISCOVERY.md](AUTO_DISCOVERY.md)** - Complete user guide
- How auto-discovery works
- Environment variable reference
- Usage scenarios (5 examples)
- Troubleshooting guide
- Migration instructions
- Multi-inverter setup examples
- FAQ section
- **[test-autodiscovery.sh](test-autodiscovery.sh)** - Local test script
- Tests auto-discovery without Docker
- Validates discovered values
- Tests data reading with new parameters
- Creates temporary test environment
### 5. Updated README
**File:** [README.md](README.md)
Added section:
- 🆕 Auto-Discovery Feature (v2.0+)
- Link to detailed documentation
- Environment variable examples
---
## 🚀 How to Use
### Quick Start (Default Setup)
1. **Edit docker-compose.yml** - Set your device:
```yaml
environment:
- INVERTER_DEVICE=/dev/ttyUSB1
```
2. **Start container:**
```bash
docker-compose up -d
```
3. **Watch logs:**
```bash
docker logs -f voltronic-mqtt
```
**Expected Output:**
```
=== Voltronic MQTT Bridge Starting ===
Version: 2.0 with Auto-Discovery
Configuration:
Device: /dev/ttyUSB1
Force Discovery: false
Skip Discovery: false
No previous discovery found, will run auto-discovery
=== Running Auto-Discovery ===
This will take about 10-15 seconds...
✓ QMOD buffer size: 5
✓ QPIGS buffer size: 110
✓ QPIRI buffer size: 103
✓ QPIWS buffer size: 40
✓ Auto-discovery completed successfully!
device=/dev/ttyUSB1
qmod=5
qpigs=110
qpiri=103
qpiws=40
=== Starting MQTT Bridge Services ===
✓ All services started successfully!
```
### Test Before Docker (Optional)
```bash
# Build the binary
cd sources/inverter-cli
make
# Run local test
cd ../..
bash test-autodiscovery.sh
```
---
## 📊 Test Results
**Hardware Tested:**
- Device: `/dev/ttyUSB1`
- Inverter: Voltronic/Axpert compatible
**Discovered Values:**
```
QMOD = 5 bytes ✓
QPIGS = 110 bytes ✓
QPIRI = 103 bytes ✓ (was 98, corrected)
QPIWS = 40 bytes ✓ (was 36, corrected)
```
**Success Rate:** 100% on tested hardware
---
## 🔧 Advanced Usage
### Scenario 1: Multiple Inverters
```yaml
services:
inverter-1:
image: bushrangers/ha-voltronic-mqtt
environment:
- INVERTER_DEVICE=/dev/ttyUSB0
volumes:
- ./config-inverter1/:/etc/inverter/
devices:
- /dev/ttyUSB0:/dev/ttyUSB0:rwm
inverter-2:
image: bushrangers/ha-voltronic-mqtt
environment:
- INVERTER_DEVICE=/dev/ttyUSB1
volumes:
- ./config-inverter2/:/etc/inverter/
devices:
- /dev/ttyUSB1:/dev/ttyUSB1:rwm
```
### Scenario 2: Force Re-Discovery
```bash
# Temporary (until restart)
docker exec voltronic-mqtt rm /etc/inverter/.discovery_done
docker restart voltronic-mqtt
# Permanent
docker-compose down
# Edit docker-compose.yml: FORCE_DISCOVERY=true
docker-compose up -d
```
### Scenario 3: Skip Discovery (Production)
```yaml
environment:
- INVERTER_DEVICE=/dev/ttyUSB1
- SKIP_DISCOVERY=true # Use values from inverter.conf
```
---
## 🐛 Troubleshooting
### Discovery Fails
**Symptoms:**
```
✗ Auto-discovery failed!
Falling back to default configuration...
```
**Solutions:**
1. Check inverter is powered on
2. Verify cable connection
3. Test device manually:
```bash
ls -la /dev/ttyUSB*
docker exec voltronic-mqtt /opt/inverter-cli/bin/inverter_poller -r QPIGS
```
### Wrong Device
**Symptoms:**
```
Unable to open device file
```
**Solution:**
```yaml
# Check available devices on host
ls -la /dev/tty*
# Update docker-compose.yml
environment:
- INVERTER_DEVICE=/dev/ttyUSB0 # Change to correct device
# Ensure device is mapped
devices:
- /dev/ttyUSB0:/dev/ttyUSB0:rwm
```
### Discovery Takes Too Long
**Normal:** ~10-15 seconds
**If > 30 seconds:** Check for interference, try different USB port
---
## 📝 Files Modified
| File | Status | Description |
|------|--------|-------------|
| `sources/inverter-cli/inverter.h` | ✅ Modified | Added AutoDiscoverBufferSizes() |
| `sources/inverter-cli/inverter.cpp` | ✅ Modified | Implemented query_auto() and discovery |
| `sources/inverter-cli/main.cpp` | ✅ Modified | Added `-a` flag |
| `sources/inverter-cli/tools.cpp` | ✅ Modified | Updated help text |
| `sources/inverter-mqtt/entrypoint.sh` | ✅ Rewritten | Smart discovery logic |
| `docker-compose.yml` | ✅ Modified | Added ENV vars |
| `README.md` | ✅ Modified | Added auto-discovery section |
| `AUTO_DISCOVERY.md` | ✅ Created | Complete documentation |
| `test-autodiscovery.sh` | ✅ Created | Local test script |
| `IMPLEMENTATION.md` | ✅ Created | This file |
---
## 🎯 Next Steps
### For Development:
1. ✅ Compile: `cd sources/inverter-cli && make`
2. ✅ Test locally: `bash test-autodiscovery.sh`
3. ✅ Verify values: Check `/tmp/inverter-test-*/` output
### For Production:
1. **Build Docker image:**
```bash
docker build -f Dockerfile.multiarch -t voltronic-mqtt:latest .
```
2. **Update docker-compose.yml:**
```yaml
image: voltronic-mqtt:latest # Use local image
# OR
image: bushrangers/ha-voltronic-mqtt:latest # Use from hub
```
3. **Deploy:**
```bash
docker-compose down
docker-compose up -d
docker logs -f voltronic-mqtt
```
4. **Verify MQTT:**
```bash
mosquitto_sub -h <mqtt-server> -t "homeassistant/#" -v
```
### For Multi-Arch Build:
```bash
# Push to Gitea - triggers automatic multi-arch build
git add .
git commit -m "feat: Add auto-discovery feature v2.0"
git tag v2.0.0
git push origin main --tags
```
---
## 💡 Key Benefits
**Plug & Play** - No manual buffer size configuration
**Hardware Agnostic** - Works with different inverter models
**Persistent** - Discovery runs once, cached forever
**Flexible** - Force/skip options for all scenarios
**Multi-Inverter** - Each container discovers independently
**Robust** - Graceful fallback on failure
**Developer Friendly** - Detailed logs and test script
---
## 📚 Related Documentation
- [AUTO_DISCOVERY.md](AUTO_DISCOVERY.md) - Complete user guide
- [.vscode/DEBUG.md](.vscode/DEBUG.md) - Development debugging guide
- [.github/copilot-instructions.md](.github/copilot-instructions.md) - AI coding guidelines
- [README.md](README.md) - Main project documentation
---
## 🏆 Version History
**v2.0 (Current)**
- ✅ Auto-discovery feature
- ✅ Smart container entrypoint
- ✅ Environment variable configuration
- ✅ Persistent caching
- ✅ Comprehensive documentation
**v1.x**
- Basic Voltronic MQTT bridge
- Manual buffer size configuration
- Static inverter.conf
---
**Implementation Date:** January 25, 2026
**Author:** GitHub Copilot + User
**Status:** ✅ Complete & Tested
+363
View File
@@ -0,0 +1,363 @@
# Quick Start Guide - Development & Debug
Questa guida fornisce un rapido riferimento per iniziare a sviluppare e debuggare il progetto.
## Setup Iniziale
### 1. Requisiti Sistema
```bash
# Aggiorna sistema
sudo apt-get update
# Installa dipendenze build
sudo apt-get install -y build-essential cmake gdb git
# Installa dipendenze runtime
sudo apt-get install -y mosquitto-clients jq
# Aggiungi utente al gruppo per accesso seriale (opzionale)
sudo usermod -a -G dialout $USER
# Logout e login necessari per applicare
```
### 2. Setup VS Code
```bash
# Apri progetto
code /home/pi/Progetti
# Installa estensioni raccomandate quando richiesto
# Oppure manualmente: Ctrl+Shift+P → "Extensions: Show Recommended Extensions"
```
### 3. Prima Build
```bash
# Opzione A: Da VS Code
# Premi Ctrl+Shift+B → Seleziona "build-inverter-cli"
# Opzione B: Da terminale
cd /home/pi/Progetti/sources/inverter-cli
mkdir -p bin
cmake .
make
```
### 4. Verifica Build
```bash
# Test esecuzione (senza device fisico, darà errore ma verifica che compili)
./sources/inverter-cli/bin/inverter_poller --help
```
## Workflow di Sviluppo
### Scenario 1: Modificare e Testare Codice
```bash
1. Apri file da modificare (es. sources/inverter-cli/main.cpp)
2. Fai modifiche al codice
3. Build: Ctrl+Shift+B (oppure F5 per build+debug)
4. Test: Tasks → "run-inverter-cli-once"
5. Verifica output JSON
```
### Scenario 2: Debug di un Bug
```bash
1. Riproduci il bug manualmente
2. Identifica file sorgente coinvolto
3. Apri file e imposta breakpoint (F9)
4. Premi F5 → Seleziona "(gdb) Debug inverter_poller - Run Once with Debug"
5. Usa Debug toolbar:
- F10: Step Over (prossima riga)
- F11: Step Into (entra in funzione)
- Shift+F11: Step Out (esci da funzione)
6. Ispeziona variabili nel pannello Variables/Watch
7. Continua (F5) o Stop (Shift+F5)
```
### Scenario 3: Aggiungere Nuovo Comando Inverter
```bash
1. Apri sources/inverter-cli/main.cpp
2. Aggiungi parsing nella sezione sscanf
3. Aggiungi output nella sezione printf JSON
4. Build e test: Ctrl+Shift+B
5. Verifica JSON output
6. Aggiorna sources/inverter-mqtt/mqtt-push.sh per pushare nuovo valore
7. Aggiorna sources/inverter-mqtt/mqtt-init.sh per auto-discovery
```
### Scenario 4: Debug con Device Reale
```bash
1. Connetti inverter via USB/RS232
2. Identifica device:
ls -la /dev/ttyUSB* # o ttyS*, hidraw*
3. Configura device:
# Modifica config/inverter.conf
device=/dev/ttyUSB0
4. Verifica permessi:
sudo chmod 666 /dev/ttyUSB0
5. Debug normale:
F5 → Seleziona configurazione debug
6. Imposta breakpoint in inverter.cpp → query()
7. Osserva comunicazione seriale in tempo reale
```
### Scenario 5: Test Docker Locale
```bash
# Opzione A: Da VS Code Tasks
1. Tasks → "docker-build"
2. Tasks → "docker-run"
3. Tasks → "docker-logs" (monitora output)
4. Quando finito: Tasks → "docker-stop"
# Opzione B: Da terminale
cd /home/pi/Progetti
docker-compose up --build
# Test manuale nel container
docker exec -it voltronic-mqtt bash
/opt/inverter-cli/bin/inverter_poller -d -1
```
## Comandi Utili
### Build e Run
```bash
# Build Release
cd sources/inverter-cli && cmake . && make
# Build Debug (con simboli)
cd sources/inverter-cli && cmake -DCMAKE_BUILD_TYPE=Debug . && make
# Clean build
cd sources/inverter-cli && rm -rf bin CMakeFiles CMakeCache.txt cmake_install.cmake Makefile
# Run con debug flag
./sources/inverter-cli/bin/inverter_poller -d -1
# Run comando raw
./sources/inverter-cli/bin/inverter_poller -r QPIGS
# Run in loop
./sources/inverter-cli/bin/inverter_poller -d
```
### Test Device
```bash
# Verifica device disponibili
ls -la /dev/tty* /dev/hidraw*
# Test read da device (richiede screen o minicom)
sudo apt-get install screen
sudo screen /dev/ttyUSB0 2400
# Verifica permessi
sudo chmod 666 /dev/ttyUSB0
# O permanente:
sudo usermod -a -G dialout $USER && newgrp dialout
```
### Debug GDB Manuale
```bash
# Build con debug symbols
cd sources/inverter-cli
cmake -DCMAKE_BUILD_TYPE=Debug . && make
# Avvia in GDB
gdb --args bin/inverter_poller -d -1
# Comandi GDB utili:
(gdb) break main.cpp:150 # Breakpoint a linea
(gdb) break cInverter::query # Breakpoint a funzione
(gdb) run # Avvia
(gdb) next # Step over (n)
(gdb) step # Step into (s)
(gdb) continue # Continua (c)
(gdb) print voltage_grid # Stampa variabile (p)
(gdb) info locals # Mostra tutte variabili locali
(gdb) backtrace # Stack trace (bt)
(gdb) quit # Esci (q)
```
### Docker
```bash
# Build locale
docker build -f Dockerfile.dev -t voltronic-mqtt:dev .
# Run
docker-compose up -d
# Logs
docker logs -f voltronic-mqtt
# Exec nel container
docker exec -it voltronic-mqtt bash
# Debug nel container
docker exec -it voltronic-mqtt /opt/inverter-cli/bin/inverter_poller -d -1
# Stop
docker-compose down
```
### Git Workflow
```bash
# Prima di modifiche
git checkout -b feature/nuova-funzionalita
# Durante sviluppo
git add sources/inverter-cli/main.cpp
git commit -m "Add: nuova metrica XYZ"
# Push
git push origin feature/nuova-funzionalita
# Gitea Actions builderà automaticamente su push
```
## Configurazioni Debug VS Code
### Configurazioni Disponibili (F5)
| Nome | Uso | Quando Usare |
|------|-----|--------------|
| Debug inverter_poller | Build Release | Debug rapido, problemi performance |
| Run Once with Debug | Build completa | Debug approfondito, simboli completi |
| Loop Mode | Loop continuo | Debug threading, problemi intermittenti |
| Raw Command | Comando specifico | Test singolo comando inverter |
| Attach to running | Attach esterno | Debug container o daemon |
### Tasks Disponibili (Ctrl+Shift+P → Tasks: Run Task)
| Task | Descrizione |
|------|-------------|
| build-inverter-cli | Build Release (default: Ctrl+Shift+B) |
| build-inverter-cli-debug | Build con simboli debug |
| clean-inverter-cli | Pulizia file build |
| rebuild-inverter-cli | Clean + Build |
| run-inverter-cli-once | Build e esegui una volta |
| run-inverter-cli-loop | Build e esegui in loop |
| docker-build | Build immagine Docker |
| docker-run | Avvia container |
| docker-logs | Visualizza log |
| docker-stop | Ferma container |
## Shortcuts VS Code
| Shortcut | Azione |
|----------|--------|
| `Ctrl+Shift+B` | Build (default task) |
| `F5` | Start Debugging |
| `Ctrl+F5` | Run Without Debugging |
| `F9` | Toggle Breakpoint |
| `F10` | Step Over |
| `F11` | Step Into |
| `Shift+F11` | Step Out |
| `Shift+F5` | Stop Debugging |
| `Ctrl+Shift+F5` | Restart Debugging |
| `Ctrl+` ` | Toggle Terminal |
| `Ctrl+Shift+P` | Command Palette |
| `Ctrl+P` | Quick Open File |
## Testing
### Unit Test Locale
```bash
# Test parsing dati
./sources/inverter-cli/bin/inverter_poller -d -1 | jq .
# Test comando specifico
./sources/inverter-cli/bin/inverter_poller -r QPIGS
# Test con output su file
./sources/inverter-cli/bin/inverter_poller -d -1 > /tmp/test_output.json
cat /tmp/test_output.json | jq .
```
### Integration Test MQTT
```bash
# Terminal 1: Subscribe a topic
mosquitto_sub -h localhost -t "homeassistant/#" -v
# Terminal 2: Esegui poller e push
cd sources/inverter-mqtt
./mqtt-push.sh
# Verifica messaggi ricevuti in Terminal 1
```
### Test Docker End-to-End
```bash
# 1. Build
docker-compose build
# 2. Run
docker-compose up -d
# 3. Verifica logs
docker logs -f voltronic-mqtt
# 4. Test MQTT output
mosquitto_sub -h [MQTT_SERVER] -t "homeassistant/sensor/voltronic/#" -v
# 5. Test comando
mosquitto_pub -h [MQTT_SERVER] \
-t "homeassistant/sensor/voltronic/command" \
-m "QPIGS"
```
## Troubleshooting Rapido
| Problema | Soluzione |
|----------|-----------|
| "Unable to open device" | Verifica device in config/inverter.conf e permessi |
| "CRC error" | Controlla cablaggio RS232 e buffer size in config |
| GDB non trova simboli | Build con: `cmake -DCMAKE_BUILD_TYPE=Debug .` |
| IntelliSense non funziona | Reload Window (Ctrl+Shift+P → "Reload Window") |
| Build fallisce | Clean: `rm -rf CMakeFiles CMakeCache.txt` poi rebuild |
| Permission denied device | `sudo chmod 666 /dev/ttyUSB0` o aggiungi a gruppo dialout |
## Risorse
- **[.vscode/DEBUG.md]** - Guida debug completa
- **[.vscode/README.md]** - Documentazione configurazioni VS Code
- **[.github/copilot-instructions.md]** - Documentazione completa progetto
- **[README.md]** - Documentazione principale
- **[manual/]** - Manuali protocollo inverter
## Prossimi Passi
1. ✅ Setup ambiente completato
2. 📖 Leggi documentazione protocollo in `/manual/`
3. 🔧 Prova modifiche semplici (es. aggiungi log)
4. 🐛 Usa debug per capire flusso programma
5. 🚀 Contribuisci: aggiungi nuove metriche o comandi
6. 🐳 Testa in Docker prima di production
## Support
- Issues: [GitHub/Gitea Issues]
- Docs: File README.md e .vscode/DEBUG.md
- Forum: AEVA Forum (link in README.md principale)
---
**Happy Coding! 🚀**
+164
View File
@@ -0,0 +1,164 @@
# VS Code Configuration
Questa directory contiene le configurazioni per sviluppo e debug del progetto in VS Code.
## File di Configurazione
### launch.json
Configurazioni di debug per inverter-cli con GDB:
- Debug con build Release
- Debug con build completa (simboli debug)
- Debug in modalità loop
- Debug comandi raw
- Attach a processo esistente
### tasks.json
Task automatizzati per:
- Build (Release/Debug)
- Clean e Rebuild
- Esecuzione diretta
- Gestione container Docker
### c_cpp_properties.json
Configurazione IntelliSense per C/C++:
- Include paths
- Standard C++11
- Compiler settings
### settings.json
Impostazioni workspace:
- Configurazione CMake
- File associations
- Esclusioni ricerca e explorer
### extensions.json
Estensioni raccomandate per il progetto:
- C/C++ tools
- CMake tools
- Docker
- ShellCheck
- YAML support
## Quick Start
### Prima Build
1. Apri il progetto in VS Code:
```bash
code /home/pi/Progetti
```
2. Installa estensioni raccomandate (popup VS Code)
3. Build del progetto:
- Premi `Ctrl+Shift+B` per build default
- Oppure `Tasks: Run Task` → `build-inverter-cli-debug`
### Debug Rapido
1. Apri `sources/inverter-cli/main.cpp`
2. Imposta breakpoint (F9 su riga)
3. Premi `F5` e seleziona configurazione debug
4. Usa `F10` (step over) e `F11` (step into)
### Testare Modifiche
1. Modifica codice in `sources/inverter-cli/`
2. Build: `Ctrl+Shift+B`
3. Run: Tasks → `run-inverter-cli-once`
4. Verifica output JSON
## Documentazione Dettagliata
Vedi [DEBUG.md](DEBUG.md) per guida completa al debug e troubleshooting.
## Configurazioni Disponibili
### Debug Configurations (F5)
- **(gdb) Debug inverter_poller** - Debug rapido con Release build
- **(gdb) Debug inverter_poller - Run Once with Debug** - Debug completo, esecuzione singola
- **(gdb) Debug inverter_poller - Loop Mode** - Debug in modalità continua
- **(gdb) Debug inverter_poller - Raw Command** - Debug comandi specifici
- **(gdb) Attach to running inverter_poller** - Attach a processo esistente
### Build Tasks (Ctrl+Shift+B)
- **build-inverter-cli** (default) - Build Release ottimizzato
- **build-inverter-cli-debug** - Build con simboli debug
- **clean-inverter-cli** - Pulizia file di build
- **rebuild-inverter-cli** - Clean + Build
### Run Tasks
- **run-inverter-cli-once** - Esegui una volta
- **run-inverter-cli-loop** - Esegui in loop
- **docker-build** - Build immagine Docker
- **docker-run** - Avvia container
- **docker-logs** - Visualizza log container
- **docker-stop** - Ferma container
## Shortcuts Utili
| Shortcut | Azione |
|----------|--------|
| `F5` | Start Debugging |
| `Ctrl+F5` | Run Without Debugging |
| `F9` | Toggle Breakpoint |
| `F10` | Step Over |
| `F11` | Step Into |
| `Shift+F11` | Step Out |
| `Ctrl+Shift+B` | Run Build Task |
| `Ctrl+Shift+P` | Command Palette |
| `Ctrl+` ` | Toggle Terminal |
## Estensioni Consigliate
### Essenziali
- **C/C++** - IntelliSense, debugging, browsing
- **CMake Tools** - Integrazione CMake
### Utili
- **Docker** - Gestione container
- **ShellCheck** - Linting script bash
- **YAML** - Syntax per configurazioni
### Opzionali
- **GitHub Copilot** - AI code assistant
- **GitLens** - Git supercharged
## Troubleshooting
### IntelliSense non funziona
1. Ricarica window: `Ctrl+Shift+P` → "Reload Window"
2. Verifica estensione C/C++ installata
3. Build il progetto almeno una volta
### GDB non trovato
```bash
sudo apt-get install gdb
```
### Permission denied su device
```bash
sudo usermod -a -G dialout $USER
# Logout e login necessari
```
### Task build fallisce
```bash
cd sources/inverter-cli
rm -rf CMakeFiles CMakeCache.txt
cmake . && make
```
## Tips
1. **Multiple Debug Windows**: Puoi avere più configurazioni debug attive contemporaneamente
2. **Watch Variables**: Usa il pannello Watch per monitorare variabili durante debug
3. **Debug Console**: Esegui comandi GDB direttamente nel Debug Console
4. **Logpoints**: Usa logpoints invece di printf per non modificare codice
## Risorse
- [VS Code C++ Docs](https://code.visualstudio.com/docs/cpp/cpp-debug)
- [CMake Tools Extension](https://github.com/microsoft/vscode-cmake-tools)
- [GDB Documentation](https://sourceware.org/gdb/documentation/)
- [DEBUG.md](DEBUG.md) - Guida debug completa del progetto