feat(v2.0): Auto-discovery, correzione bug critici, e documentazione completa
Build Docker Image for Raspberry Pi / build-and-push (push) Failing after 4m42s
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:
@@ -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.
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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! 🚀**
|
||||
@@ -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
|
||||
Reference in New Issue
Block a user