diff --git a/internal/services/alarm_control_panel.go b/internal/services/alarm_control_panel.go new file mode 100644 index 0000000..4dee6c6 --- /dev/null +++ b/internal/services/alarm_control_panel.go @@ -0,0 +1,115 @@ +package services + +import ( + "context" + + "github.com/gorilla/websocket" + ws "saml.dev/gome-assistant/internal/websocket" +) + +/* Structs */ + +type AlarmControlPanel struct { + conn *websocket.Conn + ctx context.Context +} + +/* Public API */ + +// Send the alarm the command for arm away. +// Takes an entityId and an optional +// map that is translated into service_data. +func (acp AlarmControlPanel) ArmAway(entityId string, serviceData ...map[string]any) { + req := NewBaseServiceRequest(entityId) + req.Domain = "alarm_control_panel" + req.Service = "alarm_arm_away" + if len(serviceData) != 0 { + req.ServiceData = serviceData[0] + } + + ws.WriteMessage(req, acp.conn, acp.ctx) +} + +// Send the alarm the command for arm away. +// Takes an entityId and an optional +// map that is translated into service_data. +func (acp AlarmControlPanel) ArmWithCustomBypass(entityId string, serviceData ...map[string]any) { + req := NewBaseServiceRequest(entityId) + req.Domain = "alarm_control_panel" + req.Service = "alarm_arm_custom_bypass" + if len(serviceData) != 0 { + req.ServiceData = serviceData[0] + } + + ws.WriteMessage(req, acp.conn, acp.ctx) +} + +// Send the alarm the command for arm home. +// Takes an entityId and an optional +// map that is translated into service_data. +func (acp AlarmControlPanel) ArmHome(entityId string, serviceData ...map[string]any) { + req := NewBaseServiceRequest(entityId) + req.Domain = "alarm_control_panel" + req.Service = "alarm_arm_home" + if len(serviceData) != 0 { + req.ServiceData = serviceData[0] + } + + ws.WriteMessage(req, acp.conn, acp.ctx) +} + +// Send the alarm the command for arm night. +// Takes an entityId and an optional +// map that is translated into service_data. +func (acp AlarmControlPanel) ArmNight(entityId string, serviceData ...map[string]any) { + req := NewBaseServiceRequest(entityId) + req.Domain = "alarm_control_panel" + req.Service = "alarm_arm_night" + if len(serviceData) != 0 { + req.ServiceData = serviceData[0] + } + + ws.WriteMessage(req, acp.conn, acp.ctx) +} + +// Send the alarm the command for arm vacation. +// Takes an entityId and an optional +// map that is translated into service_data. +func (acp AlarmControlPanel) ArmVacation(entityId string, serviceData ...map[string]any) { + req := NewBaseServiceRequest(entityId) + req.Domain = "alarm_control_panel" + req.Service = "alarm_arm_vacation" + if len(serviceData) != 0 { + req.ServiceData = serviceData[0] + } + + ws.WriteMessage(req, acp.conn, acp.ctx) +} + +// Send the alarm the command for disarm. +// Takes an entityId and an optional +// map that is translated into service_data. +func (acp AlarmControlPanel) Disarm(entityId string, serviceData ...map[string]any) { + req := NewBaseServiceRequest(entityId) + req.Domain = "alarm_control_panel" + req.Service = "alarm_disarm" + if len(serviceData) != 0 { + req.ServiceData = serviceData[0] + } + + ws.WriteMessage(req, acp.conn, acp.ctx) +} + +// Send the alarm the command for trigger. +// Takes an entityId and an optional +// map that is translated into service_data. +func (acp AlarmControlPanel) Trigger(entityId string, serviceData ...map[string]any) { + req := NewBaseServiceRequest(entityId) + req.Domain = "alarm_control_panel" + req.Service = "alarm_trigger" + if len(serviceData) != 0 { + req.ServiceData = serviceData[0] + } + + ws.WriteMessage(req, acp.conn, acp.ctx) +} diff --git a/internal/services/cover.go b/internal/services/cover.go new file mode 100644 index 0000000..c38d599 --- /dev/null +++ b/internal/services/cover.go @@ -0,0 +1,115 @@ +package services + +import ( + "context" + + "github.com/gorilla/websocket" + ws "saml.dev/gome-assistant/internal/websocket" +) + +/* Structs */ + +type Cover struct { + conn *websocket.Conn + ctx context.Context +} + +/* Public API */ + +// Close all or specified cover. Takes an entityId. +func (c Cover) Close(entityId string) { + req := NewBaseServiceRequest(entityId) + req.Domain = "cover" + req.Service = "close_cover" + + ws.WriteMessage(req, c.conn, c.ctx) +} + +// Close all or specified cover tilt. Takes an entityId. +func (c Cover) CloseTilt(entityId string) { + req := NewBaseServiceRequest(entityId) + req.Domain = "cover" + req.Service = "close_cover_tilt" + + ws.WriteMessage(req, c.conn, c.ctx) +} + +// Open all or specified cover. Takes an entityId. +func (c Cover) Open(entityId string) { + req := NewBaseServiceRequest(entityId) + req.Domain = "cover" + req.Service = "open_cover" + + ws.WriteMessage(req, c.conn, c.ctx) +} + +// Open all or specified cover tilt. Takes an entityId. +func (c Cover) OpenTilt(entityId string) { + req := NewBaseServiceRequest(entityId) + req.Domain = "cover" + req.Service = "open_cover_tilt" + + ws.WriteMessage(req, c.conn, c.ctx) +} + +// Move to specific position all or specified cover. Takes an entityId and an optional +// map that is translated into service_data. +func (c Cover) SetPosition(entityId string, serviceData ...map[string]any) { + req := NewBaseServiceRequest(entityId) + req.Domain = "cover" + req.Service = "set_cover_position" + if len(serviceData) != 0 { + req.ServiceData = serviceData[0] + } + + ws.WriteMessage(req, c.conn, c.ctx) +} + +// Move to specific position all or specified cover tilt. Takes an entityId and an optional +// map that is translated into service_data. +func (c Cover) SetTiltPosition(entityId string, serviceData ...map[string]any) { + req := NewBaseServiceRequest(entityId) + req.Domain = "cover" + req.Service = "set_cover_tilt_position" + if len(serviceData) != 0 { + req.ServiceData = serviceData[0] + } + + ws.WriteMessage(req, c.conn, c.ctx) +} + +// Stop a cover entity. Takes an entityId. +func (c Cover) Stop(entityId string) { + req := NewBaseServiceRequest(entityId) + req.Domain = "cover" + req.Service = "stop_cover" + + ws.WriteMessage(req, c.conn, c.ctx) +} + +// Stop a cover entity tilt. Takes an entityId. +func (c Cover) StopTilt(entityId string) { + req := NewBaseServiceRequest(entityId) + req.Domain = "cover" + req.Service = "stop_cover_tilt" + + ws.WriteMessage(req, c.conn, c.ctx) +} + +// Toggle a cover open/closed. Takes an entityId. +func (c Cover) Toggle(entityId string) { + req := NewBaseServiceRequest(entityId) + req.Domain = "cover" + req.Service = "toggle" + + ws.WriteMessage(req, c.conn, c.ctx) +} + +// Toggle a cover tilt open/closed. Takes an entityId. +func (c Cover) ToggleTilt(entityId string) { + req := NewBaseServiceRequest(entityId) + req.Domain = "cover" + req.Service = "toggle_cover_tilt" + + ws.WriteMessage(req, c.conn, c.ctx) +} diff --git a/internal/services/media_player.go b/internal/services/media_player.go new file mode 100644 index 0000000..07fb8d7 --- /dev/null +++ b/internal/services/media_player.go @@ -0,0 +1,273 @@ +package services + +import ( + "context" + + "github.com/gorilla/websocket" + ws "saml.dev/gome-assistant/internal/websocket" +) + +/* Structs */ + +type MediaPlayer struct { + conn *websocket.Conn + ctx context.Context +} + +/* Public API */ + +// Send the media player the command to clear players playlist. +// Takes an entityId. +func (mp MediaPlayer) ClearPlaylist(entityId string) { + req := NewBaseServiceRequest(entityId) + req.Domain = "media_player" + req.Service = "clear_playlist" + + ws.WriteMessage(req, mp.conn, mp.ctx) +} + +// Group players together. Only works on platforms with support for player groups. +// Takes an entityId and an optional +// map that is translated into service_data. +func (mp MediaPlayer) Join(entityId string, serviceData ...map[string]any) { + req := NewBaseServiceRequest(entityId) + req.Domain = "media_player" + req.Service = "join" + if len(serviceData) != 0 { + req.ServiceData = serviceData[0] + } + + ws.WriteMessage(req, mp.conn, mp.ctx) +} + +// Send the media player the command for next track. +// Takes an entityId. +func (mp MediaPlayer) Next(entityId string) { + req := NewBaseServiceRequest(entityId) + req.Domain = "media_player" + req.Service = "media_next_track" + + ws.WriteMessage(req, mp.conn, mp.ctx) +} + +// Send the media player the command for pause. +// Takes an entityId. +func (mp MediaPlayer) Pause(entityId string) { + req := NewBaseServiceRequest(entityId) + req.Domain = "media_player" + req.Service = "media_pause" + + ws.WriteMessage(req, mp.conn, mp.ctx) +} + +// Send the media player the command for play. +// Takes an entityId. +func (mp MediaPlayer) Play(entityId string) { + req := NewBaseServiceRequest(entityId) + req.Domain = "media_player" + req.Service = "media_play" + + ws.WriteMessage(req, mp.conn, mp.ctx) +} + +// Toggle media player play/pause state. +// Takes an entityId. +func (mp MediaPlayer) PlayPause(entityId string) { + req := NewBaseServiceRequest(entityId) + req.Domain = "media_player" + req.Service = "media_play_pause" + + ws.WriteMessage(req, mp.conn, mp.ctx) +} + +// Send the media player the command for previous track. +// Takes an entityId. +func (mp MediaPlayer) Previous(entityId string) { + req := NewBaseServiceRequest(entityId) + req.Domain = "media_player" + req.Service = "media_previous_track" + + ws.WriteMessage(req, mp.conn, mp.ctx) +} + +// Send the media player the command to seek in current playing media. +// Takes an entityId and an optional +// map that is translated into service_data. +func (mp MediaPlayer) Seek(entityId string, serviceData ...map[string]any) { + req := NewBaseServiceRequest(entityId) + req.Domain = "media_player" + req.Service = "media_seek" + if len(serviceData) != 0 { + req.ServiceData = serviceData[0] + } + + ws.WriteMessage(req, mp.conn, mp.ctx) +} + +// Send the media player the stop command. +// Takes an entityId. +func (mp MediaPlayer) Stop(entityId string) { + req := NewBaseServiceRequest(entityId) + req.Domain = "media_player" + req.Service = "media_stop" + + ws.WriteMessage(req, mp.conn, mp.ctx) +} + +// Send the media player the command for playing media. +// Takes an entityId and an optional +// map that is translated into service_data. +func (mp MediaPlayer) PlayMedia(entityId string, serviceData ...map[string]any) { + req := NewBaseServiceRequest(entityId) + req.Domain = "media_player" + req.Service = "play_media" + if len(serviceData) != 0 { + req.ServiceData = serviceData[0] + } + + ws.WriteMessage(req, mp.conn, mp.ctx) +} + +// Set repeat mode. Takes an entityId and an optional +// map that is translated into service_data. +func (mp MediaPlayer) RepeatSet(entityId string, serviceData ...map[string]any) { + req := NewBaseServiceRequest(entityId) + req.Domain = "media_player" + req.Service = "repeat_set" + if len(serviceData) != 0 { + req.ServiceData = serviceData[0] + } + + ws.WriteMessage(req, mp.conn, mp.ctx) +} + +// Send the media player the command to change sound mode. +// Takes an entityId and an optional +// map that is translated into service_data. +func (mp MediaPlayer) SelectSoundMode(entityId string, serviceData ...map[string]any) { + req := NewBaseServiceRequest(entityId) + req.Domain = "media_player" + req.Service = "select_sound_mode" + if len(serviceData) != 0 { + req.ServiceData = serviceData[0] + } + + ws.WriteMessage(req, mp.conn, mp.ctx) +} + +// Send the media player the command to change input source. +// Takes an entityId and an optional +// map that is translated into service_data. +func (mp MediaPlayer) SelectSource(entityId string, serviceData ...map[string]any) { + req := NewBaseServiceRequest(entityId) + req.Domain = "media_player" + req.Service = "select_source" + if len(serviceData) != 0 { + req.ServiceData = serviceData[0] + } + + ws.WriteMessage(req, mp.conn, mp.ctx) +} + +// Set shuffling state. +// Takes an entityId and an optional +// map that is translated into service_data. +func (mp MediaPlayer) Shuffle(entityId string, serviceData ...map[string]any) { + req := NewBaseServiceRequest(entityId) + req.Domain = "media_player" + req.Service = "shuffle_set" + if len(serviceData) != 0 { + req.ServiceData = serviceData[0] + } + + ws.WriteMessage(req, mp.conn, mp.ctx) +} + +// Toggles a media player power state. +// Takes an entityId. +func (mp MediaPlayer) Toggle(entityId string) { + req := NewBaseServiceRequest(entityId) + req.Domain = "media_player" + req.Service = "toggle" + + ws.WriteMessage(req, mp.conn, mp.ctx) +} + +// Turn a media player power off. +// Takes an entityId. +func (mp MediaPlayer) TurnOff(entityId string) { + req := NewBaseServiceRequest(entityId) + req.Domain = "media_player" + req.Service = "turn_off" + + ws.WriteMessage(req, mp.conn, mp.ctx) +} + +// Turn a media player power on. +// Takes an entityId. +func (mp MediaPlayer) TurnOn(entityId string) { + req := NewBaseServiceRequest(entityId) + req.Domain = "media_player" + req.Service = "turn_on" + + ws.WriteMessage(req, mp.conn, mp.ctx) +} + +// Unjoin the player from a group. Only works on +// platforms with support for player groups. +// Takes an entityId. +func (mp MediaPlayer) Unjoin(entityId string) { + req := NewBaseServiceRequest(entityId) + req.Domain = "media_player" + req.Service = "unjoin" + + ws.WriteMessage(req, mp.conn, mp.ctx) +} + +// Turn a media player volume down. +// Takes an entityId. +func (mp MediaPlayer) VolumeDown(entityId string) { + req := NewBaseServiceRequest(entityId) + req.Domain = "media_player" + req.Service = "volume_down" + + ws.WriteMessage(req, mp.conn, mp.ctx) +} + +// Mute a media player's volume. +// Takes an entityId and an optional +// map that is translated into service_data. +func (mp MediaPlayer) VolumeMute(entityId string, serviceData ...map[string]any) { + req := NewBaseServiceRequest(entityId) + req.Domain = "media_player" + req.Service = "volume_mute" + if len(serviceData) != 0 { + req.ServiceData = serviceData[0] + } + + ws.WriteMessage(req, mp.conn, mp.ctx) +} + +// Set a media player's volume level. +// Takes an entityId and an optional +// map that is translated into service_data. +func (mp MediaPlayer) VolumeSet(entityId string, serviceData ...map[string]any) { + req := NewBaseServiceRequest(entityId) + req.Domain = "media_player" + req.Service = "volume_set" + if len(serviceData) != 0 { + req.ServiceData = serviceData[0] + } + + ws.WriteMessage(req, mp.conn, mp.ctx) +} + +// Turn a media player volume up. +// Takes an entityId. +func (mp MediaPlayer) VolumeUp(entityId string) { + req := NewBaseServiceRequest(entityId) + req.Domain = "media_player" + req.Service = "volume_up" + + ws.WriteMessage(req, mp.conn, mp.ctx) +} diff --git a/internal/services/scene.go b/internal/services/scene.go new file mode 100644 index 0000000..4b5d9b9 --- /dev/null +++ b/internal/services/scene.go @@ -0,0 +1,64 @@ +package services + +import ( + "context" + + "github.com/gorilla/websocket" + ws "saml.dev/gome-assistant/internal/websocket" +) + +/* Structs */ + +type Scene struct { + conn *websocket.Conn + ctx context.Context +} + +/* Public API */ + +// Apply a scene. Takes map that is translated into service_data. +func (s Scene) Apply(serviceData ...map[string]any) { + req := NewBaseServiceRequest("") + req.Domain = "scene" + req.Service = "apply" + if len(serviceData) != 0 { + req.ServiceData = serviceData[0] + } + + ws.WriteMessage(req, s.conn, s.ctx) +} + +// Create a scene entity. Takes an entityId and an optional +// map that is translated into service_data. +func (s Scene) Create(entityId string, serviceData ...map[string]any) { + req := NewBaseServiceRequest(entityId) + req.Domain = "scene" + req.Service = "create" + if len(serviceData) != 0 { + req.ServiceData = serviceData[0] + } + + ws.WriteMessage(req, s.conn, s.ctx) +} + +// Reload the scenes. +func (s Scene) Reload() { + req := NewBaseServiceRequest("") + req.Domain = "scene" + req.Service = "reload" + + ws.WriteMessage(req, s.conn, s.ctx) +} + +// TurnOn a scene entity. Takes an entityId and an optional +// map that is translated into service_data. +func (s Scene) TurnOn(entityId string, serviceData ...map[string]any) { + req := NewBaseServiceRequest(entityId) + req.Domain = "scene" + req.Service = "turn_on" + if len(serviceData) != 0 { + req.ServiceData = serviceData[0] + } + + ws.WriteMessage(req, s.conn, s.ctx) +} diff --git a/internal/services/services.go b/internal/services/services.go index 4050d4d..6a2f082 100644 --- a/internal/services/services.go +++ b/internal/services/services.go @@ -9,9 +9,12 @@ import ( ) func BuildService[ - T Light | + T AlarmControlPanel | + Cover | + Light | HomeAssistant | Lock | + MediaPlayer | Switch | InputBoolean | InputButton | @@ -19,7 +22,10 @@ func BuildService[ InputText | InputNumber | Notify | - Number, + Number | + Scene | + TTS | + Vacuum, ](conn *websocket.Conn, ctx context.Context) *T { return &T{conn: conn, ctx: ctx} } diff --git a/internal/services/tts.go b/internal/services/tts.go new file mode 100644 index 0000000..712b802 --- /dev/null +++ b/internal/services/tts.go @@ -0,0 +1,54 @@ +package services + +import ( + "context" + + "github.com/gorilla/websocket" + ws "saml.dev/gome-assistant/internal/websocket" +) + +/* Structs */ + +type TTS struct { + conn *websocket.Conn + ctx context.Context +} + +/* Public API */ + +// Remove all text-to-speech cache files and RAM cache. +func (tts TTS) ClearCache() { + req := NewBaseServiceRequest("") + req.Domain = "tts" + req.Service = "clear_cache" + + ws.WriteMessage(req, tts.conn, tts.ctx) +} + +// Say something using text-to-speech on a media player with cloud. +// Takes an entityId and an optional +// map that is translated into service_data. +func (tts TTS) CloudSay(entityId string, serviceData ...map[string]any) { + req := NewBaseServiceRequest(entityId) + req.Domain = "tts" + req.Service = "cloud_say" + if len(serviceData) != 0 { + req.ServiceData = serviceData[0] + } + + ws.WriteMessage(req, tts.conn, tts.ctx) +} + +// Say something using text-to-speech on a media player with google_translate. +// Takes an entityId and an optional +// map that is translated into service_data. +func (tts TTS) GoogleTranslateSay(entityId string, serviceData ...map[string]any) { + req := NewBaseServiceRequest(entityId) + req.Domain = "tts" + req.Service = "google_translate_say" + if len(serviceData) != 0 { + req.ServiceData = serviceData[0] + } + + ws.WriteMessage(req, tts.conn, tts.ctx) +} diff --git a/internal/services/vacuum.go b/internal/services/vacuum.go new file mode 100644 index 0000000..1186410 --- /dev/null +++ b/internal/services/vacuum.go @@ -0,0 +1,134 @@ +package services + +import ( + "context" + + "github.com/gorilla/websocket" + ws "saml.dev/gome-assistant/internal/websocket" +) + +/* Structs */ + +type Vacuum struct { + conn *websocket.Conn + ctx context.Context +} + +/* Public API */ + +// Tell the vacuum cleaner to do a spot clean-up. +// Takes an entityId. +func (v Vacuum) CleanSpot(entityId string) { + req := NewBaseServiceRequest(entityId) + req.Domain = "vacuum" + req.Service = "clean_spot" + + ws.WriteMessage(req, v.conn, v.ctx) +} + +// Locate the vacuum cleaner robot. +// Takes an entityId. +func (v Vacuum) Locate(entityId string) { + req := NewBaseServiceRequest(entityId) + req.Domain = "vacuum" + req.Service = "locate" + + ws.WriteMessage(req, v.conn, v.ctx) +} + +// Pause the cleaning task. +// Takes an entityId. +func (v Vacuum) Pause(entityId string) { + req := NewBaseServiceRequest(entityId) + req.Domain = "vacuum" + req.Service = "pause" + + ws.WriteMessage(req, v.conn, v.ctx) +} + +// Tell the vacuum cleaner to return to its dock. +// Takes an entityId. +func (v Vacuum) ReturnToBase(entityId string) { + req := NewBaseServiceRequest(entityId) + req.Domain = "vacuum" + req.Service = "return_to_base" + + ws.WriteMessage(req, v.conn, v.ctx) +} + +// Send a raw command to the vacuum cleaner. Takes an entityId and an optional +// map that is translated into service_data. +func (v Vacuum) SendCommand(entityId string, serviceData ...map[string]any) { + req := NewBaseServiceRequest(entityId) + req.Domain = "vacuum" + req.Service = "send_command" + if len(serviceData) != 0 { + req.ServiceData = serviceData[0] + } + + ws.WriteMessage(req, v.conn, v.ctx) +} + +// Set the fan speed of the vacuum cleaner. Takes an entityId and an optional +// map that is translated into service_data. +func (v Vacuum) SetFanSpeed(entityId string, serviceData ...map[string]any) { + req := NewBaseServiceRequest(entityId) + req.Domain = "vacuum" + req.Service = "set_fan_speed" + + if len(serviceData) != 0 { + req.ServiceData = serviceData[0] + } + + ws.WriteMessage(req, v.conn, v.ctx) +} + +// Start or resume the cleaning task. +// Takes an entityId. +func (v Vacuum) Start(entityId string) { + req := NewBaseServiceRequest(entityId) + req.Domain = "vacuum" + req.Service = "start" + + ws.WriteMessage(req, v.conn, v.ctx) +} + +// Start, pause, or resume the cleaning task. +// Takes an entityId. +func (v Vacuum) StartPause(entityId string) { + req := NewBaseServiceRequest(entityId) + req.Domain = "vacuum" + req.Service = "start_pause" + + ws.WriteMessage(req, v.conn, v.ctx) +} + +// Stop the current cleaning task. +// Takes an entityId. +func (v Vacuum) Stop(entityId string) { + req := NewBaseServiceRequest(entityId) + req.Domain = "vacuum" + req.Service = "stop" + + ws.WriteMessage(req, v.conn, v.ctx) +} + +// Stop the current cleaning task and return to home. +// Takes an entityId. +func (v Vacuum) TurnOff(entityId string) { + req := NewBaseServiceRequest(entityId) + req.Domain = "vacuum" + req.Service = "turn_off" + + ws.WriteMessage(req, v.conn, v.ctx) +} + +// Start a new cleaning task. +// Takes an entityId. +func (v Vacuum) TurnOn(entityId string) { + req := NewBaseServiceRequest(entityId) + req.Domain = "vacuum" + req.Service = "turn_on" + + ws.WriteMessage(req, v.conn, v.ctx) +} diff --git a/service.go b/service.go index b299f22..9692d84 100644 --- a/service.go +++ b/service.go @@ -9,31 +9,43 @@ import ( ) type Service struct { - HomeAssistant *services.HomeAssistant - Light *services.Light - Lock *services.Lock - Switch *services.Switch - InputBoolean *services.InputBoolean - InputButton *services.InputButton - InputText *services.InputText - InputDatetime *services.InputDatetime - InputNumber *services.InputNumber - Notify *services.Notify - Number *services.Number + AlarmControlPanel *services.AlarmControlPanel + Cover *services.Cover + HomeAssistant *services.HomeAssistant + Light *services.Light + Lock *services.Lock + MediaPlayer *services.MediaPlayer + Switch *services.Switch + InputBoolean *services.InputBoolean + InputButton *services.InputButton + InputText *services.InputText + InputDatetime *services.InputDatetime + InputNumber *services.InputNumber + Notify *services.Notify + Number *services.Number + Scene *services.Scene + TTS *services.TTS + Vacuum *services.Vacuum } func newService(conn *websocket.Conn, ctx context.Context, httpClient *http.HttpClient) *Service { return &Service{ - Light: services.BuildService[services.Light](conn, ctx), - HomeAssistant: services.BuildService[services.HomeAssistant](conn, ctx), - Lock: services.BuildService[services.Lock](conn, ctx), - Switch: services.BuildService[services.Switch](conn, ctx), - InputBoolean: services.BuildService[services.InputBoolean](conn, ctx), - InputButton: services.BuildService[services.InputButton](conn, ctx), - InputText: services.BuildService[services.InputText](conn, ctx), - InputDatetime: services.BuildService[services.InputDatetime](conn, ctx), - InputNumber: services.BuildService[services.InputNumber](conn, ctx), - Notify: services.BuildService[services.Notify](conn, ctx), - Number: services.BuildService[services.Number](conn, ctx), + AlarmControlPanel: services.BuildService[services.AlarmControlPanel](conn, ctx), + Cover: services.BuildService[services.Cover](conn, ctx), + Light: services.BuildService[services.Light](conn, ctx), + HomeAssistant: services.BuildService[services.HomeAssistant](conn, ctx), + Lock: services.BuildService[services.Lock](conn, ctx), + MediaPlayer: services.BuildService[services.MediaPlayer](conn, ctx), + Switch: services.BuildService[services.Switch](conn, ctx), + InputBoolean: services.BuildService[services.InputBoolean](conn, ctx), + InputButton: services.BuildService[services.InputButton](conn, ctx), + InputText: services.BuildService[services.InputText](conn, ctx), + InputDatetime: services.BuildService[services.InputDatetime](conn, ctx), + InputNumber: services.BuildService[services.InputNumber](conn, ctx), + Notify: services.BuildService[services.Notify](conn, ctx), + Number: services.BuildService[services.Number](conn, ctx), + Scene: services.BuildService[services.Scene](conn, ctx), + TTS: services.BuildService[services.TTS](conn, ctx), + Vacuum: services.BuildService[services.Vacuum](conn, ctx), } }