Write strongly typed Home Assistant automations in Go!
Gome-Assistant is a new library, and I'm opening it up early to get some user feedback on the API and help shape the direction. I plan for it to grow to cover all Home Assistant use cases, services, and event types. So it's possible that breaking changes will happen before v1.0.0!
go get saml.dev/gome-assistant
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.
Keeping with the simplicity that Go is famous for, you don't need a specific environment or docker container to run Gome-Assistant. 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 gome-assistant, to make it easier to use gome-assistant on a fully managed Home Assistant installation.
The general flow is
import ga "saml.dev/gome-assistant"
// replace with IP and port of your Home Assistant installation
app, err := ga.NewApp("0.0.0.0:8123")
// 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 gome-assistant.
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. |
The function passed to .Call()
must take
*ga.Service
used to call home assistant services*ga.State
used to retrieve state from home assistantfunc myFunc(se *ga.Service, st *ga.State) {
// ...
}
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() . |
The function passed to .Call()
must take
*ga.Service
used to call home assistant services*ga.State
used to retrieve state from home assistantga.EntityData
which is the entity that triggered the listenerfunc myFunc(se *ga.Service, st *ga.State, e ga.EntityData) {
// ...
}
Event Listeners are used to respond to entities changing state. The simplest event listener looks like:
evl := ga.NewEntityListener().EntityIds("binary_sensor.front_door").Call(myFunc).Build()
Event listeners have other functions to change the behavior.
Function | Info |
---|---|
Throttle("30s") | Minimum time between function calls. |
OnlyAfter("03:00") | Only run after a specified time of day. |
OnlyBefore("03:00") | Only run before a specified time of day. |
OnlyBetween("03:00", "14:00") | Only run 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. |
ExceptionRange(time.Time, time.Time) | A one time exception between the two date/times. Both date and time are considered. |
The function passed to .Call()
must take
*ga.Service
used to call home assistant services*ga.State
used to retrieve state from home assistantga.EventData
containing the event data that triggered the listenerfunc myFunc(se *ga.Service, st *ga.State, ed ga.EventData) {
// ...
}
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. |
The function passed to .Call()
must take
*ga.Service
used to call home assistant services*ga.State
used to retrieve state from home assistantfunc myFunc(se *ga.Service, st *ga.State) {
// ...
}