Add --test-viessmann flag for end-to-end API validation
Adds GetDHWTemperature() to the Viessmann client (GET on the DHW feature endpoint) and a --test-viessmann CLI flag that runs three stages without starting the EMS control loop: Stage 1: read current DHW setpoint (confirms auth + endpoint path) Stage 2: write same value back, read-back to confirm round-trip Stage 3: write +1°C, read-back to confirm, restore original The +1°C delta is below the heat pump's 5°C hysteresis so the compressor will not fire, but the change is visible in the Viessmann app for visual confirmation before trusting the WW boost logic in production. Usage: ./ems --config /etc/ems/ems-config.yaml --test-viessmann Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -137,6 +137,52 @@ func (c *Client) featureURL(feature string) string {
|
||||
)
|
||||
}
|
||||
|
||||
// dhwFeatureResponse is the minimal structure returned by GET on the DHW temperature feature.
|
||||
type dhwFeatureResponse struct {
|
||||
Data struct {
|
||||
Properties struct {
|
||||
Value struct {
|
||||
Value float64 `json:"value"`
|
||||
} `json:"value"`
|
||||
} `json:"properties"`
|
||||
} `json:"data"`
|
||||
}
|
||||
|
||||
// GetDHWTemperature reads the current domestic hot water target temperature from the Viessmann API.
|
||||
func (c *Client) GetDHWTemperature(ctx context.Context) (float64, error) {
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
if err := c.ensureToken(ctx); err != nil {
|
||||
return 0, fmt.Errorf("ensuring token: %w", err)
|
||||
}
|
||||
|
||||
featureURL := c.featureURL("heating.dhw.temperature.main")
|
||||
|
||||
req, err := http.NewRequestWithContext(ctx, http.MethodGet, featureURL, nil)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("creating request: %w", err)
|
||||
}
|
||||
req.Header.Set("Authorization", "Bearer "+c.token.AccessToken)
|
||||
|
||||
resp, err := c.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return 0, fmt.Errorf("API call: %w", err)
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
if resp.StatusCode != http.StatusOK {
|
||||
return 0, fmt.Errorf("Viessmann API returned %d", resp.StatusCode)
|
||||
}
|
||||
|
||||
var result dhwFeatureResponse
|
||||
if err := json.NewDecoder(resp.Body).Decode(&result); err != nil {
|
||||
return 0, fmt.Errorf("decoding response: %w", err)
|
||||
}
|
||||
|
||||
return result.Data.Properties.Value.Value, nil
|
||||
}
|
||||
|
||||
// SetDHWTemperature sets the domestic hot water target temperature via the Viessmann API.
|
||||
func (c *Client) SetDHWTemperature(ctx context.Context, tempC float64) error {
|
||||
c.mu.Lock()
|
||||
|
||||
Reference in New Issue
Block a user