diff --git a/machinery/docs/docs.go b/machinery/docs/docs.go index 64defbe2..18ec24c0 100644 --- a/machinery/docs/docs.go +++ b/machinery/docs/docs.go @@ -54,6 +54,35 @@ const docTemplate = `{ } } }, + "/api/camera/onvif/gotopreset": { + "post": { + "description": "Will activate the desired ONVIF preset.", + "tags": [ + "camera" + ], + "summary": "Will activate the desired ONVIF preset.", + "operationId": "camera-onvif-gotopreset", + "parameters": [ + { + "description": "OnvifPreset", + "name": "config", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/models.OnvifPreset" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/models.APIResponse" + } + } + } + } + }, "/api/camera/onvif/login": { "post": { "description": "Try to login into ONVIF supported camera.", @@ -112,6 +141,35 @@ const docTemplate = `{ } } }, + "/api/camera/onvif/presets": { + "post": { + "description": "Will return the ONVIF presets for the specific camera.", + "tags": [ + "camera" + ], + "summary": "Will return the ONVIF presets for the specific camera.", + "operationId": "camera-onvif-presets", + "parameters": [ + { + "description": "OnvifCredentials", + "name": "config", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/models.OnvifCredentials" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/models.APIResponse" + } + } + } + } + }, "/api/camera/onvif/zoom": { "post": { "description": "Zooming in or out the camera.", @@ -317,8 +375,15 @@ const docTemplate = `{ "models.APIResponse": { "type": "object", "properties": { + "can_pan_tilt": { + "type": "boolean" + }, + "can_zoom": { + "type": "boolean" + }, "data": {}, - "message": {} + "message": {}, + "ptz_functions": {} } }, "models.Authentication": { @@ -621,6 +686,17 @@ const docTemplate = `{ } } }, + "models.OnvifPreset": { + "type": "object", + "properties": { + "onvif_credentials": { + "$ref": "#/definitions/models.OnvifCredentials" + }, + "preset": { + "type": "string" + } + } + }, "models.OnvifZoom": { "type": "object", "properties": { diff --git a/machinery/docs/swagger.json b/machinery/docs/swagger.json index 4d54f9d2..796543bc 100644 --- a/machinery/docs/swagger.json +++ b/machinery/docs/swagger.json @@ -46,6 +46,35 @@ } } }, + "/api/camera/onvif/gotopreset": { + "post": { + "description": "Will activate the desired ONVIF preset.", + "tags": [ + "camera" + ], + "summary": "Will activate the desired ONVIF preset.", + "operationId": "camera-onvif-gotopreset", + "parameters": [ + { + "description": "OnvifPreset", + "name": "config", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/models.OnvifPreset" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/models.APIResponse" + } + } + } + } + }, "/api/camera/onvif/login": { "post": { "description": "Try to login into ONVIF supported camera.", @@ -104,6 +133,35 @@ } } }, + "/api/camera/onvif/presets": { + "post": { + "description": "Will return the ONVIF presets for the specific camera.", + "tags": [ + "camera" + ], + "summary": "Will return the ONVIF presets for the specific camera.", + "operationId": "camera-onvif-presets", + "parameters": [ + { + "description": "OnvifCredentials", + "name": "config", + "in": "body", + "required": true, + "schema": { + "$ref": "#/definitions/models.OnvifCredentials" + } + } + ], + "responses": { + "200": { + "description": "OK", + "schema": { + "$ref": "#/definitions/models.APIResponse" + } + } + } + } + }, "/api/camera/onvif/zoom": { "post": { "description": "Zooming in or out the camera.", @@ -309,8 +367,15 @@ "models.APIResponse": { "type": "object", "properties": { + "can_pan_tilt": { + "type": "boolean" + }, + "can_zoom": { + "type": "boolean" + }, "data": {}, - "message": {} + "message": {}, + "ptz_functions": {} } }, "models.Authentication": { @@ -613,6 +678,17 @@ } } }, + "models.OnvifPreset": { + "type": "object", + "properties": { + "onvif_credentials": { + "$ref": "#/definitions/models.OnvifCredentials" + }, + "preset": { + "type": "string" + } + } + }, "models.OnvifZoom": { "type": "object", "properties": { diff --git a/machinery/docs/swagger.yaml b/machinery/docs/swagger.yaml index 1d9ac0f0..2d50c8d2 100644 --- a/machinery/docs/swagger.yaml +++ b/machinery/docs/swagger.yaml @@ -2,8 +2,13 @@ basePath: / definitions: models.APIResponse: properties: + can_pan_tilt: + type: boolean + can_zoom: + type: boolean data: {} message: {} + ptz_functions: {} type: object models.Authentication: properties: @@ -202,6 +207,13 @@ definitions: tilt: type: number type: object + models.OnvifPreset: + properties: + onvif_credentials: + $ref: '#/definitions/models.OnvifCredentials' + preset: + type: string + type: object models.OnvifZoom: properties: onvif_credentials: @@ -310,6 +322,25 @@ paths: summary: Will return the ONVIF capabilities for the specific camera. tags: - camera + /api/camera/onvif/gotopreset: + post: + description: Will activate the desired ONVIF preset. + operationId: camera-onvif-gotopreset + parameters: + - description: OnvifPreset + in: body + name: config + required: true + schema: + $ref: '#/definitions/models.OnvifPreset' + responses: + "200": + description: OK + schema: + $ref: '#/definitions/models.APIResponse' + summary: Will activate the desired ONVIF preset. + tags: + - camera /api/camera/onvif/login: post: description: Try to login into ONVIF supported camera. @@ -348,6 +379,25 @@ paths: summary: Panning or/and tilting the camera. tags: - camera + /api/camera/onvif/presets: + post: + description: Will return the ONVIF presets for the specific camera. + operationId: camera-onvif-presets + parameters: + - description: OnvifCredentials + in: body + name: config + required: true + schema: + $ref: '#/definitions/models.OnvifCredentials' + responses: + "200": + description: OK + schema: + $ref: '#/definitions/models.APIResponse' + summary: Will return the ONVIF presets for the specific camera. + tags: + - camera /api/camera/onvif/zoom: post: description: Zooming in or out the camera. diff --git a/machinery/go.mod b/machinery/go.mod index 37901295..8468dbdb 100644 --- a/machinery/go.mod +++ b/machinery/go.mod @@ -3,7 +3,7 @@ module github.com/kerberos-io/agent/machinery go 1.19 // replace github.com/kerberos-io/joy4 v1.0.57 => ../../../../github.com/kerberos-io/joy4 -// replace github.com/kerberos-io/onvif v0.0.5 => ../../../../github.com/kerberos-io/onvif +// replace github.com/kerberos-io/onvif v0.0.6 => ../../../../github.com/kerberos-io/onvif require ( github.com/InVisionApp/conjungo v1.1.0 @@ -25,7 +25,7 @@ require ( github.com/gorilla/websocket v1.5.0 github.com/kellydunn/golang-geo v0.7.0 github.com/kerberos-io/joy4 v1.0.58 - github.com/kerberos-io/onvif v0.0.6 + github.com/kerberos-io/onvif v0.0.7 github.com/minio/minio-go/v6 v6.0.57 github.com/nsmith5/mjpeg v0.0.0-20200913181537-54b8ada0e53e github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 diff --git a/machinery/go.sum b/machinery/go.sum index 2f560e27..f8b60450 100644 --- a/machinery/go.sum +++ b/machinery/go.sum @@ -266,8 +266,8 @@ github.com/kellydunn/golang-geo v0.7.0 h1:A5j0/BvNgGwY6Yb6inXQxzYwlPHc6WVZR+Mrar github.com/kellydunn/golang-geo v0.7.0/go.mod h1:YYlQPJ+DPEzrHx8kT3oPHC/NjyvCCXE+IuKGKdrjrcU= github.com/kerberos-io/joy4 v1.0.58 h1:R8EECSF+bG7o2yHC6cX/lF77Z+bDVGl6OioLZ3+5MN4= github.com/kerberos-io/joy4 v1.0.58/go.mod h1:nZp4AjvKvTOXRrmDyAIOw+Da+JA5OcSo/JundGfOlFU= -github.com/kerberos-io/onvif v0.0.6 h1:+nvDuxGzQgHjc7V7kiYxUIcw1bO6R9esAMcxWRiKcwA= -github.com/kerberos-io/onvif v0.0.6/go.mod h1:Hr2dJOH2LM5SpYKk17gYZ1CMjhGhUl+QlT5kwYogrW0= +github.com/kerberos-io/onvif v0.0.7 h1:LIrXjTH7G2W9DN69xZeJSB0uS3W1+C3huFO8kTqx7/A= +github.com/kerberos-io/onvif v0.0.7/go.mod h1:Hr2dJOH2LM5SpYKk17gYZ1CMjhGhUl+QlT5kwYogrW0= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.15.0 h1:xqfchp4whNFxn5A4XFyyYtitiWI8Hy5EW59jEwcyL6U= diff --git a/machinery/src/cloud/Cloud.go b/machinery/src/cloud/Cloud.go index 350f1f10..7adf988d 100644 --- a/machinery/src/cloud/Cloud.go +++ b/machinery/src/cloud/Cloud.go @@ -279,6 +279,8 @@ loop: onvifEnabled := "false" onvifZoom := "false" onvifPanTilt := "false" + onvifPresets := "false" + var onvifPresetsList []byte if config.Capture.IPCamera.ONVIFXAddr != "" { cameraConfiguration := configuration.Config.Capture.IPCamera device, err := onvif.ConnectToOnvifDevice(&cameraConfiguration) @@ -293,6 +295,15 @@ loop: if canPanTilt { onvifPanTilt = "true" } + // Try to read out presets + presets, err := onvif.GetPresetsFromDevice(device) + if err == nil && len(presets) > 0 { + onvifPresets = "true" + onvifPresetsList, err = json.Marshal(presets) + if err != nil { + log.Log.Error("HandleHeartBeat: error while marshalling presets: " + err.Error()) + } + } } } } @@ -339,6 +350,8 @@ loop: "onvif" : "%s", "onvif_zoom" : "%s", "onvif_pantilt" : "%s", + "onvif_presets": "%s", + "onvif_presets_list": %s, "cameraConnected": "%s", "numberoffiles" : "33", "timestamp" : 1564747908, @@ -346,7 +359,7 @@ loop: "docker" : true, "kios" : false, "raspberrypi" : false - }`, config.Key, system.Version, system.CPUId, username, key, name, isEnterprise, system.Hostname, system.Architecture, system.TotalMemory, system.UsedMemory, system.FreeMemory, system.ProcessUsedMemory, macs, ips, "0", "0", "0", uptimeString, boottimeString, config.HubSite, onvifEnabled, onvifZoom, onvifPanTilt, cameraConnected) + }`, config.Key, system.Version, system.CPUId, username, key, name, isEnterprise, system.Hostname, system.Architecture, system.TotalMemory, system.UsedMemory, system.FreeMemory, system.ProcessUsedMemory, macs, ips, "0", "0", "0", uptimeString, boottimeString, config.HubSite, onvifEnabled, onvifZoom, onvifPanTilt, onvifPresets, onvifPresetsList, cameraConnected) var jsonStr = []byte(object) buffy := bytes.NewBuffer(jsonStr) diff --git a/machinery/src/models/ApiResponse.go b/machinery/src/models/ApiResponse.go index bc2edfe5..1b4fab25 100644 --- a/machinery/src/models/ApiResponse.go +++ b/machinery/src/models/ApiResponse.go @@ -29,3 +29,8 @@ type OnvifZoom struct { OnvifCredentials OnvifCredentials `json:"onvif_credentials,omitempty" bson:"onvif_credentials"` Zoom float64 `json:"zoom,omitempty" bson:"zoom"` } + +type OnvifPreset struct { + OnvifCredentials OnvifCredentials `json:"onvif_credentials,omitempty" bson:"onvif_credentials"` + Preset string `json:"preset,omitempty" bson:"preset"` +} diff --git a/machinery/src/models/Onvif.go b/machinery/src/models/Onvif.go index c7869a7e..5ecb1172 100644 --- a/machinery/src/models/Onvif.go +++ b/machinery/src/models/Onvif.go @@ -15,4 +15,10 @@ type OnvifActionPTZ struct { X float64 `json:"x" bson:"x"` Y float64 `json:"y" bson:"y"` Z float64 `json:"z" bson:"z"` + Preset string `json:"preset" bson:"preset"` +} + +type OnvifActionPreset struct { + Name string `json:"name" bson:"name"` + Token string `json:"token" bson:"token"` } diff --git a/machinery/src/onvif/main.go b/machinery/src/onvif/main.go index e1632a88..46c70533 100644 --- a/machinery/src/onvif/main.go +++ b/machinery/src/onvif/main.go @@ -78,6 +78,8 @@ func HandleONVIFActions(configuration *models.Configuration, communication *mode err = AbsolutePanTiltMoveFake(device, configurations, token, x, y, z) if err != nil { log.Log.Error("HandleONVIFActions (AbsolutePanTitleMoveFake): " + err.Error()) + } else { + log.Log.Info("HandleONVIFActions (AbsolutePanTitleMoveFake): successfully moved camera") } /*if canAbsoluteMove { @@ -92,6 +94,17 @@ func HandleONVIFActions(configuration *models.Configuration, communication *mode } }*/ + } else if onvifAction.Action == "preset" { + + // Execute the preset + preset := ptzAction.Preset + err := GoToPresetFromDevice(device, preset) + if err != nil { + log.Log.Error("HandleONVIFActions (GotoPreset): " + err.Error()) + } else { + log.Log.Info("HandleONVIFActions (GotoPreset): successfully moved camera") + } + } else if onvifAction.Action == "ptz" { if err == nil { @@ -311,7 +324,7 @@ func AbsolutePanTiltMove(device *onvif.Device, configuration ptz.GetConfiguratio } bs, _ := ioutil.ReadAll(res.Body) - log.Log.Debug("AbsoluteMove: " + string(bs)) + log.Log.Info("AbsoluteMove: " + string(bs)) return err } @@ -330,18 +343,17 @@ func AbsolutePanTiltMoveFake(device *onvif.Device, configuration ptz.GetConfigur speed := 0.6 wait := 100 * time.Millisecond - err := ZoomOutCompletely(device, configuration, token) - // We'll move quickly to the position (might be inaccurate) - err = PanUntilPosition(device, configuration, token, pan, speed, wait) - err = TiltUntilPosition(device, configuration, token, tilt, speed, wait) + err = ZoomOutCompletely(device, configuration, token) + err = PanUntilPosition(device, configuration, token, pan, zoom, speed, wait) + err = TiltUntilPosition(device, configuration, token, tilt, zoom, speed, wait) // Now we'll move a bit slower to make sure we are ok (will be more accurate) - speed = 0.2 + speed = 0.1 wait = 200 * time.Millisecond - err = PanUntilPosition(device, configuration, token, pan, speed, wait) - err = TiltUntilPosition(device, configuration, token, tilt, speed, wait) + err = PanUntilPosition(device, configuration, token, pan, zoom, speed, wait) + err = TiltUntilPosition(device, configuration, token, tilt, zoom, speed, wait) err = ZoomUntilPosition(device, configuration, token, zoom, speed, wait) return err @@ -376,10 +388,10 @@ func ZoomOutCompletely(device *onvif.Device, configuration ptz.GetConfigurations return err } -func PanUntilPosition(device *onvif.Device, configuration ptz.GetConfigurationsResponse, token xsd.ReferenceToken, pan float64, speed float64, wait time.Duration) error { +func PanUntilPosition(device *onvif.Device, configuration ptz.GetConfigurationsResponse, token xsd.ReferenceToken, pan float64, zoom float64, speed float64, wait time.Duration) error { position, err := GetPosition(device, token) - if position.PanTilt.X >= pan-0.01 && position.PanTilt.X <= pan+0.01 { + if position.PanTilt.X >= pan-0.005 && position.PanTilt.X <= pan+0.005 { } else { @@ -422,6 +434,7 @@ func PanUntilPosition(device *onvif.Device, configuration ptz.GetConfigurationsR _, errStop := device.CallMethod(ptz.Stop{ ProfileToken: token, PanTilt: true, + Zoom: true, }) if errStop != nil { @@ -431,10 +444,10 @@ func PanUntilPosition(device *onvif.Device, configuration ptz.GetConfigurationsR return err } -func TiltUntilPosition(device *onvif.Device, configuration ptz.GetConfigurationsResponse, token xsd.ReferenceToken, tilt float64, speed float64, wait time.Duration) error { +func TiltUntilPosition(device *onvif.Device, configuration ptz.GetConfigurationsResponse, token xsd.ReferenceToken, tilt float64, zoom float64, speed float64, wait time.Duration) error { position, err := GetPosition(device, token) - if position.PanTilt.Y >= tilt-0.01 && position.PanTilt.Y <= tilt+0.01 { + if position.PanTilt.Y >= tilt-0.005 && position.PanTilt.Y <= tilt+0.005 { } else { @@ -477,6 +490,7 @@ func TiltUntilPosition(device *onvif.Device, configuration ptz.GetConfigurations _, errStop := device.CallMethod(ptz.Stop{ ProfileToken: token, PanTilt: true, + Zoom: true, }) if errStop != nil { @@ -489,7 +503,7 @@ func TiltUntilPosition(device *onvif.Device, configuration ptz.GetConfigurations func ZoomUntilPosition(device *onvif.Device, configuration ptz.GetConfigurationsResponse, token xsd.ReferenceToken, zoom float64, speed float64, wait time.Duration) error { position, err := GetPosition(device, token) - if position.Zoom.X >= zoom-0.01 && position.Zoom.X <= zoom+0.01 { + if position.Zoom.X >= zoom-0.005 && position.Zoom.X <= zoom+0.005 { } else { @@ -530,6 +544,7 @@ func ZoomUntilPosition(device *onvif.Device, configuration ptz.GetConfigurations _, errStop := device.CallMethod(ptz.Stop{ ProfileToken: token, + PanTilt: true, Zoom: true, }) @@ -635,6 +650,89 @@ func GetCapabilitiesFromDevice(device *onvif.Device) []string { return capabilities } +func GetPresetsFromDevice(device *onvif.Device) ([]models.OnvifActionPreset, error) { + var presets []models.OnvifActionPreset + var presetsResponse ptz.GetPresetsResponse + + // Get token from the first profile + token, err := GetTokenFromProfile(device, 0) + if err == nil { + resp, err := device.CallMethod(ptz.GetPresets{ + ProfileToken: token, + }) + + defer resp.Body.Close() + b, err := io.ReadAll(resp.Body) + if err == nil { + stringBody := string(b) + decodedXML, et, err := getXMLNode(stringBody, "GetPresetsResponse") + if err != nil { + log.Log.Error("GetPresetsFromDevice: " + err.Error()) + return presets, err + } else { + if err := decodedXML.DecodeElement(&presetsResponse, et); err != nil { + log.Log.Error("GetPresetsFromDevice: " + err.Error()) + return presets, err + } + + for _, preset := range presetsResponse.Preset { + p := models.OnvifActionPreset{ + Name: string(preset.Name), + Token: string(preset.Token), + } + + presets = append(presets, p) + } + + return presets, err + } + } else { + log.Log.Error("GetPresetsFromDevice: " + err.Error()) + } + } else { + log.Log.Error("GetPresetsFromDevice: " + err.Error()) + } + + return presets, err +} + +func GoToPresetFromDevice(device *onvif.Device, presetName string) error { + var goToPresetResponse ptz.GotoPresetResponse + + // Get token from the first profile + token, err := GetTokenFromProfile(device, 0) + if err == nil { + + resp, err := device.CallMethod(ptz.GotoPreset{ + ProfileToken: token, + PresetToken: xsd.ReferenceToken(presetName), + }) + + defer resp.Body.Close() + b, err := io.ReadAll(resp.Body) + if err == nil { + stringBody := string(b) + decodedXML, et, err := getXMLNode(stringBody, "GotoPresetResponses") + if err != nil { + log.Log.Error("GoToPresetFromDevice: " + err.Error()) + return err + } else { + if err := decodedXML.DecodeElement(&goToPresetResponse, et); err != nil { + log.Log.Error("GoToPresetFromDevice: " + err.Error()) + return err + } + return err + } + } else { + log.Log.Error("GoToPresetFromDevice: " + err.Error()) + } + } else { + log.Log.Error("GoToPresetFromDevice: " + err.Error()) + } + + return err +} + func getXMLNode(xmlBody string, nodeName string) (*xml.Decoder, *xml.StartElement, error) { xmlBytes := bytes.NewBufferString(xmlBody) decodedXML := xml.NewDecoder(xmlBytes) diff --git a/machinery/src/routers/http/Methods.go b/machinery/src/routers/http/Methods.go index 79fa4258..fa0aaa7a 100644 --- a/machinery/src/routers/http/Methods.go +++ b/machinery/src/routers/http/Methods.go @@ -250,3 +250,105 @@ func DoOnvifZoom(c *gin.Context) { }) } } + +// GetOnvifPresets godoc +// @Router /api/camera/onvif/presets [post] +// @ID camera-onvif-presets +// @Tags camera +// @Param config body models.OnvifCredentials true "OnvifCredentials" +// @Summary Will return the ONVIF presets for the specific camera. +// @Description Will return the ONVIF presets for the specific camera. +// @Success 200 {object} models.APIResponse +func GetOnvifPresets(c *gin.Context) { + var onvifCredentials models.OnvifCredentials + err := c.BindJSON(&onvifCredentials) + + if err == nil && onvifCredentials.ONVIFXAddr != "" { + + configuration := &models.Configuration{ + Config: models.Config{ + Capture: models.Capture{ + IPCamera: models.IPCamera{ + ONVIFXAddr: onvifCredentials.ONVIFXAddr, + ONVIFUsername: onvifCredentials.ONVIFUsername, + ONVIFPassword: onvifCredentials.ONVIFPassword, + }, + }, + }, + } + + cameraConfiguration := configuration.Config.Capture.IPCamera + device, err := onvif.ConnectToOnvifDevice(&cameraConfiguration) + if err == nil { + presets, err := onvif.GetPresetsFromDevice(device) + if err == nil { + c.JSON(200, gin.H{ + "presets": presets, + }) + } else { + c.JSON(400, gin.H{ + "data": "Something went wrong: " + err.Error(), + }) + } + } else { + c.JSON(400, gin.H{ + "data": "Something went wrong: " + err.Error(), + }) + } + } else { + c.JSON(400, gin.H{ + "data": "Something went wrong: " + err.Error(), + }) + } +} + +// GoToOnvifPReset godoc +// @Router /api/camera/onvif/gotopreset [post] +// @ID camera-onvif-gotopreset +// @Tags camera +// @Param config body models.OnvifPreset true "OnvifPreset" +// @Summary Will activate the desired ONVIF preset. +// @Description Will activate the desired ONVIF preset. +// @Success 200 {object} models.APIResponse +func GoToOnvifPreset(c *gin.Context) { + var onvifPreset models.OnvifPreset + err := c.BindJSON(&onvifPreset) + + if err == nil && onvifPreset.OnvifCredentials.ONVIFXAddr != "" { + + configuration := &models.Configuration{ + Config: models.Config{ + Capture: models.Capture{ + IPCamera: models.IPCamera{ + ONVIFXAddr: onvifPreset.OnvifCredentials.ONVIFXAddr, + ONVIFUsername: onvifPreset.OnvifCredentials.ONVIFUsername, + ONVIFPassword: onvifPreset.OnvifCredentials.ONVIFPassword, + }, + }, + }, + } + + cameraConfiguration := configuration.Config.Capture.IPCamera + device, err := onvif.ConnectToOnvifDevice(&cameraConfiguration) + if err == nil { + err := onvif.GoToPresetFromDevice(device, onvifPreset.Preset) + if err == nil { + c.JSON(200, gin.H{ + "data": "Camera preset activated: " + onvifPreset.Preset, + }) + } else { + c.JSON(400, gin.H{ + "data": "Something went wrong: " + err.Error(), + }) + } + } else { + c.JSON(400, gin.H{ + "data": "Something went wrong: " + err.Error(), + }) + } + } else { + c.JSON(400, gin.H{ + "data": "Something went wrong: " + err.Error(), + }) + } +} diff --git a/machinery/src/routers/http/Routes.go b/machinery/src/routers/http/Routes.go index b728a526..cd3bedac 100644 --- a/machinery/src/routers/http/Routes.go +++ b/machinery/src/routers/http/Routes.go @@ -227,6 +227,8 @@ func AddRoutes(r *gin.Engine, authMiddleware *jwt.GinJWTMiddleware, configDirect // the camera. api.POST("/camera/onvif/login", LoginToOnvif) api.POST("/camera/onvif/capabilities", GetOnvifCapabilities) + api.POST("/camera/onvif/presets", GetOnvifPresets) + api.POST("/camera/onvif/gotopreset", GoToOnvifPreset) api.POST("/camera/onvif/pantilt", DoOnvifPanTilt) api.POST("/camera/onvif/zoom", DoOnvifZoom) api.POST("/camera/verify/:streamType", capture.VerifyCamera)