mirror of
https://github.com/Xevion/go-ha.git
synced 2025-12-08 14:07:14 -06:00
documented general use cases
This commit is contained in:
109
README.md
109
README.md
@@ -1,9 +1,11 @@
|
|||||||
# Gome-Assistant
|
# Gome-Assistant
|
||||||
|
|
||||||
Golang ↔️ Home Assistant
|
|
||||||
|
|
||||||
Write your [Home Assistant](https://www.home-assistant.io/) automations with a strongly-typed Golang library!
|
Write your [Home Assistant](https://www.home-assistant.io/) automations with a strongly-typed Golang library!
|
||||||
|
|
||||||
|
## Disclaimer
|
||||||
|
|
||||||
|
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!
|
||||||
|
|
||||||
## Quick Start
|
## Quick Start
|
||||||
|
|
||||||
### Installation
|
### Installation
|
||||||
@@ -24,26 +26,37 @@ Keeping with the simplicity that Go is famous for, you don't need a specific env
|
|||||||
|
|
||||||
> _❗ 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._
|
> _❗ 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._
|
||||||
|
|
||||||
## Disclaimer
|
## gome-assistant Concepts
|
||||||
|
|
||||||
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 — maybe likely — that breaking changes will happen before v1.0.0!
|
### Overview
|
||||||
|
|
||||||
## gome-assistant Concepts (TODO)
|
The general flow is
|
||||||
|
|
||||||
First, you'll need to create your app.
|
1. Create your app
|
||||||
|
2. Register automations
|
||||||
|
3. Start app
|
||||||
|
|
||||||
```go
|
```go
|
||||||
import ga "github.com/saml-dev/gome-assistant"
|
import ga "github.com/saml-dev/gome-assistant"
|
||||||
|
|
||||||
// replace with IP and port of your Home Assistant installation if needed
|
// replace with IP and port of your Home Assistant installation
|
||||||
app := ga.App("0.0.0.0:8123")
|
app := ga.App("0.0.0.0:8123")
|
||||||
|
|
||||||
|
// create automations here (see next sections)
|
||||||
|
|
||||||
|
// register automations
|
||||||
|
app.RegisterSchedules(...)
|
||||||
|
app.RegisterEntityListeners(...)
|
||||||
|
app.RegisterEventListeners(...)
|
||||||
|
|
||||||
|
app.Start()
|
||||||
```
|
```
|
||||||
|
|
||||||
A full reference is available on [pkg.go.dev](https://pkg.go.dev/github.com/saml-dev/gome-assistant), but all you need to know to get started are the three types of automations in gome-assistant.
|
A full reference is available on [pkg.go.dev](https://pkg.go.dev/github.com/saml-dev/gome-assistant), but all you need to know to get started are the three types of automations in gome-assistant.
|
||||||
|
|
||||||
### Schedules
|
### Schedules
|
||||||
|
|
||||||
Schedules are as you expect, a way to run a function on a schedule. The most common schedule will be once a day.
|
Schedules are simply a way to run a function on a schedule. The most common schedule is once a day at a certain time.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
_7pm := ga.NewSchedule().Call(myFunc).Daily().At("19:00").Build()
|
_7pm := ga.NewSchedule().Call(myFunc).Daily().At("19:00").Build()
|
||||||
@@ -56,19 +69,13 @@ Schedules can also be run at sunrise or sunset, with an optional [offset](https:
|
|||||||
sunrise := ga.NewSchedule().Call(myFunc).Daily().Sunrise(app, "-30m").Build()
|
sunrise := ga.NewSchedule().Call(myFunc).Daily().Sunrise(app, "-30m").Build()
|
||||||
```
|
```
|
||||||
|
|
||||||
Schedules are also used to run a function on a certain interval. Offset is used to offset the first run of a schedule from midnight.
|
Schedules are also used to run a function on an interval. Offset is used to offset the first run of a schedule from midnight.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
// run every hour at the 30-minute mark
|
// run every hour at the 30-minute mark
|
||||||
interval := ga.NewSchedule().Call(a).Every("1h").Offset("30m").Build()
|
interval := ga.NewSchedule().Call(a).Every("1h").Offset("30m").Build()
|
||||||
```
|
```
|
||||||
|
|
||||||
All schedules must be registered with your app. This will panic if there are any issues with the schedule.
|
|
||||||
|
|
||||||
```go
|
|
||||||
app.RegisterSchedules(_7pm, sunrise, interval)
|
|
||||||
```
|
|
||||||
|
|
||||||
#### Schedule Callback function
|
#### Schedule Callback function
|
||||||
|
|
||||||
The function passed to `.Call()` must take
|
The function passed to `.Call()` must take
|
||||||
@@ -76,6 +83,78 @@ The function passed to `.Call()` must take
|
|||||||
- `*ga.Service` used to call home assistant services
|
- `*ga.Service` used to call home assistant services
|
||||||
- `*ga.State` used to retrieve state from home assistant
|
- `*ga.State` used to retrieve state from home assistant
|
||||||
|
|
||||||
|
```go
|
||||||
|
func myFunc(se *ga.Service, st *ga.State) {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Entity Listeners
|
### Entity Listeners
|
||||||
|
|
||||||
|
Entity Listeners are used to respond to entities changing state. The simplest entity listener looks like:
|
||||||
|
|
||||||
|
```go
|
||||||
|
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 should 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. |
|
||||||
|
| ExceptionDay(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. |
|
||||||
|
|
||||||
|
#### 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
|
||||||
|
|
||||||
|
```go
|
||||||
|
func myFunc(se *ga.Service, st *ga.State, e ga.EntityData) {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Event Listeners
|
### Event Listeners
|
||||||
|
|
||||||
|
Event Listeners are used to respond to entities changing state. The simplest event listener looks like:
|
||||||
|
|
||||||
|
```go
|
||||||
|
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 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. |
|
||||||
|
| ExceptionDay(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. |
|
||||||
|
|
||||||
|
#### Event 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
|
||||||
|
|
||||||
|
```go
|
||||||
|
func myFunc(se *ga.Service, st *ga.State) {
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
<!-- TODO: add doc for State and Service, prolly don't need it for EntityData/EntityState -->
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ type EntityListener struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: add state object as second arg
|
// TODO: add state object as second arg
|
||||||
type EntityListenerCallback func(*Service, EntityData)
|
type EntityListenerCallback func(*Service, *State, EntityData)
|
||||||
|
|
||||||
type EntityData struct {
|
type EntityData struct {
|
||||||
TriggerEntityId string
|
TriggerEntityId string
|
||||||
@@ -192,14 +192,14 @@ func callEntityListeners(app *app, msgBytes []byte) {
|
|||||||
|
|
||||||
if l.delay != 0 {
|
if l.delay != 0 {
|
||||||
l.delayTimer = time.AfterFunc(l.delay, func() {
|
l.delayTimer = time.AfterFunc(l.delay, func() {
|
||||||
go l.callback(app.service, entityData)
|
go l.callback(app.service, app.state, entityData)
|
||||||
l.lastRan = carbon.Now()
|
l.lastRan = carbon.Now()
|
||||||
})
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// run now if no delay set
|
// run now if no delay set
|
||||||
go l.callback(app.service, entityData)
|
go l.callback(app.service, app.state, entityData)
|
||||||
l.lastRan = carbon.Now()
|
l.lastRan = carbon.Now()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ func main() {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func pantryLights(service *ga.Service, sensor ga.EntityData) {
|
func pantryLights(service *ga.Service, state *ga.State, sensor ga.EntityData) {
|
||||||
l := "light.pantry"
|
l := "light.pantry"
|
||||||
if sensor.ToState == "on" {
|
if sensor.ToState == "on" {
|
||||||
service.HomeAssistant.TurnOn(l)
|
service.HomeAssistant.TurnOn(l)
|
||||||
@@ -68,6 +68,7 @@ func onEvent(service *ga.Service, data ga.EventData) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func lightsOut(service *ga.Service, state *ga.State) {
|
func lightsOut(service *ga.Service, state *ga.State) {
|
||||||
|
// always turn off outside lights
|
||||||
service.Light.TurnOff("light.outside_lights")
|
service.Light.TurnOff("light.outside_lights")
|
||||||
s, err := state.Get("binary_sensor.living_room_motion")
|
s, err := state.Get("binary_sensor.living_room_motion")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -76,7 +77,7 @@ func lightsOut(service *ga.Service, state *ga.State) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// if no motion detected in living room for 30mins
|
// if no motion detected in living room for 30mins
|
||||||
if s.State == "off" && time.Now().Sub(s.LastChanged).Minutes() > 30 {
|
if s.State == "off" && time.Since(s.LastChanged).Minutes() > 30 {
|
||||||
service.Light.TurnOff("light.main_lights")
|
service.Light.TurnOff("light.main_lights")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
8
state.go
8
state.go
@@ -32,3 +32,11 @@ func (s *State) Get(entityId string) (EntityState, error) {
|
|||||||
json.Unmarshal(resp, &es)
|
json.Unmarshal(resp, &es)
|
||||||
return es, nil
|
return es, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *State) Equals(entityId string, expectedState string) (bool, error) {
|
||||||
|
currentState, err := s.Get(entityId)
|
||||||
|
if err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return currentState.State == expectedState, nil
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user