Files
docker-voltronic-homeassistant/.github/copilot-instructions.md
T
Pi Developer 547537e761
Build Docker Image for Raspberry Pi / build-and-push (push) Failing after 1m15s
Implementazione supporto multi-inverter paralleli e fix comunicazione MQTT
- Aggiunto supporto lettura inverter paralleli tramite comandi QPGS0-QPGS9
- Implementato discovery automatico inverter con filtro duplicati e serial invalidi
- Risolti bug critici comunicazione seriale:
  * Fix buffer ExecuteCmd da 7 a 200 bytes
  * Supporto terminatori CR e LF
  * Modalità blocking con delay 500ms
  * Lettura byte-by-byte per terminatore affidabile
- Implementato script MQTT per pubblicazione dati multi-inverter:
  * mqtt-push-parallel.sh con topic separati per ogni inverter
  * Fix autenticazione MQTT con username/password
  * Aggiunto flag retain (-r) per persistenza dati
- Creato test-loop-parallel.sh per simulazione completa container
- Aggiornata documentazione con compatibilità MKS IV e guida test loop
- Aggiornati profili debug VS Code per bash e parallel discovery
- Configurazione MQTT completa con server reale (192.168.1.37:1883)

Sistema testato e funzionante con 2 inverter Voltronic Axpert MKS IV
2026-01-31 16:15:26 +01:00

474 lines
15 KiB
Markdown

# GitHub Copilot Instructions - Voltronic/Axpert MQTT Home Assistant Integration
## Panoramica del Progetto
Questo progetto è un'applicazione Docker che monitora inverter solari Voltronic, Axpert, MPPSolar PIP, Voltacon, Effekta e altri inverter OEM basati su protocollo RS232. L'applicazione raccoglie dati telemetrici dall'inverter e li invia a Home Assistant tramite MQTT, permettendo anche di inviare comandi per controllare l'inverter remotamente.
### 🆕 Version 2.0 - Auto-Discovery Feature
La versione 2.0 introduce l'**auto-discovery automatica** dei buffer sizes dell'inverter, eliminando la necessità di configurazione manuale. Al primo avvio, l'applicazione:
1. Rileva automaticamente le dimensioni corrette dei buffer per QPIGS, QPIRI, QMOD, QPIWS
2. Salva i valori in `/cache/inverter.conf.cache`
3. Nei successivi avvii, utilizza i valori cached per startup immediato
**Novità tecniche principali:**
- 🔍 **Auto-detection buffer sizes**: Metodo `AutoDiscoverBufferSizes()` con iterazione 80-120 bytes
- ⚙️ **Configurazione ENV**: Supporto variabili d'ambiente (`INVERTER_DEVICE`, `MQTT_SERVER`, etc.)
- 💾 **Caching persistente**: Volume Docker `/cache/` per persistenza tra restart
- 🐛 **Bug fixes critici**:
- Parsing interi: aggiunta `attemptAddSettingInt()` con `stoi()` invece di `stof()` che troncava valori
- Thread sync: aggiunta `ups_qpiws_changed` al loop principale e condizione exit `poll()`
- Config accuracy: corretti buffer sizes (qpiri=98→103, qpiws=36→40)
📖 **Documentazione completa:** [documentation/CODE_ARCHITECTURE.md](../documentation/CODE_ARCHITECTURE.md)
### Architettura
```
┌─────────────────┐
│ Inverter │ ← RS232/USB
│ (Hardware) │
└────────┬────────┘
┌────▼────────┐
│ inverter-cli│ (C++ - polling e parsing dati)
│ poller │ 🆕 + Auto-Discovery
└────┬────────┘
│ JSON output
┌────▼────────┐
│ mqtt-push.sh│ (bash - push su MQTT)
│ script │
└────┬────────┘
│ MQTT
┌────▼────────┐
│ Home │
│ Assistant │
└─────────────┘
```
## Struttura del Progetto
### Directory Principali
- **`sources/inverter-cli/`** - Applicazione C++ per la comunicazione con l'inverter
- `main.cpp` - Entry point, parsing argomenti, loop principale, 🆕 auto-discovery
- `inverter.cpp/h` - Classe per gestione comunicazione seriale e polling
- `tools.cpp/h` - Utilities per logging
- `inputparser.cpp/h` - Parser argomenti da riga di comando
- `CMakeLists.txt` - Configurazione build CMake
- **`sources/inverter-mqtt/`** - Script bash per integrazione MQTT
- `entrypoint.sh` - Entry point del container Docker
- `mqtt-init.sh` - Inizializzazione sensori in Home Assistant
- `mqtt-push.sh` - Invio dati MQTT e opzionalmente InfluxDB
- `mqtt-subscriber.sh` - Ascolto comandi da Home Assistant
- **`config/`** - File di configurazione
- `inverter.conf` - Configurazione device seriale, intervalli polling, fattori di correzione
- `mqtt.json` - Configurazione MQTT server, credenziali, topic, mapping InfluxDB
- **`documentation/`** - Documentazione completa del progetto
- `CODE_ARCHITECTURE.md` - 🆕 Mappa logica funzioni/variabili, flusso esecuzione, mappe concettuali
- `AUTO_DISCOVERY.md` - Guida completa auto-discovery feature
- `IMPLEMENTATION.md` - Changelog implementazione v2.0
- `QUICKSTART.md` - Setup rapido e comandi essenziali
- `DEBUG.md` - Guida completa debugging con GDB
- `README.md` - Setup ambiente sviluppo VS Code
- **`homeassistant/`** - Template Lovelace dashboard
- **`.gitea/workflows/`** - Gitea Actions per build automatica multi-arch
## Componenti Chiave
### 1. inverter-cli (C++)
**Linguaggio:** C++11
**Build system:** CMake
**Dependencies:** pthread
#### File principali:
- **main.cpp**:
- Legge configurazione da `/etc/inverter/inverter.conf`
- Supporta flag: `-d` (debug), `-1` (run-once), `-r <command>` (raw command), 🆕 `-a` (auto-discover)
- Output JSON su stdout
- Loop di polling con thread separati
- 🆕 Funzione `attemptAddSettingInt()` per parsing interi (usa `stoi()` invece di `stof()`)
- 🆕 Correzione bug: aggiunto `ups_qpiws_changed` al loop principale
- **inverter.cpp**:
- Classe `cInverter` per comunicazione seriale
- Configurazione porta seriale: 2400 baud, 8N1
- Supporta comandi: QPIGS, QPIRI, QMOD, QPIWS
- CRC checksum verification
- Thread-safe con mutex
- 🆕 Metodo `AutoDiscoverBufferSizes()` per rilevamento automatico
- 🆕 Correzione bug: aggiunto `ups_qpiws_changed` alla condizione di exit del thread `poll()`
- 🆕 Supporto ENV variables per configurazione runtime
#### Comandi supportati dall'inverter:
**Query (lettura dati):**
- `QPIGS` - General Status Parameters (voltaggio, corrente, potenza, batteria)
- `QPIRI` - Current Settings (rated voltages, currents, battery settings)
- `QMOD` - Mode inquiry (Power On, Standby, Line, Battery, Fault, Power Saving)
- `QPIWS` - Warning Status
**Controllo (scrittura):**
- `POP0x` - Set output source priority (Utility/Solar/SBU)
- `PCP0x` - Set charger priority
- `PBDV/PBCV/PBFT/PCVV` - Battery voltage settings
- `PEx/PDx` - Enable/Disable features (buzzer, bypass, power saving, etc.)
### 2. MQTT Integration (Bash)
**mqtt-push.sh**:
- Esegue `inverter_poller -1` per ottenere snapshot JSON
- Parsa JSON con `jq`
- Pubblica ogni metrica su topic separato
- Formato topic: `homeassistant/sensor/{devicename}_{metric}`
- Supporto opzionale InfluxDB
**mqtt-subscriber.sh**:
- Ascolta topic command: `homeassistant/sensor/{devicename}/command`
- Valida comandi con regex
- Esegue `inverter_poller -r <command>` per inviarli
**mqtt-init.sh**:
- Auto-discovery Home Assistant
- Crea configurazione sensori MQTT
- Definisce icone, unità di misura, device class
### 3. Docker Setup
**Dockerfile.multiarch**:
- Base: `debian:stretch`
- Architetture supportate: `linux/arm/v6`, `linux/arm/v7`, `linux/arm64`, `linux/amd64`, `linux/386`
- Build cmake dell'applicazione C++
- Healthcheck ogni 30s
**docker-compose.yml**:
- Servizio `voltronic-mqtt` con privilegi per accesso device
- Mapping device: `/dev/ttyUSB0`, `/dev/ttyS0`, `/dev/hidraw0`
- Volume config: `./config/:/etc/inverter/`
- Watchtower opzionale per auto-update
## Convenzioni di Codice
### C++ (inverter-cli)
- **Standard:** C++11 (`--std=c++0x`)
- **Stile nomi:**
- Classi: `cNomeClasse` (prefisso 'c')
- Metodi: `PascalCase` (es. `GetMode()`, `SetMode()`)
- Variabili locali: `snake_case` (es. `voltage_grid`, `batt_capacity`)
- Variabili globali: `camelCase` (es. `devicename`, `runinterval`)
- Costanti: `UPPER_CASE` (es. `LOG_FILE`)
- **Threading:**
- Usare `std::mutex` per proteggere dati condivisi
- Pattern detached thread per polling: `thread t1(&cInverter::poll, this); t1.detach();`
- Usare `atomic_bool` per flag di stato
- **Logging:**
- Funzione `lprintf()` per debug condizionale
- Scrive su stdout e file di log
- Thread-safe con mutex
- **Error handling:**
- Try-catch per parsing configurazione
- Controllo errno per operazioni file/seriale
- Sleep e retry su errori apertura device
### Bash Scripts
- **Stile:**
- Variabili uppercase per config (es. `MQTT_SERVER`)
- Backtick o `$()` per command substitution
- Controllo valori vuoti: `[ ! -z "$var" ]`
- **Pattern comuni:**
```bash
VAR=`cat /etc/inverter/mqtt.json | jq '.key' -r`
[ ! -z "$VAR" ] && pushMQTTData "metric" "$VAR"
```
## Configurazione
### inverter.conf
```properties
device=/dev/ttyUSB0 # Device seriale (/dev/ttyS0, /dev/hidraw0)
run_interval=120 # Polling frequency (120 = ogni 30s)
amperage_factor=1.0 # Fattore correzione amperaggio
watt_factor=1.01 # Fattore correzione wattaggio
qpiri=103 # 🆕 Buffer size comando QPIRI (corretto da 98)
qpiws=40 # 🆕 Buffer size comando QPIWS (corretto da 36)
qmod=5 # Buffer size comando QMOD
qpigs=110 # Buffer size comando QPIGS
```
### mqtt.json
```json
{
"server": "192.168.1.100",
"port": "1883",
"topic": "homeassistant",
"devicename": "voltronic",
"username": "",
"password": "",
"clientid": "voltronic_<random_hash>",
"influx": {
"enabled": "false",
"host": "http://influxdb:8086",
...
}
}
```
## Build e Deployment
### Build Locale (inverter-cli)
```bash
cd sources/inverter-cli
mkdir -p bin
cmake .
make
./bin/inverter_poller -h
```
### Build Docker
```bash
# Single platform
docker build -f Dockerfile.multiarch -t voltronic-mqtt .
# Multi-platform (richiede buildx)
docker buildx build \
--platform linux/arm/v6,linux/arm/v7,linux/arm64 \
-f Dockerfile.multiarch \
-t voltronic-mqtt:latest .
```
### Debug
```bash
# Test diretto con debug
docker exec -it voltronic-mqtt bash -c '/opt/inverter-cli/bin/inverter_poller -d -1'
# Test comando raw
docker exec -it voltronic-mqtt bash -c '/opt/inverter-cli/bin/inverter_poller -r QPIGS'
# Logs container
docker logs -f voltronic-mqtt
```
## Testing
### Test Comunicazione Inverter
1. Verifica device disponibile: `ls -la /dev/tty*`
2. Test read-only: `inverter_poller -d -1`
3. Test comando: `inverter_poller -r QPIGS`
### Test MQTT
```bash
# Subscribe a tutti i topic
mosquitto_sub -h localhost -t "homeassistant/#" -v
# Pubblica comando test
mosquitto_pub -h localhost \
-t "homeassistant/sensor/voltronic/command" \
-m "QPIGS"
```
## Metriche Principali
### Dati Real-time (QPIGS)
- **AC Grid:** Voltage, Frequency
- **AC Output:** Voltage, Frequency, Load (VA/Watt/%),
- **PV Input:** Voltage, Current, Watts, WattHour
- **Battery:** Voltage, Capacity %, Charge Current, Discharge Current
- **System:** Bus Voltage, Heatsink Temperature, Device Status
- **SCC:** Voltage (Solar Charge Controller)
### Configurazione Inverter (QPIRI)
- Rated values (grid, output, battery)
- Battery settings (recharge, under, bulk, float voltages)
- Max charge currents
- Priorities (output source, charger source)
### Status (QMOD)
1. Power_On
2. Standby
3. Line
4. Battery
5. Fault
6. Power_Saving
## Protocolli e Comunicazione
### RS232 Protocol
- **Baud Rate:** 2400
- **Data bits:** 8
- **Parity:** None
- **Stop bits:** 1
- **Flow control:** None
### Formato Messaggi
**Query:**
```
<command><CRC_HIGH><CRC_LOW><CR>
Esempio: QPIGS + CRC + \r
```
**Response:**
```
(<data> ... <data><CRC_HIGH><CRC_LOW><CR>
Esempio: (230.0 50.0 ... \r
```
### CRC Calculation
- CRC-16-CCITT modificato
- Polynomiale: custom implementation in `inverter.cpp`
- Verifica sia su TX che RX
## Home Assistant Integration
### Auto-Discovery
Il container pubblica automaticamente la configurazione dei sensori MQTT:
- Topic: `homeassistant/sensor/{devicename}_{metric}/config`
- Payload JSON con: name, state_topic, unit_of_measurement, device_class, icon
### Invio Comandi
Pubblica su topic: `homeassistant/sensor/{devicename}/command`
Esempio automation:
```yaml
automation:
- alias: "Switch to Solar Priority Morning"
trigger:
platform: time
at: "06:00:00"
action:
service: mqtt.publish
data:
topic: "homeassistant/sensor/voltronic/command"
payload: "POP01"
```
## Gitea Actions
### Workflows
1. **docker-build.yml** - Build e push multi-arch su tag/push
2. **docker-test.yml** - Test build su PR
3. **docker-cleanup.yml** - Pulizia immagini vecchie (schedulato)
### Secrets Richiesti
- `DOCKER_USERNAME`
- `DOCKER_PASSWORD`
## Troubleshooting
### Problemi Comuni
**"Unable to open device file":**
- Verificare permessi device: `ls -la /dev/ttyUSB0`
- Verificare mapping in docker-compose.yml
- Usare `privileged: true` nel container
**"CRC error":**
- Controllare cablaggio RS232
- Verificare buffer size in inverter.conf
- Provare con debug: `-d` flag
**"MQTT not connecting":**
- Verificare configurazione mqtt.json
- Testare con mosquitto_pub/sub manualmente
- Controllare firewall/rete
**"Wrong values":**
- Calibrare `amperage_factor` e `watt_factor`
- Confrontare con multimetro
- Verificare versione firmware inverter
## Note di Sicurezza
⚠️ **ATTENZIONE:**
- Non inviare comandi senza comprendere l'effetto
- Voltaggio batteria errato può danneggiare le batterie
- Testare in ambiente sicuro prima di produzione
- Backup configurazione inverter prima di modifiche
- Usare voltage/temperature sensors per automazioni critiche
## Risorse Utili
- **Protocol Manual:** `/manual/` directory
- **Forum AEVA:** http://forums.aeva.asn.au/viewtopic.php?t=4332
- **Skyboo Original:** https://skyboo.net/2017/03/monitoring-voltronic-power-axpert-mex-inverter-under-linux/
- **Docker Hub:** bushrangers/ha-voltronic-mqtt
- **Home Assistant MQTT:** https://www.home-assistant.io/integrations/mqtt/
## Suggerimenti per AI Coding
Quando lavori su questo progetto:
1. **Modifiche C++:**
- Sempre verificare thread-safety con mutex
- Testare con `-d -1` dopo modifiche
- Controllare CRC per nuovi comandi
- Mantenere compatibilità con buffer sizes configurabili
- 🆕 Usare `attemptAddSettingInt()` per parsing interi, `attemptAddSetting()` per float
2. **Modifiche Bash:**
- Usare jq per parsing JSON
- Verificare valori non vuoti prima di push MQTT
- Mantenere pattern consistente con script esistenti
3. **Nuove metriche:**
- Aggiungere parsing in main.cpp
- Aggiungere push in mqtt-push.sh
- Aggiungere init in mqtt-init.sh
- Documentare in README.md
4. **Testing:**
- Build prima di commit
- Test con inverter reale se possibile
- Verificare output JSON valido
- Test MQTT end-to-end
- 🆕 Testare sia con `-1` (run-once) che loop continuo
5. **Docker:**
- Testare su architettura ARM prima di push
- Verificare healthcheck funzionante
- Mantenere immagine leggera
- Documentare breaking changes
- 🆕 Verificare volume `/cache/` per persistenza config
6. **🆕 Bug Fixes & Best Practices:**
- **Integer parsing**: Sempre usare `stoi()` per interi, mai `stof()` che tronca valori
- **Thread sync**: Verificare che tutti i flag atomic siano inclusi nelle condizioni di exit
- **Config values**: Usare auto-discovery `-a` per determinare buffer sizes corretti
- **Debug output**: Usare `fprintf(stderr, ...)` per output incondizionato, `lprintf()` per debug
- **Documentazione**: Consultare [CODE_ARCHITECTURE.md](../documentation/CODE_ARCHITECTURE.md) per comprendere il flusso completo
## Version History
- **v1.x** - Supporto base Voltronic
- **v2.0** - 🆕 Multi-arch builds, Gitea Actions, Auto-discovery, Bug fixes critici
- **Future:** Extended inverter models, WebUI, Grafana integration