Compare commits

..

17 Commits

18 changed files with 631 additions and 355 deletions

3
.gitignore vendored
View File

@ -16,3 +16,6 @@
# vendor/
.lumerc
.vscode/configurationCache.log
.vscode/dryrun.log
.vscode/targets.log

View File

@ -1,7 +1,27 @@
V ?= 0
Q = $(if $(filter 1, $V),, @)
ifeq ($(OS), Windows_NT)
EXE=lume.exe
RM=del /f /q
BUILD_DATE=$(shell powershell Get-Date -Format "yyyy-MM-ddThh:mm:sszzz")
else
EXE=lume
EXE=rm -f
BUILD_DATE=$(shell date --iso-8601=seconds)
endif
LUME_VERSION ?= $(shell git describe --tags --always)
GIT_COMMIT := $(shell git rev-parse --short HEAD)
LDFLAGS := $(LDFLAGS) \
-X git.kill0.net/chill9/lume/cmd.Version=$(LUME_VERSION) \
-X git.kill0.net/chill9/lume/cmd.BuildDate=$(BUILD_DATE) \
-X git.kill0.net/chill9/lume/cmd.GitCommit=$(GIT_COMMIT)
.PHONY: build
build:
go build -o lume ./cmd/lume
$(Q) go build -o $(EXE) -ldflags="$(LDFLAGS)" ./cmd/lume
.PHONY: clean
clean:
rm -f ./lifx
$(Q) $(RM) $(EXE)

View File

@ -16,11 +16,13 @@ const (
type Config struct {
AccessToken string `toml:"access_token"`
OutputFormat string `toml:"output_format"`
Colors map[string][]float32 `toml:"colors"`
}
type CmdArgs struct {
Flags Flags
Args []string
Client *lifx.Client
Config Config
Name string
@ -55,6 +57,7 @@ var (
defaultSaturation string = ""
defaultRGB string = ""
defaultName string = ""
defaultOutputFormat string = ""
)
func (f Flags) String(name string) string {
@ -81,12 +84,11 @@ func (f Flags) Bool(name string) bool {
return val
}
func RegisterCommand(name string, cmd Command) error {
if _, ok := commandRegistry[name]; ok {
func RegisterCommand(cmd Command) error {
if _, ok := commandRegistry[cmd.Name]; ok {
return fmt.Errorf("%s command is already registered")
}
cmd.Name = name
commandRegistry[name] = cmd
commandRegistry[cmd.Name] = cmd
return nil
}

View File

@ -5,13 +5,20 @@ import (
"sort"
)
func HelpCmd(args CmdArgs) (int, error) {
argv := args.Flags.Args()
func NewCmdHelp() Command {
return Command{
Name: "help",
Func: HelpCmd,
Use: "<command>",
Short: "Show help for a command",
}
}
if len(argv) == 0 {
func HelpCmd(args CmdArgs) (int, error) {
if len(args.Args) == 0 {
printHelp(commandRegistry)
} else if len(argv) >= 1 {
printCmdHelp(argv[0])
} else if len(args.Args) >= 1 {
printCmdHelp(args.Args[0])
}
return ExitSuccess, nil
@ -48,11 +55,15 @@ func printCmdHelp(name string) error {
if subCmd.Use != "" {
fmt.Printf("usage:\n lume %s %s\n", subCmd.Name, subCmd.Use)
fmt.Println()
} else {
fmt.Printf("usage:\n lume %s\n", subCmd.Name)
}
if subCmd.Flags != nil {
fmt.Println()
fmt.Print("flags:\n")
subCmd.Flags.PrintDefaults()
}
return nil
}

View File

@ -1,12 +1,48 @@
package lumecmd
import (
"flag"
)
func NewCmdLs() Command {
return Command{
Name: "ls",
Func: LsCmd,
Flags: func() *flag.FlagSet {
fs := flag.NewFlagSet("ls", flag.ExitOnError)
selector := fs.String("selector", defaultSelector, "Set the selector")
fs.StringVar(selector, "s", defaultSelector, "Set the selector")
fs.String("format", defaultOutputFormat, "Set the output format")
return fs
}(),
Use: "[--selector=<selector>]",
Short: "List the lights",
}
}
func LsCmd(args CmdArgs) (int, error) {
c := args.Client
selector := args.Flags.String("selector")
format := args.Flags.String("format")
if format == "" && args.Config.OutputFormat != "" {
format = args.Config.OutputFormat
}
lights, err := c.ListLights(selector)
if err != nil {
return ExitFailure, err
}
switch format {
case "table":
PrintLightsTable(lights)
default:
PrintLights(lights)
}
return ExitSuccess, nil
}

View File

@ -17,194 +17,22 @@ var userAgent string
func init() {
userAgent = initUserAgent()
RegisterCommand("help", Command{
Func: HelpCmd,
Flags: func() *flag.FlagSet {
fs := flag.NewFlagSet("help", flag.ExitOnError)
return fs
}(),
Use: "<command>",
Short: "Show help for a command",
})
RegisterCommand("ls", Command{
Func: LsCmd,
Flags: func() *flag.FlagSet {
fs := flag.NewFlagSet("ls", flag.ExitOnError)
selector := fs.String("selector", defaultSelector, "Set the selector")
fs.StringVar(selector, "s", defaultSelector, "Set the selector")
return fs
}(),
Use: "[--selector=<selector>]",
Short: "List the lights",
})
RegisterCommand("poweroff", Command{
Func: PoweroffCmd,
Flags: func() *flag.FlagSet {
fs := flag.NewFlagSet("poweroff", flag.ExitOnError)
duration := fs.Float64("duration", defaultDuration, "Set the duration")
fs.Float64Var(duration, "d", defaultDuration, "Set the duration")
selector := fs.String("selector", defaultSelector, "Set the selector")
fs.StringVar(selector, "s", defaultSelector, "Set the selector")
return fs
}(),
Use: "[--selector <selector>] [--duration <sec>]",
Short: "Power on",
})
RegisterCommand("poweron", Command{
Func: PoweronCmd,
Flags: func() *flag.FlagSet {
fs := flag.NewFlagSet("poweron", flag.ExitOnError)
duration := fs.Float64("duration", defaultDuration, "Set the duration")
fs.Float64Var(duration, "d", defaultDuration, "Set the duration")
selector := fs.String("selector", defaultSelector, "Set the selector")
fs.StringVar(selector, "s", defaultSelector, "Set the selector")
return fs
}(),
Use: "[--selector <selector>] [--duration <sec>]",
Short: "Power on",
})
RegisterCommand("set-color", Command{
Func: SetColorCmd,
Flags: func() *flag.FlagSet {
fs := flag.NewFlagSet("set-color", flag.ExitOnError)
selector := fs.String("selector", "all", "the selector")
fs.StringVar(selector, "s", "all", "the selector")
power := fs.String("power", defaultPower, "power state")
fs.StringVar(power, "p", defaultPower, "power state")
hue := fs.String("hue", defaultHue, "hue level")
fs.StringVar(hue, "H", defaultHue, "hue level")
saturation := fs.String("saturation", defaultSaturation, "saturation level")
fs.StringVar(saturation, "S", defaultSaturation, "saturation level")
rgb := fs.String("rgb", defaultRGB, "RGB value")
fs.StringVar(rgb, "r", defaultRGB, "RGB value")
name := fs.String("name", defaultName, "named color")
fs.StringVar(name, "n", defaultName, "named color")
brightness := fs.String("brightness", defaultBrightness, "brightness state")
fs.StringVar(brightness, "b", defaultBrightness, "brightness state")
duration := fs.Float64("duration", defaultDuration, "duration state")
fs.Float64Var(duration, "d", defaultDuration, "duration state")
fast := fs.Bool("fast", defaultFast, "fast state")
fs.BoolVar(fast, "f", defaultFast, "fast state")
return fs
}(),
Use: "[--selector <selector>] [--power (on|off)] [--hue <hue>] [--saturation <saturation>] [--rgb <rbg>] [--name <color>] [--brightness <brightness>] [--duration <sec>] [--fast]",
Short: "Set the color",
})
RegisterCommand("set-state", Command{
Func: SetStateCmd,
Flags: func() *flag.FlagSet {
fs := flag.NewFlagSet("set-state", flag.ExitOnError)
selector := fs.String("selector", defaultSelector, "Set the selector")
fs.StringVar(selector, "s", defaultSelector, "Set the selector")
power := fs.String("power", defaultPower, "power state")
fs.StringVar(power, "p", defaultPower, "power state")
color := fs.String("color", defaultColor, "color state")
fs.StringVar(color, "c", defaultColor, "color state")
brightness := fs.String("brightness", defaultBrightness, "brightness state")
fs.StringVar(brightness, "b", defaultBrightness, "brightness state")
duration := fs.Float64("duration", defaultDuration, "duration state")
fs.Float64Var(duration, "d", defaultDuration, "duration state")
infrared := fs.String("infrared", defaultInfrared, "infrared state")
fs.StringVar(infrared, "i", defaultInfrared, "infrared state")
fast := fs.Bool("fast", defaultFast, "fast state")
fs.BoolVar(fast, "f", defaultFast, "fast state")
return fs
}(),
Use: "[--selector <selector>] [--power (on|off)] [--color <color>] [--brightness <brightness>] [--duration <sec>] [--infrared <infrared>] [--fast]",
Short: "Set various state attributes",
})
RegisterCommand("set-white", Command{
Func: SetWhiteCmd,
Flags: func() *flag.FlagSet {
fs := flag.NewFlagSet("set-white", flag.ExitOnError)
selector := fs.String("selector", "all", "the selector")
fs.StringVar(selector, "s", "all", "the selector")
power := fs.String("power", defaultPower, "power state")
fs.StringVar(power, "p", defaultPower, "power state")
kelvin := fs.String("kelvin", defaultWhiteKelvin, "kelvin level")
fs.StringVar(kelvin, "k", defaultWhiteKelvin, "kelvin level")
name := fs.String("name", defaultWhiteName, "named white level")
fs.StringVar(name, "n", defaultWhiteName, "named white level")
brightness := fs.String("brightness", defaultBrightness, "brightness state")
fs.StringVar(brightness, "b", defaultBrightness, "brightness state")
duration := fs.Float64("duration", defaultDuration, "duration state")
fs.Float64Var(duration, "d", defaultDuration, "duration state")
infrared := fs.String("infrared", defaultInfrared, "infrared state")
fs.StringVar(infrared, "i", defaultInfrared, "infrared state")
fast := fs.Bool("fast", defaultFast, "fast state")
fs.BoolVar(fast, "f", defaultFast, "fast state")
return fs
}(),
Use: "[--selector <selector>] [--power (on|off)] [--kelvin <kelvin>] [--name <color>] [--brightness <brightness>] [--duration <sec>] [--infrared] [--fast]",
Short: "Set the white level",
})
RegisterCommand("show", Command{
Func: ShowCmd,
Flags: func() *flag.FlagSet {
fs := flag.NewFlagSet("show", flag.ExitOnError)
selector := fs.String("selector", defaultSelector, "Set the selector")
fs.StringVar(selector, "s", defaultSelector, "Set the selector")
return fs
}(),
Use: "[--selector=<selector>]",
Short: "Show details about the lights",
})
RegisterCommand("toggle", Command{
Func: ToggleCmd,
Flags: func() *flag.FlagSet {
fs := flag.NewFlagSet("toggle", flag.ExitOnError)
duration := fs.Float64("duration", defaultDuration, "Set the duration")
fs.Float64Var(duration, "d", defaultDuration, "Set the duration")
selector := fs.String("selector", defaultSelector, "Set the selector")
fs.StringVar(selector, "s", defaultSelector, "Set the selector")
return fs
}(),
Use: "[--selector <selector>] [--duration <sec>]",
Short: "Toggle the power on/off",
})
RegisterCommand(NewCmdHelp())
RegisterCommand(NewCmdLs())
RegisterCommand(NewCmdPoweroff())
RegisterCommand(NewCmdPoweron())
RegisterCommand(NewCmdSetColor())
RegisterCommand(NewCmdSetState())
RegisterCommand(NewCmdSetWhite())
RegisterCommand(NewCmdShow())
RegisterCommand(NewCmdToggle())
RegisterCommand(NewCmdVersion())
}
var Version string
var BuildDate string
var GitCommit string
const lumercFile string = ".lumerc"
func Main(args []string) (int, error) {
@ -247,6 +75,7 @@ func Main(args []string) (int, error) {
cmdArgs := CmdArgs{
Client: c,
Config: config,
Args: args[2:],
}
cmd, ok := GetCommand(command)
@ -254,11 +83,14 @@ func Main(args []string) (int, error) {
err = fmt.Errorf("lume: '%s' is not lume command. See 'lume help'", command)
return ExitFailure, err
}
fs := cmd.Flags
fs.Parse(args[2:])
fs := cmd.Flags
if fs != nil {
fs.Parse(args[2:])
cmdArgs.Flags = Flags{FlagSet: fs}
}
cmdArgs.Name = command
exitCode, err := cmd.Func(cmdArgs)
if err != nil {
err = fmt.Errorf("fatal: %s", err)

View File

@ -1,19 +1,55 @@
package lumecmd
import (
"flag"
"git.kill0.net/chill9/lifx-go"
)
func NewCmdPoweroff() Command {
return Command{
Name: "poweroff",
Func: PoweroffCmd,
Flags: func() *flag.FlagSet {
fs := flag.NewFlagSet("poweroff", flag.ExitOnError)
duration := fs.Float64("duration", defaultDuration, "Set the duration")
fs.Float64Var(duration, "d", defaultDuration, "Set the duration")
selector := fs.String("selector", defaultSelector, "Set the selector")
fs.StringVar(selector, "s", defaultSelector, "Set the selector")
fs.String("format", defaultOutputFormat, "Set the output format")
return fs
}(),
Use: "[--selector <selector>] [--duration <sec>]",
Short: "Power on",
}
}
func PoweroffCmd(args CmdArgs) (int, error) {
c := args.Client
duration := args.Flags.Float64("duration")
selector := args.Flags.String("selector")
format := args.Flags.String("format")
state := lifx.State{Power: "off", Duration: duration}
if format == "" && args.Config.OutputFormat != "" {
format = args.Config.OutputFormat
}
r, err := c.SetState(selector, state)
if err != nil {
return ExitFailure, err
}
switch format {
case "table":
PrintResultsTable(r.Results)
default:
PrintResults(r.Results)
}
return ExitSuccess, nil
}

View File

@ -1,19 +1,55 @@
package lumecmd
import (
"flag"
"git.kill0.net/chill9/lifx-go"
)
func NewCmdPoweron() Command {
return Command{
Name: "poweron",
Func: PoweronCmd,
Flags: func() *flag.FlagSet {
fs := flag.NewFlagSet("poweron", flag.ExitOnError)
duration := fs.Float64("duration", defaultDuration, "Set the duration")
fs.Float64Var(duration, "d", defaultDuration, "Set the duration")
selector := fs.String("selector", defaultSelector, "Set the selector")
fs.StringVar(selector, "s", defaultSelector, "Set the selector")
fs.String("format", defaultOutputFormat, "Set the output format")
return fs
}(),
Use: "[--selector <selector>] [--duration <sec>]",
Short: "Power on",
}
}
func PoweronCmd(args CmdArgs) (int, error) {
c := args.Client
duration := args.Flags.Float64("duration")
selector := args.Flags.String("selector")
format := args.Flags.String("format")
state := lifx.State{Power: "on", Duration: duration}
if format == "" && args.Config.OutputFormat != "" {
format = args.Config.OutputFormat
}
r, err := c.SetState(selector, state)
if err != nil {
return ExitFailure, err
}
switch format {
case "table":
PrintResultsTable(r.Results)
default:
PrintResults(r.Results)
}
return ExitSuccess, nil
}

145
cmd/print.go Normal file
View File

@ -0,0 +1,145 @@
package lumecmd
import (
"fmt"
"os"
"time"
"git.kill0.net/chill9/lifx-go"
"github.com/fatih/color"
"github.com/olekukonko/tablewriter"
)
func ColorizePower(s string) string {
c := color.New(color.FgRed)
if s == "on" {
c = color.New(color.FgGreen)
}
return c.Sprint(s)
}
func ColorizeStatus(s lifx.Status) string {
c := color.New(color.FgRed)
if s == "ok" {
c = color.New(color.FgGreen)
}
return c.Sprint(s)
}
func PrintWithIndent(indent int, s string) {
fmt.Printf("%*s%s", indent, "", s)
}
func PrintfWithIndent(indent int, format string, a ...interface{}) (n int, err error) {
format = fmt.Sprintf("%*s%s", indent, "", format)
return fmt.Printf(format, a...)
}
func makeLightsTable(lights []lifx.Light) (hdr []string, rows [][]string) {
hdr = []string{"ID", "Location", "Group", "Label", "Last Seen", "Power"}
for _, l := range lights {
rows = append(rows, []string{
fmt.Sprint(l.Id),
fmt.Sprint(l.Location.Name),
fmt.Sprint(l.Group.Name),
fmt.Sprint(l.Label),
fmt.Sprint(l.LastSeen.Local().Format(time.RFC3339)),
fmt.Sprint(ColorizePower(l.Power)),
})
}
return
}
func makeResultsTable(results []lifx.Result) (hdr []string, rows [][]string) {
hdr = []string{"ID", "Label", "Status"}
for _, r := range results {
rows = append(rows, []string{
fmt.Sprint(r.Id),
fmt.Sprint(r.Label),
fmt.Sprint(ColorizeStatus(r.Status)),
})
}
return
}
func PrintLights(lights []lifx.Light) {
sortLights(lights)
table := tablewriter.NewWriter(os.Stdout)
_, rows := makeLightsTable(lights)
for _, v := range rows {
table.Append(v)
}
fmt.Printf("total %d\n", len(lights))
table.SetAlignment(tablewriter.ALIGN_LEFT)
table.SetAutoWrapText(false)
table.SetBorder(false)
table.SetCenterSeparator("")
table.SetColumnSeparator("")
table.SetHeaderLine(false)
table.SetNoWhiteSpace(true)
table.SetRowSeparator("")
table.SetTablePadding(" ")
table.Render()
}
func PrintLightsTable(lights []lifx.Light) {
sortLights(lights)
table := tablewriter.NewWriter(os.Stdout)
hdr, rows := makeLightsTable(lights)
for _, v := range rows {
table.Append(v)
}
table.SetHeader(hdr)
table.Render()
}
func PrintResults(results []lifx.Result) {
sortResults(results)
table := tablewriter.NewWriter(os.Stdout)
_, rows := makeResultsTable(results)
for _, v := range rows {
table.Append(v)
}
fmt.Printf("total %d\n", len(results))
table.SetAlignment(tablewriter.ALIGN_LEFT)
table.SetAutoWrapText(false)
table.SetBorder(false)
table.SetCenterSeparator("")
table.SetColumnSeparator("")
table.SetHeaderLine(false)
table.SetNoWhiteSpace(true)
table.SetRowSeparator("")
table.SetTablePadding(" ")
table.Render()
}
func PrintResultsTable(results []lifx.Result) {
sortResults(results)
table := tablewriter.NewWriter(os.Stdout)
hdr, rows := makeResultsTable(results)
for _, v := range rows {
table.Append(v)
}
table.SetHeader(hdr)
table.Render()
}

View File

@ -1,15 +1,64 @@
package lumecmd
import (
"flag"
"fmt"
"git.kill0.net/chill9/lifx-go"
)
func NewCmdSetColor() Command {
return Command{
Name: "set-color",
Func: SetColorCmd,
Flags: func() *flag.FlagSet {
fs := flag.NewFlagSet("set-color", flag.ExitOnError)
selector := fs.String("selector", "all", "the selector")
fs.StringVar(selector, "s", "all", "the selector")
power := fs.String("power", defaultPower, "power state")
fs.StringVar(power, "p", defaultPower, "power state")
hue := fs.String("hue", defaultHue, "hue level")
fs.StringVar(hue, "H", defaultHue, "hue level")
saturation := fs.String("saturation", defaultSaturation, "saturation level")
fs.StringVar(saturation, "S", defaultSaturation, "saturation level")
rgb := fs.String("rgb", defaultRGB, "RGB value")
fs.StringVar(rgb, "r", defaultRGB, "RGB value")
name := fs.String("name", defaultName, "named color")
fs.StringVar(name, "n", defaultName, "named color")
brightness := fs.String("brightness", defaultBrightness, "brightness state")
fs.StringVar(brightness, "b", defaultBrightness, "brightness state")
duration := fs.Float64("duration", defaultDuration, "duration state")
fs.Float64Var(duration, "d", defaultDuration, "duration state")
fast := fs.Bool("fast", defaultFast, "fast state")
fs.BoolVar(fast, "f", defaultFast, "fast state")
fs.String("format", defaultOutputFormat, "Set the output format")
return fs
}(),
Use: "[--selector <selector>] [--power (on|off)] [--hue <hue>] [--saturation <saturation>] [--rgb <rbg>] [--name <color>] [--brightness <brightness>] [--duration <sec>] [--fast]",
Short: "Set the color",
}
}
func SetColorCmd(args CmdArgs) (int, error) {
c := args.Client
state := lifx.State{}
selector := args.Flags.String("selector")
format := args.Flags.String("format")
if format == "" && args.Config.OutputFormat != "" {
format = args.Config.OutputFormat
}
power := args.Flags.String("power")
if power != "" {
@ -77,8 +126,13 @@ func SetColorCmd(args CmdArgs) (int, error) {
}
if !fast {
switch format {
case "table":
PrintResultsTable(r.Results)
default:
PrintResults(r.Results)
}
}
return ExitSuccess, nil
}

View File

@ -1,13 +1,57 @@
package lumecmd
import (
"flag"
"git.kill0.net/chill9/lifx-go"
)
func NewCmdSetState() Command {
return Command{
Name: "set-state",
Func: SetStateCmd,
Flags: func() *flag.FlagSet {
fs := flag.NewFlagSet("set-state", flag.ExitOnError)
selector := fs.String("selector", defaultSelector, "Set the selector")
fs.StringVar(selector, "s", defaultSelector, "Set the selector")
power := fs.String("power", defaultPower, "power state")
fs.StringVar(power, "p", defaultPower, "power state")
color := fs.String("color", defaultColor, "color state")
fs.StringVar(color, "c", defaultColor, "color state")
brightness := fs.String("brightness", defaultBrightness, "brightness state")
fs.StringVar(brightness, "b", defaultBrightness, "brightness state")
duration := fs.Float64("duration", defaultDuration, "duration state")
fs.Float64Var(duration, "d", defaultDuration, "duration state")
infrared := fs.String("infrared", defaultInfrared, "infrared state")
fs.StringVar(infrared, "i", defaultInfrared, "infrared state")
fast := fs.Bool("fast", defaultFast, "fast state")
fs.BoolVar(fast, "f", defaultFast, "fast state")
fs.String("format", defaultOutputFormat, "Set the output format")
return fs
}(),
Use: "[--selector <selector>] [--power (on|off)] [--color <color>] [--brightness <brightness>] [--duration <sec>] [--infrared <infrared>] [--fast]",
Short: "Set various state attributes",
}
}
func SetStateCmd(args CmdArgs) (int, error) {
c := args.Client
state := lifx.State{}
selector := args.Flags.String("selector")
format := args.Flags.String("format")
if format == "" && args.Config.OutputFormat != "" {
format = args.Config.OutputFormat
}
power := args.Flags.String("power")
if power != "" {
@ -48,8 +92,13 @@ func SetStateCmd(args CmdArgs) (int, error) {
}
if !fast {
switch format {
case "table":
PrintResultsTable(r.Results)
default:
PrintResults(r.Results)
}
}
return ExitSuccess, nil
}

View File

@ -1,13 +1,60 @@
package lumecmd
import (
"flag"
"git.kill0.net/chill9/lifx-go"
)
func NewCmdSetWhite() Command {
return Command{
Name: "set-white",
Func: SetWhiteCmd,
Flags: func() *flag.FlagSet {
fs := flag.NewFlagSet("set-white", flag.ExitOnError)
selector := fs.String("selector", "all", "the selector")
fs.StringVar(selector, "s", "all", "the selector")
power := fs.String("power", defaultPower, "power state")
fs.StringVar(power, "p", defaultPower, "power state")
kelvin := fs.String("kelvin", defaultWhiteKelvin, "kelvin level")
fs.StringVar(kelvin, "k", defaultWhiteKelvin, "kelvin level")
name := fs.String("name", defaultWhiteName, "named white level")
fs.StringVar(name, "n", defaultWhiteName, "named white level")
brightness := fs.String("brightness", defaultBrightness, "brightness state")
fs.StringVar(brightness, "b", defaultBrightness, "brightness state")
duration := fs.Float64("duration", defaultDuration, "duration state")
fs.Float64Var(duration, "d", defaultDuration, "duration state")
infrared := fs.String("infrared", defaultInfrared, "infrared state")
fs.StringVar(infrared, "i", defaultInfrared, "infrared state")
fast := fs.Bool("fast", defaultFast, "fast state")
fs.BoolVar(fast, "f", defaultFast, "fast state")
fs.String("format", defaultOutputFormat, "Set the output format")
return fs
}(),
Use: "[--selector <selector>] [--power (on|off)] [--kelvin <kelvin>] [--name <color>] [--brightness <brightness>] [--duration <sec>] [--infrared] [--fast]",
Short: "Set the white level",
}
}
func SetWhiteCmd(args CmdArgs) (int, error) {
c := args.Client
state := lifx.State{}
selector := args.Flags.String("selector")
format := args.Flags.String("format")
if format == "" && args.Config.OutputFormat != "" {
format = args.Config.OutputFormat
}
power := args.Flags.String("power")
if power != "" {
@ -63,8 +110,13 @@ func SetWhiteCmd(args CmdArgs) (int, error) {
}
if !fast {
switch format {
case "table":
PrintResultsTable(r.Results)
default:
PrintResults(r.Results)
}
}
return ExitSuccess, nil
}

View File

@ -1,8 +1,31 @@
package lumecmd
import "fmt"
import (
"flag"
"fmt"
)
const Tabstop int = 2
func NewCmdShow() Command {
return Command{
Name: "show",
Func: ShowCmd,
Flags: func() *flag.FlagSet {
fs := flag.NewFlagSet("show", flag.ExitOnError)
selector := fs.String("selector", defaultSelector, "Set the selector")
fs.StringVar(selector, "s", defaultSelector, "Set the selector")
return fs
}(),
Use: "[--selector=<selector>]",
Short: "Show details about the lights",
}
}
func ShowCmd(args CmdArgs) (int, error) {
var indent int
c := args.Client
selector := args.Flags.String("selector")
lights, err := c.ListLights(selector)
@ -14,24 +37,26 @@ func ShowCmd(args CmdArgs) (int, error) {
sortLights(lights)
for i, l := range lights {
indent = 0
fmt.Printf(
"Light ID: %s, %s, Power: %s\n",
l.Id,
connected(l.Connected),
powerColor(l.Power),
ColorizePower(l.Power),
)
fmt.Printf(" Label: %s, ID: %s\n", l.Label, l.Id)
fmt.Printf(" UUID: %s\n", l.UUID)
fmt.Printf(" Location: %s, ID: %s\n", l.Location.Name, l.Location.Id)
fmt.Printf(" Group: %s, ID: %s\n", l.Group.Name, l.Group.Id)
fmt.Printf(" Color: Hue: %.1f, Saturation: %.1f%%, Kelvin: %d\n",
indent += Tabstop
PrintfWithIndent(indent, "Label: %s, ID: %s\n", l.Label, l.Id)
PrintfWithIndent(indent, "UUID: %s\n", l.UUID)
PrintfWithIndent(indent, "Location: %s, ID: %s\n", l.Location.Name, l.Location.Id)
PrintfWithIndent(indent, "Group: %s, ID: %s\n", l.Group.Name, l.Group.Id)
PrintfWithIndent(indent, "Color: Hue: %.1f, Saturation: %.1f%%, Kelvin: %d\n",
*l.Color.H, *l.Color.S, *l.Color.K)
fmt.Printf(" Brightness: %.1f%%\n", l.Brightness*100)
PrintfWithIndent(indent, "Brightness: %.1f%%\n", l.Brightness*100)
if l.Effect != "" {
fmt.Printf(" Effect: %s\n", l.Effect)
PrintfWithIndent(indent, "Effect: %s\n", l.Effect)
}
fmt.Printf(" Product: %s\n", l.Product.Name)
fmt.Printf(" Capabilities: ")
PrintfWithIndent(indent, "Product: %s\n", l.Product.Name)
PrintfWithIndent(indent, "Capabilities: ")
fmt.Printf("Color: %s, ", YesNo(l.Product.Capabilities.HasColor))
fmt.Printf("Variable Color Temp: %s, ", YesNo(l.Product.Capabilities.HasVariableColorTemp))
fmt.Printf("IR: %s, ", YesNo(l.Product.Capabilities.HasIR))
@ -41,14 +66,16 @@ func ShowCmd(args CmdArgs) (int, error) {
fmt.Printf("Max Kelvin: %.1f ", l.Product.Capabilities.MaxKelvin)
fmt.Println()
// List applicable selectors (most to least specific)
fmt.Printf(" Selectors:\n")
fmt.Printf(" id:%s\n", l.Id)
fmt.Printf(" label:%s\n", l.Label)
fmt.Printf(" group_id:%s\n", l.Group.Id)
fmt.Printf(" group:%s\n", l.Group.Name)
fmt.Printf(" location_id:%s\n", l.Location.Id)
fmt.Printf(" location:%s\n", l.Location.Name)
fmt.Printf(" Last Seen: %s (%.1fs ago)\n", l.LastSeen, l.SecondsLastSeen)
PrintfWithIndent(indent, "Selectors:\n")
indent += Tabstop
PrintfWithIndent(indent, "id:%s\n", l.Id)
PrintfWithIndent(indent, "label:%s\n", l.Label)
PrintfWithIndent(indent, "group_id:%s\n", l.Group.Id)
PrintfWithIndent(indent, "group:%s\n", l.Group.Name)
PrintfWithIndent(indent, "location_id:%s\n", l.Location.Id)
PrintfWithIndent(indent, "location:%s\n", l.Location.Name)
indent -= Tabstop
PrintfWithIndent(indent, "Last Seen: %s (%.1fs ago)\n", l.LastSeen, l.SecondsLastSeen)
if i < len(lights)-1 {
fmt.Println()

View File

@ -1,13 +1,52 @@
package lumecmd
import (
"flag"
)
func NewCmdToggle() Command {
return Command{
Name: "toggle",
Func: ToggleCmd,
Flags: func() *flag.FlagSet {
fs := flag.NewFlagSet("toggle", flag.ExitOnError)
duration := fs.Float64("duration", defaultDuration, "Set the duration")
fs.Float64Var(duration, "d", defaultDuration, "Set the duration")
selector := fs.String("selector", defaultSelector, "Set the selector")
fs.StringVar(selector, "s", defaultSelector, "Set the selector")
fs.String("format", defaultOutputFormat, "Set the output format")
return fs
}(),
Use: "[--selector <selector>] [--duration <sec>]",
Short: "Toggle the power on/off",
}
}
func ToggleCmd(args CmdArgs) (int, error) {
c := args.Client
duration := args.Flags.Float64("duration")
selector := args.Flags.String("selector")
format := args.Flags.String("format")
if format == "" && args.Config.OutputFormat != "" {
format = args.Config.OutputFormat
}
r, err := c.Toggle(selector, duration)
if err != nil {
return ExitFailure, err
}
switch format {
case "table":
PrintResultsTable(r.Results)
default:
PrintResults(r.Results)
}
return ExitSuccess, nil
}

View File

@ -6,116 +6,10 @@ import (
"sort"
"strconv"
"strings"
"time"
"git.kill0.net/chill9/lifx-go"
)
func powerColor(s string) string {
fs := "\033[1;31m%s\033[0m"
if s == "on" {
fs = "\033[1;32m%s\033[0m"
}
return fmt.Sprintf(fs, s)
}
func statusColor(s lifx.Status) string {
fs := "\033[1;31m%s\033[0m"
if s == "ok" {
fs = "\033[1;32m%s\033[0m"
}
return fmt.Sprintf(fs, s)
}
func PrintResults(res []lifx.Result) {
var length int
var widths map[string]int
widths = make(map[string]int)
for _, r := range res {
length = len(r.Id)
if widths["id"] < length {
widths["id"] = length
}
length = len(r.Label)
if widths["label"] < length {
widths["label"] = length
}
length = len(r.Status)
if widths["status"] < length {
widths["status"] = length
}
}
sortResults(res)
for _, r := range res {
fmt.Printf("%*s %*s %*s\n",
widths["id"], r.Id,
widths["label"], r.Label,
widths["status"], statusColor(r.Status))
}
}
func PrintLights(lights []lifx.Light) {
var length int
var widths map[string]int
widths = make(map[string]int)
for _, l := range lights {
length = len(l.Id)
if widths["id"] < length {
widths["id"] = length
}
length = len(l.Location.Name)
if widths["location"] < length {
widths["location"] = length
}
length = len(l.Group.Name)
if widths["group"] < length {
widths["group"] = length
}
length = len(l.Label)
if widths["label"] < length {
widths["label"] = length
}
length = len(l.LastSeen.Local().Format(time.RFC3339))
if widths["last_seen"] < length {
widths["last_seen"] = length
}
length = len(l.Power)
if widths["power"] < length {
widths["power"] = length
}
}
sortLights(lights)
fmt.Printf("total %d\n", len(lights))
for _, l := range lights {
fmt.Printf(
"%*s %*s %*s %*s %*s %-*s\n",
widths["id"], l.Id,
widths["loction"], l.Location.Name,
widths["group"], l.Group.Name,
widths["label"], l.Label,
widths["last_seen"], l.LastSeen.Local().Format(time.RFC3339),
widths["power"], powerColor(l.Power),
)
}
}
func parseRGB(s string) (lifx.RGBColor, error) {
var c lifx.RGBColor
rgb := strings.SplitN(s, ",", 3)
@ -166,7 +60,3 @@ func YesNo(v bool) string {
}
return "no"
}
func PrintWithIndent(indent int, s string) {
fmt.Printf("%*s%s", indent, "", s)
}

View File

@ -1,3 +1,33 @@
package lumecmd
const Version = "0.1.0-pre"
import (
"fmt"
"strings"
)
func NewCmdVersion() Command {
return Command{
Name: "version",
Func: VersionCmd,
Flags: nil,
Use: "",
Short: "Show version",
}
}
func VersionCmd(args CmdArgs) (int, error) {
var b strings.Builder
fmt.Fprintf(&b, "lume %s", Version)
b.WriteString(" ")
if GitCommit != "" {
fmt.Fprintf(&b, "(git: %s)", GitCommit)
b.WriteString(" ")
}
if BuildDate != "" {
fmt.Fprintf(&b, "build_date: %s", BuildDate)
}
fmt.Println(b.String())
return ExitSuccess, nil
}

2
go.mod
View File

@ -5,5 +5,7 @@ go 1.15
require (
git.kill0.net/chill9/lifx-go v0.0.0-20210215004437-f86c28b0a5ef
github.com/BurntSushi/toml v0.3.1
github.com/fatih/color v1.10.0
github.com/olekukonko/tablewriter v0.0.5
golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061
)

12
go.sum
View File

@ -2,5 +2,17 @@ git.kill0.net/chill9/lifx-go v0.0.0-20210215004437-f86c28b0a5ef h1:8yyXAk+qiRvro
git.kill0.net/chill9/lifx-go v0.0.0-20210215004437-f86c28b0a5ef/go.mod h1:ZFKIcwdJ4Nqlrkn/eUHbeLt0NVhFsfxBREkVoA+jzUc=
github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ=
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
github.com/fatih/color v1.10.0 h1:s36xzo75JdqLaaWoiEHk767eHiwo0598uUxyfiPkDsg=
github.com/fatih/color v1.10.0/go.mod h1:ELkj/draVOlAH/xkhN6mQ50Qd0MPOk5AAr3maGEBuJM=
github.com/mattn/go-colorable v0.1.8 h1:c1ghPdyEDarC70ftn0y+A/Ee++9zz8ljHG1b13eJ0s8=
github.com/mattn/go-colorable v0.1.8/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061 h1:DQmQoKxQWtyybCtX/3dIuDBcAhFszqq8YiNeS6sNu1c=
golang.org/x/sys v0.0.0-20210110051926-789bb1bd4061/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=