All checks were successful
CI / changes (push) Successful in 19s
CI / test (push) Successful in 24s
CI / build-ai-gateway (push) Successful in 1m6s
CI / build-ha-gateway (push) Successful in 1m3s
CI / build-discord-bot (push) Successful in 1m4s
CI / build-alexa-bridge (push) Successful in 1m15s
CI / build-tts-gateway (push) Successful in 1m5s
CI / build-tts-sidecar (push) Has been skipped
CI / build-tts-model (push) Has been skipped
- Implemented SetTemperature in ClimateService for setting an absolute target temperature. - Updated ClimateServiceClient and ClimateServiceServer interfaces to include SetTemperature. - Added corresponding handler and tests for SetTemperature in ClimateGRPC. - Modified ClimateApp to handle SetTemperature requests without clamping. - Updated climate.proto to define SetTemperatureRequest message. - Adjusted Dockerfiles to include alexa-bridge dependencies.
128 lines
4.1 KiB
Go
128 lines
4.1 KiB
Go
package haclient
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"strings"
|
|
|
|
hav1 "gitea.nik4nao.com/nik/home-services/gen/ha/v1"
|
|
)
|
|
|
|
// ExecuteAction implements driven.Controller. It dispatches by entity domain
|
|
// (the entity_id prefix up to the first '.') to the matching ha-gateway
|
|
// service, then by action within that domain. See alexa-bridge/plan.md's
|
|
// action table for the full (domain, action) -> RPC mapping.
|
|
func (c *Client) ExecuteAction(ctx context.Context, entityID, action string, params map[string]any) error {
|
|
domain, _, ok := strings.Cut(entityID, ".")
|
|
if !ok {
|
|
return fmt.Errorf("entity id %q has no domain prefix", entityID)
|
|
}
|
|
|
|
switch domain {
|
|
case "light":
|
|
return c.executeLightAction(ctx, entityID, action, params)
|
|
case "switch":
|
|
return c.executeSwitchAction(ctx, entityID, action, params)
|
|
case "climate":
|
|
return c.executeClimateAction(ctx, entityID, action, params)
|
|
default:
|
|
return fmt.Errorf("unsupported entity domain %q for entity %q", domain, entityID)
|
|
}
|
|
}
|
|
|
|
func (c *Client) executeLightAction(ctx context.Context, entityID, action string, params map[string]any) error {
|
|
switch action {
|
|
case "turn_on":
|
|
_, err := c.lightClient.TurnOn(ctx, &hav1.TurnOnRequest{
|
|
EntityId: entityID,
|
|
BrightnessPct: optUint32(params, "brightness_pct"),
|
|
ColorTempKelvin: optUint32(params, "color_temp_kelvin"),
|
|
RgbColor: optRGB(params, "rgb_color"),
|
|
Transition: optUint32(params, "transition"),
|
|
})
|
|
return err
|
|
case "turn_off":
|
|
_, err := c.lightClient.TurnOff(ctx, &hav1.TurnOffRequest{
|
|
EntityId: entityID,
|
|
Transition: optUint32(params, "transition"),
|
|
})
|
|
return err
|
|
case "toggle":
|
|
_, err := c.lightClient.Toggle(ctx, &hav1.ToggleRequest{EntityId: entityID})
|
|
return err
|
|
case "set_brightness":
|
|
brightness, err := reqUint32(params, "brightness_pct")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = c.lightClient.TurnOn(ctx, &hav1.TurnOnRequest{EntityId: entityID, BrightnessPct: &brightness})
|
|
return err
|
|
case "set_color_temp":
|
|
colorTemp, err := reqUint32(params, "color_temp_kelvin")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = c.lightClient.TurnOn(ctx, &hav1.TurnOnRequest{EntityId: entityID, ColorTempKelvin: &colorTemp})
|
|
return err
|
|
case "set_color":
|
|
rgb, err := reqRGB(params, "rgb_color")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = c.lightClient.TurnOn(ctx, &hav1.TurnOnRequest{EntityId: entityID, RgbColor: rgb})
|
|
return err
|
|
default:
|
|
return fmt.Errorf("unsupported light action %q", action)
|
|
}
|
|
}
|
|
|
|
func (c *Client) executeSwitchAction(ctx context.Context, entityID, action string, _ map[string]any) error {
|
|
req := &hav1.SwitchRequest{EntityId: entityID}
|
|
switch action {
|
|
case "turn_on":
|
|
_, err := c.switchClient.TurnOn(ctx, req)
|
|
return err
|
|
case "turn_off":
|
|
_, err := c.switchClient.TurnOff(ctx, req)
|
|
return err
|
|
case "toggle":
|
|
_, err := c.switchClient.Toggle(ctx, req)
|
|
return err
|
|
default:
|
|
return fmt.Errorf("unsupported switch action %q", action)
|
|
}
|
|
}
|
|
|
|
func (c *Client) executeClimateAction(ctx context.Context, entityID, action string, params map[string]any) error {
|
|
switch action {
|
|
case "turn_on":
|
|
_, err := c.climateClient.TurnOn(ctx, &hav1.ClimateRequest{EntityId: entityID})
|
|
return err
|
|
case "turn_off":
|
|
_, err := c.climateClient.TurnOff(ctx, &hav1.ClimateRequest{EntityId: entityID})
|
|
return err
|
|
case "set_hvac_mode":
|
|
mode, err := reqString(params, "hvac_mode")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = c.climateClient.SetHVACMode(ctx, &hav1.SetHVACModeRequest{EntityId: entityID, HvacMode: mode})
|
|
return err
|
|
case "increase_temperature":
|
|
_, err := c.climateClient.IncreaseTemperature(ctx, &hav1.ClimateRequest{EntityId: entityID})
|
|
return err
|
|
case "decrease_temperature":
|
|
_, err := c.climateClient.DecreaseTemperature(ctx, &hav1.ClimateRequest{EntityId: entityID})
|
|
return err
|
|
case "set_temperature":
|
|
target, err := reqFloat64(params, "target_temperature")
|
|
if err != nil {
|
|
return err
|
|
}
|
|
_, err = c.climateClient.SetTemperature(ctx, &hav1.SetTemperatureRequest{EntityId: entityID, TargetTemperature: target})
|
|
return err
|
|
default:
|
|
return fmt.Errorf("unsupported climate action %q", action)
|
|
}
|
|
}
|