| 
				
					
						
							 | 
			||
|---|---|---|
| internal | ||
| pkg | ||
| .gitignore | ||
| Dockerfile | ||
| LICENSE | ||
| README.md | ||
| go.mod | ||
| go.sum | ||
| main.go | ||
		
			
				
				README.md
			
		
		
			
			
		
	
	HATS
Home Assistant + NATS = HATS
Features
- Push Home Assistant websocket events to a NATS message queue
 - Caching proxy for Home Assistant API
 - Generic implementations for subscribing to NATS topics
 - Clients for some application APIs (limited functionality)
 
NATS Topics
homeassistant.states.{domain}.{entity}.{state}- Home Assistant device state changes: payloadhomeassistant.attributes.{domain}.{entity}.{state}- When a device's attributes change but the state hasn't changed: payloadhomeassistant.zha.{device IEEE}- ZHA events: payloadhomeassistant.zwave-scene.{device ID}- ZwaveJS scene events: payloadhomeassistant.nfc.{tag ID}- Home Assistant NFC tag scanned: payloadhomeassistant.timer.{timer name}.finished- Home Assistant timer finished: payload is simply"finished"schedules.{schedule name}- HATS schedule finished: payload is simply"finished"command.{command name}- Command called via HATS API: payload is a byte array of the HTTP Post body
Example Client
package main
import (
	"log/slog"
	"os"
	"os/signal"
	"syscall"
	"code.jhot.me/jhot/hats/pkg/client"
	"code.jhot.me/jhot/hats/pkg/config"
	ha "code.jhot.me/jhot/hats/pkg/homeassistant"
	"code.jhot.me/jhot/hats/pkg/nats"
	n "github.com/nats-io/nats.go"
)
var (
	logger     *slog.Logger
	hatsClient *client.HatsClient
	natsClient *nats.NatsConnection
)
func main() {
	cfg := config.FromEnvironment()
	logger = slog.New(slog.NewJSONHandler(os.Stdout, &slog.HandlerOptions{
		Level: cfg.GetLogLevel(),
	}))
	hatsClient = client.NewHatsClient(cfg.GetHatsBaseUrl(), cfg.HatsToken)
	natsClient = nats.DefaultNatsConnection().WithJetstream(false).WithHostName(cfg.NatsHost).
		WithPort(cfg.NatsPort).WithConnectionOption(n.Name(cfg.NatsClientName))
	err := natsClient.Connect()
	if err != nil {
		panic(err)
	}
	defer natsClient.Close()
	go natsClient.GenericStateSubscriber(logger, "sun.sun", SunHandler)
	sigch := make(chan os.Signal, 1)
	signal.Notify(sigch, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM)
	<-sigch
	logger.Info("SIGTERM received")
}
func SunHandler(state ha.StateData) error {
	var service string
	if up := ha.StateToBool(state.State); up {
		service = ha.Services.TurnOff
	} else {
		service = ha.Services.TurnOn
	}
	return hatsClient.CallService("light.some_light", service)
}