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) } }