Go client library for HomeWizard Energy devices using the WebSocket API v2.
- Real-time WebSocket communication with HomeWizard Energy devices
- Device discovery via mDNS/Zeroconf
- Three device types supported:
- P1 Meter (HWE-P1): Grid monitoring with battery control
- kWh Meter (HWE-KWH1/3): PV/consumption monitoring
- Battery (HWE-BAT): Battery monitoring (SoC, power, cycles)
- Automatic reconnection with configurable retry delay
- Thread-safe operations with proper synchronization
go get github.com/mluiten/evcc-homewizard-v2package main
import (
"context"
"fmt"
"time"
"github.com/mluiten/evcc-homewizard-v2/discovery"
)
func main() {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
err := discovery.DiscoverDevices(ctx, func(device discovery.DiscoveredDevice) {
fmt.Printf("Found: %s (%s) at %s:%d\n",
device.Instance, device.Type, device.Host, device.Port)
})
if err != nil {
panic(err)
}
}package main
import (
"fmt"
"time"
"github.com/mluiten/evcc-homewizard-v2/device"
)
func main() {
// Create P1 device
p1 := device.NewP1Device("192.168.1.10", "your-token-here", 30*time.Second)
defer p1.Stop()
// Start connection and wait (new helper method)
if err := p1.StartAndWait(5 * time.Second); err != nil {
panic(err)
}
// Get measurements
meas, err := p1.GetMeasurement()
if err != nil {
panic(err)
}
fmt.Printf("Grid Power: %.1f W\n", meas.PowerW)
// Get battery status
batteries, err := p1.GetBatteries()
if err != nil {
panic(err)
}
fmt.Printf("Battery Mode: %s\n", batteries.Mode)
fmt.Printf("Battery Power: %.1f W\n", batteries.PowerW)
// Set battery mode
if err := p1.SetBatteryMode("zero"); err != nil { // "zero", "to_full", or "standby"
panic(err)
}
}package main
import (
"fmt"
"time"
"github.com/mluiten/evcc-homewizard-v2/device"
)
func main() {
// Create kWh device
kwh := device.NewKWHDevice("192.168.1.11", "your-token-here", 30*time.Second)
defer kwh.Stop()
// Start connection and wait
if err := kwh.StartAndWait(5 * time.Second); err != nil {
panic(err)
}
// Get measurements
meas, err := kwh.GetMeasurement()
if err != nil {
panic(err)
}
fmt.Printf("Power: %.1f W\n", meas.PowerW)
fmt.Printf("Energy Imported: %.3f kWh\n", meas.EnergyImportkWh)
fmt.Printf("Energy Exported: %.3f kWh\n", meas.EnergyExportkWh)
}package main
import (
"fmt"
"time"
"github.com/mluiten/evcc-homewizard-v2/device"
)
func main() {
// Create battery device
bat := device.NewBatteryDevice("192.168.1.12", "your-token-here", 30*time.Second)
defer bat.Stop()
// Start connection and wait
if err := bat.StartAndWait(5 * time.Second); err != nil {
panic(err)
}
// Get measurements
meas, err := bat.GetMeasurement()
if err != nil {
panic(err)
}
fmt.Printf("State of Charge: %.1f%%\n", meas.StateOfChargePct)
fmt.Printf("Power: %.1f W\n", meas.PowerW)
fmt.Printf("Charge Cycles: %d\n", meas.Cycles)
}const (
DeviceTypeP1Meter DeviceType = "p1meter"
DeviceTypeKWHMeter DeviceType = "kwhmeter"
DeviceTypeBattery DeviceType = "battery"
)
const (
DefaultTimeout = 30 * time.Second
DefaultMaxCharge = 800.0 // W
DefaultMaxDischarge = 800.0 // W
DefaultBatteryCapacity = 2.47 // kWh
)func NewP1Device(host, token string, timeout time.Duration) *P1Device
func (d *P1Device) Start(errC chan error)
func (d *P1Device) StartAndWait(timeout time.Duration) error // Convenience method
func (d *P1Device) Stop()
func (d *P1Device) GetMeasurement() (P1Measurement, error)
func (d *P1Device) GetBatteries() (BatteriesData, error)
func (d *P1Device) SetBatteryMode(mode string) error // "zero", "to_full", "standby"func NewKWHDevice(host, token string, timeout time.Duration) *KWHDevice
func (d *KWHDevice) Start(errC chan error)
func (d *KWHDevice) StartAndWait(timeout time.Duration) error // Convenience method
func (d *KWHDevice) Stop()
func (d *KWHDevice) GetMeasurement() (KWHMeasurement, error)func NewBatteryDevice(host, token string, timeout time.Duration) *BatteryDevice
func (d *BatteryDevice) Start(errC chan error)
func (d *BatteryDevice) StartAndWait(timeout time.Duration) error // Convenience method
func (d *BatteryDevice) Stop()
func (d *BatteryDevice) GetMeasurement() (BatteryMeasurement, error)
func (d *BatteryDevice) DefaultCapacity() float64func DiscoverDevices(ctx context.Context, onDevice func(DiscoveredDevice)) error
type DiscoveredDevice struct {
Instance string // Device instance name
Host string // IP address or hostname
Port int // Port number (usually 443)
Type device.DeviceType // Device type
}// Interactive pairing tool - used by evcc token command
func Run(name string, timeout int) errorTo obtain device tokens, use the evcc token homewizard command from the evcc project, or follow these steps:
- Press the button on your HomeWizard device to enable pairing mode
- Send a POST request to
https://<device-ip>/api/userwith:with header:{ "name": "local/yourapp" }X-Api-Version: 2 - The device will respond with a token
- WebSocket Connection: Persistent WebSocket connection with automatic reconnection
- Authentication: OAuth 2.0-style token authentication via WebSocket
- Topic Subscription: Subscribe to "measurement" and "batteries" topics
- Thread-Safe: All operations are protected with proper synchronization
github.com/coder/websocket- WebSocket clientgithub.com/libp2p/zeroconf/v2- mDNS discoverygithub.com/evcc-io/evcc- Utilities (util.Logger, util.Monitor, request.Helper)
MIT License - see LICENSE file for details.
Contributions welcome! Please open an issue or submit a pull request.
# Build all packages
make build
# Run tests with coverage
make test
# Format code
make fmt
# Check formatting
make fmt-check
# Run all CI checks
make ciThis library requires Go 1.23+ (go.mod specifies 1.25 due to evcc dependencies, but works with 1.23).
GitHub Actions runs:
- Tests on Go 1.23 and stable
- Format checks with
gofmt - Linting with
golangci-lint
- evcc - EV Charge Controller (uses this library)
- HomeWizard Energy API Documentation
This library is maintained independently from evcc to reduce the maintenance burden on the evcc core team while providing full HomeWizard Energy device support.