diff --git a/.DS_Store b/.DS_Store
index 6959c34..fc263ad 100644
Binary files a/.DS_Store and b/.DS_Store differ
diff --git a/.gitignore b/.gitignore
index 15f4493..0b59c55 100644
--- a/.gitignore
+++ b/.gitignore
@@ -28,5 +28,3 @@ bin/
output*.*
out*.*
out.txt
-
-.idea/
diff --git a/.goreleaser.yaml b/.goreleaser.yaml
index ce9a1a1..a65edfe 100644
--- a/.goreleaser.yaml
+++ b/.goreleaser.yaml
@@ -12,8 +12,7 @@ builds:
goos:
- linux
- windows
- - darwin
- main: ./cmd/gogoodwe
+ - darwin
archives:
- format: tar.gz
diff --git a/CHANGELOG.md b/CHANGELOG.md
index c2d9720..c3d8e47 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,21 +1,4 @@
-# GoGoodwe - CHANGELOG
-
-## v2.0.0 (2024-01-22)
-
-- Major refactoring to cleanup project structure
-- Simplified package structure
-
-## v1.4.0 (2023-08-30)
-
-- Major refactoring to move non-shared code to /internal folder
-- Abstracted core away from main()
-
-## v1.1.0 (2023-08-16)
-
-- refactored code to make errors bubble back to main package and better error reporting/logging
-- refactored main package to include run() method
-- removed staticcheck as there is a bug with Go v1.21
+# CHANGELOG
## v1.0.0 (2023-08-10)
-
- initial version 1.0 release
diff --git a/LICENSE b/LICENSE
index 06c0e27..8480972 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2024, Aaron Saikovski
+Copyright (c) 2023, Aaron Saikovski
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/Makefile b/Makefile
index 6d7edde..d82dc9a 100644
--- a/Makefile
+++ b/Makefile
@@ -1,91 +1,68 @@
# Define Go command and flags
GO = go
GOFLAGS = -ldflags="-s -w"
-TARGET = gogoodwe
-MAINAPPPATH = ./main.go
-default: help
+#export PATH=$PATH:$HOME/go/bin;
+
+# Define the target executable
+TARGET = gogoodwe
-.PHONY: help
## help - Display help about make targets for this Makefile
help:
@cat Makefile | grep '^## ' --color=never | cut -c4- | sed -e "`printf 's/ - /\t- /;'`" | column -s "`printf '\t'`" -t
-
-.PHONY: release
-## release - Builds the project in preparation for (local)release
-release: vet lint seccheck
- go build $(GOFLAGS) -o bin/${TARGET} ${MAINAPPPATH}
+## localrelease - Builds the project in preparation for (local)release
+localrelease:
+ go build $(GOFLAGS) -o bin/${TARGET} main.go
file bin/${TARGET}
-
-.PHONY: goreleaser
-## goreleaser - Builds the project in preparation for release
-goreleaser:
- goreleaser release --snapshot --clean
-
-
-.PHONY: docs
-## docs - updates the swagger docs
-docs:
- swag init
-
-
-.PHONY: build
-## build - Builds the project in preparation for debug
+## release - Builds the project in preparation for release
+release:
+ goreleaser release --snapshot --clean
+
+## debug - Builds the project in preparation for debug
build:
- go build -o bin/${TARGET} ${MAINAPPPATH}
+ go build -o bin/${TARGET} main.go
file bin/${TARGET}
+## buildandrun - builds and runs the program on the target platform
+buildandrun: build
+ ./bin/${TARGET}
-.PHONY: run
-## run - builds and runs the program on the target platform
-run:
- go run ${MAINAPPPATH}
+## run - runs main.go for testing
+run: dep
+ go run main.go
-.PHONY: clean
## clean - Remove the old builds and any debug information
clean:
go clean
rm -rf dist
rm bin/${TARGET}
-
-.PHONY: test
-## test - executes unit tests
+## test - executes unit test
test:
- go test -v ./test/...
+ go test ./...
-
-.PHONY: deps
-## deps - fetches any external dependencies and updates
-deps:
+## dep - fetches any external dependencies
+dep:
go mod tidy
go mod download
- go get -u ./...
-
-.PHONY: vet
## vet - Vet examines Go source code and reports suspicious constructs
vet:
go vet ./...
+## staticcheck - Runs static code analyzer staticcheck
+staticcheck:
+ go run honnef.co/go/tools/cmd/staticcheck@latest -checks=all,-ST1000,-U1000 ./...
-.PHONY: staticcheck
-## staticcheck - Runs static code analyzer staticcheck - currently broken
-staticcheck:
- staticcheck ./...
-
-
-.PHONY: seccheck
## seccheck - Code vulnerability check
seccheck:
+ brew install govulncheck
govulncheck ./...
-
-.PHONY: lint
## lint - format code and tidy modules
lint:
go fmt ./...
- go mod tidy -v
+ go mod tidy -v
\ No newline at end of file
diff --git a/README.md b/README.md
index f1fc363..49ece3e 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,11 @@
-# GoGoodwe
+# GoGgoodwe
-A command line tool and query the GOODWE SEMS Inverter APIs - written in 100% Go.
+A command line tool and Go packages to query the GOODWE SEMS Portal APIs - written in 100% Go.
[![Build Status](https://github.com/AaronSaikovski/gogoodwe/workflows/build/badge.svg)](https://github.com/AaronSaikovski/gogoodwe/actions)
+[![Coverage Status](https://coveralls.io/repos/github/AaronSaikovski/gogoodwe/badge.svg?branch=main)](https://coveralls.io/github/AaronSaikovski/gogoodwe?branch=main)
[![Licence](https://img.shields.io/github/license/AaronSaikovski/gogoodwe)](LICENSE)
@@ -14,19 +15,17 @@ A command line tool and query the GOODWE SEMS Inverter APIs - written in 100% Go
The toolchain is mainly driven by the Makefile.
```bash
-help - Display help about make targets for this Makefile
-release - Builds the project in preparation for (local)release
-goreleaser - Builds the project in preparation for release
-docs - updates the swagger docs
-build - Builds the project in preparation for debug
-run - builds and runs the program on the target platform
-clean - Remove the old builds and any debug information
-test - executes unit tests
-deps - fetches any external dependencies and updates
-vet - Vet examines Go source code and reports suspicious constructs
-staticcheck - Runs static code analyzer staticcheck - currently broken
-seccheck - Code vulnerability check
-lint - format code and tidy modules
+* help - Display help about make targets for this Makefile
+* release - Builds the project in preparation for release
+* debug - Builds the project in preparation for debug
+* buildandrun - builds and runs the program on the target platform
+* run - runs main.go for testing
+* clean - Remove the old builds and any debug information
+* test - executes unit test
+* dep - fetches any external dependencies
+* vet - Vet examines Go source code and reports suspicious constructs
+* staticcheck - Runs static code analyzer staticcheck
+* lint - format code and tidy modules
```
To get started type,
diff --git a/TODO.md b/TODO.md
index ef01c7d..3143314 100644
--- a/TODO.md
+++ b/TODO.md
@@ -1,22 +1,13 @@
-# GoGoodwe V2 - TODO
+# gogoodwe TODO
-### ToDo
+GoGoodwe backlog
-- [ ] Add ability to output inverter data to a file.
-- [ ] Format the inverter output to make it more human readable.
-- [ ] Add the ability to query historical data for a single day.
-- [ ] Have the ability to have a realtime logging to the screen or to a file in 5 minute intervals.
-- [ ] Add the ability to produce a daily summary of key data (Generation today, Income today, total generation, total income).
-- [ ] Add the ability to query the inverter status for Generation today and Status (check if operational).
-- [ ] Add goroutines and wait groups for the API calls and maybe channels for success/failed API calls.
-- [ ] Add Cobra for command flag parsing and processing.
-- [ ] Investigate the ability to generate .CSV files as output.
-- [ ]
+### Todo
-### In Progress
+- [ ] Add ability to output to file with a flag
+- [ ] Add ability to have a smaller output struct of just key reporting data
+- [ ] Add Golang contexts for API calls
-- [ ] add unit tests
+### In Progress
### Done ✓
-
-- [ ]
diff --git a/app/app.go b/app/app.go
deleted file mode 100644
index 2726e33..0000000
--- a/app/app.go
+++ /dev/null
@@ -1,29 +0,0 @@
-package app
-
-// Main package - This is the main program entry point
-import (
- "github.com/AaronSaikovski/gogoodwe/inverter"
- "github.com/AaronSaikovski/gogoodwe/utils"
- "github.com/alexflint/go-arg"
-)
-
-// Run - main program runner
-func Run() error {
-
- //Get the args input data
- var args utils.Args
- p := arg.MustParse(&args)
-
- //check for valid email address input
- if !utils.CheckValidEmail(args.Account) {
- p.Fail("Invalid Email address format - should be: 'user@somedomain.com'.")
- }
-
- //check for valid powerstation Id
- if !utils.CheckValidPowerstationID(args.PowerStationID) {
- p.Fail("Invalid Powerstation ID format: - should be: 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'.")
- }
-
- // Get the data from the API, return any errors. Pass in args as string
- return inverter.FetchData(args.Account, args.Password, args.PowerStationID)
-}
diff --git a/constants/constants.go b/constants/constants.go
index 70ba5dd..cb423b5 100644
--- a/constants/constants.go
+++ b/constants/constants.go
@@ -1,13 +1,8 @@
-/*
-# Name: constants - shared constants
-# Author: Aaron Saikovski - asaikovski@outlook.com
-*/
-
package constants
const (
// Auth Login Url
- AuthLoginUrl string = "https://www.semsportal.com/api/v2/Common/CrossLogin"
+ AuthLoginUrL string = "https://www.semsportal.com/api/v2/Common/CrossLogin"
// Powerstation API Url
PowerStationURL string = "v2/PowerStation/GetMonitorDetailByPowerstationId"
@@ -16,7 +11,7 @@ const (
HTTPTimeout = 20
// Version string
- VersionString string = "gogoodwe v2.0.0"
+ VersionString string = "gogoodwe v0.0.7"
//API login success response message
SemsLoginSuccessResponse string = "Successful"
diff --git a/go.mod b/go.mod
index fcddca2..c0b1f97 100644
--- a/go.mod
+++ b/go.mod
@@ -7,4 +7,4 @@ require (
github.com/logrusorgru/aurora v2.0.3+incompatible
)
-require github.com/alexflint/go-scalar v1.2.0 // indirect
+require github.com/alexflint/go-scalar v1.1.0 // indirect
diff --git a/go.sum b/go.sum
index 899e74f..d3619e9 100644
--- a/go.sum
+++ b/go.sum
@@ -1,8 +1,7 @@
github.com/alexflint/go-arg v1.4.3 h1:9rwwEBpMXfKQKceuZfYcwuc/7YY7tWJbFsgG5cAU/uo=
github.com/alexflint/go-arg v1.4.3/go.mod h1:3PZ/wp/8HuqRZMUUgu7I+e1qcpUbvmS258mRXkFH4IA=
+github.com/alexflint/go-scalar v1.1.0 h1:aaAouLLzI9TChcPXotr6gUhq+Scr8rl0P9P4PnltbhM=
github.com/alexflint/go-scalar v1.1.0/go.mod h1:LoFvNMqS1CPrMVltza4LvnGKhaSpc3oyLEBUZVhhS2o=
-github.com/alexflint/go-scalar v1.2.0 h1:WR7JPKkeNpnYIOfHRa7ivM21aWAdHD0gEWHCx+WQBRw=
-github.com/alexflint/go-scalar v1.2.0/go.mod h1:LoFvNMqS1CPrMVltza4LvnGKhaSpc3oyLEBUZVhhS2o=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
diff --git a/inverter/data.go b/inverter/data.go
deleted file mode 100644
index 92d961b..0000000
--- a/inverter/data.go
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
-# Name: data - fetches data from the goodwe API - and processes it to pass back to caller
-# Author: Aaron Saikovski - asaikovski@outlook.com
-*/
-package inverter
-
-import (
- "errors"
- "fmt"
-
- "github.com/AaronSaikovski/gogoodwe/authentication"
- "github.com/AaronSaikovski/gogoodwe/types"
- "github.com/AaronSaikovski/gogoodwe/utils"
- "github.com/logrusorgru/aurora"
-)
-
-// apiLogin - Login to the API
-func apiLogin(SemsUserLogin *types.LoginCredentials, SemsResponseData *types.LoginResponse) error {
-
- // Do the login - update the pointer to the struct SemsResponseData
- autherr := authentication.DoLogin(SemsResponseData, SemsUserLogin)
- if autherr != nil {
- utils.HandleError(autherr)
- return autherr
- } else {
- return nil
- }
-}
-
-// FetchData - Main API fetch function
-func FetchData(Account string, Password string, PowerStationID string) error {
-
- // Data types
- var SemsResponseData types.LoginResponse
- var PowerstationData types.InverterData
-
- // Create a new SemsLoginCreds object via a struct literal
- var SemsUserLogin = types.LoginCredentials{
- Account: Account,
- Password: Password,
- PowerStationID: PowerStationID,
- }
-
- // Do the login..check for errors
- err := apiLogin(&SemsUserLogin, &SemsResponseData)
- if err == nil {
-
- // Fetch the data
- dataerr := fetchInverterData(&SemsResponseData, &SemsUserLogin, &PowerstationData)
- if dataerr != nil {
- utils.HandleError(errors.New("error: fetching powerstation data, check powerstationid is correct"))
- return dataerr
- } else {
- // Get output
- dataOutput, jsonerr := GetDataJSON(&PowerstationData)
- if jsonerr != nil {
- utils.HandleError(errors.New("error: converting powerstation data"))
- return jsonerr
-
- } else {
- //Display output
- fmt.Println(aurora.BrightYellow(string(dataOutput)))
- }
- }
-
- } else {
- utils.HandleError(err)
- return err
- }
-
- return nil
-}
diff --git a/main.go b/main.go
index a9fe9bb..62ad0ad 100644
--- a/main.go
+++ b/main.go
@@ -1,20 +1,59 @@
/*
-# Name: GoGoodwe - Authenticates to and queries the SEMS Solar inverter API
+# Name: main package - Authenticates to and queries the SEMS Solar inverter API
# Author: Aaron Saikovski - asaikovski@outlook.com
*/
package main
+// Main package - This is the main program entry point
import (
- "github.com/AaronSaikovski/gogoodwe/app"
+ "github.com/AaronSaikovski/gogoodwe/constants"
+ "github.com/AaronSaikovski/gogoodwe/pkg/goodwe/fetchdata"
+ "github.com/AaronSaikovski/gogoodwe/types"
+ "github.com/AaronSaikovski/gogoodwe/utils"
+ "github.com/alexflint/go-arg"
)
+// args - srtruct using go-arg- https://github.com/alexflint/go-arg
+type args struct {
+ Account string `arg:"required,-a,--account" help:"SEMS Email Account."`
+ Pwd string `arg:"required,-p,--pwd" help:"SEMS Account password."`
+ PowerStationID string `arg:"required,-i,--powerstationid" help:"SEMS Powerstation ID."`
+}
+
+// Description - App description
+func (args) Description() string {
+ return "A command line tool and GoLang package to query the GOODWE SEMS Portal APIs and Solar SEMS API."
+}
+
+// Version - Version info
+func (args) Version() string {
+ return constants.VersionString
+}
+
// main - program main
func main() {
- //setup and run app
- err := app.Run()
+ //Get the args input data
+ var args args
+ p := arg.MustParse(&args)
- if err != nil {
- panic(err)
+ //check for valid email address input
+ if !utils.CheckValidEmail(args.Account) {
+ p.Fail("Invalid Email address format - should be: 'user@somedomain.com'.")
}
+
+ //check for valid powerstation Id
+ if !utils.CheckValidPowerstationID(args.PowerStationID) {
+ p.Fail("Invalid Powerstation ID format: - should be: 'XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'.")
+ }
+
+ // Create a new SemsLoginCreds object via a struct literal
+ SemsUserLogin := types.SemsLoginCreds{
+ Account: args.Account,
+ Pwd: args.Pwd,
+ PowerStationID: args.PowerStationID,
+ }
+
+ // Get the data from the API
+ fetchdata.GetData(&SemsUserLogin)
}
diff --git a/authentication/authentication.go b/pkg/goodwe/authentication/authentication.go
similarity index 59%
rename from authentication/authentication.go
rename to pkg/goodwe/authentication/authentication.go
index 85b4bd3..5b52eae 100644
--- a/authentication/authentication.go
+++ b/pkg/goodwe/authentication/authentication.go
@@ -15,34 +15,41 @@ import (
"github.com/AaronSaikovski/gogoodwe/utils"
)
+// SetHeaders - Set the login headers for the SEMS API login
+func SetHeaders(r *http.Request) {
+ r.Header.Add("Content-Type", "application/json")
+ r.Header.Add("Token", "{\"version\":\"v2.1.0\",\"client\":\"ios\",\"language\":\"en\"}")
+}
+
// DoLogin - Main public login function
// Logs into the SEMs API
-func DoLogin(SemsResponseData *types.LoginResponse, UserLogin *types.LoginCredentials) error {
+func DoLogin(SemsResponseData *types.SemsResponseData, UserLogin *types.SemsLoginCreds) error {
//check if the UserLogin struct is empty
- if usererr := checkUserLoginInfo(UserLogin); usererr != nil {
+ usererr := CheckUserLoginInfo(UserLogin)
+ if usererr != nil {
+ utils.HandleError(usererr)
return usererr
}
// User login struct to be converted to JSON
- jsonData, jsonErr := utils.MarshalStructToJSON(UserLogin)
- if jsonErr != nil {
- return jsonErr
- }
+ jsonData, _ := utils.MarshalStructToJSON(UserLogin)
// Create a new http request
- req, err := http.NewRequest(http.MethodPost, constants.AuthLoginUrl, bytes.NewBuffer(jsonData))
+ req, err := http.NewRequest(http.MethodPost, constants.AuthLoginUrL, bytes.NewBuffer(jsonData))
if err != nil {
+ utils.HandleError(err)
return err
}
//Add headers pass in the pointer to set the headers on the request object
- setHeaders(req)
+ SetHeaders(req)
//make the API Call
client := &http.Client{Timeout: constants.HTTPTimeout * time.Second}
resp, err := client.Do(req)
if err != nil {
+ utils.HandleError(err)
return err
}
@@ -50,22 +57,13 @@ func DoLogin(SemsResponseData *types.LoginResponse, UserLogin *types.LoginCreden
defer resp.Body.Close()
// Get the response body
- respBody, respErr := utils.FetchResponseBody(resp.Body)
- if respErr != nil {
- return respErr
- }
+ respBody, _ := utils.FetchResponseBody(resp.Body)
//marshall response to SemsRespInfo struct
- dataErr := utils.UnmarshalDataToStruct(respBody, &SemsResponseData)
- if dataErr != nil {
- return dataErr
- }
+ utils.UnmarshalDataToStruct(respBody, &SemsResponseData)
// check for successful login return value..return a login error
- loginErr := checkUserLoginResponse(SemsResponseData.Msg)
- if loginErr != nil {
- return loginErr
- }
+ CheckUserLoginResponse(SemsResponseData.Msg)
return nil
diff --git a/authentication/authutils.go b/pkg/goodwe/authentication/authhelper.go
similarity index 50%
rename from authentication/authutils.go
rename to pkg/goodwe/authentication/authhelper.go
index 49f004a..b103423 100644
--- a/authentication/authutils.go
+++ b/pkg/goodwe/authentication/authhelper.go
@@ -1,5 +1,5 @@
/*
-# Name: authentication - auth helper functions
+# Name: authhelper - auth helper functions
# Author: Aaron Saikovski - asaikovski@outlook.com
*/
@@ -7,22 +7,17 @@ package authentication
import (
"errors"
- "net/http"
"strings"
"github.com/AaronSaikovski/gogoodwe/constants"
"github.com/AaronSaikovski/gogoodwe/types"
+ "github.com/AaronSaikovski/gogoodwe/utils"
)
-// SetHeaders - Set the login headers for the SEMS API login
-func setHeaders(r *http.Request) {
- r.Header.Add("Content-Type", "application/json")
- r.Header.Add("Token", "{\"version\":\"v2.1.0\",\"client\":\"ios\",\"language\":\"en\"}")
-}
-
// CheckUserLoginInfo - Check user login struct is valid/not null
-func checkUserLoginInfo(UserLogin *types.LoginCredentials) error {
- if (*UserLogin == types.LoginCredentials{}) {
+func CheckUserLoginInfo(UserLogin *types.SemsLoginCreds) error {
+ //check if the UserLogin struct is empty
+ if (*UserLogin == types.SemsLoginCreds{}) {
return errors.New("**Error: User Login details are empty or invalid..**")
} else {
return nil
@@ -30,10 +25,9 @@ func checkUserLoginInfo(UserLogin *types.LoginCredentials) error {
}
// CheckUserLoginResponse - check for successful login return value..return a login error
-func checkUserLoginResponse(loginResponse string) error {
+func CheckUserLoginResponse(loginResponse string) {
if strings.Compare(loginResponse, constants.SemsLoginSuccessResponse) != 0 {
- return errors.New("**API Login Error: " + loginResponse)
- } else {
- return nil
+ authErr := errors.New("API Login Error: " + loginResponse)
+ utils.HandleError(authErr)
}
}
diff --git a/pkg/goodwe/fetchdata/fetchdata.go b/pkg/goodwe/fetchdata/fetchdata.go
new file mode 100644
index 0000000..e12d91b
--- /dev/null
+++ b/pkg/goodwe/fetchdata/fetchdata.go
@@ -0,0 +1,62 @@
+/*
+# Name: fetchdata - fetches data from the goodwe API - and processes it to pass back to caller
+# Author: Aaron Saikovski - asaikovski@outlook.com
+*/
+package fetchdata
+
+import (
+ "errors"
+ "fmt"
+
+ "github.com/AaronSaikovski/gogoodwe/pkg/goodwe/authentication"
+ "github.com/AaronSaikovski/gogoodwe/pkg/goodwe/powerstationdata"
+
+ "github.com/AaronSaikovski/gogoodwe/types"
+ "github.com/AaronSaikovski/gogoodwe/utils"
+ "github.com/logrusorgru/aurora"
+)
+
+// doLogin - Login to the API
+func doLogin(SemsUserLogin *types.SemsLoginCreds, SemsResponseData *types.SemsResponseData) error {
+
+ // Do the login - update the pointer to the struct SemsResponseData
+ autherr := authentication.DoLogin(SemsResponseData, SemsUserLogin)
+ if autherr != nil {
+ utils.HandleError(autherr)
+ return autherr
+ } else {
+ return nil
+ }
+}
+
+// GetData - Main process data function
+func GetData(SemsUserLogin *types.SemsLoginCreds) {
+
+ // Data types
+ var SemsResponseData types.SemsResponseData
+ var PowerstationData types.StationResponseData
+
+ // Do the login..check for errors
+ err := doLogin(SemsUserLogin, &SemsResponseData)
+ if err == nil {
+
+ // Fetch the data
+ dataerr := powerstationdata.FetchData(&SemsResponseData, SemsUserLogin, &PowerstationData)
+ if dataerr != nil {
+ utils.HandleError(errors.New("error: fetching powerstation data, check powerstationid is correct"))
+ } else {
+ // Get output
+ dataOutput, jsonerr := powerstationdata.GetDataJSON(&PowerstationData)
+ if jsonerr != nil {
+ utils.HandleError(errors.New("error: converting powerstation data"))
+
+ } else {
+ //Display output
+ fmt.Println(aurora.BrightYellow(string(dataOutput)))
+ }
+ }
+
+ } else {
+ utils.HandleError(err)
+ }
+}
diff --git a/inverter/inverter.go b/pkg/goodwe/powerstationdata/powerstationdata.go
similarity index 51%
rename from inverter/inverter.go
rename to pkg/goodwe/powerstationdata/powerstationdata.go
index ae47f7c..e4bc859 100644
--- a/inverter/inverter.go
+++ b/pkg/goodwe/powerstationdata/powerstationdata.go
@@ -1,8 +1,8 @@
/*
-# Name: inverter - gets data from the goodwe API - "v2/PowerStation/GetMonitorDetailByPowerstationId"
+# Name: powerstationdata - gets data from the goodwe API - "v2/PowerStation/GetMonitorDetailByPowerstationId"
# Author: Aaron Saikovski - asaikovski@outlook.com
*/
-package inverter
+package powerstationdata
import (
"bytes"
@@ -14,20 +14,22 @@ import (
"github.com/AaronSaikovski/gogoodwe/utils"
)
-// fetchInverterData - Fetches Data from the Inverter via the specified PowerstationID using theSEMs API
-func fetchInverterData(SemsResponseData *types.LoginResponse, UserLogin *types.LoginCredentials, PowerstationOutputData *types.InverterData) error {
+// setHeaders - Set the headers for the SEMS Data API
+func setHeaders(r *http.Request, tokenstring []byte) {
+ r.Header.Add("Content-Type", "application/json")
+ r.Header.Add("Token", string(tokenstring))
+}
+
+// FetchData - Fetches Data from the specified PowerstationID via tht SEMs API
+func FetchData(SemsResponseData *types.SemsResponseData,
+ UserLogin *types.SemsLoginCreds,
+ PowerstationOutputData *types.StationResponseData) error {
// get the Token header data
- tokenMapJSONData, tokenMapJSONErr := dataTokenJSON(SemsResponseData)
- if tokenMapJSONErr != nil {
- return tokenMapJSONErr
- }
+ tokenMapJSONData, _ := DataTokenJSON(SemsResponseData)
// get the Powerstation ID header data
- powerStationMapJSONData, powerStationMapJSONErr := powerStationIDJSON(UserLogin)
- if powerStationMapJSONErr != nil {
- return powerStationMapJSONErr
- }
+ powerStationMapJSONData, _ := PowerStationIDJSON(UserLogin)
//Get the url from the Auth API and append the data url part
url := SemsResponseData.API + constants.PowerStationURL
@@ -35,7 +37,7 @@ func fetchInverterData(SemsResponseData *types.LoginResponse, UserLogin *types.L
// Create a new http request
req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(powerStationMapJSONData))
if err != nil {
- return err
+ utils.HandleError(err)
}
//Add headers pass in the pointer to set the headers on the request object
@@ -45,6 +47,7 @@ func fetchInverterData(SemsResponseData *types.LoginResponse, UserLogin *types.L
client := &http.Client{Timeout: constants.HTTPTimeout * time.Second}
resp, err := client.Do(req)
if err != nil {
+ utils.HandleError(err)
return err
}
@@ -52,15 +55,12 @@ func fetchInverterData(SemsResponseData *types.LoginResponse, UserLogin *types.L
defer resp.Body.Close()
// Get the response body
- respBody, respBodyErr := utils.FetchResponseBody(resp.Body)
- if respBodyErr != nil {
- return respBodyErr
- }
+ respBody, _ := utils.FetchResponseBody(resp.Body)
//marshall response to SemsRespInfo struct
- dataStructErr := utils.UnmarshalDataToStruct(respBody, &PowerstationOutputData)
- if dataStructErr != nil {
- return dataStructErr
+ dataerr := utils.UnmarshalDataToStruct(respBody, &PowerstationOutputData)
+ if dataerr != nil {
+ return dataerr
}
return nil
diff --git a/inverter/datautils.go b/pkg/goodwe/powerstationdata/powerstationdatahelper.go
similarity index 64%
rename from inverter/datautils.go
rename to pkg/goodwe/powerstationdata/powerstationdatahelper.go
index b7c7386..e6a809b 100644
--- a/inverter/datautils.go
+++ b/pkg/goodwe/powerstationdata/powerstationdatahelper.go
@@ -1,31 +1,25 @@
/*
-# Name: powerstationhelper - helper functions to get the Powerstation Data from the API
+# Name: powerstationdatahelper - helper functions to get the Powerstation Data from the API
# Author: Aaron Saikovski - asaikovski@outlook.com
*/
-package inverter
+package powerstationdata
import (
"encoding/json"
- "net/http"
"strconv"
"github.com/AaronSaikovski/gogoodwe/types"
"github.com/AaronSaikovski/gogoodwe/utils"
)
-// setHeaders - Set the headers for the SEMS Data API
-func setHeaders(r *http.Request, tokenstring []byte) {
- r.Header.Add("Content-Type", "application/json")
- r.Header.Add("Token", string(tokenstring))
-}
-
// DataTokenJSON - Makes a map for the token to be passed to the Data API header and returns a JSON string
-func dataTokenJSON(SemsResponseData *types.LoginResponse) ([]byte, error) {
+func DataTokenJSON(SemsResponseData *types.SemsResponseData) ([]byte, error) {
+
tokenMap := make(map[string]string)
tokenMap["version"] = "v2.1.0"
tokenMap["client"] = "ios"
tokenMap["language"] = "en"
- tokenMap["timestamp"] = strconv.FormatInt(SemsResponseData.Data.Timestamp, 10)
+ tokenMap["timestamp"] = strconv.Itoa(SemsResponseData.Data.Timestamp)
tokenMap["uid"] = SemsResponseData.Data.UID
tokenMap["token"] = SemsResponseData.Data.Token
@@ -35,7 +29,7 @@ func dataTokenJSON(SemsResponseData *types.LoginResponse) ([]byte, error) {
}
// PowerStationIDJSON - Makes a map for the powerStationId to be passed to the Data API header and returns a JSON string
-func powerStationIDJSON(UserLogin *types.LoginCredentials) ([]byte, error) {
+func PowerStationIDJSON(UserLogin *types.SemsLoginCreds) ([]byte, error) {
powerStationMap := make(map[string]string)
powerStationMap["powerStationId"] = UserLogin.PowerStationID
@@ -45,7 +39,7 @@ func powerStationIDJSON(UserLogin *types.LoginCredentials) ([]byte, error) {
}
// GetDataJSON - Returns the PowerstationOutputData as JSON
-func GetDataJSON(PowerstationOutputData *types.InverterData) ([]byte, error) {
+func GetDataJSON(PowerstationOutputData *types.StationResponseData) ([]byte, error) {
// Get the response and return any errors
resp, err := utils.MarshalStructToJSON(&PowerstationOutputData)
diff --git a/test/README.md b/test/README.md
deleted file mode 100644
index cdcf65f..0000000
--- a/test/README.md
+++ /dev/null
@@ -1,9 +0,0 @@
-# `/test`
-
-Additional external test apps and test data. Feel free to structure the `/test` directory anyway you want. For bigger projects it makes sense to have a data subdirectory. For example, you can have `/test/data` or `/test/testdata` if you need Go to ignore what's in that directory. Note that Go will also ignore directories or files that begin with "." or "_", so you have more flexibility in terms of how you name your test data directory.
-
-Examples:
-
-* https://github.com/openshift/origin/tree/master/test (test data is in the `/testdata` subdirectory)
-
-
diff --git a/test/constants_test.go b/test/constants_test.go
deleted file mode 100644
index 5b95341..0000000
--- a/test/constants_test.go
+++ /dev/null
@@ -1,51 +0,0 @@
-package testing
-
-import (
- "testing"
-
- "github.com/AaronSaikovski/gogoodwe/constants"
-)
-
-// TestAuthLoginUrl Test Auth Login Url
-func TestAuthLoginUrl(t *testing.T) {
-
- AuthLoginUrlExpected := "https://www.semsportal.com/api/v2/Common/CrossLogin"
- if constants.AuthLoginUrl != AuthLoginUrlExpected {
- t.Errorf("AuthLoginUrl Const expected '%s' but got '%s'", AuthLoginUrlExpected, constants.AuthLoginUrl)
- }
-}
-
-// TestPowerStationURL Test Powerstation API Url
-func TestPowerStationURL(t *testing.T) {
-
- PowerStationURLExpected := "v2/PowerStation/GetMonitorDetailByPowerstationId"
- if constants.PowerStationURL != PowerStationURLExpected {
- t.Errorf("PowerStationURL const expected '%s' but got '%s'", PowerStationURLExpected, constants.PowerStationURL)
- }
-}
-
-// HTTPTimeout Test HTTPTimeout value
-// func TestHTTPTimeout(t *testing.T) {
-
-// HTTPTimeoutPowerStationURLExpected = 20
-
-// PowerStationURLExpected := "v2/PowerStation/GetMonitorDetailByPowerstationId"
-// if constants.HTTPTimeout != PowerStationURLExpected {
-// t.Errorf("PowerStationURL const expected '%d' but got '%d'", PowerStationURLExpected, constants.PowerStationURL)
-// }
-// }
-
-// Default timeout value
-
-//API login success response message
-//SemsLoginSuccessResponse string = "Successful"
-
-// TestSemsLoginSuccessResponse Test SemsLoginSuccessResponse test
-func TestSemsLoginSuccessResponse(t *testing.T) {
-
- SemsLoginSuccessResponseExpected := "Successful"
-
- if constants.SemsLoginSuccessResponse != SemsLoginSuccessResponseExpected {
- t.Errorf("SemsLoginSuccessResponse const expected '%s' but got '%s'", SemsLoginSuccessResponseExpected, constants.SemsLoginSuccessResponse)
- }
-}
diff --git a/test/samplemodule_test.go b/test/samplemodule_test.go
deleted file mode 100644
index c7bdb64..0000000
--- a/test/samplemodule_test.go
+++ /dev/null
@@ -1,22 +0,0 @@
-package testing
-
-/*
-A Sample test harness.
-*/
-
-// import (
-// "testing"
-
-// "github.com/AaronSaikovski/gostarter/internal/pkg/samplemodule"
-// )
-
-// // A testing function.
-// func TestSampleFunction(t *testing.T) {
-
-// msg := samplemodule.SampleFunction()
-// expected := "OK"
-
-// if msg != expected {
-// t.Errorf("Module expected '%q' but got '%q'", expected, msg)
-// }
-// }
diff --git a/test/samplestruct_test.go b/test/samplestruct_test.go
deleted file mode 100644
index d34e611..0000000
--- a/test/samplestruct_test.go
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
-A Sample test harness.
-*/
-
-package testing
-
-// import (
-// "github.com/AaronSaikovski/gostarter/internal/app/types"
-// "testing"
-// )
-
-// // A testing function.
-// func TestSampleStructString(t *testing.T) {
-
-// expected := "test data"
-// ateststruct := types.Sample{SampleString: "test data", SampleInt: 1}
-
-// if ateststruct.SampleString != expected {
-// t.Errorf("struct expected '%s' but got '%s'", expected, ateststruct.SampleString)
-// }
-// }
diff --git a/types/logincredentials.go b/types/logincredentials.go
deleted file mode 100644
index 64a12c1..0000000
--- a/types/logincredentials.go
+++ /dev/null
@@ -1,12 +0,0 @@
-/*
-# Name: LoginCredentials - Struct to hold User login data
-# Author: Aaron Saikovski - asaikovski@outlook.com
-*/
-package types
-
-// LoginCredentials - Struct to hold User login data
-type LoginCredentials struct {
- Account string `json:"account"`
- Password string `json:"pwd"`
- PowerStationID string `json:"powerstationid"`
-}
diff --git a/types/semslogincreds.go b/types/semslogincreds.go
new file mode 100644
index 0000000..b08db27
--- /dev/null
+++ b/types/semslogincreds.go
@@ -0,0 +1,8 @@
+package types
+
+// SemsLoginCreds - Struct to hold User login data
+type SemsLoginCreds struct {
+ Account string `json:"account"`
+ Pwd string `json:"pwd"`
+ PowerStationID string `json:"powerstationid"`
+}
diff --git a/types/loginresponse.go b/types/semsresponsedata.go
similarity index 59%
rename from types/loginresponse.go
rename to types/semsresponsedata.go
index 5d11885..5abcd61 100644
--- a/types/loginresponse.go
+++ b/types/semsresponsedata.go
@@ -1,19 +1,15 @@
-/*
-# Name: LoginResponse - SEMS API Response Data struct
-# Contains all the JSON Response data returned from the authentication API - "https://www.semsportal.com/api/v2/Common/CrossLogin"
-# Will be unmarshalled to a struct via a pointer
-# Author: Aaron Saikovski - asaikovski@outlook.com
-*/
package types
-// LoginResponse - SEMS API Response Data struct
-type LoginResponse struct {
+// SemsResponseData - SEMS API Response Data struct
+// Contains all the JSON Response data returned from the authentication API - "https://www.semsportal.com/api/v2/Common/CrossLogin"
+// Will be unmarshalled to a struct via a pointer
+type SemsResponseData struct {
HasError bool `json:"hasError"`
Code int32 `json:"code"`
Msg string `json:"msg"`
Data struct {
UID string `json:"uid"`
- Timestamp int64 `json:"timestamp"`
+ Timestamp int `json:"timestamp"`
Token string `json:"token"`
Client string `json:"client"`
Version string `json:"version"`
diff --git a/types/inverterrdata.go b/types/stationresponsedata.go
similarity index 72%
rename from types/inverterrdata.go
rename to types/stationresponsedata.go
index 81cdbfb..8239905 100644
--- a/types/inverterrdata.go
+++ b/types/stationresponsedata.go
@@ -1,18 +1,43 @@
-/*
-# Name: InverterData - Struct to hold data returned from the Powerstation API
-# Minimised version - removed any sensitive data
-# Author: Aaron Saikovski - asaikovski@outlook.com
-*/
package types
-// InverterData - Struct to hold data returned from the Inverter Powerstation API
-type InverterData struct {
+// StationResponseData - Struct to hold data returned from the Powerstation API
+type StationResponseData struct {
Language string `json:"language"`
Function []string `json:"function"`
HasError bool `json:"hasError"`
Msg string `json:"msg"`
Code string `json:"code"`
Data struct {
+ Info struct {
+ PowerstationID string `json:"powerstation_id"`
+ Time string `json:"time"`
+ DateFormat string `json:"date_format"`
+ DateFormatYm string `json:"date_format_ym"`
+ Stationname string `json:"stationname"`
+ Address string `json:"address"`
+ OwnerName string `json:"owner_name"`
+ OwnerPhone string `json:"owner_phone"`
+ OwnerEmail string `json:"owner_email"`
+ BatteryCapacity float64 `json:"battery_capacity"`
+ TurnonTime string `json:"turnon_time"`
+ CreateTime string `json:"create_time"`
+ Capacity float64 `json:"capacity"`
+ Longitude float64 `json:"longitude"`
+ Latitude float64 `json:"latitude"`
+ PowerstationType string `json:"powerstation_type"`
+ Status int `json:"status"`
+ IsStored bool `json:"is_stored"`
+ IsPowerflow bool `json:"is_powerflow"`
+ ChartsType int `json:"charts_type"`
+ HasPv bool `json:"has_pv"`
+ HasStatisticsCharts bool `json:"has_statistics_charts"`
+ OnlyBps bool `json:"only_bps"`
+ OnlyBpu bool `json:"only_bpu"`
+ TimeSpan float64 `json:"time_span"`
+ PrValue string `json:"pr_value"`
+ OrgCode string `json:"org_code"`
+ OrgName string `json:"org_name"`
+ } `json:"info"`
Kpi struct {
MonthGeneration float64 `json:"month_generation"`
Pac float64 `json:"pac"`
@@ -25,18 +50,80 @@ type InverterData struct {
} `json:"kpi"`
PowercontrolStatus int `json:"powercontrol_status"`
Images []any `json:"images"`
- Inverter []struct {
- IsStored bool `json:"is_stored"`
- InPac float64 `json:"in_pac"`
- OutPac float64 `json:"out_pac"`
- Eday float64 `json:"eday"`
- Emonth float64 `json:"emonth"`
- Etotal float64 `json:"etotal"`
- Status int `json:"status"`
- TurnonTime string `json:"turnon_time"`
- Type string `json:"type"`
- Capacity float64 `json:"capacity"`
- D struct {
+ Weather struct {
+ HeWeather6 []struct {
+ Basic struct {
+ Cid any `json:"cid"`
+ Location any `json:"location"`
+ ParentCity any `json:"parent_city"`
+ AdminArea any `json:"admin_area"`
+ Cnty any `json:"cnty"`
+ Lat any `json:"lat"`
+ Lon any `json:"lon"`
+ Tz any `json:"tz"`
+ } `json:"basic"`
+ Update struct {
+ Loc any `json:"loc"`
+ Utc any `json:"utc"`
+ } `json:"update"`
+ Status string `json:"status"`
+ DailyForecast []struct {
+ CondCodeD string `json:"cond_code_d"`
+ CondCodeN string `json:"cond_code_n"`
+ CondTxtD string `json:"cond_txt_d"`
+ CondTxtN string `json:"cond_txt_n"`
+ Date string `json:"date"`
+ Hum string `json:"hum"`
+ Pcpn string `json:"pcpn"`
+ Pop string `json:"pop"`
+ Pres string `json:"pres"`
+ TmpMax string `json:"tmp_max"`
+ TmpMin string `json:"tmp_min"`
+ UvIndex string `json:"uv_index"`
+ Vis string `json:"vis"`
+ WindDeg string `json:"wind_deg"`
+ WindDir string `json:"wind_dir"`
+ WindSc string `json:"wind_sc"`
+ WindSpd string `json:"wind_spd"`
+ } `json:"daily_forecast"`
+ } `json:"HeWeather6"`
+ } `json:"weather"`
+ Inverter []struct {
+ Sn string `json:"sn"`
+ Dict struct {
+ Left []struct {
+ IsHT bool `json:"isHT"`
+ IsStoreSkip bool `json:"isStoreSkip"`
+ Key string `json:"key"`
+ Value string `json:"value"`
+ Unit string `json:"unit"`
+ IsFaultMsg int `json:"isFaultMsg"`
+ FaultMsgCode int `json:"faultMsgCode"`
+ } `json:"left"`
+ Right []struct {
+ IsHT bool `json:"isHT"`
+ IsStoreSkip bool `json:"isStoreSkip"`
+ Key string `json:"key"`
+ Value string `json:"value"`
+ Unit string `json:"unit"`
+ IsFaultMsg int `json:"isFaultMsg"`
+ FaultMsgCode int `json:"faultMsgCode"`
+ } `json:"right"`
+ } `json:"dict"`
+ IsStored bool `json:"is_stored"`
+ Name string `json:"name"`
+ InPac float64 `json:"in_pac"`
+ OutPac float64 `json:"out_pac"`
+ Eday float64 `json:"eday"`
+ Emonth float64 `json:"emonth"`
+ Etotal float64 `json:"etotal"`
+ Status int `json:"status"`
+ TurnonTime string `json:"turnon_time"`
+ ReleationID string `json:"releation_id"`
+ Type string `json:"type"`
+ Capacity float64 `json:"capacity"`
+ D struct {
+ PwID string `json:"pw_id"`
Capacity string `json:"capacity"`
Model string `json:"model"`
OutputPower string `json:"output_power"`
@@ -110,7 +197,10 @@ type InverterData struct {
InvertFull struct {
CtSolutionType int `json:"ct_solution_type"`
Cts any `json:"cts"`
+ Sn string `json:"sn"`
CheckCode string `json:"check_code"`
+ PowerstationID string `json:"powerstation_id"`
+ Name string `json:"name"`
ModelType string `json:"model_type"`
ChangeType int `json:"change_type"`
ChangeTime int `json:"change_time"`
@@ -271,29 +361,43 @@ type InverterData struct {
BatteryCharging string `json:"battery_charging"`
LastRefreshTime string `json:"last_refresh_time"`
BmsStatus string `json:"bms_status"`
+ PwID string `json:"pw_id"`
FaultMessage string `json:"fault_message"`
WarningCode any `json:"warning_code"`
BatteryPower float64 `json:"battery_power"`
- BackupPloadS float64 `json:"backup_pload_s"`
- BackupVloadS float64 `json:"backup_vload_s"`
- BackupIloadS float64 `json:"backup_iload_s"`
- BackupPloadT float64 `json:"backup_pload_t"`
- BackupVloadT float64 `json:"backup_vload_t"`
- BackupIloadT float64 `json:"backup_iload_t"`
- EtotalBuy any `json:"etotal_buy"`
- EdayBuy float64 `json:"eday_buy"`
- EbatteryCharge any `json:"ebattery_charge"`
- EchargeDay float64 `json:"echarge_day"`
- EbatteryDischarge any `json:"ebattery_discharge"`
- EdischargeDay float64 `json:"edischarge_day"`
- BattStrings any `json:"batt_strings"`
- MeterConnectStatus any `json:"meter_connect_status"`
- MtactivepowerR float64 `json:"mtactivepower_r"`
- MtactivepowerS float64 `json:"mtactivepower_s"`
- MtactivepowerT float64 `json:"mtactivepower_t"`
- HasTigo bool `json:"has_tigo"`
- CanStartIV bool `json:"canStartIV"`
- BatteryCount any `json:"battery_count"`
+ PointIndex string `json:"point_index"`
+ Points []struct {
+ TargetIndex int `json:"target_index"`
+ TargetName string `json:"target_name"`
+ Display string `json:"display"`
+ Unit string `json:"unit"`
+ TargetKey string `json:"target_key"`
+ TextCn string `json:"text_cn"`
+ TargetSnSix any `json:"target_sn_six"`
+ TargetSnSeven any `json:"target_sn_seven"`
+ TargetType any `json:"target_type"`
+ StorageName any `json:"storage_name"`
+ } `json:"points"`
+ BackupPloadS float64 `json:"backup_pload_s"`
+ BackupVloadS float64 `json:"backup_vload_s"`
+ BackupIloadS float64 `json:"backup_iload_s"`
+ BackupPloadT float64 `json:"backup_pload_t"`
+ BackupVloadT float64 `json:"backup_vload_t"`
+ BackupIloadT float64 `json:"backup_iload_t"`
+ EtotalBuy any `json:"etotal_buy"`
+ EdayBuy float64 `json:"eday_buy"`
+ EbatteryCharge any `json:"ebattery_charge"`
+ EchargeDay float64 `json:"echarge_day"`
+ EbatteryDischarge any `json:"ebattery_discharge"`
+ EdischargeDay float64 `json:"edischarge_day"`
+ BattStrings any `json:"batt_strings"`
+ MeterConnectStatus any `json:"meter_connect_status"`
+ MtactivepowerR float64 `json:"mtactivepower_r"`
+ MtactivepowerS float64 `json:"mtactivepower_s"`
+ MtactivepowerT float64 `json:"mtactivepower_t"`
+ HasTigo bool `json:"has_tigo"`
+ CanStartIV bool `json:"canStartIV"`
+ BatteryCount any `json:"battery_count"`
} `json:"inverter"`
Hjgx struct {
Co2 float64 `json:"co2"`
@@ -362,6 +466,7 @@ type InverterData struct {
Environmental []any `json:"environmental"`
Equipment []struct {
Type string `json:"type"`
+ Title string `json:"title"`
Status int `json:"status"`
Model any `json:"model"`
StatusText any `json:"statusText"`
@@ -374,6 +479,8 @@ type InverterData struct {
IsStored bool `json:"isStored"`
Soc string `json:"soc"`
IsChange bool `json:"isChange"`
+ RelationID string `json:"relationId"`
+ Sn string `json:"sn"`
HasTigo bool `json:"has_tigo"`
IsSec bool `json:"is_sec"`
IsSecs bool `json:"is_secs"`
@@ -382,4 +489,11 @@ type InverterData struct {
TitleSn any `json:"titleSn"`
} `json:"equipment"`
} `json:"data"`
+ Components struct {
+ Para string `json:"para"`
+ LangVer int `json:"langVer"`
+ TimeSpan int `json:"timeSpan"`
+ API string `json:"api"`
+ MsgSocketAdr any `json:"msgSocketAdr"`
+ } `json:"components"`
}
diff --git a/utils/args.go b/utils/args.go
deleted file mode 100644
index 56786cd..0000000
--- a/utils/args.go
+++ /dev/null
@@ -1,20 +0,0 @@
-package utils
-
-import "github.com/AaronSaikovski/gogoodwe/constants"
-
-// Args - struct using go-arg- https://github.com/alexflint/go-arg
-type Args struct {
- Account string `arg:"required,-a,--account" help:"SEMS Email Account."`
- Password string `arg:"required,-p,--password" help:"SEMS Account password."`
- PowerStationID string `arg:"required,-i,--powerstationid" help:"SEMS Powerstation ID."`
-}
-
-// Description - App description
-func (Args) Description() string {
- return "A command line tool to query the GOODWE SEMS Portal APIs and Solar SEMS API."
-}
-
-// Version - Version info
-func (Args) Version() string {
- return constants.VersionString
-}
diff --git a/utils/errorhandler.go b/utils/errorhandler.go
index 2beccae..a365476 100644
--- a/utils/errorhandler.go
+++ b/utils/errorhandler.go
@@ -2,7 +2,6 @@ package utils
import (
"log"
-
"github.com/logrusorgru/aurora"
)