gomeassistant

package module
v0.7.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 2, 2025 License: Apache-2.0 Imports: 16 Imported by: 0

README

go-ha

Write strongly typed Home Assistant automations in Go!

go get github.com/Xevion/go-ha

or in go.mod:

require github.com/Xevion/go-ha

Generate Entity Constants

You can generate type-safe constants for all your Home Assistant entities using go generate. This makes it easier to reference entities in your code.

  1. Create a gen.yaml file in your project root:
url: "http://192.168.1.123:8123"
ha_auth_token: "your_auth_token" # Or set HA_AUTH_TOKEN env var
home_zone_entity_id: "zone.home" # Optional: defaults to zone.home

# Optional: List of domains to include when generating constants
# If provided, only these domains will be processed
include_domains: ["light", "switch", "climate"]

# Optional: List of domains to exclude when generating constants
# Only used if include_domains is empty
exclude_domains: ["device_tracker", "person"]
  1. Add a //go:generate comment in your project:
//go:generate go run github.com/Xevion/go-ha/cmd/generate

Optionally use the -config flag to customize the file path of the config file.

  1. Run the generator:
go generate

This will create an entities package with type-safe constants for all your Home Assistant entities, organized by domain. For example:

import "your_project/entities"

// Instead of writing "light.living_room" as a string:
entities.Light.LivingRoom // Type-safe constant

// All your entities are organized by domain
entities.Switch.Kitchen
entities.Climate.Bedroom
entities.MediaPlayer.TVRoom

The constants are based on the entity ID itself, not the name of the entity in Home Assistant.

Write your automations

Check out example/example.go for an example of the 3 types of automations — schedules, entity listeners, and event listeners.

ℹ️ Instead of copying and pasting, try typing it yourself to see how autocomplete guides you through the setup using a builder pattern.

Run your code

Keeping with the simplicity that Go is famous for, you don't need a specific environment or docker container to run go-ha. You just write and run your code like any other Go binary. So once you build your code, you can run it however you like — using screen or tmux, a cron job, a linux service, or wrap it up in a docker container if you like!

❗ No promises, but I may provide a Docker image with file watching to automatically restart go-ha, to make it easier to use go-ha on a fully managed Home Assistant installation.

go-ha Concepts

Overview

The general flow is

  1. Create your app
  2. Register automations
  3. Start app
import ha "github.com/Xevion/go-ha"

// replace with IP and port of your Home Assistant installation
app, err := ga.NewApp(ga.NewAppRequest{
 URL:              "http://192.168.1.123:8123",
 HAAuthToken:      os.Getenv("HA_AUTH_TOKEN"),
 HomeZoneEntityId: "zone.home",
})

// create automations here (see next sections)

// register automations
app.RegisterSchedules(...)
app.RegisterEntityListeners(...)
app.RegisterEventListeners(...)
app.RegisterIntervals(...)

app.Start()

A full reference is available on pkg.go.dev, but all you need to know to get started are the four types of automations in go-ha.

Daily Schedule

Daily Schedules run at a specific time each day.

_7pm := ga.NewDailySchedule().Call(myFunc).At("19:00").Build()

Schedules can also be run at sunrise or sunset, with an optional offset.

// 30 mins before sunrise
sunrise := ga.NewDailySchedule().Call(myFunc).Sunrise(app, "-30m").Build()
// at sunset
sunset := ga.NewDailySchedule().Call(myFunc).Sunset().Build()

Daily schedules have other functions to change the behavior.

Function Info
ExceptionDates(t time.Time, ...time.Time) Skip the schedule on the given date(s). Functions like a blocklist. Cannot be combined with OnlyOnDates.
OnlyOnDates(t time.Time, ...time.Time) Run only on the given date(s). Functions like an allowlist. Cannot be combined with ExceptionDates.
Schedule Callback function

The function passed to .Call() must take

  • *ga.Service used to call home assistant services
  • *ga.State used to retrieve state from home assistant
func myFunc(se *ga.Service, st *ga.State) {
  // ...
}
Entity Listener

Entity Listeners are used to respond to entities changing state. The simplest entity listener looks like:

etl := ga.NewEntityListener().EntityIds("binary_sensor.front_door").Call(myFunc).Build()

Entity listeners have other functions to change the behavior.

Function Info
ToState("on") Function only called if new state matches argument.
FromState("on") Function only called if old state matches argument.
Throttle("30s") Minimum time between function calls.
Duration("30s") Requires ToState(). Sets how long the entity must be in the state before running your function.
OnlyAfter("03:00") Only run your function after a specified time of day.
OnlyBefore("03:00") Only run your function before a specified time of day.
OnlyBetween("03:00", "14:00") Only run your function between two specified times of day.
ExceptionDates(time.Time, ...time.Time) A one time exception on the given date. Time is ignored, applies to whole day. Functions like a "blocklist".
ExceptionRange(time.Time, time.Time) A one time exception between the two date/times. Both date and time are considered. Functions like a "blocklist".
RunOnStartup() Run your callback during App.Start().
Entity Listener Callback function

The function passed to .Call() must take

  • *ga.Service used to call home assistant services
  • *ga.State used to retrieve state from home assistant
  • ga.EntityData which is the entity that triggered the listener
func myFunc(se *ga.Service, st *ga.State, e ga.EntityData) {
  // ...
}
Event Listeners

Event listeners allow you to respond to Home Assistant events in real-time. You can create an event listener using the builder pattern:

eventListener := ga.
    NewEventListener().
    EventTypes("zwave_js_value_notification"). // Specify one or more event types
    Call(myCallbackFunc).                     // Specify the callback function
    Build()

// Register the listener with your app
app.RegisterEventListeners(eventListener)

Event listeners have other functions to change the behavior.

Function Info
OnlyBetween("03:00", "14:00") Only run your function between two specified times of day
OnlyAfter("03:00") Only run your function after a specified time of day
OnlyBefore("03:00") Only run your function before a specified time of day
Throttle("30s") Minimum time between function calls
ExceptionDates(time.Time, ...time.Time) A one time exception on the given date. Time is ignored, applies to whole day. Functions like a "blocklist"
ExceptionRange(time.Time, time.Time) A one time exception between the two date/times. Both date and time are considered. Functions like a "blocklist"

The callback function receives three parameters:

func myCallback(service *ga.Service, state ga.State, data ga.EventData) {
    // You can unmarshal the raw JSON into a type-safe struct
    ev := ga.EventZWaveJSValueNotification{}
    json.Unmarshal(data.RawEventJSON, &ev)

    // Handle the event...
}

💡 Check eventTypes.go for pre-defined event types, or create your own struct type for custom events and contribute them back to go-ha with a PR.

Interval

Intervals are used to run a function on an interval.

// run every hour at the 30-minute mark
interval := ga.NewInterval().Call(myFunc).Every("1h").StartingAt("00:30").Build()
// run every 5 minutes between 10am and 5pm
interval = ga.NewInterval().Call(myFunc).Every("5m").StartingAt("10:00").EndingAt("17:00").Build()

Intervals have other functions to change the behavior.

Function Info
StartingAt(TimeString) What time the interval begins to run each day.
EndingAt(TimeString) What time the interval stops running each day.
ExceptionDates(time.Time, ...time.Time) A one time exception on the given date. Time is ignored, applies to whole day.
ExceptionRange(time.Time, time.Time) A one time exception between the two date/times. Both date and time are considered.
Interval Callback function

The function passed to .Call() must take

  • *ga.Service used to call home assistant services
  • *ga.State used to retrieve state from home assistant
func myFunc(se *ga.Service, st *ga.State) {
  // ...
}

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ErrInvalidArgs = errors.New("invalid arguments provided")

Functions

func NewDailySchedule

func NewDailySchedule() scheduleBuilder

func NewEntityListener

func NewEntityListener() elBuilder1

func NewEventListener

func NewEventListener() eventListenerBuilder1

func NewInterval

func NewInterval() intervalBuilder

Types

type App

type App struct {
	// contains filtered or unexported fields
}

func NewApp

func NewApp(request types.NewAppRequest) (*App, error)

NewApp establishes the websocket connection and returns an object you can use to register schedules and listeners.

func (*App) Cleanup

func (app *App) Cleanup()

func (*App) Close

func (app *App) Close() error

Close performs a clean shutdown of the application. It cancels the context, closes the websocket connection, and ensures all background processes are properly terminated.

func (*App) GetService

func (app *App) GetService() *Service

func (*App) GetState

func (app *App) GetState() State

func (*App) RegisterEntityListeners

func (app *App) RegisterEntityListeners(etls ...EntityListener)

func (*App) RegisterEventListeners

func (app *App) RegisterEventListeners(evls ...EventListener)

func (*App) RegisterIntervals

func (app *App) RegisterIntervals(intervals ...Interval)

func (*App) RegisterSchedules

func (app *App) RegisterSchedules(schedules ...DailySchedule)

func (*App) Start

func (app *App) Start()

type BaseEventMsg

type BaseEventMsg struct {
	Event struct {
		EventType string `json:"event_type"`
	} `json:"event"`
}

type ConditionCheck added in v0.7.1

type ConditionCheck struct {
	// contains filtered or unexported fields
}

func CheckAllowlistDates added in v0.7.1

func CheckAllowlistDates(eList []time.Time) ConditionCheck

func CheckDisabledEntity added in v0.7.1

func CheckDisabledEntity(s State, infos []internal.EnabledDisabledInfo) ConditionCheck

func CheckEnabledEntity added in v0.7.1

func CheckEnabledEntity(s State, infos []internal.EnabledDisabledInfo) ConditionCheck

func CheckExceptionDates added in v0.7.1

func CheckExceptionDates(eList []time.Time) ConditionCheck

func CheckExceptionRanges added in v0.7.1

func CheckExceptionRanges(eList []types.TimeRange) ConditionCheck

func CheckStartEndTime added in v0.7.1

func CheckStartEndTime(s types.TimeString, isStart bool) ConditionCheck

func CheckStatesMatch added in v0.7.1

func CheckStatesMatch(listenerState, s string) ConditionCheck

func CheckThrottle added in v0.7.1

func CheckThrottle(throttle time.Duration, lastRan *carbon.Carbon) ConditionCheck

func CheckWithinTimeRange added in v0.7.1

func CheckWithinTimeRange(startTime, endTime string) ConditionCheck

type DailySchedule

type DailySchedule struct {
	// contains filtered or unexported fields
}

func (DailySchedule) Hash

func (s DailySchedule) Hash() string

func (DailySchedule) String

func (s DailySchedule) String() string

type EntityData

type EntityData struct {
	TriggerEntityId string
	FromState       string
	FromAttributes  map[string]any
	ToState         string
	ToAttributes    map[string]any
	LastChanged     time.Time
}

type EntityListener

type EntityListener struct {
	// contains filtered or unexported fields
}

type EntityListenerCallback

type EntityListenerCallback func(*Service, State, EntityData)

type EntityState

type EntityState struct {
	EntityID    string         `json:"entity_id"`
	State       string         `json:"state"`
	Attributes  map[string]any `json:"attributes"`
	LastChanged time.Time      `json:"last_changed"`
}

type EventData

type EventData struct {
	Type         string
	RawEventJSON []byte
}

type EventListener

type EventListener struct {
	// contains filtered or unexported fields
}

type EventListenerCallback

type EventListenerCallback func(*Service, State, EventData)

type Interval

type Interval struct {
	// contains filtered or unexported fields
}

func (Interval) Hash

func (i Interval) Hash() string

func (Interval) String

func (i Interval) String() string

type IntervalCallback

type IntervalCallback func(*Service, State)

type Item

type Item types.Item

func (Item) Compare

func (mi Item) Compare(other queue.Item) int

type ScheduleCallback

type ScheduleCallback func(*Service, State)

type Service

type Service struct {
	AdaptiveLighting  *services.AdaptiveLighting
	AlarmControlPanel *services.AlarmControlPanel
	Climate           *services.Climate
	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
	Event             *services.Event
	Notify            *services.Notify
	Number            *services.Number
	Scene             *services.Scene
	Script            *services.Script
	Timer             *services.Timer
	TTS               *services.TTS
	Vacuum            *services.Vacuum
	ZWaveJS           *services.ZWaveJS
}

type State

type State interface {
	AfterSunrise(...types.DurationString) bool
	BeforeSunrise(...types.DurationString) bool
	AfterSunset(...types.DurationString) bool
	BeforeSunset(...types.DurationString) bool
	ListEntities() ([]EntityState, error)
	Get(entityId string) (EntityState, error)
	Equals(entityId, state string) (bool, error)
}

type StateImpl

type StateImpl struct {
	// contains filtered or unexported fields
}

State is used to retrieve state from Home Assistant.

func (*StateImpl) AfterSunrise

func (s *StateImpl) AfterSunrise(offset ...types.DurationString) bool

func (*StateImpl) AfterSunset

func (s *StateImpl) AfterSunset(offset ...types.DurationString) bool

func (*StateImpl) BeforeSunrise

func (s *StateImpl) BeforeSunrise(offset ...types.DurationString) bool

func (*StateImpl) BeforeSunset

func (s *StateImpl) BeforeSunset(offset ...types.DurationString) bool

func (*StateImpl) Equals

func (s *StateImpl) Equals(entityId string, expectedState string) (bool, error)

func (*StateImpl) Get

func (s *StateImpl) Get(entityId string) (EntityState, error)

func (*StateImpl) ListEntities

func (s *StateImpl) ListEntities() ([]EntityState, error)

ListEntities returns a list of all entities in Home Assistant. see rest documentation for more details: https://developers.home-assistant.io/docs/api/rest/#actions

Directories

Path Synopsis
cmd
generate command
Package main provides the generate command for generating Home Assistant entity constants
Package main provides the generate command for generating Home Assistant entity constants
http is used to interact with the home assistant REST API.
http is used to interact with the home assistant REST API.
connect
Package websocket is used to interact with the Home Assistant websocket API.
Package websocket is used to interact with the Home Assistant websocket API.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL