Rewrite itctl to use urfave/cli instead of spf13/cobra

This commit is contained in:
2022-02-24 21:26:40 -08:00
parent 9e63401db3
commit a885eacc70
36 changed files with 576 additions and 2333 deletions

View File

@@ -1,35 +0,0 @@
/*
* itd uses bluetooth low energy to communicate with InfiniTime devices
* Copyright (C) 2021 Arsen Musayelyan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package filesystem
import (
"github.com/spf13/cobra"
"go.arsenm.dev/itd/cmd/itctl/root"
)
// filesystemCmd represents the filesystem command
var filesystemCmd = &cobra.Command{
Use: "filesystem",
Aliases: []string{"fs"},
Short: "Perform filesystem operations on the PineTime",
}
func init() {
root.RootCmd.AddCommand(filesystemCmd)
}

View File

@@ -1,56 +0,0 @@
/*
* itd uses bluetooth low energy to communicate with InfiniTime devices
* Copyright (C) 2021 Arsen Musayelyan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package filesystem
import (
"fmt"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"go.arsenm.dev/itd/api"
)
// listCmd represents the list command
var listCmd = &cobra.Command{
Use: "list [path]",
Aliases: []string{"ls"},
Short: "List a directory",
Run: func(cmd *cobra.Command, args []string) {
dirPath := "/"
if len(args) > 0 {
dirPath = args[0]
}
client := viper.Get("client").(*api.Client)
listing, err := client.ReadDir(dirPath)
if err != nil {
log.Fatal().Err(err).Msg("Error getting directory listing")
}
for _, entry := range listing {
fmt.Println(entry)
}
},
}
func init() {
filesystemCmd.AddCommand(listCmd)
}

View File

@@ -1,49 +0,0 @@
/*
* itd uses bluetooth low energy to communicate with InfiniTime devices
* Copyright (C) 2021 Arsen Musayelyan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package filesystem
import (
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"go.arsenm.dev/itd/api"
)
// mkdirCmd represents the mkdir command
var mkdirCmd = &cobra.Command{
Use: "mkdir <path...>",
Short: "Create a new directory",
Run: func(cmd *cobra.Command, args []string) {
if len(args) < 1 {
cmd.Usage()
log.Fatal().Msg("Command mkdir requires one or more arguments")
}
client := viper.Get("client").(*api.Client)
err := client.Mkdir(args...)
if err != nil {
log.Fatal().Err(err).Msg("Error creating directory")
}
},
}
func init() {
filesystemCmd.AddCommand(mkdirCmd)
}

View File

@@ -1,50 +0,0 @@
/*
* itd uses bluetooth low energy to communicate with InfiniTime devices
* Copyright (C) 2021 Arsen Musayelyan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package filesystem
import (
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"go.arsenm.dev/itd/api"
)
// moveCmd represents the move command
var moveCmd = &cobra.Command{
Use: "move <old> <new>",
Aliases: []string{"mv"},
Short: "Move a file or directory",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 2 {
cmd.Usage()
log.Fatal().Msg("Command move requires two arguments")
}
client := viper.Get("client").(*api.Client)
err := client.Rename(args[0], args[1])
if err != nil {
log.Fatal().Err(err).Msg("Error moving file or directory")
}
},
}
func init() {
filesystemCmd.AddCommand(moveCmd)
}

View File

@@ -1,95 +0,0 @@
/*
* itd uses bluetooth low energy to communicate with InfiniTime devices
* Copyright (C) 2021 Arsen Musayelyan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package filesystem
import (
"io"
"io/ioutil"
"os"
"path/filepath"
"github.com/cheggaaa/pb/v3"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"go.arsenm.dev/itd/api"
)
// readCmd represents the read command
var readCmd = &cobra.Command{
Use: `read <remote path> <local path | "-">`,
Short: "Read a file from InfiniTime",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 2 {
cmd.Usage()
log.Fatal().Msg("Command read requires two arguments")
}
var tmpFile *os.File
var path string
var err error
if args[1] == "-" {
tmpFile, err = ioutil.TempFile("/tmp", "itctl.*")
if err != nil {
log.Fatal().Err(err).Msg("Error creating temporary file")
}
path = tmpFile.Name()
} else {
path, err = filepath.Abs(args[1])
if err != nil {
log.Fatal().Err(err).Msg("Error making absolute directory")
}
}
client := viper.Get("client").(*api.Client)
progress, err := client.ReadFile(path, args[0])
if err != nil {
log.Fatal().Err(err).Msg("Error reading remote file")
}
// Create progress bar template
barTmpl := `{{counters . }} B {{bar . "|" "-" (cycle .) " " "|"}} {{percent . }} {{rtime . "%s"}}`
// Start full bar at 0 total
bar := pb.ProgressBarTemplate(barTmpl).Start(0)
// Get progress events
for event := range progress {
// Set total bytes in progress bar
bar.SetTotal(int64(event.Total))
// Set amount of bytes sent in progress bar
bar.SetCurrent(int64(event.Sent))
// If transfer finished, break
if event.Done {
bar.Finish()
break
}
}
if args[1] == "-" {
io.Copy(os.Stdout, tmpFile)
os.Stdout.WriteString("\n")
os.Stdout.Sync()
tmpFile.Close()
}
},
}
func init() {
filesystemCmd.AddCommand(readCmd)
}

View File

@@ -1,50 +0,0 @@
/*
* itd uses bluetooth low energy to communicate with InfiniTime devices
* Copyright (C) 2021 Arsen Musayelyan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package filesystem
import (
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"go.arsenm.dev/itd/api"
)
// removeCmd represents the remove command
var removeCmd = &cobra.Command{
Use: "remove <path...>",
Aliases: []string{"rm"},
Short: "Create a new directory",
Run: func(cmd *cobra.Command, args []string) {
if len(args) < 1 {
cmd.Usage()
log.Fatal().Msg("Command mkdir requires one or more arguments")
}
client := viper.Get("client").(*api.Client)
err := client.Remove(args...)
if err != nil {
log.Fatal().Err(err).Msg("Error removing file or directory")
}
},
}
func init() {
filesystemCmd.AddCommand(removeCmd)
}

View File

@@ -1,94 +0,0 @@
/*
* itd uses bluetooth low energy to communicate with InfiniTime devices
* Copyright (C) 2021 Arsen Musayelyan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package filesystem
import (
"io"
"io/ioutil"
"os"
"path/filepath"
"github.com/cheggaaa/pb/v3"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"go.arsenm.dev/itd/api"
)
// writeCmd represents the write command
var writeCmd = &cobra.Command{
Use: `write <local path | "-"> <remote path>`,
Short: "Write a file to InfiniTime",
Run: func(cmd *cobra.Command, args []string) {
if len(args) != 2 {
cmd.Usage()
log.Fatal().Msg("Command write requires two arguments")
}
var tmpFile *os.File
var path string
var err error
if args[0] == "-" {
tmpFile, err = ioutil.TempFile("/tmp", "itctl.*")
if err != nil {
log.Fatal().Err(err).Msg("Error creating temporary file")
}
path = tmpFile.Name()
} else {
path, err = filepath.Abs(args[0])
if err != nil {
log.Fatal().Err(err).Msg("Error making absolute directory")
}
}
client := viper.Get("client").(*api.Client)
if args[0] == "-" {
io.Copy(tmpFile, os.Stdin)
defer tmpFile.Close()
defer os.Remove(path)
}
progress, err := client.WriteFile(path, args[1])
if err != nil {
log.Fatal().Err(err).Msg("Error moving file or directory")
}
// Create progress bar template
barTmpl := `{{counters . }} B {{bar . "|" "-" (cycle .) " " "|"}} {{percent . }} {{rtime . "%s"}}`
// Start full bar at 0 total
bar := pb.ProgressBarTemplate(barTmpl).Start(0)
// Get progress events
for event := range progress {
// Set total bytes in progress bar
bar.SetTotal(int64(event.Total))
// Set amount of bytes sent in progress bar
bar.SetCurrent(int64(event.Sent))
// If transfer finished, break
if event.Done {
bar.Finish()
break
}
}
},
}
func init() {
filesystemCmd.AddCommand(writeCmd)
}

80
cmd/itctl/firmware.go Normal file
View File

@@ -0,0 +1,80 @@
package main
import (
"fmt"
"path/filepath"
"time"
"github.com/cheggaaa/pb/v3"
"github.com/urfave/cli/v2"
"go.arsenm.dev/itd/api"
"go.arsenm.dev/itd/internal/types"
)
func fwUpgrade(c *cli.Context) error {
start := time.Now()
var upgType api.UpgradeType
var files []string
// Get relevant data struct
if c.String("archive") != "" {
// Get archive data struct
upgType = types.UpgradeTypeArchive
files = []string{c.String("archive")}
} else if c.String("init-packet") != "" && c.String("firmware") != "" {
// Get files data struct
upgType = types.UpgradeTypeFiles
files = []string{c.String("init-packet"), c.String("firmware")}
} else {
return cli.Exit("Upgrade command requires either archive or init packet and firmware.", 1)
}
progress, err := client.FirmwareUpgrade(upgType, abs(files)...)
if err != nil {
return err
}
// Create progress bar template
barTmpl := `{{counters . }} B {{bar . "|" "-" (cycle .) " " "|"}} {{percent . }} {{rtime . "%s"}}`
// Start full bar at 0 total
bar := pb.ProgressBarTemplate(barTmpl).Start(0)
// Create new scanner of connection
for event := range progress {
// Set total bytes in progress bar
bar.SetTotal(event.Total)
// Set amount of bytes received in progress bar
bar.SetCurrent(event.Received)
// If transfer finished, break
if event.Sent == event.Total {
break
}
}
// Finish progress bar
bar.Finish()
fmt.Printf("Transferred %d B in %s.\n", bar.Total(), time.Since(start))
fmt.Println("Remember to validate the new firmware in the InfiniTime settings.")
return nil
}
func fwVersion(c *cli.Context) error {
version, err := client.Version()
if err != nil {
return err
}
fmt.Println(version)
return nil
}
func abs(paths []string) []string {
for index, path := range paths {
newPath, err := filepath.Abs(path)
if err != nil {
continue
}
paths[index] = newPath
}
return paths
}

View File

@@ -1,35 +0,0 @@
/*
* itd uses bluetooth low energy to communicate with InfiniTime devices
* Copyright (C) 2021 Arsen Musayelyan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package firmware
import (
"github.com/spf13/cobra"
"go.arsenm.dev/itd/cmd/itctl/root"
)
// firmwareCmd represents the firmware command
var firmwareCmd = &cobra.Command{
Use: "firmware",
Short: "Manage InfiniTime firmware",
Aliases: []string{"fw"},
}
func init() {
root.RootCmd.AddCommand(firmwareCmd)
}

View File

@@ -1,117 +0,0 @@
/*
* itd uses bluetooth low energy to communicate with InfiniTime devices
* Copyright (C) 2021 Arsen Musayelyan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package firmware
import (
"fmt"
"path/filepath"
"time"
"github.com/cheggaaa/pb/v3"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"go.arsenm.dev/itd/api"
"go.arsenm.dev/itd/internal/types"
)
type DFUProgress struct {
Received int64 `mapstructure:"recvd"`
Total int64 `mapstructure:"total"`
}
// upgradeCmd represents the upgrade command
var upgradeCmd = &cobra.Command{
Use: "upgrade",
Short: "Upgrade InfiniTime firmware using files or archive",
Aliases: []string{"upg"},
Run: func(cmd *cobra.Command, args []string) {
start := time.Now()
client := viper.Get("client").(*api.Client)
var upgType api.UpgradeType
var files []string
// Get relevant data struct
if viper.GetString("archive") != "" {
// Get archive data struct
upgType = types.UpgradeTypeArchive
files = []string{viper.GetString("archive")}
} else if viper.GetString("initPkt") != "" && viper.GetString("firmware") != "" {
// Get files data struct
upgType = types.UpgradeTypeFiles
files = []string{viper.GetString("initPkt"), viper.GetString("firmware")}
} else {
cmd.Usage()
log.Warn().Msg("Upgrade command requires either archive or init packet and firmware.")
return
}
progress, err := client.FirmwareUpgrade(upgType, abs(files)...)
if err != nil {
log.Fatal().Err(err).Msg("Error initiating DFU")
}
// Create progress bar template
barTmpl := `{{counters . }} B {{bar . "|" "-" (cycle .) " " "|"}} {{percent . }} {{rtime . "%s"}}`
// Start full bar at 0 total
bar := pb.ProgressBarTemplate(barTmpl).Start(0)
// Create new scanner of connection
for event := range progress {
// Set total bytes in progress bar
bar.SetTotal(event.Total)
// Set amount of bytes received in progress bar
bar.SetCurrent(event.Received)
// If transfer finished, break
if event.Sent == event.Total {
break
}
}
// Finish progress bar
bar.Finish()
fmt.Printf("Transferred %d B in %s.\n", bar.Total(), time.Since(start))
fmt.Println("Remember to validate the new firmware in the InfiniTime settings.")
},
}
func abs(paths []string) []string {
for index, path := range paths {
newPath, err := filepath.Abs(path)
if err != nil {
continue
}
paths[index] = newPath
}
return paths
}
func init() {
firmwareCmd.AddCommand(upgradeCmd)
// Register flags
upgradeCmd.Flags().StringP("archive", "a", "", "Path to firmware archive")
upgradeCmd.Flags().StringP("init-pkt", "i", "", "Path to init packet (.dat file)")
upgradeCmd.Flags().StringP("firmware", "f", "", "Path to firmware image (.bin file)")
// Bind flags to viper keys
viper.BindPFlag("archive", upgradeCmd.Flags().Lookup("archive"))
viper.BindPFlag("initPkt", upgradeCmd.Flags().Lookup("init-pkt"))
viper.BindPFlag("firmware", upgradeCmd.Flags().Lookup("firmware"))
}

View File

@@ -1,49 +0,0 @@
/*
* itd uses bluetooth low energy to communicate with InfiniTime devices
* Copyright (C) 2021 Arsen Musayelyan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package firmware
import (
"fmt"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"go.arsenm.dev/itd/api"
)
// versionCmd represents the version command
var versionCmd = &cobra.Command{
Use: "version",
Aliases: []string{"ver"},
Short: "Get firmware version of InfiniTime",
Run: func(cmd *cobra.Command, args []string) {
client := viper.Get("client").(*api.Client)
version, err := client.Version()
if err != nil {
log.Fatal().Err(err).Msg("Error getting firmware version")
}
fmt.Println(version)
},
}
func init() {
firmwareCmd.AddCommand(versionCmd)
}

174
cmd/itctl/fs.go Normal file
View File

@@ -0,0 +1,174 @@
package main
import (
"fmt"
"io"
"io/ioutil"
"os"
"path/filepath"
"github.com/cheggaaa/pb/v3"
"github.com/urfave/cli/v2"
)
func fsList(c *cli.Context) error {
dirPath := "/"
if c.Args().Len() > 0 {
dirPath = c.Args().Get(0)
}
listing, err := client.ReadDir(dirPath)
if err != nil {
return err
}
for _, entry := range listing {
fmt.Println(entry)
}
return nil
}
func fsMkdir(c *cli.Context) error {
if c.Args().Len() < 1 {
return cli.Exit("Command mkdir requires one or more arguments", 1)
}
err := client.Mkdir(c.Args().Slice()...)
if err != nil {
return err
}
return nil
}
func fsMove(c *cli.Context) error {
if c.Args().Len() != 2 {
return cli.Exit("Command move requires two arguments", 1)
}
err := client.Rename(c.Args().Get(0), c.Args().Get(1))
if err != nil {
return err
}
return nil
}
func fsRead(c *cli.Context) error {
if c.Args().Len() != 2 {
return cli.Exit("Command read requires two arguments", 1)
}
var tmpFile *os.File
var path string
var err error
if c.Args().Get(1) == "-" {
tmpFile, err = ioutil.TempFile("/tmp", "itctl.*")
if err != nil {
return err
}
path = tmpFile.Name()
} else {
path, err = filepath.Abs(c.Args().Get(1))
if err != nil {
return err
}
}
progress, err := client.ReadFile(path, c.Args().Get(0))
if err != nil {
return err
}
// Create progress bar template
barTmpl := `{{counters . }} B {{bar . "|" "-" (cycle .) " " "|"}} {{percent . }} {{rtime . "%s"}}`
// Start full bar at 0 total
bar := pb.ProgressBarTemplate(barTmpl).Start(0)
// Get progress events
for event := range progress {
// Set total bytes in progress bar
bar.SetTotal(int64(event.Total))
// Set amount of bytes sent in progress bar
bar.SetCurrent(int64(event.Sent))
// If transfer finished, break
if event.Done {
bar.Finish()
break
}
}
if c.Args().Get(1) == "-" {
io.Copy(os.Stdout, tmpFile)
os.Stdout.WriteString("\n")
os.Stdout.Sync()
tmpFile.Close()
}
return nil
}
func fsRemove(c *cli.Context) error {
if c.Args().Len() < 1 {
return cli.Exit("Command remove requires one or more arguments", 1)
}
err := client.Remove(c.Args().Slice()...)
if err != nil {
return err
}
return nil
}
func fsWrite(c *cli.Context) error {
if c.Args().Len() != 2 {
return cli.Exit("Command write requires two arguments", 1)
}
var tmpFile *os.File
var path string
var err error
if c.Args().Get(0) == "-" {
tmpFile, err = ioutil.TempFile("/tmp", "itctl.*")
if err != nil {
return err
}
path = tmpFile.Name()
} else {
path, err = filepath.Abs(c.Args().Get(0))
if err != nil {
return err
}
}
if c.Args().Get(0) == "-" {
io.Copy(tmpFile, os.Stdin)
defer tmpFile.Close()
defer os.Remove(path)
}
progress, err := client.WriteFile(path, c.Args().Get(1))
if err != nil {
return err
}
// Create progress bar template
barTmpl := `{{counters . }} B {{bar . "|" "-" (cycle .) " " "|"}} {{percent . }} {{rtime . "%s"}}`
// Start full bar at 0 total
bar := pb.ProgressBarTemplate(barTmpl).Start(0)
// Get progress events
for event := range progress {
// Set total bytes in progress bar
bar.SetTotal(int64(event.Total))
// Set amount of bytes sent in progress bar
bar.SetCurrent(int64(event.Sent))
// If transfer finished, break
if event.Done {
bar.Finish()
break
}
}
return nil
}

71
cmd/itctl/get.go Normal file
View File

@@ -0,0 +1,71 @@
package main
import (
"encoding/json"
"fmt"
"os"
"github.com/urfave/cli/v2"
)
func getAddress(c *cli.Context) error {
address, err := client.Address()
if err != nil {
return err
}
fmt.Println(address)
return nil
}
func getBattery(c *cli.Context) error {
battLevel, err := client.BatteryLevel()
if err != nil {
return err
}
// Print returned percentage
fmt.Printf("%d%%\n", battLevel)
return nil
}
func getHeart(c *cli.Context) error {
heartRate, err := client.HeartRate()
if err != nil {
return err
}
// Print returned BPM
fmt.Printf("%d BPM\n", heartRate)
return nil
}
func getMotion(c *cli.Context) error {
motionVals, err := client.Motion()
if err != nil {
return err
}
if c.Bool("shell") {
fmt.Printf(
"X=%d\nY=%d\nZ=%d\n",
motionVals.X,
motionVals.Y,
motionVals.Z,
)
} else {
return json.NewEncoder(os.Stdout).Encode(motionVals)
}
return nil
}
func getSteps(c *cli.Context) error {
stepCount, err := client.StepCount()
if err != nil {
return err
}
// Print returned BPM
fmt.Printf("%d Steps\n", stepCount)
return nil
}

View File

@@ -1,59 +0,0 @@
/*
* itd uses bluetooth low energy to communicate with InfiniTime devices
* Copyright (C) 2021 Arsen Musayelyan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package get
import (
"fmt"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"go.arsenm.dev/itd/api"
)
// addressCmd represents the address command
var addressCmd = &cobra.Command{
Use: "address",
Aliases: []string{"addr"},
Short: "Get InfiniTime's bluetooth address",
Run: func(cmd *cobra.Command, args []string) {
client := viper.Get("client").(*api.Client)
address, err := client.Address()
if err != nil {
log.Fatal().Err(err).Msg("Error getting bluetooth address")
}
fmt.Println(address)
},
}
func init() {
getCmd.AddCommand(addressCmd)
// Here you will define your flags and configuration settings.
// Cobra supports Persistent Flags which will work for this command
// and all subcommands, e.g.:
// addressCmd.PersistentFlags().String("foo", "", "A help for foo")
// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
// addressCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

View File

@@ -1,50 +0,0 @@
/*
* itd uses bluetooth low energy to communicate with InfiniTime devices
* Copyright (C) 2021 Arsen Musayelyan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package get
import (
"fmt"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"go.arsenm.dev/itd/api"
)
// batteryCmd represents the batt command
var batteryCmd = &cobra.Command{
Use: "battery",
Aliases: []string{"batt"},
Short: "Get battery level from InfiniTime",
Run: func(cmd *cobra.Command, args []string) {
client := viper.Get("client").(*api.Client)
battLevel, err := client.BatteryLevel()
if err != nil {
log.Fatal().Err(err).Msg("Error getting battery level")
}
// Print returned percentage
fmt.Printf("%d%%\n", battLevel)
},
}
func init() {
getCmd.AddCommand(batteryCmd)
}

View File

@@ -1,34 +0,0 @@
/*
* itd uses bluetooth low energy to communicate with InfiniTime devices
* Copyright (C) 2021 Arsen Musayelyan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package get
import (
"github.com/spf13/cobra"
"go.arsenm.dev/itd/cmd/itctl/root"
)
// getCmd represents the get command
var getCmd = &cobra.Command{
Use: "get",
Short: "Get information from InfiniTime",
}
func init() {
root.RootCmd.AddCommand(getCmd)
}

View File

@@ -1,49 +0,0 @@
/*
* itd uses bluetooth low energy to communicate with InfiniTime devices
* Copyright (C) 2021 Arsen Musayelyan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package get
import (
"fmt"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"go.arsenm.dev/itd/api"
)
// heartCmd represents the heart command
var heartCmd = &cobra.Command{
Use: "heart",
Short: "Get heart rate from InfiniTime",
Run: func(cmd *cobra.Command, args []string) {
client := viper.Get("client").(*api.Client)
heartRate, err := client.HeartRate()
if err != nil {
log.Fatal().Err(err).Msg("Error getting heart rate")
}
// Print returned BPM
fmt.Printf("%d BPM\n", heartRate)
},
}
func init() {
getCmd.AddCommand(heartCmd)
}

View File

@@ -1,68 +0,0 @@
/*
* itd uses bluetooth low energy to communicate with InfiniTime devices
* Copyright (C) 2021 Arsen Musayelyan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package get
import (
"fmt"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"go.arsenm.dev/itd/api"
)
// steps.goCmd represents the steps.go command
var motionCmd = &cobra.Command{
Use: "motion",
Short: "Get motion values from InfiniTime",
Run: func(cmd *cobra.Command, args []string) {
client := viper.Get("client").(*api.Client)
motionVals, err := client.Motion()
if err != nil {
log.Fatal().Err(err).Msg("Error getting motion values")
}
if viper.GetBool("shell") {
fmt.Printf(
"X=%d\nY=%d\nZ=%d",
motionVals.X,
motionVals.Y,
motionVals.Z,
)
} else {
fmt.Printf("%+v\n", motionVals)
}
},
}
func init() {
getCmd.AddCommand(motionCmd)
// Here you will define your flags and configuration settings.
// Cobra supports Persistent Flags which will work for this command
// and all subcommands, e.g.:
// steps.goCmd.PersistentFlags().String("foo", "", "A help for foo")
// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
motionCmd.Flags().BoolP("shell", "s", false, "Output data in shell-compatible format")
viper.BindPFlag("shell", motionCmd.Flags().Lookup("shell"))
}

View File

@@ -1,59 +0,0 @@
/*
* itd uses bluetooth low energy to communicate with InfiniTime devices
* Copyright (C) 2021 Arsen Musayelyan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package get
import (
"fmt"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"go.arsenm.dev/itd/api"
)
// steps.goCmd represents the steps.go command
var stepsCmd = &cobra.Command{
Use: "steps",
Short: "Get step count from InfiniTime",
Run: func(cmd *cobra.Command, args []string) {
client := viper.Get("client").(*api.Client)
stepCount, err := client.StepCount()
if err != nil {
log.Fatal().Err(err).Msg("Error getting step count")
}
// Print returned BPM
fmt.Printf("%d Steps\n", stepCount)
},
}
func init() {
getCmd.AddCommand(stepsCmd)
// Here you will define your flags and configuration settings.
// Cobra supports Persistent Flags which will work for this command
// and all subcommands, e.g.:
// steps.goCmd.PersistentFlags().String("foo", "", "A help for foo")
// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
// steps.goCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

View File

@@ -1,43 +1,202 @@
/*
* itd uses bluetooth low energy to communicate with InfiniTime devices
* Copyright (C) 2021 Arsen Musayelyan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package main
import (
_ "go.arsenm.dev/itd/cmd/itctl/firmware"
_ "go.arsenm.dev/itd/cmd/itctl/get"
_ "go.arsenm.dev/itd/cmd/itctl/notify"
"go.arsenm.dev/itd/cmd/itctl/root"
_ "go.arsenm.dev/itd/cmd/itctl/set"
_ "go.arsenm.dev/itd/cmd/itctl/watch"
_ "go.arsenm.dev/itd/cmd/itctl/filesystem"
_ "go.arsenm.dev/itd/cmd/itctl/update"
"os"
"github.com/rs/zerolog"
"github.com/rs/zerolog/log"
"github.com/urfave/cli/v2"
"go.arsenm.dev/itd/api"
)
func init() {
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
}
var client *api.Client
func main() {
root.Execute()
log.Logger = log.Output(zerolog.ConsoleWriter{Out: os.Stderr})
app := cli.App{
Name: "itctl",
Flags: []cli.Flag{
&cli.StringFlag{
Name: "socket-path",
Aliases: []string{"s"},
Value: api.DefaultAddr,
Usage: "Path to itd socket",
},
},
Commands: []*cli.Command{
{
Name: "filesystem",
Aliases: []string{"fs"},
Usage: "Perform filesystem operations on the PineTime",
Subcommands: []*cli.Command{
{
Name: "list",
ArgsUsage: "[dir]",
Aliases: []string{"ls"},
Usage: "List a directory",
Action: fsList,
},
{
Name: "mkdir",
ArgsUsage: "<paths...>",
Usage: "Create new directories",
Action: fsMkdir,
},
{
Name: "move",
ArgsUsage: "<old> <new>",
Aliases: []string{"mv"},
Usage: "Move a file or directory",
Action: fsMove,
},
{
Name: "read",
ArgsUsage: `<remote path> <local path>`,
Usage: "Read a file from InfiniTime.",
Description: `Read is used to read files from InfiniTime's filesystem. A "-" can be used to signify stdout`,
Action: fsRead,
},
{
Name: "remove",
ArgsUsage: "<paths...>",
Aliases: []string{"rm"},
Usage: "Create a new directory",
Action: fsRemove,
},
{
Name: "write",
ArgsUsage: `<local path> <remote path>`,
Usage: "Write a file to InfiniTime",
Description: `Write is used to write files to InfiniTime's filesystem. A "-" can be used to signify stdin`,
Action: fsWrite,
},
},
},
{
Name: "firmware",
Aliases: []string{"fw"},
Usage: "Manage InfiniTime firmware",
Subcommands: []*cli.Command{
{
Flags: []cli.Flag{
&cli.PathFlag{
Name: "init-packet",
Aliases: []string{"i"},
Usage: "Path to init packet (.dat file)",
},
&cli.PathFlag{
Name: "firmware",
Aliases: []string{"f"},
Usage: "Path to firmware image (.bin file)",
},
&cli.PathFlag{
Name: "archive",
Aliases: []string{"a"},
Usage: "Path to firmware archive (.zip file)",
},
},
Name: "upgrade",
Aliases: []string{"upg"},
Usage: "Upgrade InfiniTime firmware using files or archive",
Action: fwUpgrade,
},
{
Name: "version",
Aliases: []string{"ver"},
Usage: "Get firmware version of InfiniTime",
Action: fwVersion,
},
},
},
{
Name: "get",
Usage: "Get information from InfiniTime",
Subcommands: []*cli.Command{
{
Name: "address",
Aliases: []string{"addr"},
Usage: "Get InfiniTime's bluetooth address",
Action: getAddress,
},
{
Name: "battery",
Aliases: []string{"batt"},
Usage: "Get InfiniTime's battery percentage",
Action: getBattery,
},
{
Name: "heart",
Usage: "Get heart rate from InfiniTime",
Action: getHeart,
},
{
Flags: []cli.Flag{
&cli.BoolFlag{Name: "shell"},
},
Name: "motion",
Usage: "Get motion values from InfiniTime",
Action: getMotion,
},
{
Name: "steps",
Usage: "Get step count from InfiniTime",
Action: getSteps,
},
},
},
{
Name: "notify",
Usage: "Send notification to InfiniTime",
Action: notify,
},
{
Name: "set",
Usage: "Set information on InfiniTime",
Subcommands: []*cli.Command{
{
Name: "time",
ArgsUsage: `<ISO8601|"now">`,
Usage: "Set InfiniTime's clock to specified time",
Action: setTime,
},
},
},
{
Name: "update",
Usage: "Update information on InfiniTime",
Aliases: []string{"upd"},
Subcommands: []*cli.Command{
{
Name: "weather",
Usage: "Force an immediate update of weather data",
Action: updateWeather,
},
},
},
},
Before: func(c *cli.Context) error {
newClient, err := api.New(c.String("socket-path"))
if err != nil {
return err
}
client = newClient
return nil
},
After: func(*cli.Context) error {
return client.Close()
},
ExitErrHandler: func(c *cli.Context, err error) {
cli.ShowCommandHelp(c, c.Command.Name)
if err != nil {
log.Fatal().Msgf("%v", err)
}
os.Exit(0)
},
}
err := app.Run(os.Args)
if err != nil {
log.Fatal().Err(err).Msg("Error while running app")
}
}

17
cmd/itctl/notify.go Normal file
View File

@@ -0,0 +1,17 @@
package main
import "github.com/urfave/cli/v2"
func notify(c *cli.Context) error {
// Ensure required arguments
if c.Args().Len() != 2 {
return cli.Exit("Command notify requires two arguments", 1)
}
err := client.Notify(c.Args().Get(0), c.Args().Get(1))
if err != nil {
return err
}
return nil
}

View File

@@ -1,51 +0,0 @@
/*
* itd uses bluetooth low energy to communicate with InfiniTime devices
* Copyright (C) 2021 Arsen Musayelyan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package notify
import (
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"go.arsenm.dev/itd/api"
"go.arsenm.dev/itd/cmd/itctl/root"
)
// notifyCmd represents the notify command
var notifyCmd = &cobra.Command{
Use: "notify <title> <body>",
Short: "Send notification to InfiniTime",
Run: func(cmd *cobra.Command, args []string) {
// Ensure required arguments
if len(args) != 2 {
cmd.Usage()
log.Fatal().Msg("Command notify requires two arguments")
}
client := viper.Get("client").(*api.Client)
err := client.Notify(args[0], args[1])
if err != nil {
log.Fatal().Err(err).Msg("Error sending notification")
}
},
}
func init() {
root.RootCmd.AddCommand(notifyCmd)
}

View File

@@ -1,87 +0,0 @@
/*
* itd uses bluetooth low energy to communicate with InfiniTime devices
* Copyright (C) 2021 Arsen Musayelyan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package root
import (
"github.com/abiosoft/ishell"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"go.arsenm.dev/itd/api"
)
// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
Use: "itctl",
Short: "Control the itd daemon for InfiniTime smartwatches",
Run: func(cmd *cobra.Command, args []string) {
// Create new shell
sh := ishell.New()
sh.SetPrompt("itctl> ")
// For every command in cobra
for _, subCmd := range cmd.Commands() {
// Add top level command to ishell
sh.AddCmd(&ishell.Cmd{
Name: subCmd.Name(),
Help: subCmd.Short,
Aliases: subCmd.Aliases,
LongHelp: subCmd.Long,
Func: func(ctx *ishell.Context) {
// Append name and arguments of command
args := append([]string{ctx.Cmd.Name}, ctx.Args...)
// Set root command arguments
cmd.SetArgs(args)
// Execute root command with new arguments
cmd.Execute()
},
})
}
// Start shell
sh.Run()
},
}
// Execute adds all child commands to the root command and sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
client, err := api.New(viper.GetString("sockPath"))
if err != nil {
log.Fatal().Err(err).Msg("Error connecting to socket. Is itd running?")
}
defer client.Close()
viper.Set("client", client)
RootCmd.CompletionOptions.DisableDefaultCmd = true
cobra.CheckErr(RootCmd.Execute())
}
func init() {
// Register flag for socket path
RootCmd.Flags().StringP("socket-path", "s", api.DefaultAddr, "Path to itd socket")
// Bind flag and environment variable to viper key
viper.BindPFlag("sockPath", RootCmd.Flags().Lookup("socket-path"))
viper.BindEnv("sockPath", "ITCTL_SOCKET_PATH")
// Set default value for socket path
viper.SetDefault("sockPath", api.DefaultAddr)
}

24
cmd/itctl/set.go Normal file
View File

@@ -0,0 +1,24 @@
package main
import (
"time"
"github.com/urfave/cli/v2"
)
func setTime(c *cli.Context) error {
// Ensure required arguments
if c.Args().Len() < 1 {
return cli.Exit("Command time requires one argument", 1)
}
if c.Args().Get(0) == "now" {
return client.SetTimeNow()
} else {
parsed, err := time.Parse(time.RFC3339, c.Args().Get(0))
if err != nil {
return err
}
return client.SetTime(parsed)
}
}

View File

@@ -1,34 +0,0 @@
/*
* itd uses bluetooth low energy to communicate with InfiniTime devices
* Copyright (C) 2021 Arsen Musayelyan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package set
import (
"github.com/spf13/cobra"
"go.arsenm.dev/itd/cmd/itctl/root"
)
// setCmd represents the set command
var setCmd = &cobra.Command{
Use: "set",
Short: "Set information on InfiniTime",
}
func init() {
root.RootCmd.AddCommand(setCmd)
}

View File

@@ -1,81 +0,0 @@
/*
* itd uses bluetooth low energy to communicate with InfiniTime devices
* Copyright (C) 2021 Arsen Musayelyan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package set
import (
"bufio"
"encoding/json"
"net"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"go.arsenm.dev/itd/internal/types"
)
// timeCmd represents the time command
var timeCmd = &cobra.Command{
Use: `time <ISO8601|"now">`,
Short: "Set InfiniTime's clock to specified time",
Run: func(cmd *cobra.Command, args []string) {
// Ensure required arguments
if len(args) != 1 {
cmd.Usage()
log.Warn().Msg("Command time requires one argument")
return
}
// Connect to itd UNIX socket
conn, err := net.Dial("unix", viper.GetString("sockPath"))
if err != nil {
log.Fatal().Err(err).Msg("Error dialing socket. Is itd running?")
}
defer conn.Close()
// Encode request into connection
err = json.NewEncoder(conn).Encode(types.Request{
Type: types.ReqTypeSetTime,
Data: args[0],
})
if err != nil {
log.Fatal().Err(err).Msg("Error making request")
}
// Read one line from connetion
line, _, err := bufio.NewReader(conn).ReadLine()
if err != nil {
log.Fatal().Err(err).Msg("Error reading line from connection")
}
var res types.Response
// Decode line into response
err = json.Unmarshal(line, &res)
if err != nil {
log.Fatal().Err(err).Msg("Error decoding JSON data")
}
if res.Error {
log.Fatal().Msg(res.Message)
}
},
}
func init() {
setCmd.AddCommand(timeCmd)
}

7
cmd/itctl/update.go Normal file
View File

@@ -0,0 +1,7 @@
package main
import "github.com/urfave/cli/v2"
func updateWeather(c *cli.Context) error {
return client.UpdateWeather()
}

View File

@@ -1,44 +0,0 @@
/*
* itd uses bluetooth low energy to communicate with InfiniTime devices
* Copyright (C) 2021 Arsen Musayelyan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package update
import (
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"go.arsenm.dev/itd/api"
)
// weatherCmd represents the time command
var weatherCmd = &cobra.Command{
Use: `weather`,
Short: "Force an immediate update of weather data",
Run: func(cmd *cobra.Command, args []string) {
client := viper.Get("client").(*api.Client)
err := client.UpdateWeather()
if err != nil {
log.Fatal().Err(err).Msg("Error updating weather")
}
},
}
func init() {
updateCmd.AddCommand(weatherCmd)
}

View File

@@ -1,35 +0,0 @@
/*
* itd uses bluetooth low energy to communicate with InfiniTime devices
* Copyright (C) 2021 Arsen Musayelyan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package update
import (
"github.com/spf13/cobra"
"go.arsenm.dev/itd/cmd/itctl/root"
)
// updateCmd represents the update command
var updateCmd = &cobra.Command{
Use: "update",
Short: "Update information on InfiniTime",
Aliases: []string{"upd"},
}
func init() {
root.RootCmd.AddCommand(updateCmd)
}

View File

@@ -1,76 +0,0 @@
/*
* itd uses bluetooth low energy to communicate with InfiniTime devices
* Copyright (C) 2021 Arsen Musayelyan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package watch
import (
"fmt"
"os"
"os/signal"
"syscall"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"go.arsenm.dev/itd/api"
)
// heartCmd represents the address command
var batteryCmd = &cobra.Command{
Use: "battery",
Aliases: []string{"batt"},
Short: "Watch InfiniTime's battery level for changes",
Run: func(cmd *cobra.Command, args []string) {
client := viper.Get("client").(*api.Client)
battLevelCh, cancel, err := client.WatchBatteryLevel()
if err != nil {
log.Fatal().Err(err).Msg("Error getting battery level channel")
}
defer cancel()
signalCh := make(chan os.Signal, 1)
go func() {
<-signalCh
cancel()
os.Exit(0)
}()
signal.Notify(signalCh,
syscall.SIGINT,
syscall.SIGTERM,
)
for battlevel := range battLevelCh {
fmt.Printf("%d%%\n", battlevel)
}
},
}
func init() {
watchCmd.AddCommand(batteryCmd)
// Here you will define your flags and configuration settings.
// Cobra supports Persistent Flags which will work for this command
// and all subcommands, e.g.:
// addressCmd.PersistentFlags().String("foo", "", "A help for foo")
// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
// addressCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

View File

@@ -1,75 +0,0 @@
/*
* itd uses bluetooth low energy to communicate with InfiniTime devices
* Copyright (C) 2021 Arsen Musayelyan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package watch
import (
"fmt"
"os"
"os/signal"
"syscall"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"go.arsenm.dev/itd/api"
)
// heartCmd represents the address command
var heartCmd = &cobra.Command{
Use: "heart",
Short: "Watch InfiniTime's heart rate for changes",
Run: func(cmd *cobra.Command, args []string) {
client := viper.Get("client").(*api.Client)
heartRateCh, cancel, err := client.WatchHeartRate()
if err != nil {
log.Fatal().Err(err).Msg("Error getting heart rate channel")
}
defer cancel()
signalCh := make(chan os.Signal, 1)
go func() {
<-signalCh
cancel()
os.Exit(0)
}()
signal.Notify(signalCh,
syscall.SIGINT,
syscall.SIGTERM,
)
for heartRate := range heartRateCh {
fmt.Println(heartRate, "BPM")
}
},
}
func init() {
watchCmd.AddCommand(heartCmd)
// Here you will define your flags and configuration settings.
// Cobra supports Persistent Flags which will work for this command
// and all subcommands, e.g.:
// addressCmd.PersistentFlags().String("foo", "", "A help for foo")
// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
// addressCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

View File

@@ -1,86 +0,0 @@
/*
* itd uses bluetooth low energy to communicate with InfiniTime devices
* Copyright (C) 2021 Arsen Musayelyan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package watch
import (
"fmt"
"os"
"os/signal"
"syscall"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"go.arsenm.dev/itd/api"
)
// heartCmd represents the address command
var motionCmd = &cobra.Command{
Use: "motion",
Short: "Watch InfiniTime's motion values for changes",
Run: func(cmd *cobra.Command, args []string) {
client := viper.Get("client").(*api.Client)
motionValCh, cancel, err := client.WatchMotion()
if err != nil {
log.Fatal().Err(err).Msg("Error getting motion value channel")
}
defer cancel()
signalCh := make(chan os.Signal, 1)
go func() {
<-signalCh
cancel()
os.Exit(0)
}()
signal.Notify(signalCh,
syscall.SIGINT,
syscall.SIGTERM,
)
for motionVals := range motionValCh {
if viper.GetBool("shell") {
fmt.Printf(
"X=%d\nY=%d\nZ=%d\n",
motionVals.X,
motionVals.Y,
motionVals.Z,
)
} else {
fmt.Printf("%+v\n", motionVals)
}
}
},
}
func init() {
watchCmd.AddCommand(motionCmd)
// Here you will define your flags and configuration settings.
// Cobra supports Persistent Flags which will work for this command
// and all subcommands, e.g.:
// addressCmd.PersistentFlags().String("foo", "", "A help for foo")
// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
// addressCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
motionCmd.Flags().BoolP("shell", "s", false, "Output data in shell-compatible format")
viper.BindPFlag("shell", motionCmd.Flags().Lookup("shell"))
}

View File

@@ -1,75 +0,0 @@
/*
* itd uses bluetooth low energy to communicate with InfiniTime devices
* Copyright (C) 2021 Arsen Musayelyan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package watch
import (
"fmt"
"os"
"os/signal"
"syscall"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"
"github.com/spf13/viper"
"go.arsenm.dev/itd/api"
)
// heartCmd represents the address command
var stepsCmd = &cobra.Command{
Use: "steps",
Short: "Watch InfiniTime's step count for changes",
Run: func(cmd *cobra.Command, args []string) {
client := viper.Get("client").(*api.Client)
stepCountCh, cancel, err := client.WatchStepCount()
if err != nil {
log.Fatal().Err(err).Msg("Error getting step count channel")
}
defer cancel()
signalCh := make(chan os.Signal, 1)
go func() {
<-signalCh
cancel()
os.Exit(0)
}()
signal.Notify(signalCh,
syscall.SIGINT,
syscall.SIGTERM,
)
for stepCount := range stepCountCh {
fmt.Println(stepCount, "Steps")
}
},
}
func init() {
watchCmd.AddCommand(stepsCmd)
// Here you will define your flags and configuration settings.
// Cobra supports Persistent Flags which will work for this command
// and all subcommands, e.g.:
// addressCmd.PersistentFlags().String("foo", "", "A help for foo")
// Cobra supports local flags which will only run when this command
// is called directly, e.g.:
// addressCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

View File

@@ -1,34 +0,0 @@
/*
* itd uses bluetooth low energy to communicate with InfiniTime devices
* Copyright (C) 2021 Arsen Musayelyan
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package watch
import (
"github.com/spf13/cobra"
"go.arsenm.dev/itd/cmd/itctl/root"
)
// watchCmd represents the watch command
var watchCmd = &cobra.Command{
Use: "watch",
Short: "Watch values from InfiniTime for changes",
}
func init() {
root.RootCmd.AddCommand(watchCmd)
}