When creating a list of IPs to ping we should ignore the network and broadcast address since it will not detect any devices anyway
140 lines
3.6 KiB
Go
140 lines
3.6 KiB
Go
package cmd
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
"net"
|
|
"os"
|
|
"strings"
|
|
|
|
"github.com/andig/evcc/detect"
|
|
"github.com/andig/evcc/detect/tasks"
|
|
"github.com/andig/evcc/util"
|
|
"github.com/korylprince/ipnetgen"
|
|
"github.com/olekukonko/tablewriter"
|
|
"github.com/spf13/cobra"
|
|
"github.com/spf13/viper"
|
|
)
|
|
|
|
// detectCmd represents the vehicle command
|
|
var detectCmd = &cobra.Command{
|
|
Use: "detect [host ...] [subnet ...]",
|
|
Short: "Auto-detect compatible hardware",
|
|
Long: `Automatic discovery using detect scans the local network for available devices.
|
|
Scanning focuses on devices that are commonly used that are detectable with reasonable efforts.
|
|
|
|
On successful detection, suggestions for EVCC configuration can be made. The suggestions should simplify
|
|
configuring EVCC but are probably not sufficient for fully automatic configuration.`,
|
|
Run: runDetect,
|
|
}
|
|
|
|
func init() {
|
|
rootCmd.AddCommand(detectCmd)
|
|
}
|
|
|
|
// IPsFromSubnet creates a list of ip addresses for given subnet
|
|
func IPsFromSubnet(arg string) (res []string) {
|
|
gen, err := ipnetgen.New(arg)
|
|
if err != nil {
|
|
log.FATAL.Fatal("could not create iterator")
|
|
}
|
|
|
|
for ip := gen.Next(); ip != nil; ip = gen.Next() {
|
|
res = append(res, ip.String())
|
|
}
|
|
// remove network and broadcast address
|
|
return res[1 : len(res)-1]
|
|
}
|
|
|
|
// ParseHostIPNet converts host or cidr into a host list
|
|
func ParseHostIPNet(arg string) (res []string) {
|
|
if ip := net.ParseIP(arg); ip != nil {
|
|
return []string{ip.String()}
|
|
}
|
|
|
|
_, ipnet, err := net.ParseCIDR(arg)
|
|
|
|
// simple host
|
|
if err != nil {
|
|
return []string{arg}
|
|
}
|
|
|
|
// check subnet size
|
|
if bits, _ := ipnet.Mask.Size(); bits < 24 {
|
|
log.INFO.Println("skipping large subnet:", ipnet)
|
|
return
|
|
}
|
|
|
|
return IPsFromSubnet(arg)
|
|
}
|
|
|
|
func display(res []tasks.Result) {
|
|
table := tablewriter.NewWriter(os.Stdout)
|
|
table.SetHeader([]string{"IP", "Hostname", "Task", "Details"})
|
|
table.SetAutoMergeCells(true)
|
|
table.SetRowLine(true)
|
|
|
|
for _, hit := range res {
|
|
switch hit.ID {
|
|
case detect.TaskPing, detect.TaskHttp, detect.TaskModbus:
|
|
continue
|
|
|
|
default:
|
|
host := ""
|
|
hosts, err := net.LookupAddr(hit.ResultDetails.IP)
|
|
if err == nil && len(hosts) > 0 {
|
|
host = strings.TrimSuffix(hosts[0], ".")
|
|
}
|
|
|
|
b, _ := json.Marshal(hit.ResultDetails)
|
|
|
|
// fmt.Printf("%-16s %-20s %-16s %s\n", hit.ResultDetails.IP, host, hit.ID, details)
|
|
table.Append([]string{hit.ResultDetails.IP, host, hit.ID, string(b)})
|
|
}
|
|
}
|
|
|
|
fmt.Println("")
|
|
table.Render()
|
|
|
|
fmt.Println(`
|
|
Please open https://github.com/andig/evcc/issues/new in your browser and copy the
|
|
results above into a new issue. Please tell us:
|
|
|
|
1. Is the scan result correct?
|
|
2. If not correct: please describe your hardware setup.`)
|
|
}
|
|
|
|
func runDetect(cmd *cobra.Command, args []string) {
|
|
util.LogLevel(viper.GetString("log"), nil)
|
|
|
|
fmt.Println(`
|
|
Auto detection will now start to scan the network for available devices.
|
|
Scanning focuses on devices that are commonly used that are detectable with reasonable efforts.
|
|
On successful detection, suggestions for EVCC configuration can be made. The suggestions should simplify
|
|
configuring EVCC but are probably not sufficient for fully automatic configuration.`)
|
|
fmt.Println()
|
|
|
|
// args
|
|
var hosts []string
|
|
for _, arg := range args {
|
|
hosts = append(hosts, ParseHostIPNet(arg)...)
|
|
}
|
|
|
|
// autodetect
|
|
if len(hosts) == 0 {
|
|
ips := util.LocalIPs()
|
|
if len(ips) == 0 {
|
|
log.FATAL.Fatal("could not find ip")
|
|
}
|
|
|
|
myIP := ips[0]
|
|
log.INFO.Println("my ip:", myIP.IP)
|
|
|
|
hosts = append(hosts, "127.0.0.1")
|
|
hosts = append(hosts, IPsFromSubnet(myIP.String())...)
|
|
}
|
|
|
|
// magic happens here
|
|
res := detect.Work(log, 50, hosts)
|
|
display(res)
|
|
}
|