- Modificato docker-build.yml per usare gitea.home-nas-ds.org invece di Docker Hub - Modificato docker-cleanup.yml per autenticazione con registry Gitea - Usato github.token automatico invece di secrets esterni - Aggiornata documentazione per riflettere i cambiamenti
15 KiB
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:
- Rileva automaticamente le dimensioni corrette dei buffer per QPIGS, QPIRI, QMOD, QPIWS
- Salva i valori in
/cache/inverter.conf.cache - 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()constoi()invece distof()che troncava valori - Thread sync: aggiunta
ups_qpiws_changedal loop principale e condizione exitpoll() - Config accuracy: corretti buffer sizes (qpiri=98→103, qpiws=36→40)
- Parsing interi: aggiunta
📖 Documentazione completa: 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'invertermain.cpp- Entry point, parsing argomenti, loop principale, 🆕 auto-discoveryinverter.cpp/h- Classe per gestione comunicazione seriale e pollingtools.cpp/h- Utilities per logginginputparser.cpp/h- Parser argomenti da riga di comandoCMakeLists.txt- Configurazione build CMake
-
sources/inverter-mqtt/- Script bash per integrazione MQTTentrypoint.sh- Entry point del container Dockermqtt-init.sh- Inizializzazione sensori in Home Assistantmqtt-push.sh- Invio dati MQTT e opzionalmente InfluxDBmqtt-subscriber.sh- Ascolto comandi da Home Assistant
-
config/- File di configurazioneinverter.conf- Configurazione device seriale, intervalli polling, fattori di correzionemqtt.json- Configurazione MQTT server, credenziali, topic, mapping InfluxDB
-
documentation/- Documentazione completa del progettoCODE_ARCHITECTURE.md- 🆕 Mappa logica funzioni/variabili, flusso esecuzione, mappe concettualiAUTO_DISCOVERY.md- Guida completa auto-discovery featureIMPLEMENTATION.md- Changelog implementazione v2.0QUICKSTART.md- Setup rapido e comandi essenzialiDEBUG.md- Guida completa debugging con GDBREADME.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 (usastoi()invece distof()) - 🆕 Correzione bug: aggiunto
ups_qpiws_changedal loop principale
- Legge configurazione da
-
inverter.cpp:
- Classe
cInverterper 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_changedalla condizione di exit del threadpoll() - 🆕 Supporto ENV variables per configurazione runtime
- Classe
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 priorityPBDV/PBCV/PBFT/PCVV- Battery voltage settingsPEx/PDx- Enable/Disable features (buzzer, bypass, power saving, etc.)
2. MQTT Integration (Bash)
mqtt-push.sh:
- Esegue
inverter_poller -1per 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-mqttcon 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)
- Classi:
-
Threading:
- Usare
std::mutexper proteggere dati condivisi - Pattern detached thread per polling:
thread t1(&cInverter::poll, this); t1.detach(); - Usare
atomic_boolper flag di stato
- Usare
-
Logging:
- Funzione
lprintf()per debug condizionale - Scrive su stdout e file di log
- Thread-safe con mutex
- Funzione
-
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" ]
- Variabili uppercase per config (es.
-
Pattern comuni:
VAR=`cat /etc/inverter/mqtt.json | jq '.key' -r` [ ! -z "$VAR" ] && pushMQTTData "metric" "$VAR"
Configurazione
inverter.conf
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
{
"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)
cd sources/inverter-cli
mkdir -p bin
cmake .
make
./bin/inverter_poller -h
Build Docker
# 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
# 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
- Verifica device disponibile:
ls -la /dev/tty* - Test read-only:
inverter_poller -d -1 - Test comando:
inverter_poller -r QPIGS
Test MQTT
# 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)
- Power_On
- Standby
- Line
- Battery
- Fault
- 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:
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
- docker-build.yml - Build e push multi-arch su Gitea Registry
- docker-test.yml - Test build su PR
- docker-cleanup.yml - Pulizia immagini vecchie (schedulato)
Autenticazione
Gitea Actions usa automaticamente ${{ github.token }} per autenticarsi al registry interno. Non sono necessari secrets esterni.
Registry
Le immagini Docker vengono pubblicate su: gitea.home-nas-ds.org/<username>/<repository>:tag
Troubleshooting
Problemi Comuni
"Unable to open device file":
- Verificare permessi device:
ls -la /dev/ttyUSB0 - Verificare mapping in docker-compose.yml
- Usare
privileged: truenel container
"CRC error":
- Controllare cablaggio RS232
- Verificare buffer size in inverter.conf
- Provare con debug:
-dflag
"MQTT not connecting":
- Verificare configurazione mqtt.json
- Testare con mosquitto_pub/sub manualmente
- Controllare firewall/rete
"Wrong values":
- Calibrare
amperage_factorewatt_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:
-
Modifiche C++:
- Sempre verificare thread-safety con mutex
- Testare con
-d -1dopo modifiche - Controllare CRC per nuovi comandi
- Mantenere compatibilità con buffer sizes configurabili
- 🆕 Usare
attemptAddSettingInt()per parsing interi,attemptAddSetting()per float
-
Modifiche Bash:
- Usare jq per parsing JSON
- Verificare valori non vuoti prima di push MQTT
- Mantenere pattern consistente con script esistenti
-
Nuove metriche:
- Aggiungere parsing in main.cpp
- Aggiungere push in mqtt-push.sh
- Aggiungere init in mqtt-init.sh
- Documentare in README.md
-
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
-
Docker:
- Testare su architettura ARM prima di push
- Verificare healthcheck funzionante
- Mantenere immagine leggera
- Documentare breaking changes
- 🆕 Verificare volume
/cache/per persistenza config
-
🆕 Bug Fixes & Best Practices:
- Integer parsing: Sempre usare
stoi()per interi, maistof()che tronca valori - Thread sync: Verificare che tutti i flag atomic siano inclusi nelle condizioni di exit
- Config values: Usare auto-discovery
-aper determinare buffer sizes corretti - Debug output: Usare
fprintf(stderr, ...)per output incondizionato,lprintf()per debug - Documentazione: Consultare CODE_ARCHITECTURE.md per comprendere il flusso completo
- Integer parsing: Sempre usare
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