Skip to content

Commit 5f551e3

Browse files
committed
Updated home assistant
1 parent e8ff351 commit 5f551e3

File tree

9 files changed

+276
-233
lines changed

9 files changed

+276
-233
lines changed

cmd/api/cmd.go

Lines changed: 3 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ type Fn struct {
2323
Description string
2424
MinArgs uint
2525
MaxArgs uint
26+
Syntax string
2627
Call func(context.Context, *tablewriter.Writer, []string) error
2728
}
2829

@@ -39,51 +40,8 @@ func (c *Cmd) Get(name string) *Fn {
3940
}
4041

4142
func (fn *Fn) CheckArgs(args []string) error {
42-
// Check number of arguments
43-
if fn.MinArgs != 0 && uint(len(args)) < fn.MinArgs {
44-
return fmt.Errorf("not enough arguments for %q (expected >= %d)", fn.Name, fn.MinArgs)
45-
}
46-
if fn.MaxArgs != 0 && uint(len(args)) > fn.MaxArgs {
47-
return fmt.Errorf("too many arguments for %q (expected <= %d)", fn.Name, fn.MaxArgs)
43+
if (fn.MinArgs != 0 && uint(len(args)) < fn.MinArgs) || (fn.MaxArgs != 0 && uint(len(args)) > fn.MaxArgs) {
44+
return fmt.Errorf("syntax error: %s %s", fn.Name, fn.Syntax)
4845
}
4946
return nil
5047
}
51-
52-
/*
53-
if fn == nil {
54-
return nil, fmt.Errorf("unknown command %q", name)
55-
}
56-
57-
return c.getFn(name), nil
58-
// Get the command function
59-
var fn *Fn
60-
var nargs uint
61-
var out []string
62-
if len(args) == 0 {
63-
fn = c.getFn("")
64-
} else {
65-
fn = c.getFn(args[0])
66-
nargs = uint(len(args) - 1)
67-
out = args[1:]
68-
}
69-
if fn == nil {
70-
// No arguments and no default command
71-
return nil, nil, nil
72-
}
73-
74-
// Check number of arguments
75-
name := fn.Name
76-
if name == "" {
77-
name = c.Name
78-
}
79-
if fn.MinArgs != 0 && nargs < fn.MinArgs {
80-
return nil, nil, fmt.Errorf("not enough arguments for %q", name)
81-
}
82-
if fn.MaxArgs != 0 && nargs > fn.MaxArgs {
83-
return nil, nil, fmt.Errorf("too many arguments for %q", name)
84-
}
85-
86-
// Return the command
87-
return fn, out, nil
88-
}
89-
*/

cmd/api/flags.go

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ func (flags *Flags) Parse(args []string) (*Fn, []string, error) {
7979
// Parse command line
8080
err := flags.FlagSet.Parse(args)
8181

82-
// If there is a version argument, print the version and exit
82+
// Check for global commands
8383
if flags.NArg() == 1 {
8484
switch flags.Arg(0) {
8585
case "version":
@@ -104,10 +104,16 @@ func (flags *Flags) Parse(args []string) (*Fn, []string, error) {
104104
flags.cmd = cmd
105105
flags.root = strings.Join([]string{flags.Name(), cmd.Name}, " ")
106106
flags.fn = flags.Arg(1)
107-
flags.args = flags.Args()[1:]
107+
if len(flags.Args()) > 1 {
108+
flags.args = flags.Args()[2:]
109+
}
108110
}
109111
}
110112

113+
if flags.GetBool("debug") {
114+
fmt.Fprintf(os.Stderr, "Function: %q Args: %q\n", flags.fn, flags.args)
115+
}
116+
111117
// Print usage
112118
if err != nil {
113119
if err != flag.ErrHelp {
@@ -117,7 +123,7 @@ func (flags *Flags) Parse(args []string) (*Fn, []string, error) {
117123
}
118124
return nil, nil, err
119125
} else if flags.cmd == nil {
120-
fmt.Fprintln(os.Stderr, "Unknown command, try -help")
126+
fmt.Fprintf(os.Stderr, "Unknown command, try \"%s -help\"\n", flags.Name())
121127
return nil, nil, ErrHelp
122128
}
123129

@@ -140,7 +146,7 @@ func (flags *Flags) Parse(args []string) (*Fn, []string, error) {
140146
// Set the function to call
141147
fn := flags.cmd.Get(flags.fn)
142148
if fn == nil {
143-
fmt.Fprintf(os.Stderr, "Unknown command %q, try -help\n", flags.fn)
149+
fmt.Fprintf(os.Stderr, "Unknown command, try \"%s -help\"\n", flags.Name())
144150
return nil, nil, ErrHelp
145151
}
146152

@@ -151,7 +157,7 @@ func (flags *Flags) Parse(args []string) (*Fn, []string, error) {
151157
}
152158

153159
// Return success
154-
return fn, args, nil
160+
return fn, flags.args, nil
155161
}
156162

157163
// Get returns the value of a flag, and returns true if the flag exists
@@ -252,7 +258,7 @@ func (flags *Flags) PrintCommandUsage(cmd *Cmd) {
252258
// Help for command sets
253259
fmt.Fprintln(w, "Commands:")
254260
for _, fn := range cmd.Fn {
255-
fmt.Fprintln(w, " ", flags.root, fn.Name)
261+
fmt.Fprintln(w, " ", flags.root, fn.Name, fn.Syntax)
256262
fmt.Fprintln(w, " ", fn.Description)
257263
fmt.Fprintln(w, "")
258264
}

cmd/api/homeassistant.go

Lines changed: 68 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,6 @@ package main
22

33
import (
44
"context"
5-
"fmt"
6-
"slices"
75
"strings"
86
"time"
97

@@ -16,16 +14,19 @@ import (
1614
// TYPES
1715

1816
type haEntity struct {
19-
Id string `json:"entity_id"`
17+
Id string `json:"entity_id,width:40"`
2018
Name string `json:"name,omitempty"`
2119
Class string `json:"class,omitempty"`
20+
Domain string `json:"domain,omitempty"`
2221
State string `json:"state,omitempty"`
2322
Attributes map[string]interface{} `json:"attributes,omitempty,wrap"`
24-
UpdatedAt time.Time `json:"last_updated,omitempty"`
23+
UpdatedAt time.Time `json:"last_updated,omitempty,width:34"`
24+
ChangedAt time.Time `json:"last_changed,omitempty,width:34"`
2525
}
2626

27-
type haClass struct {
28-
Class string `json:"class,omitempty"`
27+
type haDomain struct {
28+
Name string `json:"domain"`
29+
Services string `json:"services,omitempty"`
2930
}
3031

3132
///////////////////////////////////////////////////////////////////////////////
@@ -49,8 +50,9 @@ func haRegister(flags *Flags) {
4950
Description: "Information from home assistant",
5051
Parse: haParse,
5152
Fn: []Fn{
52-
{Name: "classes", Call: haClasses, Description: "Return entity classes"},
53-
{Name: "states", Call: haStates, Description: "Return entity states"},
53+
{Name: "domains", Call: haDomains, Description: "Enumerate entity domains"},
54+
{Name: "states", Call: haStates, Description: "Show current entity states", MaxArgs: 1, Syntax: "(<name>)"},
55+
{Name: "services", Call: haServices, Description: "Show services for an entity", MinArgs: 1, MaxArgs: 1, Syntax: "<entity>"},
5456
},
5557
})
5658
}
@@ -71,14 +73,25 @@ func haParse(flags *Flags, opts ...client.ClientOpt) error {
7173
// METHODS
7274

7375
func haStates(_ context.Context, w *tablewriter.Writer, args []string) error {
74-
if states, err := haGetStates(args); err != nil {
76+
var result []haEntity
77+
states, err := haGetStates(nil)
78+
if err != nil {
7579
return err
76-
} else {
77-
return w.Write(states)
7880
}
81+
82+
for _, state := range states {
83+
if len(args) == 1 {
84+
if !haMatchString(args[0], state.Name, state.Id) {
85+
continue
86+
}
87+
88+
}
89+
result = append(result, state)
90+
}
91+
return w.Write(result)
7992
}
8093

81-
func haClasses(_ context.Context, w *tablewriter.Writer, args []string) error {
94+
func haDomains(_ context.Context, w *tablewriter.Writer, args []string) error {
8295
states, err := haGetStates(nil)
8396
if err != nil {
8497
return err
@@ -89,17 +102,42 @@ func haClasses(_ context.Context, w *tablewriter.Writer, args []string) error {
89102
classes[state.Class] = true
90103
}
91104

92-
result := []haClass{}
105+
result := []haDomain{}
93106
for c := range classes {
94-
result = append(result, haClass{Class: c})
107+
result = append(result, haDomain{
108+
Name: c,
109+
})
95110
}
96111
return w.Write(result)
97112
}
98113

114+
func haServices(_ context.Context, w *tablewriter.Writer, args []string) error {
115+
service, err := haClient.State(args[0])
116+
if err != nil {
117+
return err
118+
}
119+
services, err := haClient.Services(service.Domain())
120+
if err != nil {
121+
return err
122+
}
123+
return w.Write(services)
124+
}
125+
99126
///////////////////////////////////////////////////////////////////////////////
100127
// PRIVATE METHODS
101128

102-
func haGetStates(classes []string) ([]haEntity, error) {
129+
func haMatchString(q string, values ...string) bool {
130+
q = strings.ToLower(q)
131+
for _, v := range values {
132+
v = strings.ToLower(v)
133+
if strings.Contains(v, q) {
134+
return true
135+
}
136+
}
137+
return false
138+
}
139+
140+
func haGetStates(domains []string) ([]haEntity, error) {
103141
var result []haEntity
104142

105143
// Get states from the remote service
@@ -112,37 +150,29 @@ func haGetStates(classes []string) ([]haEntity, error) {
112150
for _, state := range states {
113151
entity := haEntity{
114152
Id: state.Entity,
115-
State: state.State,
153+
Name: state.Name(),
154+
Domain: state.Domain(),
155+
Class: state.Class(),
156+
State: state.Value(),
116157
Attributes: state.Attributes,
117-
UpdatedAt: state.LastChanged,
158+
UpdatedAt: state.LastUpdated,
159+
ChangedAt: state.LastChanged,
118160
}
119161

120-
// Ignore entities without state
121-
if entity.State == "" || entity.State == "unknown" || entity.State == "unavailable" {
162+
// Ignore any fields where the state is empty
163+
if entity.State == "" {
122164
continue
123165
}
124166

125-
// Set entity type and name from entity id
126-
parts := strings.SplitN(entity.Id, ".", 2)
127-
if len(parts) >= 2 {
128-
entity.Class = strings.ToLower(parts[0])
129-
entity.Name = parts[1]
130-
}
131-
132-
// Set entity type from device class
133-
if t, exists := state.Attributes["device_class"]; exists {
134-
entity.Class = fmt.Sprint(t)
167+
// Add unit of measurement
168+
if unit := state.UnitOfMeasurement(); unit != "" {
169+
entity.State += " " + unit
135170
}
136171

137-
// Filter classes
138-
if len(classes) > 0 && !slices.Contains(classes, entity.Class) {
139-
continue
140-
}
141-
142-
// Set entity name from attributes
143-
if name, exists := state.Attributes["friendly_name"]; exists {
144-
entity.Name = fmt.Sprint(name)
145-
}
172+
// Filter domains
173+
//if len(domains) > 0 && !slices.Contains(domains, entity.Domain) {
174+
// continue
175+
//}
146176

147177
// Append results
148178
result = append(result, entity)

pkg/homeassistant/client_test.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -22,18 +22,18 @@ func Test_client_001(t *testing.T) {
2222
// ENVIRONMENT
2323

2424
func GetApiKey(t *testing.T) string {
25-
key := os.Getenv("HA_API_KEY")
25+
key := os.Getenv("HA_TOKEN")
2626
if key == "" {
27-
t.Skip("HA_API_KEY not set")
27+
t.Skip("HA_TOKEN not set")
2828
t.SkipNow()
2929
}
3030
return key
3131
}
3232

3333
func GetEndPoint(t *testing.T) string {
34-
key := os.Getenv("HA_API_URL")
34+
key := os.Getenv("HA_ENDPOINT")
3535
if key == "" {
36-
t.Skip("HA_API_URL not set")
36+
t.Skip("HA_ENDPOINT not set")
3737
t.SkipNow()
3838
}
3939
return key

0 commit comments

Comments
 (0)