From a843b284ab2b10f6a662693190bdf9af22399abf Mon Sep 17 00:00:00 2001 From: Preethi Satishchandra Date: Tue, 7 Feb 2023 17:25:05 -0700 Subject: [PATCH] fix: Modify pan tilt function by getting pan/tilt range dynamically (#181) * fix: Get pan/tilt values dynamically Signed-off-by: preethi-satishcandra --- .../custom/camera-management/appcamera/app.go | 3 ++ .../camera-management/appcamera/commands.go | 39 ++++++++++----- .../camera-management/appcamera/routes.go | 42 +++++++++++++--- .../camera-management/appcamera/types.go | 48 +++++++++++++++++-- 4 files changed, 112 insertions(+), 20 deletions(-) diff --git a/application-services/custom/camera-management/appcamera/app.go b/application-services/custom/camera-management/appcamera/app.go index 248a3c73..1091a811 100644 --- a/application-services/custom/camera-management/appcamera/app.go +++ b/application-services/custom/camera-management/appcamera/app.go @@ -19,6 +19,8 @@ type CameraManagementApp struct { config *ServiceConfig pipelinesMap map[string]PipelineInfo pipelinesMutex sync.RWMutex + panTiltMap map[string]PanTiltRange + panTiltMutex sync.RWMutex fileServer http.Handler } @@ -28,6 +30,7 @@ func NewCameraManagementApp(service interfaces.ApplicationService) *CameraManage lc: service.LoggingClient(), config: &ServiceConfig{}, pipelinesMap: make(map[string]PipelineInfo), + panTiltMap: make(map[string]PanTiltRange), } } diff --git a/application-services/custom/camera-management/appcamera/commands.go b/application-services/custom/camera-management/appcamera/commands.go index 962cffaf..03f3eb9e 100644 --- a/application-services/custom/camera-management/appcamera/commands.go +++ b/application-services/custom/camera-management/appcamera/commands.go @@ -16,15 +16,14 @@ import ( ) const ( - relativeMoveCommand = "RelativeMove" - gotoPresetCommand = "GotoPreset" - streamUriCommand = "StreamUri" - profilesCommand = "Profiles" - getPresetsCommand = "GetPresets" - - moveScaleX = 10 - moveScaleY = 5 - zoomScale = 1 + relativeMoveCommand = "RelativeMove" + gotoPresetCommand = "GotoPreset" + streamUriCommand = "StreamUri" + profilesCommand = "Profiles" + getPresetsCommand = "GetPresets" + getConfigurationsCommand = "GetConfigurations" + + zoomScale = 1 ) func (app *CameraManagementApp) getProfiles(deviceName string) (ProfilesResponse, error) { @@ -60,8 +59,8 @@ func (app *CameraManagementApp) queryStreamUri(deviceName, profileToken string) func (app *CameraManagementApp) doPTZ(deviceName, profileToken string, x, y, zoom float64) (dtosCommon.BaseResponse, error) { trans := ptz.Vector{ PanTilt: &onvif.Vector2D{ - X: x * moveScaleX, - Y: y * moveScaleY, + X: x, + Y: y, }, } if zoom != 0 { @@ -97,6 +96,24 @@ func (app *CameraManagementApp) getPresets(deviceName string, profileToken strin return pr, err } +func (app *CameraManagementApp) getPTZConfiguration(deviceName string) (GetPTZConfigurationsResponse, error) { + cmd := &ptz.GetConfigurations{} + + config, err := app.issueGetCommand(context.Background(), deviceName, getConfigurationsCommand, cmd) + if err != nil { + return GetPTZConfigurationsResponse{}, errors.Wrapf(err, "failed to issue get configurations command") + } + + val := config.Event.Readings[0].ObjectValue + js, err := json.Marshal(val) + if err != nil { + return GetPTZConfigurationsResponse{}, errors.Wrapf(err, "failed to marshal configurations json object") + } + pr := GetPTZConfigurationsResponse{} + err = json.Unmarshal(js, &pr) + return pr, err +} + func (app *CameraManagementApp) gotoPreset(deviceName string, profile string, preset string) (dtosCommon.BaseResponse, error) { cmd := &ptz.GotoPreset{ ProfileToken: (*onvif.ReferenceToken)(&profile), diff --git a/application-services/custom/camera-management/appcamera/routes.go b/application-services/custom/camera-management/appcamera/routes.go index 376dd10e..1205fe0c 100644 --- a/application-services/custom/camera-management/appcamera/routes.go +++ b/application-services/custom/camera-management/appcamera/routes.go @@ -17,12 +17,9 @@ import ( ) const ( - left = -1 - right = 1 - up = 1 - down = -1 - zoomIn = 1 - zoomOut = -1 + panTiltOffset = 0.05 + zoomIn = 1 + zoomOut = -1 webUIDistDir = "./web-ui/dist" @@ -257,6 +254,18 @@ func (app *CameraManagementApp) ptzRoute(w http.ResponseWriter, req *http.Reques var res dtosCommon.BaseResponse var err error + panTiltRange, err := app.getPanTiltRange(deviceName) + if err != nil { + respondError(app.lc, w, http.StatusInternalServerError, + fmt.Sprintf("Failed to get PTZ configuration for the device %s: %v", deviceName, err)) + return + } + + right := panTiltOffset * panTiltRange.XRange + left := -right + up := panTiltOffset * panTiltRange.YRange + down := -up + switch action { case "left": res, err = app.doPTZ(deviceName, profileToken, left, 0, 0) @@ -296,3 +305,24 @@ func (app *CameraManagementApp) ptzRoute(w http.ResponseWriter, req *http.Reques app.lc.Error(err.Error()) } } + +func (app *CameraManagementApp) getPanTiltRange(deviceName string) (PanTiltRange, error) { + app.panTiltMutex.Lock() + defer app.panTiltMutex.Unlock() + panTiltRange, exists := app.panTiltMap[deviceName] + if !exists { + ptzConfigs, err := app.getPTZConfiguration(deviceName) + if err != nil { + return PanTiltRange{}, err + } + + xRange := ptzConfigs.PTZConfiguration[0].PanTiltLimits.Range.XRange.Max - ptzConfigs.PTZConfiguration[0].PanTiltLimits.Range.XRange.Min + yRange := ptzConfigs.PTZConfiguration[0].PanTiltLimits.Range.YRange.Max - ptzConfigs.PTZConfiguration[0].PanTiltLimits.Range.YRange.Min + panTiltRange = PanTiltRange{ + XRange: xRange, + YRange: yRange, + } + app.panTiltMap[deviceName] = panTiltRange + } + return panTiltRange, nil +} diff --git a/application-services/custom/camera-management/appcamera/types.go b/application-services/custom/camera-management/appcamera/types.go index b82b5163..54b5a91a 100644 --- a/application-services/custom/camera-management/appcamera/types.go +++ b/application-services/custom/camera-management/appcamera/types.go @@ -188,17 +188,59 @@ type GetPresetsResponse struct { Name string `json:"Name"` PTZPosition struct { PanTilt struct { - Space string `json:"Space"` - X int `json:"X"` - Y int `json:"Y"` + Space string `json:"Space"` + X float64 `json:"X"` + Y float64 `json:"Y"` } `json:"PanTilt"` } `json:"PTZPosition"` Token string `json:"Token"` } `json:"Preset"` } +type GetPTZConfigurationsResponse struct { + PTZConfiguration []struct { + DefaultAbsolutePantTiltPositionSpace string `json:"DefaultAbsolutePantTiltPositionSpace"` + DefaultAbsoluteZoomPositionSpace string `json:"DefaultAbsoluteZoomPositionSpace"` + DefaultContinuousPanTiltVelocitySpace string `json:"DefaultContinuousPanTiltVelocitySpace"` + DefaultContinuousZoomVelocitySpace string `json:"DefaultContinuousZoomVelocitySpace"` + DefaultPTZSpeed struct { + } `json:"DefaultPTZSpeed"` + DefaultPTZTimeout string `json:"DefaultPTZTimeout"` + DefaultRelativePanTiltTranslationSpace string `json:"DefaultRelativePanTiltTranslationSpace"` + DefaultRelativeZoomTranslationSpace string `json:"DefaultRelativeZoomTranslationSpace"` + PanTiltLimits struct { + Range struct { + URI string `json:"URI"` + XRange struct { + Max float64 `json:"Max"` + Min float64 `json:"Min"` + } `json:"XRange"` + YRange struct { + Max float64 `json:"Max"` + Min float64 `json:"Min"` + } `json:"YRange"` + } `json:"Range"` + } `json:"PanTiltLimits"` + Token string `json:"Token"` + ZoomLimits struct { + Range struct { + URI string `json:"URI"` + XRange struct { + Max float64 `json:"Max"` + Min float64 `json:"Min"` + } `json:"XRange"` + } `json:"Range"` + } `json:"ZoomLimits"` + } `json:"PTZConfiguration"` +} + type StartPipelineRequest struct { ProfileToken string `json:"profile_token"` PipelineName string `json:"pipeline_name"` PipelineVersion string `json:"pipeline_version"` } + +type PanTiltRange struct { + XRange float64 `json:"XRange"` + YRange float64 `json:"YRange"` +}