Added new app, ha-gateway
This commit is contained in:
parent
3d9690e939
commit
2e99c464ff
10
buf.gen.yaml
Normal file
10
buf.gen.yaml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
version: v2
|
||||||
|
plugins:
|
||||||
|
- remote: buf.build/protocolbuffers/go
|
||||||
|
out: gen
|
||||||
|
opt:
|
||||||
|
- paths=source_relative
|
||||||
|
- remote: buf.build/grpc/go
|
||||||
|
out: gen
|
||||||
|
opt:
|
||||||
|
- paths=source_relative
|
||||||
15
gen/go.mod
Normal file
15
gen/go.mod
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
module gitea.nik4nao.com/nik/home-services/gen
|
||||||
|
|
||||||
|
go 1.26
|
||||||
|
|
||||||
|
require (
|
||||||
|
google.golang.org/grpc v1.79.3
|
||||||
|
google.golang.org/protobuf v1.36.11
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
golang.org/x/net v0.48.0 // indirect
|
||||||
|
golang.org/x/sys v0.39.0 // indirect
|
||||||
|
golang.org/x/text v0.32.0 // indirect
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect
|
||||||
|
)
|
||||||
38
gen/go.sum
Normal file
38
gen/go.sum
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||||
|
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
|
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||||
|
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||||
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||||
|
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||||
|
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
||||||
|
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
||||||
|
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
|
||||||
|
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
||||||
|
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
|
||||||
|
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
||||||
|
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
||||||
|
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
||||||
|
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
|
||||||
|
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
|
||||||
|
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
|
||||||
|
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
|
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
|
||||||
|
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
|
||||||
|
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||||
|
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
|
||||||
|
google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE=
|
||||||
|
google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||||
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
230
gen/ha/v1/common.pb.go
Normal file
230
gen/ha/v1/common.pb.go
Normal file
@ -0,0 +1,230 @@
|
|||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// protoc-gen-go v1.36.11
|
||||||
|
// protoc (unknown)
|
||||||
|
// source: ha/v1/common.proto
|
||||||
|
|
||||||
|
package hav1
|
||||||
|
|
||||||
|
import (
|
||||||
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
reflect "reflect"
|
||||||
|
sync "sync"
|
||||||
|
unsafe "unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Verify that this generated code is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||||
|
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
|
)
|
||||||
|
|
||||||
|
type EntityState struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
EntityId string `protobuf:"bytes,1,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"`
|
||||||
|
State string `protobuf:"bytes,2,opt,name=state,proto3" json:"state,omitempty"`
|
||||||
|
Attributes map[string]string `protobuf:"bytes,3,rep,name=attributes,proto3" json:"attributes,omitempty" protobuf_key:"bytes,1,opt,name=key" protobuf_val:"bytes,2,opt,name=value"`
|
||||||
|
LastChanged string `protobuf:"bytes,4,opt,name=last_changed,json=lastChanged,proto3" json:"last_changed,omitempty"` // RFC3339
|
||||||
|
LastUpdated string `protobuf:"bytes,5,opt,name=last_updated,json=lastUpdated,proto3" json:"last_updated,omitempty"` // RFC3339
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *EntityState) Reset() {
|
||||||
|
*x = EntityState{}
|
||||||
|
mi := &file_ha_v1_common_proto_msgTypes[0]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *EntityState) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*EntityState) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *EntityState) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_ha_v1_common_proto_msgTypes[0]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use EntityState.ProtoReflect.Descriptor instead.
|
||||||
|
func (*EntityState) Descriptor() ([]byte, []int) {
|
||||||
|
return file_ha_v1_common_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *EntityState) GetEntityId() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.EntityId
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *EntityState) GetState() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.State
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *EntityState) GetAttributes() map[string]string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Attributes
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *EntityState) GetLastChanged() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.LastChanged
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *EntityState) GetLastUpdated() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.LastUpdated
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type RGBColor struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
R uint32 `protobuf:"varint,1,opt,name=r,proto3" json:"r,omitempty"`
|
||||||
|
G uint32 `protobuf:"varint,2,opt,name=g,proto3" json:"g,omitempty"`
|
||||||
|
B uint32 `protobuf:"varint,3,opt,name=b,proto3" json:"b,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *RGBColor) Reset() {
|
||||||
|
*x = RGBColor{}
|
||||||
|
mi := &file_ha_v1_common_proto_msgTypes[1]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *RGBColor) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*RGBColor) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *RGBColor) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_ha_v1_common_proto_msgTypes[1]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use RGBColor.ProtoReflect.Descriptor instead.
|
||||||
|
func (*RGBColor) Descriptor() ([]byte, []int) {
|
||||||
|
return file_ha_v1_common_proto_rawDescGZIP(), []int{1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *RGBColor) GetR() uint32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.R
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *RGBColor) GetG() uint32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.G
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *RGBColor) GetB() uint32 {
|
||||||
|
if x != nil {
|
||||||
|
return x.B
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
var File_ha_v1_common_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
|
const file_ha_v1_common_proto_rawDesc = "" +
|
||||||
|
"\n" +
|
||||||
|
"\x12ha/v1/common.proto\x12\x05ha.v1\"\x89\x02\n" +
|
||||||
|
"\vEntityState\x12\x1b\n" +
|
||||||
|
"\tentity_id\x18\x01 \x01(\tR\bentityId\x12\x14\n" +
|
||||||
|
"\x05state\x18\x02 \x01(\tR\x05state\x12B\n" +
|
||||||
|
"\n" +
|
||||||
|
"attributes\x18\x03 \x03(\v2\".ha.v1.EntityState.AttributesEntryR\n" +
|
||||||
|
"attributes\x12!\n" +
|
||||||
|
"\flast_changed\x18\x04 \x01(\tR\vlastChanged\x12!\n" +
|
||||||
|
"\flast_updated\x18\x05 \x01(\tR\vlastUpdated\x1a=\n" +
|
||||||
|
"\x0fAttributesEntry\x12\x10\n" +
|
||||||
|
"\x03key\x18\x01 \x01(\tR\x03key\x12\x14\n" +
|
||||||
|
"\x05value\x18\x02 \x01(\tR\x05value:\x028\x01\"4\n" +
|
||||||
|
"\bRGBColor\x12\f\n" +
|
||||||
|
"\x01r\x18\x01 \x01(\rR\x01r\x12\f\n" +
|
||||||
|
"\x01g\x18\x02 \x01(\rR\x01g\x12\f\n" +
|
||||||
|
"\x01b\x18\x03 \x01(\rR\x01bB4Z2gitea.nik4nao.com/nik/home-services/gen/ha/v1;hav1b\x06proto3"
|
||||||
|
|
||||||
|
var (
|
||||||
|
file_ha_v1_common_proto_rawDescOnce sync.Once
|
||||||
|
file_ha_v1_common_proto_rawDescData []byte
|
||||||
|
)
|
||||||
|
|
||||||
|
func file_ha_v1_common_proto_rawDescGZIP() []byte {
|
||||||
|
file_ha_v1_common_proto_rawDescOnce.Do(func() {
|
||||||
|
file_ha_v1_common_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ha_v1_common_proto_rawDesc), len(file_ha_v1_common_proto_rawDesc)))
|
||||||
|
})
|
||||||
|
return file_ha_v1_common_proto_rawDescData
|
||||||
|
}
|
||||||
|
|
||||||
|
var file_ha_v1_common_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
|
||||||
|
var file_ha_v1_common_proto_goTypes = []any{
|
||||||
|
(*EntityState)(nil), // 0: ha.v1.EntityState
|
||||||
|
(*RGBColor)(nil), // 1: ha.v1.RGBColor
|
||||||
|
nil, // 2: ha.v1.EntityState.AttributesEntry
|
||||||
|
}
|
||||||
|
var file_ha_v1_common_proto_depIdxs = []int32{
|
||||||
|
2, // 0: ha.v1.EntityState.attributes:type_name -> ha.v1.EntityState.AttributesEntry
|
||||||
|
1, // [1:1] is the sub-list for method output_type
|
||||||
|
1, // [1:1] is the sub-list for method input_type
|
||||||
|
1, // [1:1] is the sub-list for extension type_name
|
||||||
|
1, // [1:1] is the sub-list for extension extendee
|
||||||
|
0, // [0:1] is the sub-list for field type_name
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { file_ha_v1_common_proto_init() }
|
||||||
|
func file_ha_v1_common_proto_init() {
|
||||||
|
if File_ha_v1_common_proto != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
type x struct{}
|
||||||
|
out := protoimpl.TypeBuilder{
|
||||||
|
File: protoimpl.DescBuilder{
|
||||||
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
|
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ha_v1_common_proto_rawDesc), len(file_ha_v1_common_proto_rawDesc)),
|
||||||
|
NumEnums: 0,
|
||||||
|
NumMessages: 3,
|
||||||
|
NumExtensions: 0,
|
||||||
|
NumServices: 0,
|
||||||
|
},
|
||||||
|
GoTypes: file_ha_v1_common_proto_goTypes,
|
||||||
|
DependencyIndexes: file_ha_v1_common_proto_depIdxs,
|
||||||
|
MessageInfos: file_ha_v1_common_proto_msgTypes,
|
||||||
|
}.Build()
|
||||||
|
File_ha_v1_common_proto = out.File
|
||||||
|
file_ha_v1_common_proto_goTypes = nil
|
||||||
|
file_ha_v1_common_proto_depIdxs = nil
|
||||||
|
}
|
||||||
285
gen/ha/v1/entity.pb.go
Normal file
285
gen/ha/v1/entity.pb.go
Normal file
@ -0,0 +1,285 @@
|
|||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// protoc-gen-go v1.36.11
|
||||||
|
// protoc (unknown)
|
||||||
|
// source: ha/v1/entity.proto
|
||||||
|
|
||||||
|
package hav1
|
||||||
|
|
||||||
|
import (
|
||||||
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
reflect "reflect"
|
||||||
|
sync "sync"
|
||||||
|
unsafe "unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Verify that this generated code is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||||
|
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
|
)
|
||||||
|
|
||||||
|
type GetStateRequest struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
EntityId string `protobuf:"bytes,1,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetStateRequest) Reset() {
|
||||||
|
*x = GetStateRequest{}
|
||||||
|
mi := &file_ha_v1_entity_proto_msgTypes[0]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetStateRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*GetStateRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *GetStateRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_ha_v1_entity_proto_msgTypes[0]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use GetStateRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*GetStateRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_ha_v1_entity_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetStateRequest) GetEntityId() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.EntityId
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type GetStateResponse struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
State *EntityState `protobuf:"bytes,1,opt,name=state,proto3" json:"state,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetStateResponse) Reset() {
|
||||||
|
*x = GetStateResponse{}
|
||||||
|
mi := &file_ha_v1_entity_proto_msgTypes[1]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetStateResponse) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*GetStateResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *GetStateResponse) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_ha_v1_entity_proto_msgTypes[1]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use GetStateResponse.ProtoReflect.Descriptor instead.
|
||||||
|
func (*GetStateResponse) Descriptor() ([]byte, []int) {
|
||||||
|
return file_ha_v1_entity_proto_rawDescGZIP(), []int{1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *GetStateResponse) GetState() *EntityState {
|
||||||
|
if x != nil {
|
||||||
|
return x.State
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListStatesRequest struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
EntityIds []string `protobuf:"bytes,1,rep,name=entity_ids,json=entityIds,proto3" json:"entity_ids,omitempty"`
|
||||||
|
Domain string `protobuf:"bytes,2,opt,name=domain,proto3" json:"domain,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ListStatesRequest) Reset() {
|
||||||
|
*x = ListStatesRequest{}
|
||||||
|
mi := &file_ha_v1_entity_proto_msgTypes[2]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ListStatesRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ListStatesRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *ListStatesRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_ha_v1_entity_proto_msgTypes[2]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ListStatesRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*ListStatesRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_ha_v1_entity_proto_rawDescGZIP(), []int{2}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ListStatesRequest) GetEntityIds() []string {
|
||||||
|
if x != nil {
|
||||||
|
return x.EntityIds
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ListStatesRequest) GetDomain() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Domain
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type ListStatesResponse struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
States []*EntityState `protobuf:"bytes,1,rep,name=states,proto3" json:"states,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ListStatesResponse) Reset() {
|
||||||
|
*x = ListStatesResponse{}
|
||||||
|
mi := &file_ha_v1_entity_proto_msgTypes[3]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ListStatesResponse) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ListStatesResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *ListStatesResponse) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_ha_v1_entity_proto_msgTypes[3]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ListStatesResponse.ProtoReflect.Descriptor instead.
|
||||||
|
func (*ListStatesResponse) Descriptor() ([]byte, []int) {
|
||||||
|
return file_ha_v1_entity_proto_rawDescGZIP(), []int{3}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ListStatesResponse) GetStates() []*EntityState {
|
||||||
|
if x != nil {
|
||||||
|
return x.States
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var File_ha_v1_entity_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
|
const file_ha_v1_entity_proto_rawDesc = "" +
|
||||||
|
"\n" +
|
||||||
|
"\x12ha/v1/entity.proto\x12\x05ha.v1\x1a\x12ha/v1/common.proto\".\n" +
|
||||||
|
"\x0fGetStateRequest\x12\x1b\n" +
|
||||||
|
"\tentity_id\x18\x01 \x01(\tR\bentityId\"<\n" +
|
||||||
|
"\x10GetStateResponse\x12(\n" +
|
||||||
|
"\x05state\x18\x01 \x01(\v2\x12.ha.v1.EntityStateR\x05state\"J\n" +
|
||||||
|
"\x11ListStatesRequest\x12\x1d\n" +
|
||||||
|
"\n" +
|
||||||
|
"entity_ids\x18\x01 \x03(\tR\tentityIds\x12\x16\n" +
|
||||||
|
"\x06domain\x18\x02 \x01(\tR\x06domain\"@\n" +
|
||||||
|
"\x12ListStatesResponse\x12*\n" +
|
||||||
|
"\x06states\x18\x01 \x03(\v2\x12.ha.v1.EntityStateR\x06states2\x8f\x01\n" +
|
||||||
|
"\rEntityService\x12;\n" +
|
||||||
|
"\bGetState\x12\x16.ha.v1.GetStateRequest\x1a\x17.ha.v1.GetStateResponse\x12A\n" +
|
||||||
|
"\n" +
|
||||||
|
"ListStates\x12\x18.ha.v1.ListStatesRequest\x1a\x19.ha.v1.ListStatesResponseB4Z2gitea.nik4nao.com/nik/home-services/gen/ha/v1;hav1b\x06proto3"
|
||||||
|
|
||||||
|
var (
|
||||||
|
file_ha_v1_entity_proto_rawDescOnce sync.Once
|
||||||
|
file_ha_v1_entity_proto_rawDescData []byte
|
||||||
|
)
|
||||||
|
|
||||||
|
func file_ha_v1_entity_proto_rawDescGZIP() []byte {
|
||||||
|
file_ha_v1_entity_proto_rawDescOnce.Do(func() {
|
||||||
|
file_ha_v1_entity_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ha_v1_entity_proto_rawDesc), len(file_ha_v1_entity_proto_rawDesc)))
|
||||||
|
})
|
||||||
|
return file_ha_v1_entity_proto_rawDescData
|
||||||
|
}
|
||||||
|
|
||||||
|
var file_ha_v1_entity_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
|
||||||
|
var file_ha_v1_entity_proto_goTypes = []any{
|
||||||
|
(*GetStateRequest)(nil), // 0: ha.v1.GetStateRequest
|
||||||
|
(*GetStateResponse)(nil), // 1: ha.v1.GetStateResponse
|
||||||
|
(*ListStatesRequest)(nil), // 2: ha.v1.ListStatesRequest
|
||||||
|
(*ListStatesResponse)(nil), // 3: ha.v1.ListStatesResponse
|
||||||
|
(*EntityState)(nil), // 4: ha.v1.EntityState
|
||||||
|
}
|
||||||
|
var file_ha_v1_entity_proto_depIdxs = []int32{
|
||||||
|
4, // 0: ha.v1.GetStateResponse.state:type_name -> ha.v1.EntityState
|
||||||
|
4, // 1: ha.v1.ListStatesResponse.states:type_name -> ha.v1.EntityState
|
||||||
|
0, // 2: ha.v1.EntityService.GetState:input_type -> ha.v1.GetStateRequest
|
||||||
|
2, // 3: ha.v1.EntityService.ListStates:input_type -> ha.v1.ListStatesRequest
|
||||||
|
1, // 4: ha.v1.EntityService.GetState:output_type -> ha.v1.GetStateResponse
|
||||||
|
3, // 5: ha.v1.EntityService.ListStates:output_type -> ha.v1.ListStatesResponse
|
||||||
|
4, // [4:6] is the sub-list for method output_type
|
||||||
|
2, // [2:4] is the sub-list for method input_type
|
||||||
|
2, // [2:2] is the sub-list for extension type_name
|
||||||
|
2, // [2:2] is the sub-list for extension extendee
|
||||||
|
0, // [0:2] is the sub-list for field type_name
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { file_ha_v1_entity_proto_init() }
|
||||||
|
func file_ha_v1_entity_proto_init() {
|
||||||
|
if File_ha_v1_entity_proto != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
file_ha_v1_common_proto_init()
|
||||||
|
type x struct{}
|
||||||
|
out := protoimpl.TypeBuilder{
|
||||||
|
File: protoimpl.DescBuilder{
|
||||||
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
|
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ha_v1_entity_proto_rawDesc), len(file_ha_v1_entity_proto_rawDesc)),
|
||||||
|
NumEnums: 0,
|
||||||
|
NumMessages: 4,
|
||||||
|
NumExtensions: 0,
|
||||||
|
NumServices: 1,
|
||||||
|
},
|
||||||
|
GoTypes: file_ha_v1_entity_proto_goTypes,
|
||||||
|
DependencyIndexes: file_ha_v1_entity_proto_depIdxs,
|
||||||
|
MessageInfos: file_ha_v1_entity_proto_msgTypes,
|
||||||
|
}.Build()
|
||||||
|
File_ha_v1_entity_proto = out.File
|
||||||
|
file_ha_v1_entity_proto_goTypes = nil
|
||||||
|
file_ha_v1_entity_proto_depIdxs = nil
|
||||||
|
}
|
||||||
159
gen/ha/v1/entity_grpc.pb.go
Normal file
159
gen/ha/v1/entity_grpc.pb.go
Normal file
@ -0,0 +1,159 @@
|
|||||||
|
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// - protoc-gen-go-grpc v1.6.1
|
||||||
|
// - protoc (unknown)
|
||||||
|
// source: ha/v1/entity.proto
|
||||||
|
|
||||||
|
package hav1
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
grpc "google.golang.org/grpc"
|
||||||
|
codes "google.golang.org/grpc/codes"
|
||||||
|
status "google.golang.org/grpc/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the grpc package it is being compiled against.
|
||||||
|
// Requires gRPC-Go v1.64.0 or later.
|
||||||
|
const _ = grpc.SupportPackageIsVersion9
|
||||||
|
|
||||||
|
const (
|
||||||
|
EntityService_GetState_FullMethodName = "/ha.v1.EntityService/GetState"
|
||||||
|
EntityService_ListStates_FullMethodName = "/ha.v1.EntityService/ListStates"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EntityServiceClient is the client API for EntityService service.
|
||||||
|
//
|
||||||
|
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||||
|
type EntityServiceClient interface {
|
||||||
|
GetState(ctx context.Context, in *GetStateRequest, opts ...grpc.CallOption) (*GetStateResponse, error)
|
||||||
|
ListStates(ctx context.Context, in *ListStatesRequest, opts ...grpc.CallOption) (*ListStatesResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type entityServiceClient struct {
|
||||||
|
cc grpc.ClientConnInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEntityServiceClient(cc grpc.ClientConnInterface) EntityServiceClient {
|
||||||
|
return &entityServiceClient{cc}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *entityServiceClient) GetState(ctx context.Context, in *GetStateRequest, opts ...grpc.CallOption) (*GetStateResponse, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(GetStateResponse)
|
||||||
|
err := c.cc.Invoke(ctx, EntityService_GetState_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *entityServiceClient) ListStates(ctx context.Context, in *ListStatesRequest, opts ...grpc.CallOption) (*ListStatesResponse, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(ListStatesResponse)
|
||||||
|
err := c.cc.Invoke(ctx, EntityService_ListStates_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// EntityServiceServer is the server API for EntityService service.
|
||||||
|
// All implementations must embed UnimplementedEntityServiceServer
|
||||||
|
// for forward compatibility.
|
||||||
|
type EntityServiceServer interface {
|
||||||
|
GetState(context.Context, *GetStateRequest) (*GetStateResponse, error)
|
||||||
|
ListStates(context.Context, *ListStatesRequest) (*ListStatesResponse, error)
|
||||||
|
mustEmbedUnimplementedEntityServiceServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnimplementedEntityServiceServer must be embedded to have
|
||||||
|
// forward compatible implementations.
|
||||||
|
//
|
||||||
|
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
||||||
|
// pointer dereference when methods are called.
|
||||||
|
type UnimplementedEntityServiceServer struct{}
|
||||||
|
|
||||||
|
func (UnimplementedEntityServiceServer) GetState(context.Context, *GetStateRequest) (*GetStateResponse, error) {
|
||||||
|
return nil, status.Error(codes.Unimplemented, "method GetState not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedEntityServiceServer) ListStates(context.Context, *ListStatesRequest) (*ListStatesResponse, error) {
|
||||||
|
return nil, status.Error(codes.Unimplemented, "method ListStates not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedEntityServiceServer) mustEmbedUnimplementedEntityServiceServer() {}
|
||||||
|
func (UnimplementedEntityServiceServer) testEmbeddedByValue() {}
|
||||||
|
|
||||||
|
// UnsafeEntityServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||||
|
// Use of this interface is not recommended, as added methods to EntityServiceServer will
|
||||||
|
// result in compilation errors.
|
||||||
|
type UnsafeEntityServiceServer interface {
|
||||||
|
mustEmbedUnimplementedEntityServiceServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterEntityServiceServer(s grpc.ServiceRegistrar, srv EntityServiceServer) {
|
||||||
|
// If the following call panics, it indicates UnimplementedEntityServiceServer was
|
||||||
|
// embedded by pointer and is nil. This will cause panics if an
|
||||||
|
// unimplemented method is ever invoked, so we test this at initialization
|
||||||
|
// time to prevent it from happening at runtime later due to I/O.
|
||||||
|
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||||
|
t.testEmbeddedByValue()
|
||||||
|
}
|
||||||
|
s.RegisterService(&EntityService_ServiceDesc, srv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _EntityService_GetState_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(GetStateRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(EntityServiceServer).GetState(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: EntityService_GetState_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(EntityServiceServer).GetState(ctx, req.(*GetStateRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _EntityService_ListStates_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(ListStatesRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(EntityServiceServer).ListStates(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: EntityService_ListStates_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(EntityServiceServer).ListStates(ctx, req.(*ListStatesRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// EntityService_ServiceDesc is the grpc.ServiceDesc for EntityService service.
|
||||||
|
// It's only intended for direct use with grpc.RegisterService,
|
||||||
|
// and not to be introspected or modified (even as a copy)
|
||||||
|
var EntityService_ServiceDesc = grpc.ServiceDesc{
|
||||||
|
ServiceName: "ha.v1.EntityService",
|
||||||
|
HandlerType: (*EntityServiceServer)(nil),
|
||||||
|
Methods: []grpc.MethodDesc{
|
||||||
|
{
|
||||||
|
MethodName: "GetState",
|
||||||
|
Handler: _EntityService_GetState_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "ListStates",
|
||||||
|
Handler: _EntityService_ListStates_Handler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Streams: []grpc.StreamDesc{},
|
||||||
|
Metadata: "ha/v1/entity.proto",
|
||||||
|
}
|
||||||
218
gen/ha/v1/event.pb.go
Normal file
218
gen/ha/v1/event.pb.go
Normal file
@ -0,0 +1,218 @@
|
|||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// protoc-gen-go v1.36.11
|
||||||
|
// protoc (unknown)
|
||||||
|
// source: ha/v1/event.proto
|
||||||
|
|
||||||
|
package hav1
|
||||||
|
|
||||||
|
import (
|
||||||
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
reflect "reflect"
|
||||||
|
sync "sync"
|
||||||
|
unsafe "unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Verify that this generated code is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||||
|
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
|
)
|
||||||
|
|
||||||
|
type SubscribeRequest struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
EntityIds []string `protobuf:"bytes,1,rep,name=entity_ids,json=entityIds,proto3" json:"entity_ids,omitempty"`
|
||||||
|
Domains []string `protobuf:"bytes,2,rep,name=domains,proto3" json:"domains,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SubscribeRequest) Reset() {
|
||||||
|
*x = SubscribeRequest{}
|
||||||
|
mi := &file_ha_v1_event_proto_msgTypes[0]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SubscribeRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*SubscribeRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *SubscribeRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_ha_v1_event_proto_msgTypes[0]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use SubscribeRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*SubscribeRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_ha_v1_event_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SubscribeRequest) GetEntityIds() []string {
|
||||||
|
if x != nil {
|
||||||
|
return x.EntityIds
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SubscribeRequest) GetDomains() []string {
|
||||||
|
if x != nil {
|
||||||
|
return x.Domains
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type StateChangeEvent struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
EntityId string `protobuf:"bytes,1,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"`
|
||||||
|
OldState *EntityState `protobuf:"bytes,2,opt,name=old_state,json=oldState,proto3,oneof" json:"old_state,omitempty"` // absent on first appearance
|
||||||
|
NewState *EntityState `protobuf:"bytes,3,opt,name=new_state,json=newState,proto3" json:"new_state,omitempty"`
|
||||||
|
EventTime string `protobuf:"bytes,4,opt,name=event_time,json=eventTime,proto3" json:"event_time,omitempty"` // RFC3339
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *StateChangeEvent) Reset() {
|
||||||
|
*x = StateChangeEvent{}
|
||||||
|
mi := &file_ha_v1_event_proto_msgTypes[1]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *StateChangeEvent) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*StateChangeEvent) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *StateChangeEvent) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_ha_v1_event_proto_msgTypes[1]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use StateChangeEvent.ProtoReflect.Descriptor instead.
|
||||||
|
func (*StateChangeEvent) Descriptor() ([]byte, []int) {
|
||||||
|
return file_ha_v1_event_proto_rawDescGZIP(), []int{1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *StateChangeEvent) GetEntityId() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.EntityId
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *StateChangeEvent) GetOldState() *EntityState {
|
||||||
|
if x != nil {
|
||||||
|
return x.OldState
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *StateChangeEvent) GetNewState() *EntityState {
|
||||||
|
if x != nil {
|
||||||
|
return x.NewState
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *StateChangeEvent) GetEventTime() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.EventTime
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
var File_ha_v1_event_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
|
const file_ha_v1_event_proto_rawDesc = "" +
|
||||||
|
"\n" +
|
||||||
|
"\x11ha/v1/event.proto\x12\x05ha.v1\x1a\x12ha/v1/common.proto\"K\n" +
|
||||||
|
"\x10SubscribeRequest\x12\x1d\n" +
|
||||||
|
"\n" +
|
||||||
|
"entity_ids\x18\x01 \x03(\tR\tentityIds\x12\x18\n" +
|
||||||
|
"\adomains\x18\x02 \x03(\tR\adomains\"\xc3\x01\n" +
|
||||||
|
"\x10StateChangeEvent\x12\x1b\n" +
|
||||||
|
"\tentity_id\x18\x01 \x01(\tR\bentityId\x124\n" +
|
||||||
|
"\told_state\x18\x02 \x01(\v2\x12.ha.v1.EntityStateH\x00R\boldState\x88\x01\x01\x12/\n" +
|
||||||
|
"\tnew_state\x18\x03 \x01(\v2\x12.ha.v1.EntityStateR\bnewState\x12\x1d\n" +
|
||||||
|
"\n" +
|
||||||
|
"event_time\x18\x04 \x01(\tR\teventTimeB\f\n" +
|
||||||
|
"\n" +
|
||||||
|
"_old_state2O\n" +
|
||||||
|
"\fEventService\x12?\n" +
|
||||||
|
"\tSubscribe\x12\x17.ha.v1.SubscribeRequest\x1a\x17.ha.v1.StateChangeEvent0\x01B4Z2gitea.nik4nao.com/nik/home-services/gen/ha/v1;hav1b\x06proto3"
|
||||||
|
|
||||||
|
var (
|
||||||
|
file_ha_v1_event_proto_rawDescOnce sync.Once
|
||||||
|
file_ha_v1_event_proto_rawDescData []byte
|
||||||
|
)
|
||||||
|
|
||||||
|
func file_ha_v1_event_proto_rawDescGZIP() []byte {
|
||||||
|
file_ha_v1_event_proto_rawDescOnce.Do(func() {
|
||||||
|
file_ha_v1_event_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ha_v1_event_proto_rawDesc), len(file_ha_v1_event_proto_rawDesc)))
|
||||||
|
})
|
||||||
|
return file_ha_v1_event_proto_rawDescData
|
||||||
|
}
|
||||||
|
|
||||||
|
var file_ha_v1_event_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||||
|
var file_ha_v1_event_proto_goTypes = []any{
|
||||||
|
(*SubscribeRequest)(nil), // 0: ha.v1.SubscribeRequest
|
||||||
|
(*StateChangeEvent)(nil), // 1: ha.v1.StateChangeEvent
|
||||||
|
(*EntityState)(nil), // 2: ha.v1.EntityState
|
||||||
|
}
|
||||||
|
var file_ha_v1_event_proto_depIdxs = []int32{
|
||||||
|
2, // 0: ha.v1.StateChangeEvent.old_state:type_name -> ha.v1.EntityState
|
||||||
|
2, // 1: ha.v1.StateChangeEvent.new_state:type_name -> ha.v1.EntityState
|
||||||
|
0, // 2: ha.v1.EventService.Subscribe:input_type -> ha.v1.SubscribeRequest
|
||||||
|
1, // 3: ha.v1.EventService.Subscribe:output_type -> ha.v1.StateChangeEvent
|
||||||
|
3, // [3:4] is the sub-list for method output_type
|
||||||
|
2, // [2:3] is the sub-list for method input_type
|
||||||
|
2, // [2:2] is the sub-list for extension type_name
|
||||||
|
2, // [2:2] is the sub-list for extension extendee
|
||||||
|
0, // [0:2] is the sub-list for field type_name
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { file_ha_v1_event_proto_init() }
|
||||||
|
func file_ha_v1_event_proto_init() {
|
||||||
|
if File_ha_v1_event_proto != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
file_ha_v1_common_proto_init()
|
||||||
|
file_ha_v1_event_proto_msgTypes[1].OneofWrappers = []any{}
|
||||||
|
type x struct{}
|
||||||
|
out := protoimpl.TypeBuilder{
|
||||||
|
File: protoimpl.DescBuilder{
|
||||||
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
|
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ha_v1_event_proto_rawDesc), len(file_ha_v1_event_proto_rawDesc)),
|
||||||
|
NumEnums: 0,
|
||||||
|
NumMessages: 2,
|
||||||
|
NumExtensions: 0,
|
||||||
|
NumServices: 1,
|
||||||
|
},
|
||||||
|
GoTypes: file_ha_v1_event_proto_goTypes,
|
||||||
|
DependencyIndexes: file_ha_v1_event_proto_depIdxs,
|
||||||
|
MessageInfos: file_ha_v1_event_proto_msgTypes,
|
||||||
|
}.Build()
|
||||||
|
File_ha_v1_event_proto = out.File
|
||||||
|
file_ha_v1_event_proto_goTypes = nil
|
||||||
|
file_ha_v1_event_proto_depIdxs = nil
|
||||||
|
}
|
||||||
144
gen/ha/v1/event_grpc.pb.go
Normal file
144
gen/ha/v1/event_grpc.pb.go
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// - protoc-gen-go-grpc v1.6.1
|
||||||
|
// - protoc (unknown)
|
||||||
|
// source: ha/v1/event.proto
|
||||||
|
|
||||||
|
package hav1
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
grpc "google.golang.org/grpc"
|
||||||
|
codes "google.golang.org/grpc/codes"
|
||||||
|
status "google.golang.org/grpc/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the grpc package it is being compiled against.
|
||||||
|
// Requires gRPC-Go v1.64.0 or later.
|
||||||
|
const _ = grpc.SupportPackageIsVersion9
|
||||||
|
|
||||||
|
const (
|
||||||
|
EventService_Subscribe_FullMethodName = "/ha.v1.EventService/Subscribe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// EventServiceClient is the client API for EventService service.
|
||||||
|
//
|
||||||
|
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||||
|
//
|
||||||
|
// TODO: implement EventService fan-out.
|
||||||
|
// Architecture:
|
||||||
|
// 1. adapters/secondary/ha/websocket.go connects to HA WebSocket,
|
||||||
|
// authenticates, and subscribes to state_changed events.
|
||||||
|
// 2. An internal broker (internal/fanout/broker.go) holds a sync.Map of
|
||||||
|
// subscriber channels, one per active Subscribe stream.
|
||||||
|
// 3. The WebSocket adapter publishes to the broker; the gRPC Subscribe
|
||||||
|
// handler reads from its channel and streams to the client.
|
||||||
|
// 4. On client disconnect (ctx.Done()), the handler deregisters its channel.
|
||||||
|
type EventServiceClient interface {
|
||||||
|
Subscribe(ctx context.Context, in *SubscribeRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[StateChangeEvent], error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type eventServiceClient struct {
|
||||||
|
cc grpc.ClientConnInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEventServiceClient(cc grpc.ClientConnInterface) EventServiceClient {
|
||||||
|
return &eventServiceClient{cc}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *eventServiceClient) Subscribe(ctx context.Context, in *SubscribeRequest, opts ...grpc.CallOption) (grpc.ServerStreamingClient[StateChangeEvent], error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
stream, err := c.cc.NewStream(ctx, &EventService_ServiceDesc.Streams[0], EventService_Subscribe_FullMethodName, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
x := &grpc.GenericClientStream[SubscribeRequest, StateChangeEvent]{ClientStream: stream}
|
||||||
|
if err := x.ClientStream.SendMsg(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if err := x.ClientStream.CloseSend(); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return x, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||||
|
type EventService_SubscribeClient = grpc.ServerStreamingClient[StateChangeEvent]
|
||||||
|
|
||||||
|
// EventServiceServer is the server API for EventService service.
|
||||||
|
// All implementations must embed UnimplementedEventServiceServer
|
||||||
|
// for forward compatibility.
|
||||||
|
//
|
||||||
|
// TODO: implement EventService fan-out.
|
||||||
|
// Architecture:
|
||||||
|
// 1. adapters/secondary/ha/websocket.go connects to HA WebSocket,
|
||||||
|
// authenticates, and subscribes to state_changed events.
|
||||||
|
// 2. An internal broker (internal/fanout/broker.go) holds a sync.Map of
|
||||||
|
// subscriber channels, one per active Subscribe stream.
|
||||||
|
// 3. The WebSocket adapter publishes to the broker; the gRPC Subscribe
|
||||||
|
// handler reads from its channel and streams to the client.
|
||||||
|
// 4. On client disconnect (ctx.Done()), the handler deregisters its channel.
|
||||||
|
type EventServiceServer interface {
|
||||||
|
Subscribe(*SubscribeRequest, grpc.ServerStreamingServer[StateChangeEvent]) error
|
||||||
|
mustEmbedUnimplementedEventServiceServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnimplementedEventServiceServer must be embedded to have
|
||||||
|
// forward compatible implementations.
|
||||||
|
//
|
||||||
|
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
||||||
|
// pointer dereference when methods are called.
|
||||||
|
type UnimplementedEventServiceServer struct{}
|
||||||
|
|
||||||
|
func (UnimplementedEventServiceServer) Subscribe(*SubscribeRequest, grpc.ServerStreamingServer[StateChangeEvent]) error {
|
||||||
|
return status.Error(codes.Unimplemented, "method Subscribe not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedEventServiceServer) mustEmbedUnimplementedEventServiceServer() {}
|
||||||
|
func (UnimplementedEventServiceServer) testEmbeddedByValue() {}
|
||||||
|
|
||||||
|
// UnsafeEventServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||||
|
// Use of this interface is not recommended, as added methods to EventServiceServer will
|
||||||
|
// result in compilation errors.
|
||||||
|
type UnsafeEventServiceServer interface {
|
||||||
|
mustEmbedUnimplementedEventServiceServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterEventServiceServer(s grpc.ServiceRegistrar, srv EventServiceServer) {
|
||||||
|
// If the following call panics, it indicates UnimplementedEventServiceServer was
|
||||||
|
// embedded by pointer and is nil. This will cause panics if an
|
||||||
|
// unimplemented method is ever invoked, so we test this at initialization
|
||||||
|
// time to prevent it from happening at runtime later due to I/O.
|
||||||
|
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||||
|
t.testEmbeddedByValue()
|
||||||
|
}
|
||||||
|
s.RegisterService(&EventService_ServiceDesc, srv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _EventService_Subscribe_Handler(srv interface{}, stream grpc.ServerStream) error {
|
||||||
|
m := new(SubscribeRequest)
|
||||||
|
if err := stream.RecvMsg(m); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return srv.(EventServiceServer).Subscribe(m, &grpc.GenericServerStream[SubscribeRequest, StateChangeEvent]{ServerStream: stream})
|
||||||
|
}
|
||||||
|
|
||||||
|
// This type alias is provided for backwards compatibility with existing code that references the prior non-generic stream type by name.
|
||||||
|
type EventService_SubscribeServer = grpc.ServerStreamingServer[StateChangeEvent]
|
||||||
|
|
||||||
|
// EventService_ServiceDesc is the grpc.ServiceDesc for EventService service.
|
||||||
|
// It's only intended for direct use with grpc.RegisterService,
|
||||||
|
// and not to be introspected or modified (even as a copy)
|
||||||
|
var EventService_ServiceDesc = grpc.ServiceDesc{
|
||||||
|
ServiceName: "ha.v1.EventService",
|
||||||
|
HandlerType: (*EventServiceServer)(nil),
|
||||||
|
Methods: []grpc.MethodDesc{},
|
||||||
|
Streams: []grpc.StreamDesc{
|
||||||
|
{
|
||||||
|
StreamName: "Subscribe",
|
||||||
|
Handler: _EventService_Subscribe_Handler,
|
||||||
|
ServerStreams: true,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Metadata: "ha/v1/event.proto",
|
||||||
|
}
|
||||||
338
gen/ha/v1/light.pb.go
Normal file
338
gen/ha/v1/light.pb.go
Normal file
@ -0,0 +1,338 @@
|
|||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// protoc-gen-go v1.36.11
|
||||||
|
// protoc (unknown)
|
||||||
|
// source: ha/v1/light.proto
|
||||||
|
|
||||||
|
package hav1
|
||||||
|
|
||||||
|
import (
|
||||||
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
reflect "reflect"
|
||||||
|
sync "sync"
|
||||||
|
unsafe "unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Verify that this generated code is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||||
|
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
|
)
|
||||||
|
|
||||||
|
// optional fields require protobuf 3.15+ / buf >= 1.0. They generate
|
||||||
|
// pointer fields in Go with Has*() accessor methods. This is intentional —
|
||||||
|
// it lets the gateway distinguish "brightness not set" from "brightness = 0".
|
||||||
|
type TurnOnRequest struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
EntityId string `protobuf:"bytes,1,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"`
|
||||||
|
BrightnessPct *uint32 `protobuf:"varint,2,opt,name=brightness_pct,json=brightnessPct,proto3,oneof" json:"brightness_pct,omitempty"` // 0–100
|
||||||
|
ColorTempKelvin *uint32 `protobuf:"varint,3,opt,name=color_temp_kelvin,json=colorTempKelvin,proto3,oneof" json:"color_temp_kelvin,omitempty"` // e.g. 2700–6500
|
||||||
|
RgbColor *RGBColor `protobuf:"bytes,4,opt,name=rgb_color,json=rgbColor,proto3,oneof" json:"rgb_color,omitempty"` // ignored if color_temp_kelvin set
|
||||||
|
Transition *uint32 `protobuf:"varint,5,opt,name=transition,proto3,oneof" json:"transition,omitempty"` // seconds
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *TurnOnRequest) Reset() {
|
||||||
|
*x = TurnOnRequest{}
|
||||||
|
mi := &file_ha_v1_light_proto_msgTypes[0]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *TurnOnRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*TurnOnRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *TurnOnRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_ha_v1_light_proto_msgTypes[0]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use TurnOnRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*TurnOnRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_ha_v1_light_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *TurnOnRequest) GetEntityId() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.EntityId
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *TurnOnRequest) GetBrightnessPct() uint32 {
|
||||||
|
if x != nil && x.BrightnessPct != nil {
|
||||||
|
return *x.BrightnessPct
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *TurnOnRequest) GetColorTempKelvin() uint32 {
|
||||||
|
if x != nil && x.ColorTempKelvin != nil {
|
||||||
|
return *x.ColorTempKelvin
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *TurnOnRequest) GetRgbColor() *RGBColor {
|
||||||
|
if x != nil {
|
||||||
|
return x.RgbColor
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *TurnOnRequest) GetTransition() uint32 {
|
||||||
|
if x != nil && x.Transition != nil {
|
||||||
|
return *x.Transition
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type TurnOffRequest struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
EntityId string `protobuf:"bytes,1,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"`
|
||||||
|
Transition *uint32 `protobuf:"varint,2,opt,name=transition,proto3,oneof" json:"transition,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *TurnOffRequest) Reset() {
|
||||||
|
*x = TurnOffRequest{}
|
||||||
|
mi := &file_ha_v1_light_proto_msgTypes[1]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *TurnOffRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*TurnOffRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *TurnOffRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_ha_v1_light_proto_msgTypes[1]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use TurnOffRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*TurnOffRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_ha_v1_light_proto_rawDescGZIP(), []int{1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *TurnOffRequest) GetEntityId() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.EntityId
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *TurnOffRequest) GetTransition() uint32 {
|
||||||
|
if x != nil && x.Transition != nil {
|
||||||
|
return *x.Transition
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
||||||
|
type ToggleRequest struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
EntityId string `protobuf:"bytes,1,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ToggleRequest) Reset() {
|
||||||
|
*x = ToggleRequest{}
|
||||||
|
mi := &file_ha_v1_light_proto_msgTypes[2]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ToggleRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*ToggleRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *ToggleRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_ha_v1_light_proto_msgTypes[2]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use ToggleRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*ToggleRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_ha_v1_light_proto_rawDescGZIP(), []int{2}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *ToggleRequest) GetEntityId() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.EntityId
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type LightResponse struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
State *EntityState `protobuf:"bytes,1,opt,name=state,proto3" json:"state,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *LightResponse) Reset() {
|
||||||
|
*x = LightResponse{}
|
||||||
|
mi := &file_ha_v1_light_proto_msgTypes[3]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *LightResponse) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*LightResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *LightResponse) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_ha_v1_light_proto_msgTypes[3]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use LightResponse.ProtoReflect.Descriptor instead.
|
||||||
|
func (*LightResponse) Descriptor() ([]byte, []int) {
|
||||||
|
return file_ha_v1_light_proto_rawDescGZIP(), []int{3}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *LightResponse) GetState() *EntityState {
|
||||||
|
if x != nil {
|
||||||
|
return x.State
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var File_ha_v1_light_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
|
const file_ha_v1_light_proto_rawDesc = "" +
|
||||||
|
"\n" +
|
||||||
|
"\x11ha/v1/light.proto\x12\x05ha.v1\x1a\x12ha/v1/common.proto\"\xa7\x02\n" +
|
||||||
|
"\rTurnOnRequest\x12\x1b\n" +
|
||||||
|
"\tentity_id\x18\x01 \x01(\tR\bentityId\x12*\n" +
|
||||||
|
"\x0ebrightness_pct\x18\x02 \x01(\rH\x00R\rbrightnessPct\x88\x01\x01\x12/\n" +
|
||||||
|
"\x11color_temp_kelvin\x18\x03 \x01(\rH\x01R\x0fcolorTempKelvin\x88\x01\x01\x121\n" +
|
||||||
|
"\trgb_color\x18\x04 \x01(\v2\x0f.ha.v1.RGBColorH\x02R\brgbColor\x88\x01\x01\x12#\n" +
|
||||||
|
"\n" +
|
||||||
|
"transition\x18\x05 \x01(\rH\x03R\n" +
|
||||||
|
"transition\x88\x01\x01B\x11\n" +
|
||||||
|
"\x0f_brightness_pctB\x14\n" +
|
||||||
|
"\x12_color_temp_kelvinB\f\n" +
|
||||||
|
"\n" +
|
||||||
|
"_rgb_colorB\r\n" +
|
||||||
|
"\v_transition\"a\n" +
|
||||||
|
"\x0eTurnOffRequest\x12\x1b\n" +
|
||||||
|
"\tentity_id\x18\x01 \x01(\tR\bentityId\x12#\n" +
|
||||||
|
"\n" +
|
||||||
|
"transition\x18\x02 \x01(\rH\x00R\n" +
|
||||||
|
"transition\x88\x01\x01B\r\n" +
|
||||||
|
"\v_transition\",\n" +
|
||||||
|
"\rToggleRequest\x12\x1b\n" +
|
||||||
|
"\tentity_id\x18\x01 \x01(\tR\bentityId\"9\n" +
|
||||||
|
"\rLightResponse\x12(\n" +
|
||||||
|
"\x05state\x18\x01 \x01(\v2\x12.ha.v1.EntityStateR\x05state2\xb2\x01\n" +
|
||||||
|
"\fLightService\x124\n" +
|
||||||
|
"\x06TurnOn\x12\x14.ha.v1.TurnOnRequest\x1a\x14.ha.v1.LightResponse\x126\n" +
|
||||||
|
"\aTurnOff\x12\x15.ha.v1.TurnOffRequest\x1a\x14.ha.v1.LightResponse\x124\n" +
|
||||||
|
"\x06Toggle\x12\x14.ha.v1.ToggleRequest\x1a\x14.ha.v1.LightResponseB4Z2gitea.nik4nao.com/nik/home-services/gen/ha/v1;hav1b\x06proto3"
|
||||||
|
|
||||||
|
var (
|
||||||
|
file_ha_v1_light_proto_rawDescOnce sync.Once
|
||||||
|
file_ha_v1_light_proto_rawDescData []byte
|
||||||
|
)
|
||||||
|
|
||||||
|
func file_ha_v1_light_proto_rawDescGZIP() []byte {
|
||||||
|
file_ha_v1_light_proto_rawDescOnce.Do(func() {
|
||||||
|
file_ha_v1_light_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ha_v1_light_proto_rawDesc), len(file_ha_v1_light_proto_rawDesc)))
|
||||||
|
})
|
||||||
|
return file_ha_v1_light_proto_rawDescData
|
||||||
|
}
|
||||||
|
|
||||||
|
var file_ha_v1_light_proto_msgTypes = make([]protoimpl.MessageInfo, 4)
|
||||||
|
var file_ha_v1_light_proto_goTypes = []any{
|
||||||
|
(*TurnOnRequest)(nil), // 0: ha.v1.TurnOnRequest
|
||||||
|
(*TurnOffRequest)(nil), // 1: ha.v1.TurnOffRequest
|
||||||
|
(*ToggleRequest)(nil), // 2: ha.v1.ToggleRequest
|
||||||
|
(*LightResponse)(nil), // 3: ha.v1.LightResponse
|
||||||
|
(*RGBColor)(nil), // 4: ha.v1.RGBColor
|
||||||
|
(*EntityState)(nil), // 5: ha.v1.EntityState
|
||||||
|
}
|
||||||
|
var file_ha_v1_light_proto_depIdxs = []int32{
|
||||||
|
4, // 0: ha.v1.TurnOnRequest.rgb_color:type_name -> ha.v1.RGBColor
|
||||||
|
5, // 1: ha.v1.LightResponse.state:type_name -> ha.v1.EntityState
|
||||||
|
0, // 2: ha.v1.LightService.TurnOn:input_type -> ha.v1.TurnOnRequest
|
||||||
|
1, // 3: ha.v1.LightService.TurnOff:input_type -> ha.v1.TurnOffRequest
|
||||||
|
2, // 4: ha.v1.LightService.Toggle:input_type -> ha.v1.ToggleRequest
|
||||||
|
3, // 5: ha.v1.LightService.TurnOn:output_type -> ha.v1.LightResponse
|
||||||
|
3, // 6: ha.v1.LightService.TurnOff:output_type -> ha.v1.LightResponse
|
||||||
|
3, // 7: ha.v1.LightService.Toggle:output_type -> ha.v1.LightResponse
|
||||||
|
5, // [5:8] is the sub-list for method output_type
|
||||||
|
2, // [2:5] is the sub-list for method input_type
|
||||||
|
2, // [2:2] is the sub-list for extension type_name
|
||||||
|
2, // [2:2] is the sub-list for extension extendee
|
||||||
|
0, // [0:2] is the sub-list for field type_name
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { file_ha_v1_light_proto_init() }
|
||||||
|
func file_ha_v1_light_proto_init() {
|
||||||
|
if File_ha_v1_light_proto != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
file_ha_v1_common_proto_init()
|
||||||
|
file_ha_v1_light_proto_msgTypes[0].OneofWrappers = []any{}
|
||||||
|
file_ha_v1_light_proto_msgTypes[1].OneofWrappers = []any{}
|
||||||
|
type x struct{}
|
||||||
|
out := protoimpl.TypeBuilder{
|
||||||
|
File: protoimpl.DescBuilder{
|
||||||
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
|
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ha_v1_light_proto_rawDesc), len(file_ha_v1_light_proto_rawDesc)),
|
||||||
|
NumEnums: 0,
|
||||||
|
NumMessages: 4,
|
||||||
|
NumExtensions: 0,
|
||||||
|
NumServices: 1,
|
||||||
|
},
|
||||||
|
GoTypes: file_ha_v1_light_proto_goTypes,
|
||||||
|
DependencyIndexes: file_ha_v1_light_proto_depIdxs,
|
||||||
|
MessageInfos: file_ha_v1_light_proto_msgTypes,
|
||||||
|
}.Build()
|
||||||
|
File_ha_v1_light_proto = out.File
|
||||||
|
file_ha_v1_light_proto_goTypes = nil
|
||||||
|
file_ha_v1_light_proto_depIdxs = nil
|
||||||
|
}
|
||||||
197
gen/ha/v1/light_grpc.pb.go
Normal file
197
gen/ha/v1/light_grpc.pb.go
Normal file
@ -0,0 +1,197 @@
|
|||||||
|
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// - protoc-gen-go-grpc v1.6.1
|
||||||
|
// - protoc (unknown)
|
||||||
|
// source: ha/v1/light.proto
|
||||||
|
|
||||||
|
package hav1
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
grpc "google.golang.org/grpc"
|
||||||
|
codes "google.golang.org/grpc/codes"
|
||||||
|
status "google.golang.org/grpc/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the grpc package it is being compiled against.
|
||||||
|
// Requires gRPC-Go v1.64.0 or later.
|
||||||
|
const _ = grpc.SupportPackageIsVersion9
|
||||||
|
|
||||||
|
const (
|
||||||
|
LightService_TurnOn_FullMethodName = "/ha.v1.LightService/TurnOn"
|
||||||
|
LightService_TurnOff_FullMethodName = "/ha.v1.LightService/TurnOff"
|
||||||
|
LightService_Toggle_FullMethodName = "/ha.v1.LightService/Toggle"
|
||||||
|
)
|
||||||
|
|
||||||
|
// LightServiceClient is the client API for LightService service.
|
||||||
|
//
|
||||||
|
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||||
|
type LightServiceClient interface {
|
||||||
|
TurnOn(ctx context.Context, in *TurnOnRequest, opts ...grpc.CallOption) (*LightResponse, error)
|
||||||
|
TurnOff(ctx context.Context, in *TurnOffRequest, opts ...grpc.CallOption) (*LightResponse, error)
|
||||||
|
Toggle(ctx context.Context, in *ToggleRequest, opts ...grpc.CallOption) (*LightResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type lightServiceClient struct {
|
||||||
|
cc grpc.ClientConnInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLightServiceClient(cc grpc.ClientConnInterface) LightServiceClient {
|
||||||
|
return &lightServiceClient{cc}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *lightServiceClient) TurnOn(ctx context.Context, in *TurnOnRequest, opts ...grpc.CallOption) (*LightResponse, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(LightResponse)
|
||||||
|
err := c.cc.Invoke(ctx, LightService_TurnOn_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *lightServiceClient) TurnOff(ctx context.Context, in *TurnOffRequest, opts ...grpc.CallOption) (*LightResponse, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(LightResponse)
|
||||||
|
err := c.cc.Invoke(ctx, LightService_TurnOff_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *lightServiceClient) Toggle(ctx context.Context, in *ToggleRequest, opts ...grpc.CallOption) (*LightResponse, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(LightResponse)
|
||||||
|
err := c.cc.Invoke(ctx, LightService_Toggle_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// LightServiceServer is the server API for LightService service.
|
||||||
|
// All implementations must embed UnimplementedLightServiceServer
|
||||||
|
// for forward compatibility.
|
||||||
|
type LightServiceServer interface {
|
||||||
|
TurnOn(context.Context, *TurnOnRequest) (*LightResponse, error)
|
||||||
|
TurnOff(context.Context, *TurnOffRequest) (*LightResponse, error)
|
||||||
|
Toggle(context.Context, *ToggleRequest) (*LightResponse, error)
|
||||||
|
mustEmbedUnimplementedLightServiceServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnimplementedLightServiceServer must be embedded to have
|
||||||
|
// forward compatible implementations.
|
||||||
|
//
|
||||||
|
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
||||||
|
// pointer dereference when methods are called.
|
||||||
|
type UnimplementedLightServiceServer struct{}
|
||||||
|
|
||||||
|
func (UnimplementedLightServiceServer) TurnOn(context.Context, *TurnOnRequest) (*LightResponse, error) {
|
||||||
|
return nil, status.Error(codes.Unimplemented, "method TurnOn not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedLightServiceServer) TurnOff(context.Context, *TurnOffRequest) (*LightResponse, error) {
|
||||||
|
return nil, status.Error(codes.Unimplemented, "method TurnOff not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedLightServiceServer) Toggle(context.Context, *ToggleRequest) (*LightResponse, error) {
|
||||||
|
return nil, status.Error(codes.Unimplemented, "method Toggle not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedLightServiceServer) mustEmbedUnimplementedLightServiceServer() {}
|
||||||
|
func (UnimplementedLightServiceServer) testEmbeddedByValue() {}
|
||||||
|
|
||||||
|
// UnsafeLightServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||||
|
// Use of this interface is not recommended, as added methods to LightServiceServer will
|
||||||
|
// result in compilation errors.
|
||||||
|
type UnsafeLightServiceServer interface {
|
||||||
|
mustEmbedUnimplementedLightServiceServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterLightServiceServer(s grpc.ServiceRegistrar, srv LightServiceServer) {
|
||||||
|
// If the following call panics, it indicates UnimplementedLightServiceServer was
|
||||||
|
// embedded by pointer and is nil. This will cause panics if an
|
||||||
|
// unimplemented method is ever invoked, so we test this at initialization
|
||||||
|
// time to prevent it from happening at runtime later due to I/O.
|
||||||
|
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||||
|
t.testEmbeddedByValue()
|
||||||
|
}
|
||||||
|
s.RegisterService(&LightService_ServiceDesc, srv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _LightService_TurnOn_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(TurnOnRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(LightServiceServer).TurnOn(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: LightService_TurnOn_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(LightServiceServer).TurnOn(ctx, req.(*TurnOnRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _LightService_TurnOff_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(TurnOffRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(LightServiceServer).TurnOff(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: LightService_TurnOff_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(LightServiceServer).TurnOff(ctx, req.(*TurnOffRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _LightService_Toggle_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(ToggleRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(LightServiceServer).Toggle(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: LightService_Toggle_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(LightServiceServer).Toggle(ctx, req.(*ToggleRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// LightService_ServiceDesc is the grpc.ServiceDesc for LightService service.
|
||||||
|
// It's only intended for direct use with grpc.RegisterService,
|
||||||
|
// and not to be introspected or modified (even as a copy)
|
||||||
|
var LightService_ServiceDesc = grpc.ServiceDesc{
|
||||||
|
ServiceName: "ha.v1.LightService",
|
||||||
|
HandlerType: (*LightServiceServer)(nil),
|
||||||
|
Methods: []grpc.MethodDesc{
|
||||||
|
{
|
||||||
|
MethodName: "TurnOn",
|
||||||
|
Handler: _LightService_TurnOn_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "TurnOff",
|
||||||
|
Handler: _LightService_TurnOff_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "Toggle",
|
||||||
|
Handler: _LightService_Toggle_Handler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Streams: []grpc.StreamDesc{},
|
||||||
|
Metadata: "ha/v1/light.proto",
|
||||||
|
}
|
||||||
182
gen/ha/v1/switch.pb.go
Normal file
182
gen/ha/v1/switch.pb.go
Normal file
@ -0,0 +1,182 @@
|
|||||||
|
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// protoc-gen-go v1.36.11
|
||||||
|
// protoc (unknown)
|
||||||
|
// source: ha/v1/switch.proto
|
||||||
|
|
||||||
|
package hav1
|
||||||
|
|
||||||
|
import (
|
||||||
|
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||||
|
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||||
|
reflect "reflect"
|
||||||
|
sync "sync"
|
||||||
|
unsafe "unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
// Verify that this generated code is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||||
|
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||||
|
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||||
|
)
|
||||||
|
|
||||||
|
type SwitchRequest struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
EntityId string `protobuf:"bytes,1,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SwitchRequest) Reset() {
|
||||||
|
*x = SwitchRequest{}
|
||||||
|
mi := &file_ha_v1_switch_proto_msgTypes[0]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SwitchRequest) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*SwitchRequest) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *SwitchRequest) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_ha_v1_switch_proto_msgTypes[0]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use SwitchRequest.ProtoReflect.Descriptor instead.
|
||||||
|
func (*SwitchRequest) Descriptor() ([]byte, []int) {
|
||||||
|
return file_ha_v1_switch_proto_rawDescGZIP(), []int{0}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SwitchRequest) GetEntityId() string {
|
||||||
|
if x != nil {
|
||||||
|
return x.EntityId
|
||||||
|
}
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
|
||||||
|
type SwitchResponse struct {
|
||||||
|
state protoimpl.MessageState `protogen:"open.v1"`
|
||||||
|
State *EntityState `protobuf:"bytes,1,opt,name=state,proto3" json:"state,omitempty"`
|
||||||
|
unknownFields protoimpl.UnknownFields
|
||||||
|
sizeCache protoimpl.SizeCache
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SwitchResponse) Reset() {
|
||||||
|
*x = SwitchResponse{}
|
||||||
|
mi := &file_ha_v1_switch_proto_msgTypes[1]
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SwitchResponse) String() string {
|
||||||
|
return protoimpl.X.MessageStringOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (*SwitchResponse) ProtoMessage() {}
|
||||||
|
|
||||||
|
func (x *SwitchResponse) ProtoReflect() protoreflect.Message {
|
||||||
|
mi := &file_ha_v1_switch_proto_msgTypes[1]
|
||||||
|
if x != nil {
|
||||||
|
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||||
|
if ms.LoadMessageInfo() == nil {
|
||||||
|
ms.StoreMessageInfo(mi)
|
||||||
|
}
|
||||||
|
return ms
|
||||||
|
}
|
||||||
|
return mi.MessageOf(x)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Deprecated: Use SwitchResponse.ProtoReflect.Descriptor instead.
|
||||||
|
func (*SwitchResponse) Descriptor() ([]byte, []int) {
|
||||||
|
return file_ha_v1_switch_proto_rawDescGZIP(), []int{1}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (x *SwitchResponse) GetState() *EntityState {
|
||||||
|
if x != nil {
|
||||||
|
return x.State
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var File_ha_v1_switch_proto protoreflect.FileDescriptor
|
||||||
|
|
||||||
|
const file_ha_v1_switch_proto_rawDesc = "" +
|
||||||
|
"\n" +
|
||||||
|
"\x12ha/v1/switch.proto\x12\x05ha.v1\x1a\x12ha/v1/common.proto\",\n" +
|
||||||
|
"\rSwitchRequest\x12\x1b\n" +
|
||||||
|
"\tentity_id\x18\x01 \x01(\tR\bentityId\":\n" +
|
||||||
|
"\x0eSwitchResponse\x12(\n" +
|
||||||
|
"\x05state\x18\x01 \x01(\v2\x12.ha.v1.EntityStateR\x05state2\xb5\x01\n" +
|
||||||
|
"\rSwitchService\x125\n" +
|
||||||
|
"\x06TurnOn\x12\x14.ha.v1.SwitchRequest\x1a\x15.ha.v1.SwitchResponse\x126\n" +
|
||||||
|
"\aTurnOff\x12\x14.ha.v1.SwitchRequest\x1a\x15.ha.v1.SwitchResponse\x125\n" +
|
||||||
|
"\x06Toggle\x12\x14.ha.v1.SwitchRequest\x1a\x15.ha.v1.SwitchResponseB4Z2gitea.nik4nao.com/nik/home-services/gen/ha/v1;hav1b\x06proto3"
|
||||||
|
|
||||||
|
var (
|
||||||
|
file_ha_v1_switch_proto_rawDescOnce sync.Once
|
||||||
|
file_ha_v1_switch_proto_rawDescData []byte
|
||||||
|
)
|
||||||
|
|
||||||
|
func file_ha_v1_switch_proto_rawDescGZIP() []byte {
|
||||||
|
file_ha_v1_switch_proto_rawDescOnce.Do(func() {
|
||||||
|
file_ha_v1_switch_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_ha_v1_switch_proto_rawDesc), len(file_ha_v1_switch_proto_rawDesc)))
|
||||||
|
})
|
||||||
|
return file_ha_v1_switch_proto_rawDescData
|
||||||
|
}
|
||||||
|
|
||||||
|
var file_ha_v1_switch_proto_msgTypes = make([]protoimpl.MessageInfo, 2)
|
||||||
|
var file_ha_v1_switch_proto_goTypes = []any{
|
||||||
|
(*SwitchRequest)(nil), // 0: ha.v1.SwitchRequest
|
||||||
|
(*SwitchResponse)(nil), // 1: ha.v1.SwitchResponse
|
||||||
|
(*EntityState)(nil), // 2: ha.v1.EntityState
|
||||||
|
}
|
||||||
|
var file_ha_v1_switch_proto_depIdxs = []int32{
|
||||||
|
2, // 0: ha.v1.SwitchResponse.state:type_name -> ha.v1.EntityState
|
||||||
|
0, // 1: ha.v1.SwitchService.TurnOn:input_type -> ha.v1.SwitchRequest
|
||||||
|
0, // 2: ha.v1.SwitchService.TurnOff:input_type -> ha.v1.SwitchRequest
|
||||||
|
0, // 3: ha.v1.SwitchService.Toggle:input_type -> ha.v1.SwitchRequest
|
||||||
|
1, // 4: ha.v1.SwitchService.TurnOn:output_type -> ha.v1.SwitchResponse
|
||||||
|
1, // 5: ha.v1.SwitchService.TurnOff:output_type -> ha.v1.SwitchResponse
|
||||||
|
1, // 6: ha.v1.SwitchService.Toggle:output_type -> ha.v1.SwitchResponse
|
||||||
|
4, // [4:7] is the sub-list for method output_type
|
||||||
|
1, // [1:4] is the sub-list for method input_type
|
||||||
|
1, // [1:1] is the sub-list for extension type_name
|
||||||
|
1, // [1:1] is the sub-list for extension extendee
|
||||||
|
0, // [0:1] is the sub-list for field type_name
|
||||||
|
}
|
||||||
|
|
||||||
|
func init() { file_ha_v1_switch_proto_init() }
|
||||||
|
func file_ha_v1_switch_proto_init() {
|
||||||
|
if File_ha_v1_switch_proto != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
file_ha_v1_common_proto_init()
|
||||||
|
type x struct{}
|
||||||
|
out := protoimpl.TypeBuilder{
|
||||||
|
File: protoimpl.DescBuilder{
|
||||||
|
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||||
|
RawDescriptor: unsafe.Slice(unsafe.StringData(file_ha_v1_switch_proto_rawDesc), len(file_ha_v1_switch_proto_rawDesc)),
|
||||||
|
NumEnums: 0,
|
||||||
|
NumMessages: 2,
|
||||||
|
NumExtensions: 0,
|
||||||
|
NumServices: 1,
|
||||||
|
},
|
||||||
|
GoTypes: file_ha_v1_switch_proto_goTypes,
|
||||||
|
DependencyIndexes: file_ha_v1_switch_proto_depIdxs,
|
||||||
|
MessageInfos: file_ha_v1_switch_proto_msgTypes,
|
||||||
|
}.Build()
|
||||||
|
File_ha_v1_switch_proto = out.File
|
||||||
|
file_ha_v1_switch_proto_goTypes = nil
|
||||||
|
file_ha_v1_switch_proto_depIdxs = nil
|
||||||
|
}
|
||||||
209
gen/ha/v1/switch_grpc.pb.go
Normal file
209
gen/ha/v1/switch_grpc.pb.go
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||||
|
// versions:
|
||||||
|
// - protoc-gen-go-grpc v1.6.1
|
||||||
|
// - protoc (unknown)
|
||||||
|
// source: ha/v1/switch.proto
|
||||||
|
|
||||||
|
package hav1
|
||||||
|
|
||||||
|
import (
|
||||||
|
context "context"
|
||||||
|
grpc "google.golang.org/grpc"
|
||||||
|
codes "google.golang.org/grpc/codes"
|
||||||
|
status "google.golang.org/grpc/status"
|
||||||
|
)
|
||||||
|
|
||||||
|
// This is a compile-time assertion to ensure that this generated file
|
||||||
|
// is compatible with the grpc package it is being compiled against.
|
||||||
|
// Requires gRPC-Go v1.64.0 or later.
|
||||||
|
const _ = grpc.SupportPackageIsVersion9
|
||||||
|
|
||||||
|
const (
|
||||||
|
SwitchService_TurnOn_FullMethodName = "/ha.v1.SwitchService/TurnOn"
|
||||||
|
SwitchService_TurnOff_FullMethodName = "/ha.v1.SwitchService/TurnOff"
|
||||||
|
SwitchService_Toggle_FullMethodName = "/ha.v1.SwitchService/Toggle"
|
||||||
|
)
|
||||||
|
|
||||||
|
// SwitchServiceClient is the client API for SwitchService service.
|
||||||
|
//
|
||||||
|
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||||
|
//
|
||||||
|
// TODO: implement SwitchService. Follow the same pattern as LightService:
|
||||||
|
// - domain type in core/domain/switch.go
|
||||||
|
// - port interface in core/ports/driving/switch.go
|
||||||
|
// - application logic in app/switch.go
|
||||||
|
// - gRPC adapter in adapters/primary/grpc/switch.go
|
||||||
|
type SwitchServiceClient interface {
|
||||||
|
TurnOn(ctx context.Context, in *SwitchRequest, opts ...grpc.CallOption) (*SwitchResponse, error)
|
||||||
|
TurnOff(ctx context.Context, in *SwitchRequest, opts ...grpc.CallOption) (*SwitchResponse, error)
|
||||||
|
Toggle(ctx context.Context, in *SwitchRequest, opts ...grpc.CallOption) (*SwitchResponse, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
type switchServiceClient struct {
|
||||||
|
cc grpc.ClientConnInterface
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewSwitchServiceClient(cc grpc.ClientConnInterface) SwitchServiceClient {
|
||||||
|
return &switchServiceClient{cc}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *switchServiceClient) TurnOn(ctx context.Context, in *SwitchRequest, opts ...grpc.CallOption) (*SwitchResponse, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(SwitchResponse)
|
||||||
|
err := c.cc.Invoke(ctx, SwitchService_TurnOn_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *switchServiceClient) TurnOff(ctx context.Context, in *SwitchRequest, opts ...grpc.CallOption) (*SwitchResponse, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(SwitchResponse)
|
||||||
|
err := c.cc.Invoke(ctx, SwitchService_TurnOff_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *switchServiceClient) Toggle(ctx context.Context, in *SwitchRequest, opts ...grpc.CallOption) (*SwitchResponse, error) {
|
||||||
|
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||||
|
out := new(SwitchResponse)
|
||||||
|
err := c.cc.Invoke(ctx, SwitchService_Toggle_FullMethodName, in, out, cOpts...)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SwitchServiceServer is the server API for SwitchService service.
|
||||||
|
// All implementations must embed UnimplementedSwitchServiceServer
|
||||||
|
// for forward compatibility.
|
||||||
|
//
|
||||||
|
// TODO: implement SwitchService. Follow the same pattern as LightService:
|
||||||
|
// - domain type in core/domain/switch.go
|
||||||
|
// - port interface in core/ports/driving/switch.go
|
||||||
|
// - application logic in app/switch.go
|
||||||
|
// - gRPC adapter in adapters/primary/grpc/switch.go
|
||||||
|
type SwitchServiceServer interface {
|
||||||
|
TurnOn(context.Context, *SwitchRequest) (*SwitchResponse, error)
|
||||||
|
TurnOff(context.Context, *SwitchRequest) (*SwitchResponse, error)
|
||||||
|
Toggle(context.Context, *SwitchRequest) (*SwitchResponse, error)
|
||||||
|
mustEmbedUnimplementedSwitchServiceServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
// UnimplementedSwitchServiceServer must be embedded to have
|
||||||
|
// forward compatible implementations.
|
||||||
|
//
|
||||||
|
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
||||||
|
// pointer dereference when methods are called.
|
||||||
|
type UnimplementedSwitchServiceServer struct{}
|
||||||
|
|
||||||
|
func (UnimplementedSwitchServiceServer) TurnOn(context.Context, *SwitchRequest) (*SwitchResponse, error) {
|
||||||
|
return nil, status.Error(codes.Unimplemented, "method TurnOn not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedSwitchServiceServer) TurnOff(context.Context, *SwitchRequest) (*SwitchResponse, error) {
|
||||||
|
return nil, status.Error(codes.Unimplemented, "method TurnOff not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedSwitchServiceServer) Toggle(context.Context, *SwitchRequest) (*SwitchResponse, error) {
|
||||||
|
return nil, status.Error(codes.Unimplemented, "method Toggle not implemented")
|
||||||
|
}
|
||||||
|
func (UnimplementedSwitchServiceServer) mustEmbedUnimplementedSwitchServiceServer() {}
|
||||||
|
func (UnimplementedSwitchServiceServer) testEmbeddedByValue() {}
|
||||||
|
|
||||||
|
// UnsafeSwitchServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||||
|
// Use of this interface is not recommended, as added methods to SwitchServiceServer will
|
||||||
|
// result in compilation errors.
|
||||||
|
type UnsafeSwitchServiceServer interface {
|
||||||
|
mustEmbedUnimplementedSwitchServiceServer()
|
||||||
|
}
|
||||||
|
|
||||||
|
func RegisterSwitchServiceServer(s grpc.ServiceRegistrar, srv SwitchServiceServer) {
|
||||||
|
// If the following call panics, it indicates UnimplementedSwitchServiceServer was
|
||||||
|
// embedded by pointer and is nil. This will cause panics if an
|
||||||
|
// unimplemented method is ever invoked, so we test this at initialization
|
||||||
|
// time to prevent it from happening at runtime later due to I/O.
|
||||||
|
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||||
|
t.testEmbeddedByValue()
|
||||||
|
}
|
||||||
|
s.RegisterService(&SwitchService_ServiceDesc, srv)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _SwitchService_TurnOn_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(SwitchRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(SwitchServiceServer).TurnOn(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: SwitchService_TurnOn_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(SwitchServiceServer).TurnOn(ctx, req.(*SwitchRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _SwitchService_TurnOff_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(SwitchRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(SwitchServiceServer).TurnOff(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: SwitchService_TurnOff_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(SwitchServiceServer).TurnOff(ctx, req.(*SwitchRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
func _SwitchService_Toggle_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||||
|
in := new(SwitchRequest)
|
||||||
|
if err := dec(in); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if interceptor == nil {
|
||||||
|
return srv.(SwitchServiceServer).Toggle(ctx, in)
|
||||||
|
}
|
||||||
|
info := &grpc.UnaryServerInfo{
|
||||||
|
Server: srv,
|
||||||
|
FullMethod: SwitchService_Toggle_FullMethodName,
|
||||||
|
}
|
||||||
|
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||||
|
return srv.(SwitchServiceServer).Toggle(ctx, req.(*SwitchRequest))
|
||||||
|
}
|
||||||
|
return interceptor(ctx, in, info, handler)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SwitchService_ServiceDesc is the grpc.ServiceDesc for SwitchService service.
|
||||||
|
// It's only intended for direct use with grpc.RegisterService,
|
||||||
|
// and not to be introspected or modified (even as a copy)
|
||||||
|
var SwitchService_ServiceDesc = grpc.ServiceDesc{
|
||||||
|
ServiceName: "ha.v1.SwitchService",
|
||||||
|
HandlerType: (*SwitchServiceServer)(nil),
|
||||||
|
Methods: []grpc.MethodDesc{
|
||||||
|
{
|
||||||
|
MethodName: "TurnOn",
|
||||||
|
Handler: _SwitchService_TurnOn_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "TurnOff",
|
||||||
|
Handler: _SwitchService_TurnOff_Handler,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
MethodName: "Toggle",
|
||||||
|
Handler: _SwitchService_Toggle_Handler,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
Streams: []grpc.StreamDesc{},
|
||||||
|
Metadata: "ha/v1/switch.proto",
|
||||||
|
}
|
||||||
92
go.work.sum
Normal file
92
go.work.sum
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
cel.dev/expr v0.19.1/go.mod h1:MrpN08Q+lEBs+bGYdLxxHkZoUSsCp0nSKTs0nTymJgw=
|
||||||
|
cel.dev/expr v0.25.1/go.mod h1:hrXvqGP6G6gyx8UAHSHJ5RGk//1Oj5nXQ2NI02Nrsg4=
|
||||||
|
cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
|
||||||
|
cloud.google.com/go/compute/metadata v0.9.0/go.mod h1:E0bWwX5wTnLPedCKqk3pJmVgCBSM6qQI1yTBdEb3C10=
|
||||||
|
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.25.0/go.mod h1:obipzmGjfSjam60XLwGfqUkJsfiheAl+TUjG+4yzyPM=
|
||||||
|
github.com/GoogleCloudPlatform/opentelemetry-operations-go/detectors/gcp v1.30.0/go.mod h1:P4WPRUkOhJC13W//jWpyfJNDAIpvRbAUIYLX/4jtlE0=
|
||||||
|
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||||
|
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||||
|
github.com/cncf/xds/go v0.0.0-20241223141626-cff3c89139a3/go.mod h1:W+zGtBO5Y1IgJhy4+A9GOqVhqLpfZi+vwmdNXUehLA8=
|
||||||
|
github.com/cncf/xds/go v0.0.0-20251210132809-ee656c7534f5/go.mod h1:KdCmV+x/BuvyMxRnYBlmVaq4OLiKW6iRQfvC62cvdkI=
|
||||||
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.13.4/go.mod h1:kDfuBlDVsSj2MjrLEtRWtHlsWIFcGyB2RMO44Dc5GZA=
|
||||||
|
github.com/envoyproxy/go-control-plane v0.14.0/go.mod h1:NcS5X47pLl/hfqxU70yPwL9ZMkUlwlKxtAohpi2wBEU=
|
||||||
|
github.com/envoyproxy/go-control-plane/envoy v1.32.4/go.mod h1:Gzjc5k8JcJswLjAx1Zm+wSYE20UrLtt7JZMWiWQXQEw=
|
||||||
|
github.com/envoyproxy/go-control-plane/envoy v1.36.0/go.mod h1:ty89S1YCCVruQAm9OtKeEkQLTb+Lkz0k8v9W0Oxsv98=
|
||||||
|
github.com/envoyproxy/go-control-plane/ratelimit v0.1.0/go.mod h1:Wk+tMFAFbCXaJPzVVHnPgRKdUdwW/KdbRt94AzgRee4=
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v1.2.1/go.mod h1:d/C80l/jxXLdfEIhX1W2TmLfsJ31lvEjwamM4DxlWXU=
|
||||||
|
github.com/envoyproxy/protoc-gen-validate v1.3.0/go.mod h1:HvYl7zwPa5mffgyeTUHA9zHIH36nmrm7oCbo4YKoSWA=
|
||||||
|
github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08=
|
||||||
|
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
|
github.com/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
|
||||||
|
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
|
github.com/golang/glog v1.2.4/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
|
||||||
|
github.com/golang/glog v1.2.5/go.mod h1:6AhwSGph0fcJtXVM/PEHPqZlFeoLxhs7/t5UDAwmO+w=
|
||||||
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 h1:e9Rjr40Z98/clHv5Yg79Is0NtosR5LXRvdr7o/6NwbA=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1/go.mod h1:tIxuGz/9mpox++sgp9fJjHO0+q1X9/UOWd798aAm22M=
|
||||||
|
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||||
|
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||||
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
|
github.com/planetscale/vtprotobuf v0.6.1-0.20240319094008-0393e58bdf10/go.mod h1:t/avpk3KcrXxUnYOhZhMXJlSEyie6gQbtLq5NM3loB8=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/spiffe/go-spiffe/v2 v2.6.0/go.mod h1:gm2SeUoMZEtpnzPNs2Csc0D/gX33k1xIx7lEzqblHEs=
|
||||||
|
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
|
||||||
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
|
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
|
||||||
|
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
|
||||||
|
go.opentelemetry.io/contrib/detectors/gcp v1.34.0/go.mod h1:cV4BMFcscUR/ckqLkbfQmF0PRsq8w/lMGzdbCSveBHo=
|
||||||
|
go.opentelemetry.io/contrib/detectors/gcp v1.39.0/go.mod h1:t/OGqzHBa5v6RHZwrDBJ2OirWc+4q/w2fTbLZwAKjTk=
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 h1:x7wzEgXfnzJcHDwStJT+mxOz4etr2EcexjqhBvmoakw=
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM=
|
||||||
|
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
|
||||||
|
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.35.0 h1:QcFwRrZLc82r8wODjvyCbP7Ifp3UANaBSmhDSFjnqSc=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.35.0/go.mod h1:CXIWhUomyWBG/oY2/r/kLp6K/cmx9e/7DLpBuuGdLCA=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 h1:m639+BofXTvcY1q8CGs4ItwQarYtJPOWmVobfM1HpVI=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0/go.mod h1:LjReUci/F4BUyv+y4dwnq3h/26iNOeC3wAIqgvTIZVo=
|
||||||
|
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
|
||||||
|
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
|
||||||
|
go.opentelemetry.io/otel/sdk/metric v1.35.0 h1:1RriWBmCKgkeHEhM7a2uMjMUfP7MsOF5JpUCaEqEI9o=
|
||||||
|
go.opentelemetry.io/otel/sdk/metric v1.35.0/go.mod h1:is6XYCUMpcKi+ZsOvfluY5YstFnhW0BidkR+gL+qN+w=
|
||||||
|
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
|
||||||
|
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.7.1 h1:gTOMpGDb0WTBOP8JaO72iL3auEZhVmAQg4ipjOVAtj4=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.7.1/go.mod h1:b2rVh6rfI/s2pHWNlB7ILJcRALpcNDzKhACevjI+ZnE=
|
||||||
|
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||||
|
golang.org/x/net v0.35.0 h1:T5GQRQb2y08kTAByq9L4/bz8cipCdA8FbRTXewonqY8=
|
||||||
|
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
|
||||||
|
golang.org/x/oauth2 v0.25.0/go.mod h1:XYTD2NtWslqkgxebSiOHnXEap4TF09sJSc7H1sXbhtI=
|
||||||
|
golang.org/x/oauth2 v0.34.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA=
|
||||||
|
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
|
||||||
|
golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI=
|
||||||
|
golang.org/x/sys v0.30.0 h1:QjkSwP/36a20jFYWkSue1YwXzLmsV5Gfq7Eiy72C1uc=
|
||||||
|
golang.org/x/sys v0.30.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/text v0.22.0 h1:bofq7m3/HAFvbF51jz3Q9wLg3jkvSPuiZu/pD1XwgtM=
|
||||||
|
golang.org/x/text v0.22.0/go.mod h1:YRoo4H8PVmsu+E3Ou7cqLVH8oXWIHVoX0jqUWALQhfY=
|
||||||
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a h1:nwKuGPlUAt+aR+pcrkfFRrTU1BVrSmYyYMxYbUIVHr0=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20250218202821-56aae31c358a/go.mod h1:3kWAYMk1I75K4vykHtKt2ycnOgpA6974V7bREqbsenU=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 h1:fCvbg86sFXwdrl5LgVcTEvNC+2txB5mgROGmRL5mrls=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a h1:51aaUVRocpvUOSQKM6Q7VuoaktNIaMCLuhZB6DKksq4=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20250218202821-56aae31c358a/go.mod h1:uRxBH1mhmO8PGhU89cMcHaXKZqO+OfakD8QQO0oYwlQ=
|
||||||
|
google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg=
|
||||||
|
google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
|
||||||
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
|
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
|
||||||
|
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
|
||||||
|
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
|
||||||
|
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
|
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
4
ha-gateway/.env.example
Normal file
4
ha-gateway/.env.example
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
GRPC_PORT=50051
|
||||||
|
HA_BASE_URL=http://ha.home.arpa:8123
|
||||||
|
HA_TOKEN=your-long-lived-token-here
|
||||||
|
OTEL_ENDPOINT=
|
||||||
19
ha-gateway/Dockerfile
Normal file
19
ha-gateway/Dockerfile
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
FROM golang:1.26-alpine AS builder
|
||||||
|
WORKDIR /workspace
|
||||||
|
|
||||||
|
COPY go.work go.work.sum ./
|
||||||
|
COPY gen/ ./gen/
|
||||||
|
COPY ha-gateway/ ./ha-gateway/
|
||||||
|
|
||||||
|
WORKDIR /workspace/ha-gateway
|
||||||
|
RUN go mod download
|
||||||
|
|
||||||
|
ARG VERSION=dev
|
||||||
|
RUN CGO_ENABLED=0 GOOS=linux go build \
|
||||||
|
-ldflags="-s -w -X main.version=${VERSION}" \
|
||||||
|
-o /ha-gateway ./cmd/gateway
|
||||||
|
|
||||||
|
FROM gcr.io/distroless/static:nonroot
|
||||||
|
COPY --from=builder /ha-gateway /ha-gateway
|
||||||
|
EXPOSE 50051
|
||||||
|
ENTRYPOINT ["/ha-gateway"]
|
||||||
143
ha-gateway/cmd/gateway/main.go
Normal file
143
ha-gateway/cmd/gateway/main.go
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"log/slog"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"os/signal"
|
||||||
|
"syscall"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/joho/godotenv"
|
||||||
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/peer"
|
||||||
|
"go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc"
|
||||||
|
|
||||||
|
hav1 "gitea.nik4nao.com/nik/home-services/gen/ha/v1"
|
||||||
|
"gitea.nik4nao.com/nik/home-services/ha-gateway/internal/adapters/secondary/ha"
|
||||||
|
grpcadapter "gitea.nik4nao.com/nik/home-services/ha-gateway/internal/adapters/primary/grpc"
|
||||||
|
"gitea.nik4nao.com/nik/home-services/ha-gateway/internal/app"
|
||||||
|
"gitea.nik4nao.com/nik/home-services/ha-gateway/internal/config"
|
||||||
|
"gitea.nik4nao.com/nik/home-services/ha-gateway/internal/telemetry"
|
||||||
|
)
|
||||||
|
|
||||||
|
// MEMO: auth is not implemented.
|
||||||
|
// Add one of the following before exposing this service to any untrusted network:
|
||||||
|
// Option A — shared API key per client: unary + stream interceptors read
|
||||||
|
// "authorization" from gRPC metadata and compare to a secret
|
||||||
|
// from config. Good for small number of known clients.
|
||||||
|
// Option B — mTLS (recommended): tls.Config with ClientAuth: RequireAndVerifyClientCert,
|
||||||
|
// cert pool from the internal CA. Each client gets a cert from
|
||||||
|
// cert-manager. No runtime auth dependency, identity in the cert CN/SAN.
|
||||||
|
|
||||||
|
// version is set at build time via -ldflags "-X main.version=<tag>".
|
||||||
|
var version = "dev"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// 1. Load .env if present (ignored in K8s where env vars come from Secrets/ConfigMaps).
|
||||||
|
_ = godotenv.Load()
|
||||||
|
|
||||||
|
// 2. Load and validate config.
|
||||||
|
cfg, err := config.Load()
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("config error", "err", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
ctx, stop := signal.NotifyContext(context.Background(), syscall.SIGTERM, syscall.SIGINT)
|
||||||
|
defer stop()
|
||||||
|
|
||||||
|
// 3. Set up telemetry.
|
||||||
|
shutdown, err := telemetry.Setup(ctx, cfg, version)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("telemetry setup failed", "err", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 4. Build the secondary adapter.
|
||||||
|
haClient := ha.NewClient(cfg)
|
||||||
|
|
||||||
|
// 5. Build application services.
|
||||||
|
entityApp := app.NewEntityApp(haClient)
|
||||||
|
lightApp := app.NewLightApp(haClient)
|
||||||
|
|
||||||
|
// 6. Build the gRPC server with OTel stats handler and logging interceptors.
|
||||||
|
srv := grpc.NewServer(
|
||||||
|
grpc.StatsHandler(otelgrpc.NewServerHandler()),
|
||||||
|
grpc.ChainUnaryInterceptor(loggingUnaryInterceptor),
|
||||||
|
grpc.ChainStreamInterceptor(loggingStreamInterceptor),
|
||||||
|
)
|
||||||
|
|
||||||
|
// 7. Register services.
|
||||||
|
hav1.RegisterEntityServiceServer(srv, grpcadapter.NewEntityGRPC(entityApp))
|
||||||
|
hav1.RegisterLightServiceServer(srv, grpcadapter.NewLightGRPC(lightApp))
|
||||||
|
hav1.RegisterSwitchServiceServer(srv, &grpcadapter.SwitchGRPC{})
|
||||||
|
hav1.RegisterEventServiceServer(srv, &grpcadapter.EventGRPC{})
|
||||||
|
|
||||||
|
// 8. Start listener.
|
||||||
|
lis, err := net.Listen("tcp", ":"+cfg.GRPCPort)
|
||||||
|
if err != nil {
|
||||||
|
slog.Error("listen failed", "err", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 9. Serve in background.
|
||||||
|
go func() {
|
||||||
|
slog.Info("listening", "port", cfg.GRPCPort, "version", version)
|
||||||
|
if err := srv.Serve(lis); err != nil {
|
||||||
|
slog.Error("serve failed", "err", err)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
// 10. Block until signal.
|
||||||
|
<-ctx.Done()
|
||||||
|
slog.Info("shutting down")
|
||||||
|
|
||||||
|
// 11. Graceful stop, then flush telemetry.
|
||||||
|
srv.GracefulStop()
|
||||||
|
|
||||||
|
shutdownCtx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
|
||||||
|
defer cancel()
|
||||||
|
if err := shutdown(shutdownCtx); err != nil {
|
||||||
|
slog.Error("telemetry shutdown error", "err", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func loggingUnaryInterceptor(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
|
||||||
|
start := time.Now()
|
||||||
|
resp, err := handler(ctx, req)
|
||||||
|
attrs := []any{
|
||||||
|
"method", info.FullMethod,
|
||||||
|
"duration", time.Since(start).String(),
|
||||||
|
}
|
||||||
|
if p, ok := peer.FromContext(ctx); ok {
|
||||||
|
attrs = append(attrs, "peer", p.Addr.String())
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
attrs = append(attrs, "err", err)
|
||||||
|
slog.ErrorContext(ctx, "rpc", attrs...)
|
||||||
|
} else {
|
||||||
|
slog.InfoContext(ctx, "rpc", attrs...)
|
||||||
|
}
|
||||||
|
return resp, err
|
||||||
|
}
|
||||||
|
|
||||||
|
func loggingStreamInterceptor(srv any, ss grpc.ServerStream, info *grpc.StreamServerInfo, handler grpc.StreamHandler) error {
|
||||||
|
start := time.Now()
|
||||||
|
err := handler(srv, ss)
|
||||||
|
attrs := []any{
|
||||||
|
"method", info.FullMethod,
|
||||||
|
"duration", time.Since(start).String(),
|
||||||
|
}
|
||||||
|
if p, ok := peer.FromContext(ss.Context()); ok {
|
||||||
|
attrs = append(attrs, "peer", p.Addr.String())
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
attrs = append(attrs, "err", err)
|
||||||
|
slog.ErrorContext(ss.Context(), "rpc stream", attrs...)
|
||||||
|
} else {
|
||||||
|
slog.InfoContext(ss.Context(), "rpc stream", attrs...)
|
||||||
|
}
|
||||||
|
return err
|
||||||
|
}
|
||||||
37
ha-gateway/go.mod
Normal file
37
ha-gateway/go.mod
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
module gitea.nik4nao.com/nik/home-services/ha-gateway
|
||||||
|
|
||||||
|
go 1.26
|
||||||
|
|
||||||
|
require (
|
||||||
|
gitea.nik4nao.com/nik/home-services/gen v0.0.0
|
||||||
|
github.com/joho/godotenv v1.5.1
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0
|
||||||
|
go.opentelemetry.io/otel v1.39.0
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.35.0
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0
|
||||||
|
go.opentelemetry.io/otel/sdk v1.39.0
|
||||||
|
go.opentelemetry.io/otel/sdk/metric v1.39.0
|
||||||
|
google.golang.org/grpc v1.79.3
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/cenkalti/backoff/v4 v4.3.0 // indirect
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 // indirect
|
||||||
|
github.com/go-logr/logr v1.4.3 // indirect
|
||||||
|
github.com/go-logr/stdr v1.2.2 // indirect
|
||||||
|
github.com/google/uuid v1.6.0 // indirect
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 // indirect
|
||||||
|
go.opentelemetry.io/auto/sdk v1.2.1 // indirect
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/metric v1.39.0 // indirect
|
||||||
|
go.opentelemetry.io/otel/trace v1.39.0 // indirect
|
||||||
|
go.opentelemetry.io/proto/otlp v1.5.0 // indirect
|
||||||
|
golang.org/x/net v0.48.0 // indirect
|
||||||
|
golang.org/x/sys v0.39.0 // indirect
|
||||||
|
golang.org/x/text v0.32.0 // indirect
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 // indirect
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect
|
||||||
|
google.golang.org/protobuf v1.36.11 // indirect
|
||||||
|
)
|
||||||
|
|
||||||
|
replace gitea.nik4nao.com/nik/home-services/gen => ../gen
|
||||||
67
ha-gateway/go.sum
Normal file
67
ha-gateway/go.sum
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8=
|
||||||
|
github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
|
||||||
|
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
||||||
|
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
|
github.com/go-logr/logr v1.2.2/go.mod h1:jdQByPbusPIv2/zmleS9BjJVeZ6kBagPoEUsqbVz/1A=
|
||||||
|
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
|
||||||
|
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
|
||||||
|
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
|
||||||
|
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
|
||||||
|
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
|
||||||
|
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
|
||||||
|
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||||
|
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||||
|
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
|
||||||
|
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1 h1:e9Rjr40Z98/clHv5Yg79Is0NtosR5LXRvdr7o/6NwbA=
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.1/go.mod h1:tIxuGz/9mpox++sgp9fJjHO0+q1X9/UOWd798aAm22M=
|
||||||
|
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
|
||||||
|
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
|
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
|
||||||
|
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
|
||||||
|
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
|
||||||
|
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0 h1:x7wzEgXfnzJcHDwStJT+mxOz4etr2EcexjqhBvmoakw=
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.60.0/go.mod h1:rg+RlpR5dKwaS95IyyZqj5Wd4E13lk/msnTS0Xl9lJM=
|
||||||
|
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
|
||||||
|
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.35.0 h1:QcFwRrZLc82r8wODjvyCbP7Ifp3UANaBSmhDSFjnqSc=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc v1.35.0/go.mod h1:CXIWhUomyWBG/oY2/r/kLp6K/cmx9e/7DLpBuuGdLCA=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0 h1:1fTNlAIJZGWLP5FVu0fikVry1IsiUnXjf7QFvoNN3Xw=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.35.0/go.mod h1:zjPK58DtkqQFn+YUMbx0M2XV3QgKU0gS9LeGohREyK4=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0 h1:m639+BofXTvcY1q8CGs4ItwQarYtJPOWmVobfM1HpVI=
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.35.0/go.mod h1:LjReUci/F4BUyv+y4dwnq3h/26iNOeC3wAIqgvTIZVo=
|
||||||
|
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
|
||||||
|
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
|
||||||
|
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
|
||||||
|
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
|
||||||
|
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
|
||||||
|
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
|
||||||
|
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4=
|
||||||
|
go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4=
|
||||||
|
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
|
||||||
|
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
|
||||||
|
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
|
||||||
|
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
|
||||||
|
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
|
||||||
|
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
|
||||||
|
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
|
||||||
|
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
|
||||||
|
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
|
||||||
|
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217 h1:fCvbg86sFXwdrl5LgVcTEvNC+2txB5mgROGmRL5mrls=
|
||||||
|
google.golang.org/genproto/googleapis/api v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:+rXWjjaukWZun3mLfjmVnQi18E1AsFbDN9QdJ5YXLto=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww=
|
||||||
|
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
|
||||||
|
google.golang.org/grpc v1.79.3 h1:sybAEdRIEtvcD68Gx7dmnwjZKlyfuc61Dyo9pGXXkKE=
|
||||||
|
google.golang.org/grpc v1.79.3/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
|
||||||
|
google.golang.org/protobuf v1.36.11 h1:fV6ZwhNocDyBLK0dj+fg8ektcVegBBuEolpbTQyBNVE=
|
||||||
|
google.golang.org/protobuf v1.36.11/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
59
ha-gateway/internal/adapters/primary/grpc/entity.go
Normal file
59
ha-gateway/internal/adapters/primary/grpc/entity.go
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
package grpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"errors"
|
||||||
|
|
||||||
|
"google.golang.org/grpc/codes"
|
||||||
|
"google.golang.org/grpc/status"
|
||||||
|
|
||||||
|
hav1 "gitea.nik4nao.com/nik/home-services/gen/ha/v1"
|
||||||
|
"gitea.nik4nao.com/nik/home-services/ha-gateway/internal/core/domain"
|
||||||
|
"gitea.nik4nao.com/nik/home-services/ha-gateway/internal/core/ports/driving"
|
||||||
|
)
|
||||||
|
|
||||||
|
type EntityGRPC struct {
|
||||||
|
hav1.UnimplementedEntityServiceServer
|
||||||
|
svc driving.EntityService
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEntityGRPC(svc driving.EntityService) *EntityGRPC {
|
||||||
|
return &EntityGRPC{svc: svc}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *EntityGRPC) GetState(ctx context.Context, req *hav1.GetStateRequest) (*hav1.GetStateResponse, error) {
|
||||||
|
s, err := h.svc.GetState(ctx, domain.EntityID(req.EntityId))
|
||||||
|
if err != nil {
|
||||||
|
return nil, grpcError(err)
|
||||||
|
}
|
||||||
|
return &hav1.GetStateResponse{State: domainStateToProto(s)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *EntityGRPC) ListStates(ctx context.Context, req *hav1.ListStatesRequest) (*hav1.ListStatesResponse, error) {
|
||||||
|
ids := make([]domain.EntityID, len(req.EntityIds))
|
||||||
|
for i, id := range req.EntityIds {
|
||||||
|
ids[i] = domain.EntityID(id)
|
||||||
|
}
|
||||||
|
|
||||||
|
states, err := h.svc.ListStates(ctx, ids, req.Domain)
|
||||||
|
if err != nil {
|
||||||
|
return nil, grpcError(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
proto := make([]*hav1.EntityState, len(states))
|
||||||
|
for i, s := range states {
|
||||||
|
proto[i] = domainStateToProto(s)
|
||||||
|
}
|
||||||
|
return &hav1.ListStatesResponse{States: proto}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// grpcError maps domain errors to appropriate gRPC status codes.
|
||||||
|
func grpcError(err error) error {
|
||||||
|
if errors.Is(err, ErrNotFound) {
|
||||||
|
return status.Errorf(codes.NotFound, "%v", err)
|
||||||
|
}
|
||||||
|
return status.Errorf(codes.Internal, "%v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrNotFound is returned by the app layer when an entity does not exist.
|
||||||
|
var ErrNotFound = errors.New("not found")
|
||||||
12
ha-gateway/internal/adapters/primary/grpc/event.go
Normal file
12
ha-gateway/internal/adapters/primary/grpc/event.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package grpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
hav1 "gitea.nik4nao.com/nik/home-services/gen/ha/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
type EventGRPC struct {
|
||||||
|
hav1.UnimplementedEventServiceServer
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subscribe returns codes.Unimplemented via the embedded UnimplementedEventServiceServer.
|
||||||
|
// TODO: inject fanout broker here once websocket.go is implemented.
|
||||||
42
ha-gateway/internal/adapters/primary/grpc/light.go
Normal file
42
ha-gateway/internal/adapters/primary/grpc/light.go
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
package grpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
hav1 "gitea.nik4nao.com/nik/home-services/gen/ha/v1"
|
||||||
|
"gitea.nik4nao.com/nik/home-services/ha-gateway/internal/core/domain"
|
||||||
|
"gitea.nik4nao.com/nik/home-services/ha-gateway/internal/core/ports/driving"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LightGRPC struct {
|
||||||
|
hav1.UnimplementedLightServiceServer
|
||||||
|
svc driving.LightService
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLightGRPC(svc driving.LightService) *LightGRPC {
|
||||||
|
return &LightGRPC{svc: svc}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *LightGRPC) TurnOn(ctx context.Context, req *hav1.TurnOnRequest) (*hav1.LightResponse, error) {
|
||||||
|
s, err := h.svc.TurnOn(ctx, protoTurnOnToParams(req))
|
||||||
|
if err != nil {
|
||||||
|
return nil, grpcError(err)
|
||||||
|
}
|
||||||
|
return &hav1.LightResponse{State: domainStateToProto(s)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *LightGRPC) TurnOff(ctx context.Context, req *hav1.TurnOffRequest) (*hav1.LightResponse, error) {
|
||||||
|
s, err := h.svc.TurnOff(ctx, protoTurnOffToParams(req))
|
||||||
|
if err != nil {
|
||||||
|
return nil, grpcError(err)
|
||||||
|
}
|
||||||
|
return &hav1.LightResponse{State: domainStateToProto(s)}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (h *LightGRPC) Toggle(ctx context.Context, req *hav1.ToggleRequest) (*hav1.LightResponse, error) {
|
||||||
|
s, err := h.svc.Toggle(ctx, domain.EntityID(req.EntityId))
|
||||||
|
if err != nil {
|
||||||
|
return nil, grpcError(err)
|
||||||
|
}
|
||||||
|
return &hav1.LightResponse{State: domainStateToProto(s)}, nil
|
||||||
|
}
|
||||||
53
ha-gateway/internal/adapters/primary/grpc/mapping.go
Normal file
53
ha-gateway/internal/adapters/primary/grpc/mapping.go
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
package grpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
"gitea.nik4nao.com/nik/home-services/ha-gateway/internal/core/domain"
|
||||||
|
hav1 "gitea.nik4nao.com/nik/home-services/gen/ha/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
func domainStateToProto(s *domain.EntityState) *hav1.EntityState {
|
||||||
|
return &hav1.EntityState{
|
||||||
|
EntityId: string(s.EntityID),
|
||||||
|
State: s.State,
|
||||||
|
Attributes: s.Attributes,
|
||||||
|
LastChanged: s.LastChanged.Format("2006-01-02T15:04:05Z07:00"),
|
||||||
|
LastUpdated: s.LastUpdated.Format("2006-01-02T15:04:05Z07:00"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func protoTurnOnToParams(r *hav1.TurnOnRequest) domain.TurnOnParams {
|
||||||
|
p := domain.TurnOnParams{
|
||||||
|
EntityID: domain.EntityID(r.EntityId),
|
||||||
|
}
|
||||||
|
if r.BrightnessPct != nil {
|
||||||
|
v := r.GetBrightnessPct()
|
||||||
|
p.BrightnessPct = &v
|
||||||
|
}
|
||||||
|
if r.ColorTempKelvin != nil {
|
||||||
|
v := r.GetColorTempKelvin()
|
||||||
|
p.ColorTempKelvin = &v
|
||||||
|
}
|
||||||
|
if r.RgbColor != nil {
|
||||||
|
p.RGBColor = &domain.RGBColor{
|
||||||
|
R: uint8(r.RgbColor.R),
|
||||||
|
G: uint8(r.RgbColor.G),
|
||||||
|
B: uint8(r.RgbColor.B),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if r.Transition != nil {
|
||||||
|
v := r.GetTransition()
|
||||||
|
p.Transition = &v
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
|
|
||||||
|
func protoTurnOffToParams(r *hav1.TurnOffRequest) domain.TurnOffParams {
|
||||||
|
p := domain.TurnOffParams{
|
||||||
|
EntityID: domain.EntityID(r.EntityId),
|
||||||
|
}
|
||||||
|
if r.Transition != nil {
|
||||||
|
v := r.GetTransition()
|
||||||
|
p.Transition = &v
|
||||||
|
}
|
||||||
|
return p
|
||||||
|
}
|
||||||
12
ha-gateway/internal/adapters/primary/grpc/switch.go
Normal file
12
ha-gateway/internal/adapters/primary/grpc/switch.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package grpc
|
||||||
|
|
||||||
|
import (
|
||||||
|
hav1 "gitea.nik4nao.com/nik/home-services/gen/ha/v1"
|
||||||
|
)
|
||||||
|
|
||||||
|
type SwitchGRPC struct {
|
||||||
|
hav1.UnimplementedSwitchServiceServer
|
||||||
|
}
|
||||||
|
|
||||||
|
// All methods return codes.Unimplemented via the embedded UnimplementedSwitchServiceServer.
|
||||||
|
// TODO: follow the same pattern as LightGRPC once app/switch.go is implemented.
|
||||||
183
ha-gateway/internal/adapters/secondary/ha/client.go
Normal file
183
ha-gateway/internal/adapters/secondary/ha/client.go
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
package ha
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"strings"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"gitea.nik4nao.com/nik/home-services/ha-gateway/internal/config"
|
||||||
|
"gitea.nik4nao.com/nik/home-services/ha-gateway/internal/core/ports/driven"
|
||||||
|
"go.opentelemetry.io/otel"
|
||||||
|
"go.opentelemetry.io/otel/attribute"
|
||||||
|
"go.opentelemetry.io/otel/codes"
|
||||||
|
)
|
||||||
|
|
||||||
|
var tracer = otel.Tracer("ha-gateway/ha-client")
|
||||||
|
|
||||||
|
type Client struct {
|
||||||
|
baseURL string
|
||||||
|
token string
|
||||||
|
httpClient *http.Client
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewClient(cfg *config.Config) *Client {
|
||||||
|
return &Client{
|
||||||
|
baseURL: strings.TrimRight(cfg.HABaseURL, "/"),
|
||||||
|
token: cfg.HAToken,
|
||||||
|
httpClient: &http.Client{Timeout: 10 * time.Second},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) GetState(ctx context.Context, entityID string) (*driven.HAState, error) {
|
||||||
|
ctx, span := tracer.Start(ctx, "ha.GetState")
|
||||||
|
defer span.End()
|
||||||
|
span.SetAttributes(attribute.String("entity_id", entityID))
|
||||||
|
|
||||||
|
var raw haStateRaw
|
||||||
|
if err := c.get(ctx, "/api/states/"+entityID, &raw); err != nil {
|
||||||
|
span.RecordError(err)
|
||||||
|
span.SetStatus(codes.Error, err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return raw.toDriven()
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) ListStates(ctx context.Context) ([]*driven.HAState, error) {
|
||||||
|
ctx, span := tracer.Start(ctx, "ha.ListStates")
|
||||||
|
defer span.End()
|
||||||
|
|
||||||
|
var raw []haStateRaw
|
||||||
|
if err := c.get(ctx, "/api/states", &raw); err != nil {
|
||||||
|
span.RecordError(err)
|
||||||
|
span.SetStatus(codes.Error, err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
out := make([]*driven.HAState, 0, len(raw))
|
||||||
|
for i := range raw {
|
||||||
|
s, err := raw[i].toDriven()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
out = append(out, s)
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) CallService(ctx context.Context, domain, service string, payload map[string]any) ([]*driven.HAState, error) {
|
||||||
|
ctx, span := tracer.Start(ctx, "ha.CallService")
|
||||||
|
defer span.End()
|
||||||
|
span.SetAttributes(
|
||||||
|
attribute.String("ha.domain", domain),
|
||||||
|
attribute.String("ha.service", service),
|
||||||
|
)
|
||||||
|
|
||||||
|
body, err := json.Marshal(payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("marshal payload: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodPost,
|
||||||
|
c.baseURL+"/api/services/"+domain+"/"+service,
|
||||||
|
strings.NewReader(string(body)))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("build request: %w", err)
|
||||||
|
}
|
||||||
|
req.Header.Set("Authorization", "Bearer "+c.token)
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
resp, err := c.httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
span.RecordError(err)
|
||||||
|
span.SetStatus(codes.Error, err.Error())
|
||||||
|
return nil, fmt.Errorf("call service %s/%s: %w", domain, service, err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
respBody, _ := io.ReadAll(io.LimitReader(resp.Body, 4096))
|
||||||
|
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||||
|
preview := string(respBody)
|
||||||
|
if len(preview) > 200 {
|
||||||
|
preview = preview[:200]
|
||||||
|
}
|
||||||
|
err := fmt.Errorf("HA returned %d: %s", resp.StatusCode, preview)
|
||||||
|
span.RecordError(err)
|
||||||
|
span.SetStatus(codes.Error, err.Error())
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var raw []haStateRaw
|
||||||
|
if err := json.Unmarshal(respBody, &raw); err != nil {
|
||||||
|
// HA may return an empty body or non-array on some calls; treat as empty.
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
out := make([]*driven.HAState, 0, len(raw))
|
||||||
|
for i := range raw {
|
||||||
|
s, err := raw[i].toDriven()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
out = append(out, s)
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (c *Client) get(ctx context.Context, path string, dst any) error {
|
||||||
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, c.baseURL+path, nil)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("build request: %w", err)
|
||||||
|
}
|
||||||
|
req.Header.Set("Authorization", "Bearer "+c.token)
|
||||||
|
|
||||||
|
resp, err := c.httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("GET %s: %w", path, err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
body, _ := io.ReadAll(io.LimitReader(resp.Body, 1<<20))
|
||||||
|
if resp.StatusCode < 200 || resp.StatusCode >= 300 {
|
||||||
|
preview := string(body)
|
||||||
|
if len(preview) > 200 {
|
||||||
|
preview = preview[:200]
|
||||||
|
}
|
||||||
|
return fmt.Errorf("HA returned %d for GET %s: %s", resp.StatusCode, path, preview)
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.Unmarshal(body, dst); err != nil {
|
||||||
|
return fmt.Errorf("decode response for GET %s: %w", path, err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// haStateRaw is the raw JSON shape returned by the HA REST API.
|
||||||
|
type haStateRaw struct {
|
||||||
|
EntityID string `json:"entity_id"`
|
||||||
|
State string `json:"state"`
|
||||||
|
Attributes map[string]any `json:"attributes"`
|
||||||
|
LastChanged string `json:"last_changed"`
|
||||||
|
LastUpdated string `json:"last_updated"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (r *haStateRaw) toDriven() (*driven.HAState, error) {
|
||||||
|
lc, err := time.Parse(time.RFC3339, r.LastChanged)
|
||||||
|
if err != nil {
|
||||||
|
lc = time.Time{}
|
||||||
|
}
|
||||||
|
lu, err := time.Parse(time.RFC3339, r.LastUpdated)
|
||||||
|
if err != nil {
|
||||||
|
lu = time.Time{}
|
||||||
|
}
|
||||||
|
return &driven.HAState{
|
||||||
|
EntityID: r.EntityID,
|
||||||
|
State: r.State,
|
||||||
|
Attributes: r.Attributes,
|
||||||
|
LastChanged: lc,
|
||||||
|
LastUpdated: lu,
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
7
ha-gateway/internal/adapters/secondary/ha/websocket.go
Normal file
7
ha-gateway/internal/adapters/secondary/ha/websocket.go
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package ha
|
||||||
|
|
||||||
|
// TODO: implement HA WebSocket client.
|
||||||
|
// Auth flow: receive auth_required → send {"type":"auth","access_token":"..."} → receive auth_ok.
|
||||||
|
// Subscribe: send {"id":1,"type":"subscribe_events","event_type":"state_changed"}
|
||||||
|
// Events: stream {"type":"event","event":{"event_type":"state_changed","data":{...}}}
|
||||||
|
// This adapter will publish to the internal fanout broker once EventService is implemented.
|
||||||
68
ha-gateway/internal/app/entity.go
Normal file
68
ha-gateway/internal/app/entity.go
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"fmt"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
"gitea.nik4nao.com/nik/home-services/ha-gateway/internal/core/domain"
|
||||||
|
"gitea.nik4nao.com/nik/home-services/ha-gateway/internal/core/ports/driven"
|
||||||
|
)
|
||||||
|
|
||||||
|
type EntityApp struct {
|
||||||
|
ha driven.HAClient
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewEntityApp(ha driven.HAClient) *EntityApp {
|
||||||
|
return &EntityApp{ha: ha}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *EntityApp) GetState(ctx context.Context, id domain.EntityID) (*domain.EntityState, error) {
|
||||||
|
s, err := a.ha.GetState(ctx, string(id))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return haStateToDomain(s), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *EntityApp) ListStates(ctx context.Context, ids []domain.EntityID, domainFilter string) ([]*domain.EntityState, error) {
|
||||||
|
all, err := a.ha.ListStates(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
idSet := make(map[string]struct{}, len(ids))
|
||||||
|
for _, id := range ids {
|
||||||
|
idSet[string(id)] = struct{}{}
|
||||||
|
}
|
||||||
|
|
||||||
|
var out []*domain.EntityState
|
||||||
|
for _, s := range all {
|
||||||
|
if len(ids) > 0 {
|
||||||
|
if _, ok := idSet[s.EntityID]; !ok {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if domainFilter != "" {
|
||||||
|
if !strings.HasPrefix(s.EntityID, domainFilter+".") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
out = append(out, haStateToDomain(s))
|
||||||
|
}
|
||||||
|
return out, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func haStateToDomain(s *driven.HAState) *domain.EntityState {
|
||||||
|
attrs := make(map[string]string, len(s.Attributes))
|
||||||
|
for k, v := range s.Attributes {
|
||||||
|
attrs[k] = fmt.Sprintf("%v", v)
|
||||||
|
}
|
||||||
|
return &domain.EntityState{
|
||||||
|
EntityID: domain.EntityID(s.EntityID),
|
||||||
|
State: s.State,
|
||||||
|
Attributes: attrs,
|
||||||
|
LastChanged: s.LastChanged,
|
||||||
|
LastUpdated: s.LastUpdated,
|
||||||
|
}
|
||||||
|
}
|
||||||
65
ha-gateway/internal/app/light.go
Normal file
65
ha-gateway/internal/app/light.go
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
package app
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"gitea.nik4nao.com/nik/home-services/ha-gateway/internal/core/domain"
|
||||||
|
"gitea.nik4nao.com/nik/home-services/ha-gateway/internal/core/ports/driven"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LightApp struct {
|
||||||
|
ha driven.HAClient
|
||||||
|
}
|
||||||
|
|
||||||
|
func NewLightApp(ha driven.HAClient) *LightApp {
|
||||||
|
return &LightApp{ha: ha}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *LightApp) TurnOn(ctx context.Context, p domain.TurnOnParams) (*domain.EntityState, error) {
|
||||||
|
payload := map[string]any{"entity_id": string(p.EntityID)}
|
||||||
|
if p.BrightnessPct != nil {
|
||||||
|
payload["brightness_pct"] = *p.BrightnessPct
|
||||||
|
}
|
||||||
|
if p.ColorTempKelvin != nil {
|
||||||
|
payload["color_temp_kelvin"] = *p.ColorTempKelvin
|
||||||
|
}
|
||||||
|
if p.RGBColor != nil {
|
||||||
|
payload["rgb_color"] = []uint8{p.RGBColor.R, p.RGBColor.G, p.RGBColor.B}
|
||||||
|
}
|
||||||
|
if p.Transition != nil {
|
||||||
|
payload["transition"] = *p.Transition
|
||||||
|
}
|
||||||
|
return a.callService(ctx, "light", "turn_on", payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *LightApp) TurnOff(ctx context.Context, p domain.TurnOffParams) (*domain.EntityState, error) {
|
||||||
|
payload := map[string]any{"entity_id": string(p.EntityID)}
|
||||||
|
if p.Transition != nil {
|
||||||
|
payload["transition"] = *p.Transition
|
||||||
|
}
|
||||||
|
return a.callService(ctx, "light", "turn_off", payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *LightApp) Toggle(ctx context.Context, id domain.EntityID) (*domain.EntityState, error) {
|
||||||
|
payload := map[string]any{"entity_id": string(id)}
|
||||||
|
return a.callService(ctx, "light", "toggle", payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (a *LightApp) callService(ctx context.Context, svcDomain, service string, payload map[string]any) (*domain.EntityState, error) {
|
||||||
|
states, err := a.ha.CallService(ctx, svcDomain, service, payload)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
entityID, _ := payload["entity_id"].(string)
|
||||||
|
for _, s := range states {
|
||||||
|
if s.EntityID == entityID {
|
||||||
|
return haStateToDomain(s), nil
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// HA may return an empty list on success; fall back to GetState.
|
||||||
|
s, err := a.ha.GetState(ctx, entityID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return haStateToDomain(s), nil
|
||||||
|
}
|
||||||
33
ha-gateway/internal/config/config.go
Normal file
33
ha-gateway/internal/config/config.go
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
GRPCPort string // GRPC_PORT, default "50051"
|
||||||
|
HABaseURL string // HA_BASE_URL, e.g. "http://ha.home.arpa:8123"
|
||||||
|
HAToken string // HA_TOKEN — long-lived access token (required)
|
||||||
|
OTELEndpoint string // OTEL_ENDPOINT, e.g. "otel-collector.monitoring.svc:4317"
|
||||||
|
// empty = telemetry disabled (local dev default)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Load() (*Config, error) {
|
||||||
|
token := os.Getenv("HA_TOKEN")
|
||||||
|
if token == "" {
|
||||||
|
return nil, errors.New("HA_TOKEN is required but not set")
|
||||||
|
}
|
||||||
|
|
||||||
|
port := os.Getenv("GRPC_PORT")
|
||||||
|
if port == "" {
|
||||||
|
port = "50051"
|
||||||
|
}
|
||||||
|
|
||||||
|
return &Config{
|
||||||
|
GRPCPort: port,
|
||||||
|
HABaseURL: os.Getenv("HA_BASE_URL"),
|
||||||
|
HAToken: token,
|
||||||
|
OTELEndpoint: os.Getenv("OTEL_ENDPOINT"),
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
13
ha-gateway/internal/core/domain/entity.go
Normal file
13
ha-gateway/internal/core/domain/entity.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package domain
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type EntityID string
|
||||||
|
|
||||||
|
type EntityState struct {
|
||||||
|
EntityID EntityID
|
||||||
|
State string
|
||||||
|
Attributes map[string]string
|
||||||
|
LastChanged time.Time
|
||||||
|
LastUpdated time.Time
|
||||||
|
}
|
||||||
18
ha-gateway/internal/core/domain/light.go
Normal file
18
ha-gateway/internal/core/domain/light.go
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
package domain
|
||||||
|
|
||||||
|
type TurnOnParams struct {
|
||||||
|
EntityID EntityID
|
||||||
|
BrightnessPct *uint32 // nil = not set
|
||||||
|
ColorTempKelvin *uint32
|
||||||
|
RGBColor *RGBColor
|
||||||
|
Transition *uint32
|
||||||
|
}
|
||||||
|
|
||||||
|
type RGBColor struct {
|
||||||
|
R, G, B uint8
|
||||||
|
}
|
||||||
|
|
||||||
|
type TurnOffParams struct {
|
||||||
|
EntityID EntityID
|
||||||
|
Transition *uint32
|
||||||
|
}
|
||||||
22
ha-gateway/internal/core/ports/driven/ha.go
Normal file
22
ha-gateway/internal/core/ports/driven/ha.go
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
package driven
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
type HAClient interface {
|
||||||
|
GetState(ctx context.Context, entityID string) (*HAState, error)
|
||||||
|
ListStates(ctx context.Context) ([]*HAState, error)
|
||||||
|
CallService(ctx context.Context, domain, service string, payload map[string]any) ([]*HAState, error)
|
||||||
|
}
|
||||||
|
|
||||||
|
// HAState mirrors the HA REST response. Internal type — not exposed outside
|
||||||
|
// the driven port layer.
|
||||||
|
type HAState struct {
|
||||||
|
EntityID string
|
||||||
|
State string
|
||||||
|
Attributes map[string]any
|
||||||
|
LastChanged time.Time
|
||||||
|
LastUpdated time.Time
|
||||||
|
}
|
||||||
12
ha-gateway/internal/core/ports/driving/entity.go
Normal file
12
ha-gateway/internal/core/ports/driving/entity.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
package driving
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"gitea.nik4nao.com/nik/home-services/ha-gateway/internal/core/domain"
|
||||||
|
)
|
||||||
|
|
||||||
|
type EntityService interface {
|
||||||
|
GetState(ctx context.Context, id domain.EntityID) (*domain.EntityState, error)
|
||||||
|
ListStates(ctx context.Context, ids []domain.EntityID, domainFilter string) ([]*domain.EntityState, error)
|
||||||
|
}
|
||||||
13
ha-gateway/internal/core/ports/driving/light.go
Normal file
13
ha-gateway/internal/core/ports/driving/light.go
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
package driving
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
|
||||||
|
"gitea.nik4nao.com/nik/home-services/ha-gateway/internal/core/domain"
|
||||||
|
)
|
||||||
|
|
||||||
|
type LightService interface {
|
||||||
|
TurnOn(ctx context.Context, p domain.TurnOnParams) (*domain.EntityState, error)
|
||||||
|
TurnOff(ctx context.Context, p domain.TurnOffParams) (*domain.EntityState, error)
|
||||||
|
Toggle(ctx context.Context, id domain.EntityID) (*domain.EntityState, error)
|
||||||
|
}
|
||||||
78
ha-gateway/internal/telemetry/telemetry.go
Normal file
78
ha-gateway/internal/telemetry/telemetry.go
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
package telemetry
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"go.opentelemetry.io/otel"
|
||||||
|
"go.opentelemetry.io/otel/exporters/otlp/otlpmetric/otlpmetricgrpc"
|
||||||
|
"go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc"
|
||||||
|
"go.opentelemetry.io/otel/propagation"
|
||||||
|
sdkmetric "go.opentelemetry.io/otel/sdk/metric"
|
||||||
|
"go.opentelemetry.io/otel/sdk/resource"
|
||||||
|
sdktrace "go.opentelemetry.io/otel/sdk/trace"
|
||||||
|
semconv "go.opentelemetry.io/otel/semconv/v1.26.0"
|
||||||
|
|
||||||
|
"gitea.nik4nao.com/nik/home-services/ha-gateway/internal/config"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Setup initialises OTel trace and metric providers. If cfg.OTELEndpoint is
|
||||||
|
// empty, no-op providers are installed and Setup returns immediately. The
|
||||||
|
// returned shutdown func flushes and closes both exporters.
|
||||||
|
func Setup(ctx context.Context, cfg *config.Config, version string) (shutdown func(context.Context) error, err error) {
|
||||||
|
if cfg.OTELEndpoint == "" {
|
||||||
|
// Local dev — no telemetry.
|
||||||
|
return func(context.Context) error { return nil }, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
res, err := resource.New(ctx,
|
||||||
|
resource.WithAttributes(
|
||||||
|
semconv.ServiceName("ha-gateway"),
|
||||||
|
semconv.ServiceVersion(version),
|
||||||
|
),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trace exporter.
|
||||||
|
traceExp, err := otlptracegrpc.New(ctx,
|
||||||
|
otlptracegrpc.WithEndpoint(cfg.OTELEndpoint),
|
||||||
|
otlptracegrpc.WithInsecure(),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
tp := sdktrace.NewTracerProvider(
|
||||||
|
sdktrace.WithBatcher(traceExp),
|
||||||
|
sdktrace.WithResource(res),
|
||||||
|
)
|
||||||
|
otel.SetTracerProvider(tp)
|
||||||
|
otel.SetTextMapPropagator(propagation.NewCompositeTextMapPropagator(
|
||||||
|
propagation.TraceContext{},
|
||||||
|
propagation.Baggage{},
|
||||||
|
))
|
||||||
|
|
||||||
|
// Metric exporter.
|
||||||
|
metricExp, err := otlpmetricgrpc.New(ctx,
|
||||||
|
otlpmetricgrpc.WithEndpoint(cfg.OTELEndpoint),
|
||||||
|
otlpmetricgrpc.WithInsecure(),
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
_ = tp.Shutdown(ctx)
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
mp := sdkmetric.NewMeterProvider(
|
||||||
|
sdkmetric.WithReader(sdkmetric.NewPeriodicReader(metricExp,
|
||||||
|
sdkmetric.WithInterval(30*time.Second))),
|
||||||
|
sdkmetric.WithResource(res),
|
||||||
|
)
|
||||||
|
otel.SetMeterProvider(mp)
|
||||||
|
|
||||||
|
return func(ctx context.Context) error {
|
||||||
|
if err := tp.Shutdown(ctx); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return mp.Shutdown(ctx)
|
||||||
|
}, nil
|
||||||
|
}
|
||||||
17
proto/ha/v1/common.proto
Normal file
17
proto/ha/v1/common.proto
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
package ha.v1;
|
||||||
|
option go_package = "gitea.nik4nao.com/nik/home-services/gen/ha/v1;hav1";
|
||||||
|
|
||||||
|
message EntityState {
|
||||||
|
string entity_id = 1;
|
||||||
|
string state = 2;
|
||||||
|
map<string, string> attributes = 3;
|
||||||
|
string last_changed = 4; // RFC3339
|
||||||
|
string last_updated = 5; // RFC3339
|
||||||
|
}
|
||||||
|
|
||||||
|
message RGBColor {
|
||||||
|
uint32 r = 1;
|
||||||
|
uint32 g = 2;
|
||||||
|
uint32 b = 3;
|
||||||
|
}
|
||||||
18
proto/ha/v1/entity.proto
Normal file
18
proto/ha/v1/entity.proto
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
package ha.v1;
|
||||||
|
option go_package = "gitea.nik4nao.com/nik/home-services/gen/ha/v1;hav1";
|
||||||
|
import "ha/v1/common.proto";
|
||||||
|
|
||||||
|
service EntityService {
|
||||||
|
rpc GetState(GetStateRequest) returns (GetStateResponse);
|
||||||
|
rpc ListStates(ListStatesRequest) returns (ListStatesResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
message GetStateRequest { string entity_id = 1; }
|
||||||
|
message GetStateResponse { EntityState state = 1; }
|
||||||
|
|
||||||
|
message ListStatesRequest {
|
||||||
|
repeated string entity_ids = 1;
|
||||||
|
string domain = 2;
|
||||||
|
}
|
||||||
|
message ListStatesResponse { repeated EntityState states = 1; }
|
||||||
29
proto/ha/v1/event.proto
Normal file
29
proto/ha/v1/event.proto
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
package ha.v1;
|
||||||
|
option go_package = "gitea.nik4nao.com/nik/home-services/gen/ha/v1;hav1";
|
||||||
|
import "ha/v1/common.proto";
|
||||||
|
|
||||||
|
// TODO: implement EventService fan-out.
|
||||||
|
// Architecture:
|
||||||
|
// 1. adapters/secondary/ha/websocket.go connects to HA WebSocket,
|
||||||
|
// authenticates, and subscribes to state_changed events.
|
||||||
|
// 2. An internal broker (internal/fanout/broker.go) holds a sync.Map of
|
||||||
|
// subscriber channels, one per active Subscribe stream.
|
||||||
|
// 3. The WebSocket adapter publishes to the broker; the gRPC Subscribe
|
||||||
|
// handler reads from its channel and streams to the client.
|
||||||
|
// 4. On client disconnect (ctx.Done()), the handler deregisters its channel.
|
||||||
|
service EventService {
|
||||||
|
rpc Subscribe(SubscribeRequest) returns (stream StateChangeEvent);
|
||||||
|
}
|
||||||
|
|
||||||
|
message SubscribeRequest {
|
||||||
|
repeated string entity_ids = 1;
|
||||||
|
repeated string domains = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message StateChangeEvent {
|
||||||
|
string entity_id = 1;
|
||||||
|
optional EntityState old_state = 2; // absent on first appearance
|
||||||
|
EntityState new_state = 3;
|
||||||
|
string event_time = 4; // RFC3339
|
||||||
|
}
|
||||||
27
proto/ha/v1/light.proto
Normal file
27
proto/ha/v1/light.proto
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
package ha.v1;
|
||||||
|
option go_package = "gitea.nik4nao.com/nik/home-services/gen/ha/v1;hav1";
|
||||||
|
import "ha/v1/common.proto";
|
||||||
|
|
||||||
|
service LightService {
|
||||||
|
rpc TurnOn(TurnOnRequest) returns (LightResponse);
|
||||||
|
rpc TurnOff(TurnOffRequest) returns (LightResponse);
|
||||||
|
rpc Toggle(ToggleRequest) returns (LightResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
// optional fields require protobuf 3.15+ / buf >= 1.0. They generate
|
||||||
|
// pointer fields in Go with Has*() accessor methods. This is intentional —
|
||||||
|
// it lets the gateway distinguish "brightness not set" from "brightness = 0".
|
||||||
|
message TurnOnRequest {
|
||||||
|
string entity_id = 1;
|
||||||
|
optional uint32 brightness_pct = 2; // 0–100
|
||||||
|
optional uint32 color_temp_kelvin = 3; // e.g. 2700–6500
|
||||||
|
optional RGBColor rgb_color = 4; // ignored if color_temp_kelvin set
|
||||||
|
optional uint32 transition = 5; // seconds
|
||||||
|
}
|
||||||
|
message TurnOffRequest {
|
||||||
|
string entity_id = 1;
|
||||||
|
optional uint32 transition = 2;
|
||||||
|
}
|
||||||
|
message ToggleRequest { string entity_id = 1; }
|
||||||
|
message LightResponse { EntityState state = 1; }
|
||||||
18
proto/ha/v1/switch.proto
Normal file
18
proto/ha/v1/switch.proto
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
syntax = "proto3";
|
||||||
|
package ha.v1;
|
||||||
|
option go_package = "gitea.nik4nao.com/nik/home-services/gen/ha/v1;hav1";
|
||||||
|
import "ha/v1/common.proto";
|
||||||
|
|
||||||
|
// TODO: implement SwitchService. Follow the same pattern as LightService:
|
||||||
|
// - domain type in core/domain/switch.go
|
||||||
|
// - port interface in core/ports/driving/switch.go
|
||||||
|
// - application logic in app/switch.go
|
||||||
|
// - gRPC adapter in adapters/primary/grpc/switch.go
|
||||||
|
service SwitchService {
|
||||||
|
rpc TurnOn(SwitchRequest) returns (SwitchResponse);
|
||||||
|
rpc TurnOff(SwitchRequest) returns (SwitchResponse);
|
||||||
|
rpc Toggle(SwitchRequest) returns (SwitchResponse);
|
||||||
|
}
|
||||||
|
|
||||||
|
message SwitchRequest { string entity_id = 1; }
|
||||||
|
message SwitchResponse { EntityState state = 1; }
|
||||||
Loading…
x
Reference in New Issue
Block a user