547537e761
Build Docker Image for Raspberry Pi / build-and-push (push) Failing after 1m15s
- 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
474 lines
15 KiB
Markdown
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
|