Added Auto-Discovery through UDP Broadcasts

This commit is contained in:
Jonas Köritz 2019-09-03 15:28:22 +02:00
parent 6451deea33
commit 6570ac93c0
2 changed files with 135 additions and 18 deletions

View file

@ -42,7 +42,7 @@ func main() {
var rootCmd = &cobra.Command{ var rootCmd = &cobra.Command{
Use: "ipcamera [Cameras IP Address]", Use: "ipcamera [Cameras IP Address]",
Short: "ipcamera is a tool to stream the video preview of cheap action cameras without the mobile application", Short: "ipcamera is a tool to stream the video preview of cheap action cameras without the mobile application",
Args: cobra.ExactArgs(1), Args: cobra.MaximumNArgs(1),
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
defer camera.Disconnect() defer camera.Disconnect()
relay := libipcamera.CreateRTPRelay(net.ParseIP("127.0.0.1"), 5220) relay := libipcamera.CreateRTPRelay(net.ParseIP("127.0.0.1"), 5220)
@ -66,7 +66,11 @@ func main() {
} }
}, },
PreRun: func(cmd *cobra.Command, args []string) { PreRun: func(cmd *cobra.Command, args []string) {
camera = connectAndLogin(net.ParseIP(args[0]), int(port), username, password, verbose) if len(args) == 0 {
camera = connectAndLogin(discoverCamera(verbose), int(port), username, password, verbose)
} else {
camera = connectAndLogin(net.ParseIP(args[0]), int(port), username, password, verbose)
}
}, },
PostRun: func(cmd *cobra.Command, args []string) { PostRun: func(cmd *cobra.Command, args []string) {
camera.Disconnect() camera.Disconnect()
@ -103,7 +107,7 @@ func main() {
var ls = &cobra.Command{ var ls = &cobra.Command{
Use: "ls [Cameras IP Address]", Use: "ls [Cameras IP Address]",
Short: "List files stored on the cameras SD-Card", Short: "List files stored on the cameras SD-Card",
Args: cobra.ExactArgs(1), Args: cobra.MaximumNArgs(1),
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
files, err := camera.GetFileList() files, err := camera.GetFileList()
if err != nil { if err != nil {
@ -116,22 +120,44 @@ func main() {
} }
}, },
PreRun: func(cmd *cobra.Command, args []string) { PreRun: func(cmd *cobra.Command, args []string) {
camera = connectAndLogin(net.ParseIP(args[0]), int(port), username, password, verbose) if len(args) == 0 {
camera = connectAndLogin(discoverCamera(verbose), int(port), username, password, verbose)
} else {
camera = connectAndLogin(net.ParseIP(args[0]), int(port), username, password, verbose)
}
}, },
PostRun: func(cmd *cobra.Command, args []string) { PostRun: func(cmd *cobra.Command, args []string) {
camera.Disconnect() camera.Disconnect()
}, },
} }
var discover = &cobra.Command{
Use: "discover",
Short: "Try to discover a camera by sending UDP broadcasts",
Args: cobra.MaximumNArgs(0),
Run: func(cmd *cobra.Command, args []string) {
cameraIP, err := libipcamera.AutodiscoverCamera(verbose)
if err != nil {
log.Printf("ERROR Discovering Camera: %s\n", err)
}
log.Printf("Found Camera: %+v\n", cameraIP)
},
}
var still = &cobra.Command{ var still = &cobra.Command{
Use: "still [Cameras IP Address]", Use: "still [Cameras IP Address]",
Short: "Take a still image and save to SD-Card", Short: "Take a still image and save to SD-Card",
Args: cobra.ExactArgs(1), Args: cobra.MaximumNArgs(1),
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
camera.TakePicture() camera.TakePicture()
}, },
PreRun: func(cmd *cobra.Command, args []string) { PreRun: func(cmd *cobra.Command, args []string) {
camera = connectAndLogin(net.ParseIP(args[0]), int(port), username, password, verbose) if len(args) == 0 {
camera = connectAndLogin(discoverCamera(verbose), int(port), username, password, verbose)
} else {
camera = connectAndLogin(net.ParseIP(args[0]), int(port), username, password, verbose)
}
}, },
PostRun: func(cmd *cobra.Command, args []string) { PostRun: func(cmd *cobra.Command, args []string) {
camera.Disconnect() camera.Disconnect()
@ -141,12 +167,16 @@ func main() {
var record = &cobra.Command{ var record = &cobra.Command{
Use: "record [Cameras IP Address]", Use: "record [Cameras IP Address]",
Short: "Start recording video to SD-Card", Short: "Start recording video to SD-Card",
Args: cobra.ExactArgs(1), Args: cobra.MaximumNArgs(1),
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
camera.StartRecording() camera.StartRecording()
}, },
PreRun: func(cmd *cobra.Command, args []string) { PreRun: func(cmd *cobra.Command, args []string) {
camera = connectAndLogin(net.ParseIP(args[0]), int(port), username, password, verbose) if len(args) == 0 {
camera = connectAndLogin(discoverCamera(verbose), int(port), username, password, verbose)
} else {
camera = connectAndLogin(net.ParseIP(args[0]), int(port), username, password, verbose)
}
}, },
PostRun: func(cmd *cobra.Command, args []string) { PostRun: func(cmd *cobra.Command, args []string) {
camera.Disconnect() camera.Disconnect()
@ -156,12 +186,16 @@ func main() {
var stop = &cobra.Command{ var stop = &cobra.Command{
Use: "stop [Cameras IP Address]", Use: "stop [Cameras IP Address]",
Short: "Stop recording video to SD-Card", Short: "Stop recording video to SD-Card",
Args: cobra.ExactArgs(1), Args: cobra.MaximumNArgs(1),
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
camera.StopRecording() camera.StopRecording()
}, },
PreRun: func(cmd *cobra.Command, args []string) { PreRun: func(cmd *cobra.Command, args []string) {
camera = connectAndLogin(net.ParseIP(args[0]), int(port), username, password, verbose) if len(args) == 0 {
camera = connectAndLogin(discoverCamera(verbose), int(port), username, password, verbose)
} else {
camera = connectAndLogin(net.ParseIP(args[0]), int(port), username, password, verbose)
}
}, },
PostRun: func(cmd *cobra.Command, args []string) { PostRun: func(cmd *cobra.Command, args []string) {
camera.Disconnect() camera.Disconnect()
@ -171,7 +205,7 @@ func main() {
var firmware = &cobra.Command{ var firmware = &cobra.Command{
Use: "firmware [Cameras IP Address]", Use: "firmware [Cameras IP Address]",
Short: "Retrieve firmware version information from the camera", Short: "Retrieve firmware version information from the camera",
Args: cobra.ExactArgs(1), Args: cobra.MaximumNArgs(1),
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
firmware, err := camera.GetFirmwareInfo() firmware, err := camera.GetFirmwareInfo()
if err != nil { if err != nil {
@ -181,7 +215,11 @@ func main() {
log.Printf("Firmware Version: %s\n", firmware) log.Printf("Firmware Version: %s\n", firmware)
}, },
PreRun: func(cmd *cobra.Command, args []string) { PreRun: func(cmd *cobra.Command, args []string) {
camera = connectAndLogin(net.ParseIP(args[0]), int(port), username, password, verbose) if len(args) == 0 {
camera = connectAndLogin(discoverCamera(verbose), int(port), username, password, verbose)
} else {
camera = connectAndLogin(net.ParseIP(args[0]), int(port), username, password, verbose)
}
}, },
PostRun: func(cmd *cobra.Command, args []string) { PostRun: func(cmd *cobra.Command, args []string) {
camera.Disconnect() camera.Disconnect()
@ -191,7 +229,7 @@ func main() {
var rtsp = &cobra.Command{ var rtsp = &cobra.Command{
Use: "rtsp [Cameras IP Address]", Use: "rtsp [Cameras IP Address]",
Short: "Start an RTSP-Server serving the cameras preview.", Short: "Start an RTSP-Server serving the cameras preview.",
Args: cobra.ExactArgs(1), Args: cobra.MaximumNArgs(1),
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
rtspServer := rtsp.CreateServer("127.0.0.1", 8554, camera) rtspServer := rtsp.CreateServer("127.0.0.1", 8554, camera)
@ -203,7 +241,11 @@ func main() {
} }
}, },
PreRun: func(cmd *cobra.Command, args []string) { PreRun: func(cmd *cobra.Command, args []string) {
camera = connectAndLogin(net.ParseIP(args[0]), int(port), username, password, verbose) if len(args) == 0 {
camera = connectAndLogin(discoverCamera(verbose), int(port), username, password, verbose)
} else {
camera = connectAndLogin(net.ParseIP(args[0]), int(port), username, password, verbose)
}
}, },
PostRun: func(cmd *cobra.Command, args []string) { PostRun: func(cmd *cobra.Command, args []string) {
camera.Disconnect() camera.Disconnect()
@ -213,7 +255,7 @@ func main() {
var cmd = &cobra.Command{ var cmd = &cobra.Command{
Use: "cmd [RAW Command] [Cameras IP Address]", Use: "cmd [RAW Command] [Cameras IP Address]",
Short: "Send a raw command to the camera", Short: "Send a raw command to the camera",
Args: cobra.ExactArgs(2), Args: cobra.RangeArgs(1, 2),
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
command, err := hex.DecodeString(args[0]) command, err := hex.DecodeString(args[0])
if err != nil { if err != nil {
@ -233,7 +275,11 @@ func main() {
bufio.NewReader(os.Stdin).ReadBytes('\n') bufio.NewReader(os.Stdin).ReadBytes('\n')
}, },
PreRun: func(cmd *cobra.Command, args []string) { PreRun: func(cmd *cobra.Command, args []string) {
camera = connectAndLogin(net.ParseIP(args[1]), int(port), username, password, verbose) if len(args) != 2 {
camera = connectAndLogin(discoverCamera(verbose), int(port), username, password, verbose)
} else {
camera = connectAndLogin(net.ParseIP(args[1]), int(port), username, password, verbose)
}
}, },
PostRun: func(cmd *cobra.Command, args []string) { PostRun: func(cmd *cobra.Command, args []string) {
camera.Disconnect() camera.Disconnect()
@ -243,7 +289,7 @@ func main() {
var fetch = &cobra.Command{ var fetch = &cobra.Command{
Use: "fetch [Cameras IP Address]", Use: "fetch [Cameras IP Address]",
Short: "List files stored on the cameras SD-Card", Short: "List files stored on the cameras SD-Card",
Args: cobra.ExactArgs(1), Args: cobra.MaximumNArgs(1),
Run: func(cmd *cobra.Command, args []string) { Run: func(cmd *cobra.Command, args []string) {
files, err := camera.GetFileList() files, err := camera.GetFileList()
if err != nil { if err != nil {
@ -257,7 +303,11 @@ func main() {
downloadFile(filepath.Base(newestFile), url) downloadFile(filepath.Base(newestFile), url)
}, },
PreRun: func(cmd *cobra.Command, args []string) { PreRun: func(cmd *cobra.Command, args []string) {
camera = connectAndLogin(net.ParseIP(args[0]), int(port), username, password, verbose) if len(args) == 0 {
camera = connectAndLogin(discoverCamera(verbose), int(port), username, password, verbose)
} else {
camera = connectAndLogin(net.ParseIP(args[0]), int(port), username, password, verbose)
}
}, },
PostRun: func(cmd *cobra.Command, args []string) { PostRun: func(cmd *cobra.Command, args []string) {
camera.Disconnect() camera.Disconnect()
@ -272,6 +322,7 @@ func main() {
rootCmd.AddCommand(record) rootCmd.AddCommand(record)
rootCmd.AddCommand(firmware) rootCmd.AddCommand(firmware)
rootCmd.AddCommand(rtsp) rootCmd.AddCommand(rtsp)
rootCmd.AddCommand(discover)
if err := rootCmd.Execute(); err != nil { if err := rootCmd.Execute(); err != nil {
log.Println(err) log.Println(err)
@ -299,3 +350,14 @@ func downloadFile(filepath string, url string) error {
_, err = io.Copy(out, resp.Body) _, err = io.Copy(out, resp.Body)
return err return err
} }
func discoverCamera(verbose bool) net.IP {
cameraIP, err := libipcamera.AutodiscoverCamera(verbose)
if err != nil {
log.Printf("ERROR during Autodiscover: %s\n", err)
}
if verbose {
log.Printf("Found Camera: %s\n", cameraIP)
}
return cameraIP
}

55
libipcamera/Discovery.go Normal file
View file

@ -0,0 +1,55 @@
package libipcamera
import (
"fmt"
"log"
"net"
"time"
)
// Ports to try discovery on
var targetPorts = []int{22600, 21600}
// AutodiscoverCamera will try to find a camera using UDP Broadcasts
func AutodiscoverCamera(verbose bool) (net.IP, error) {
conn, err := net.ListenPacket("udp", ":22601")
if err != nil {
return nil, err
}
defer conn.Close()
for _, port := range targetPorts {
go sendDiscoveryBroadcasts(conn, port, 5, verbose)
}
buffer := make([]byte, 80)
_, remoteAddr, err := conn.ReadFrom(buffer)
if err != nil {
return nil, err
}
udpAddr := remoteAddr.(*net.UDPAddr)
return udpAddr.IP, nil
}
func sendDiscoveryBroadcasts(localConn net.PacketConn, port, count int, verbose bool) {
broadcastAddress, err := net.ResolveUDPAddr("udp", fmt.Sprintf("255.255.255.255:%d", port))
if err != nil {
return
}
broadcastPacket := CreateCommandPacket(0x0114)
if verbose {
log.Printf("Trying Autodiscovery using UDP Port %d\n", port)
}
for i := 0; i < count; i++ {
_, err = localConn.WriteTo(broadcastPacket, broadcastAddress)
if err != nil {
return
}
time.Sleep(time.Millisecond * 500)
}
}