diff --git a/machinery/go.mod b/machinery/go.mod index d019f5cb..d0ec68b8 100644 --- a/machinery/go.mod +++ b/machinery/go.mod @@ -24,7 +24,7 @@ require ( github.com/gorilla/websocket v1.5.3 github.com/kellydunn/golang-geo v0.7.0 github.com/kerberos-io/joy4 v1.0.64 - github.com/kerberos-io/onvif v1.0.0 + github.com/kerberos-io/onvif v0.0.7 github.com/minio/minio-go/v6 v6.0.57 github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 @@ -56,7 +56,6 @@ require ( github.com/bytedance/sonic/loader v0.2.4 // indirect github.com/cenkalti/backoff/v5 v5.0.2 // indirect github.com/clbanning/mxj v1.8.4 // indirect - github.com/clbanning/mxj/v2 v2.7.0 // indirect github.com/cloudwego/base64x v0.1.5 // indirect github.com/elastic/go-windows v1.0.2 // indirect github.com/elgs/gostrgen v0.0.0-20161222160715-9d61ae07eeae // indirect @@ -76,10 +75,8 @@ require ( github.com/golang/snappy v0.0.4 // indirect github.com/google/uuid v1.6.0 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 // indirect - github.com/icholy/digest v0.1.23 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect - github.com/juju/errors v1.0.0 // indirect github.com/klauspost/compress v1.16.7 // indirect github.com/klauspost/cpuid v1.2.3 // indirect github.com/klauspost/cpuid/v2 v2.2.10 // indirect diff --git a/machinery/go.sum b/machinery/go.sum index c2249640..3bc8b6e8 100644 --- a/machinery/go.sum +++ b/machinery/go.sum @@ -391,6 +391,7 @@ github.com/appleboy/gin-jwt/v2 v2.10.3/go.mod h1:LDUaQ8mF2W6LyXIbd5wqlV2SFebuyYs github.com/appleboy/gofight/v2 v2.1.2 h1:VOy3jow4vIK8BRQJoC/I9muxyYlJ2yb9ht2hZoS3rf4= github.com/appleboy/gofight/v2 v2.1.2/go.mod h1:frW+U1QZEdDgixycTj4CygQ48yLTUhplt43+Wczp3rw= github.com/bazelbuild/rules_go v0.49.0/go.mod h1:Dhcz716Kqg1RHNWos+N6MlXNkjNP2EwZQ0LukRKJfMs= +github.com/beevik/etree v1.1.0/go.mod h1:r8Aw8JqVegEf0w2fDnATrX9VpkMcyFeM0FhwO62wh+A= github.com/beevik/etree v1.2.0 h1:l7WETslUG/T+xOPs47dtd6jov2Ii/8/OjCldk5fYfQw= github.com/beevik/etree v1.2.0/go.mod h1:aiPf89g/1k3AShMVAzriilpcE4R/Vuor90y83zVZWFc= github.com/bluenviron/gortsplib/v4 v4.14.1 h1:v99NmXeeJFfbrO+ipPzPxYGibQaR5ZOUESOA9UQZhsI= @@ -425,8 +426,6 @@ github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMn github.com/chzyer/test v0.0.0-20210722231415-061457976a23/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= github.com/clbanning/mxj v1.8.4 h1:HuhwZtbyvyOw+3Z1AowPkU87JkJUSv751ELWaiTpj8I= github.com/clbanning/mxj v1.8.4/go.mod h1:BVjHeAH+rl9rs6f+QIpeRl0tfu10SXn1pUSa5PVGJng= -github.com/clbanning/mxj/v2 v2.7.0 h1:WA/La7UGCanFe5NpHF0Q3DNtnCsVoxbPKuyBNHWRyME= -github.com/clbanning/mxj/v2 v2.7.0/go.mod h1:hNiWqW14h+kc+MdF9C6/YoRfjEJoR3ou6tn/Qo+ve2s= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= github.com/cloudwego/base64x v0.1.5 h1:XPciSp1xaq2VCSt6lF0phncD4koWyULpl5bUxbfCyP4= github.com/cloudwego/base64x v0.1.5/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= @@ -526,10 +525,12 @@ github.com/gin-contrib/gzip v0.0.6 h1:NjcunTcGAj5CO1gn4N8jHOSIeRFHIbn51z6K+xaN4d github.com/gin-contrib/gzip v0.0.6/go.mod h1:QOJlmV2xmayAjkNS2Y8NQsMneuRShOU/kjovCXNuzzk= github.com/gin-contrib/pprof v1.5.3 h1:Bj5SxJ3kQDVez/s/+f9+meedJIqLS+xlkIVDe/lcvgM= github.com/gin-contrib/pprof v1.5.3/go.mod h1:0+LQSZ4SLO0B6+2n6JBzaEygpTBxe/nI+YEYpfQQ6xY= +github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-contrib/sse v1.0.0 h1:y3bT1mUWUxDpW4JLQg/HnTqV4rozuW4tC9eFKTxYI9E= github.com/gin-contrib/sse v1.0.0/go.mod h1:zNuFdwarAygJBht0NTKiSi3jRf6RbqeILZ9Sp6Slhe0= github.com/gin-gonic/contrib v0.0.0-20250521004450-2b1292699c15 h1:AoSudS8CW8Mc9rRf5sO1vBtNxr2Ok6TaAICjgg5oKUY= github.com/gin-gonic/contrib v0.0.0-20250521004450-2b1292699c15/go.mod h1:iqneQ2Df3omzIVTkIfn7c1acsVnMGiSLn4XF5Blh3Yg= +github.com/gin-gonic/gin v1.6.2/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= github.com/gin-gonic/gin v1.10.1 h1:T0ujvqyCSqRopADpgPgiTT63DUQVSfojyME59Ei63pQ= github.com/gin-gonic/gin v1.10.1/go.mod h1:4PMNQiOhvDRa013RKVbsiNwoyezlm2rm0uX/T7kzp5Y= github.com/go-fonts/dejavu v0.1.0/go.mod h1:4Wt4I4OU2Nq9asgDCteaAaWZOV24E+0/Pwo0gppep4g= @@ -571,6 +572,7 @@ github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/Nu github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= +github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= github.com/go-playground/validator/v10 v10.4.1/go.mod h1:nlOn6nFhuKACm19sB/8EGNn9GlaMV7XkbRSipzJ0Ii4= github.com/go-playground/validator/v10 v10.26.0 h1:SP05Nqhjcvz81uJaRfEV0YBSSSGMc/iMaVtFbr3Sw2k= github.com/go-playground/validator/v10 v10.26.0/go.mod h1:I5QpIEbmr8On7W0TktmJAumgzX4CA1XNl4ZmDuVHKKo= @@ -581,6 +583,7 @@ github.com/goccy/go-json v0.10.5 h1:Fq85nIqj+gXn/S5ahsiTlK3TmC85qgirsdTP/+DeaC4= github.com/goccy/go-json v0.10.5/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/goccy/go-yaml v1.9.8/go.mod h1:JubOolP3gh0HpiBc4BLRD4YmjEjHAmIIB2aaXKkTfoE= github.com/goccy/go-yaml v1.11.0/go.mod h1:H+mJrWtjPTJAHvRbV09MCK9xYwODM+wRTVFFTWckfng= +github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gofrs/uuid v4.4.0+incompatible h1:3qXRTX8/NbyulANqlc0lchS1gqAVxRgsuW1YrTJupqA= github.com/gofrs/uuid v4.4.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= @@ -755,8 +758,6 @@ github.com/iancoleman/strcase v0.3.0/go.mod h1:iwCmte+B7n89clKwxIoIXy/HfoL7AsD47 github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= github.com/ianlancetaylor/demangle v0.0.0-20220319035150-800ac71e25c2/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= -github.com/icholy/digest v0.1.23 h1:4hX2pIloP0aDx7RJW0JewhPPy3R8kU+vWKdxPsCCGtY= -github.com/icholy/digest v0.1.23/go.mod h1:QNrsSGQ5v7v9cReDI0+eyjsXGUoRSUZQHeQ5C4XLa0Y= github.com/jessevdk/go-flags v1.4.0/go.mod h1:4FA24M0QyGHXBuZZK/XkWh8h0e1EYbRYJSGM75WSRxI= github.com/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= @@ -767,8 +768,6 @@ github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1 github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/jtolds/gls v4.20.0+incompatible h1:xdiiI2gbIgH/gLH7ADydsJ1uDOEzR8yvV7C0MuV77Wo= github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= -github.com/juju/errors v1.0.0 h1:yiq7kjCLll1BiaRuNY53MGI0+EQ3rF6GB+wvboZDefM= -github.com/juju/errors v1.0.0/go.mod h1:B5x9thDqx0wIMH3+aLIMP9HjItInYWObRovoCFM5Qe8= github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= @@ -776,8 +775,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.64 h1:gTUSotHSOhp9mNqEecgq88tQHvpj7TjmrvPUsPm0idg= github.com/kerberos-io/joy4 v1.0.64/go.mod h1:nZp4AjvKvTOXRrmDyAIOw+Da+JA5OcSo/JundGfOlFU= -github.com/kerberos-io/onvif v1.0.0 h1:pLJrK6skPkK+5Bj4XfqHUkQ2I+p5pwELnp+kQTJWXiQ= -github.com/kerberos-io/onvif v1.0.0/go.mod h1:P1kUcCfeotJSlL1jwGseH6NSnCwWiuJLl3gAzafnLbA= +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/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/klauspost/asmfmt v1.3.2/go.mod h1:AG8TuvYojzulgDAMCnYn50l/5QV3Bs/tp6j0HLHbNSE= @@ -976,6 +975,8 @@ github.com/tidwall/pretty v1.2.0/go.mod h1:ITEVvHYasfjBbM0u2Pg8T2nJnzm8xPwvNhhso github.com/tidwall/sjson v1.2.5/go.mod h1:Fvgq9kS/6ociJEDnK0Fk1cpYF4FIW6ZF7LAe+6jwd28= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/ugorji/go/codec v1.2.12 h1:9LC83zGrHhuUA9l16C9AHXAqEV/2wBQ4nkvumAE65EE= github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/wlynxg/anet v0.0.5 h1:J3VJGi1gvo0JwZ/P1/Yc/8p63SoW98B5dHkYDmpgvvU= @@ -1255,6 +1256,7 @@ golang.org/x/net v0.0.0-20200222125558-5a598a2470a0/go.mod h1:z5CRVTTTmAJ677TzLL golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200324143707-d3edc9973b7e/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= +golang.org/x/net v0.0.0-20200425230154-ff2c4b7c35a0/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200501053045-e0ff5e5a1de5/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= @@ -2103,13 +2105,13 @@ gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWD gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY= gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gotest.tools/v3 v3.5.1 h1:EENdUnS3pdur5nybKYIh2Vfgc8IUNBjxDPSjtiJcOzU= gotest.tools/v3 v3.5.1/go.mod h1:isy3WKz7GK6uNw/sbHzfKBLvlvXwUyV06n6brMxxopU= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/machinery/main.go b/machinery/main.go index f98c2b25..ec30ca33 100644 --- a/machinery/main.go +++ b/machinery/main.go @@ -11,7 +11,6 @@ import ( "github.com/kerberos-io/agent/machinery/src/components" "github.com/kerberos-io/agent/machinery/src/log" "github.com/kerberos-io/agent/machinery/src/models" - "github.com/kerberos-io/agent/machinery/src/onvif" "go.opentelemetry.io/otel" "go.opentelemetry.io/otel/attribute" "go.opentelemetry.io/otel/exporters/otlp/otlptrace" @@ -105,12 +104,12 @@ func main() { case "discover": // Convert duration to int - timeout, err := time.ParseDuration(timeout + "ms") + /*timeout, err := time.ParseDuration(timeout + "ms") if err != nil { log.Log.Fatal("main.Main(): could not parse timeout: " + err.Error()) return } - onvif.Discover(timeout) + onvif.Discover(timeout)*/ case "decrypt": log.Log.Info("main.Main(): Decrypting: " + flag.Arg(0) + " with key: " + flag.Arg(1)) diff --git a/machinery/src/cloud/Cloud.go b/machinery/src/cloud/Cloud.go index e800ec2a..88fd605e 100644 --- a/machinery/src/cloud/Cloud.go +++ b/machinery/src/cloud/Cloud.go @@ -234,17 +234,17 @@ func HandleHeartBeat(configuration *models.Configuration, communication *models. // Create a loop pull point address, which we will use to retrieve async events // As you'll read below camera manufactures are having different implementations of events. - var pullPointAddressLoopState string + /*var pullPointAddressLoopState string if configuration.Config.Capture.IPCamera.ONVIFXAddr != "" { cameraConfiguration := configuration.Config.Capture.IPCamera - device, _, err := onvif.ConnectToOnvifDevice(&cameraConfiguration) + device, err := onvif.ConnectToOnvifDevice(&cameraConfiguration) if err != nil { pullPointAddressLoopState, err = onvif.CreatePullPointSubscription(device) if err != nil { log.Log.Error("cloud.HandleHeartBeat(): error while creating pull point subscription: " + err.Error()) } } - } + }*/ loop: for { @@ -261,7 +261,7 @@ loop: var onvifEventsList []byte if config.Capture.IPCamera.ONVIFXAddr != "" { cameraConfiguration := configuration.Config.Capture.IPCamera - device, _, err := onvif.ConnectToOnvifDevice(&cameraConfiguration) + device, err := onvif.ConnectToOnvifDevice(&cameraConfiguration) if err == nil { // We will try to retrieve the PTZ configurations from the device. onvifEnabled = "true" @@ -306,7 +306,7 @@ loop: // - In this scenario we are creating a new subscription to retrieve the initial (current) state of the inputs and outputs. // Get a new pull point address, to get the initiatal state of the inputs and outputs. - pullPointAddressInitialState, err := onvif.CreatePullPointSubscription(device) + /*pullPointAddressInitialState, err := onvif.CreatePullPointSubscription(device) if err != nil { log.Log.Error("cloud.HandleHeartBeat(): error while creating pull point subscription: " + err.Error()) } @@ -402,7 +402,10 @@ loop: log.Log.Error("cloud.HandleHeartBeat(): error while marshalling events: " + err.Error()) onvifEventsList = []byte("[]") } - } + }*/ + + onvifEventsList = []byte("[]") + } else { log.Log.Error("cloud.HandleHeartBeat(): error while connecting to ONVIF device: " + err.Error()) onvifPresetsList = []byte("[]") @@ -647,13 +650,13 @@ loop: } } - if pullPointAddressLoopState != "" { + /*if pullPointAddressLoopState != "" { cameraConfiguration := configuration.Config.Capture.IPCamera - device, _, err := onvif.ConnectToOnvifDevice(&cameraConfiguration) + device, err := onvif.ConnectToOnvifDevice(&cameraConfiguration) if err != nil { onvif.UnsubscribePullPoint(device, pullPointAddressLoopState) } - } + }*/ log.Log.Debug("cloud.HandleHeartBeat(): finished") } diff --git a/machinery/src/onvif/main.go b/machinery/src/onvif/main.go index 45623d77..2259ac9e 100644 --- a/machinery/src/onvif/main.go +++ b/machinery/src/onvif/main.go @@ -6,43 +6,22 @@ import ( "encoding/xml" "errors" "io" - "strconv" + "io/ioutil" "strings" "time" - onvifc "github.com/cedricve/go-onvif" "github.com/gin-gonic/gin" "github.com/kerberos-io/agent/machinery/src/log" "github.com/kerberos-io/agent/machinery/src/models" - "github.com/kerberos-io/onvif" - "github.com/kerberos-io/onvif/device" - "github.com/kerberos-io/onvif/deviceio" - "github.com/kerberos-io/onvif/event" "github.com/kerberos-io/onvif/media" + + "github.com/kerberos-io/onvif" "github.com/kerberos-io/onvif/ptz" - xsd "github.com/kerberos-io/onvif/xsd" - xsdonvif "github.com/kerberos-io/onvif/xsd/onvif" + xsd "github.com/kerberos-io/onvif/xsd/onvif" ) -func Discover(timeout time.Duration) { - log.Log.Info("onvif.Discover(): Discovering devices") - log.Log.Info("Waiting for " + timeout.String()) - devices, err := onvifc.StartDiscovery(timeout) - if err != nil { - log.Log.Error("onvif.Discover(): " + err.Error()) - } else { - for _, device := range devices { - hostname, _ := device.GetHostname() - log.Log.Info("onvif.Discover(): " + hostname.Name + " (" + device.XAddr + ")") - } - if len(devices) == 0 { - log.Log.Info("onvif.Discover(): No devices descovered\n") - } - } -} - func HandleONVIFActions(configuration *models.Configuration, communication *models.Communication) { - log.Log.Debug("onvif.HandleONVIFActions(): started") + log.Log.Debug("HandleONVIFActions: started") for onvifAction := range communication.HandleONVIF { @@ -54,7 +33,7 @@ func HandleONVIFActions(configuration *models.Configuration, communication *mode // Connect to Onvif device cameraConfiguration := configuration.Config.Capture.IPCamera - device, _, err := ConnectToOnvifDevice(&cameraConfiguration) + device, err := ConnectToOnvifDevice(&cameraConfiguration) if err == nil { // Get token from the first profile @@ -77,7 +56,7 @@ func HandleONVIFActions(configuration *models.Configuration, communication *mode functions, _, _ := GetPTZFunctionsFromDevice(configurations) // Log functions - log.Log.Debug("onvif.HandleONVIFActions(): functions: " + strings.Join(functions, ", ")) + log.Log.Info("HandleONVIFActions: functions: " + strings.Join(functions, ", ")) // Check if we need to use absolute or continuous move /*canAbsoluteMove := false @@ -98,9 +77,9 @@ func HandleONVIFActions(configuration *models.Configuration, communication *mode // on the ContinuousPanTiltMove function which is more compatible with more cameras. err = AbsolutePanTiltMoveFake(device, configurations, token, x, y, z) if err != nil { - log.Log.Debug("onvif.HandleONVIFActions() - AbsolutePanTitleMoveFake: " + err.Error()) + log.Log.Error("HandleONVIFActions (AbsolutePanTitleMoveFake): " + err.Error()) } else { - log.Log.Info("onvif.HandleONVIFActions() - AbsolutePanTitleMoveFake: successfully moved camera.") + log.Log.Info("HandleONVIFActions (AbsolutePanTitleMoveFake): successfully moved camera") } /*if canAbsoluteMove { @@ -121,9 +100,9 @@ func HandleONVIFActions(configuration *models.Configuration, communication *mode preset := ptzAction.Preset err := GoToPresetFromDevice(device, preset) if err != nil { - log.Log.Debug("onvif.HandleONVIFActions() - GotoPreset: " + err.Error()) + log.Log.Error("HandleONVIFActions (GotoPreset): " + err.Error()) } else { - log.Log.Info("onvif.HandleONVIFActions() - GotoPreset: successfully moved camera") + log.Log.Info("HandleONVIFActions (GotoPreset): successfully moved camera") } } else if onvifAction.Action == "ptz" { @@ -135,9 +114,7 @@ func HandleONVIFActions(configuration *models.Configuration, communication *mode // We will move the camera to zero position. err := AbsolutePanTiltMove(device, configurations, token, 0, 0, 0) if err != nil { - log.Log.Debug("onvif.HandleONVIFActions() - AbsolutePanTitleMove: " + err.Error()) - } else { - log.Log.Info("onvif.HandleONVIFActions() - AbsolutePanTitleMove: successfully centered camera") + log.Log.Error("HandleONVIFActions (AbsolutePanTitleMove): " + err.Error()) } } else { @@ -164,9 +141,7 @@ func HandleONVIFActions(configuration *models.Configuration, communication *mode err := ContinuousPanTilt(device, configurations, token, x, y) if err != nil { - log.Log.Debug("onvif.HandleONVIFActions() - ContinuousPanTilt: " + err.Error()) - } else { - log.Log.Info("onvif.HandleONVIFActions() - ContinuousPanTilt: successfully pan tilted camera") + log.Log.Error("HandleONVIFActions (ContinuousPanTilt): " + err.Error()) } } } @@ -176,9 +151,7 @@ func HandleONVIFActions(configuration *models.Configuration, communication *mode zoom := ptzAction.Zoom err := ContinuousZoom(device, configurations, token, zoom) if err != nil { - log.Log.Debug("onvif.HandleONVIFActions() - ContinuousZoom: " + err.Error()) - } else { - log.Log.Info("onvif.HandleONVIFActions() - ContinuousZoom: successfully zoomed camera") + log.Log.Error("HandleONVIFActions (ContinuousZoom): " + err.Error()) } } } @@ -186,85 +159,46 @@ func HandleONVIFActions(configuration *models.Configuration, communication *mode } } } - log.Log.Debug("onvif.HandleONVIFActions(): finished") + log.Log.Debug("HandleONVIFActions: finished") } -func ConnectToOnvifDevice(cameraConfiguration *models.IPCamera) (*onvif.Device, device.GetCapabilitiesResponse, error) { - log.Log.Debug("onvif.ConnectToOnvifDevice(): started") - dev, err := onvif.NewDevice(onvif.DeviceParams{ +func ConnectToOnvifDevice(cameraConfiguration *models.IPCamera) (*onvif.Device, error) { + log.Log.Debug("ConnectToOnvifDevice: started") + + device, err := onvif.NewDevice(onvif.DeviceParams{ Xaddr: cameraConfiguration.ONVIFXAddr, Username: cameraConfiguration.ONVIFUsername, Password: cameraConfiguration.ONVIFPassword, - AuthMode: "both", }) - var capabilities device.GetCapabilitiesResponse if err != nil { - // Try again with other authentication mode - dev, err = onvif.NewDevice(onvif.DeviceParams{ - Xaddr: cameraConfiguration.ONVIFXAddr, - Username: cameraConfiguration.ONVIFUsername, - Password: cameraConfiguration.ONVIFPassword, - AuthMode: "digest", - }) - if err != nil { - log.Log.Debug("onvif.ConnectToOnvifDevice(): " + err.Error()) - } + log.Log.Error("ConnectToOnvifDevice: " + err.Error()) } - if err == nil { - getCapabilities := device.GetCapabilities{Category: []xsdonvif.CapabilityCategory{"All"}} - resp, err := dev.CallMethod(getCapabilities) - if err != nil { - log.Log.Error("onvif.ConnectToOnvifDevice(): " + err.Error()) - } - - var b []byte - if resp != nil { - b, err = io.ReadAll(resp.Body) - resp.Body.Close() // Ensure the response body is closed - if err != nil { - log.Log.Error("onvif.ConnectToOnvifDevice(): " + err.Error()) - } - } - stringBody := string(b) - decodedXML, et, err := getXMLNode(stringBody, "GetCapabilitiesResponse") - if err != nil { - log.Log.Error("onvif.ConnectToOnvifDevice(): " + err.Error()) - } else { - if err := decodedXML.DecodeElement(&capabilities, et); err != nil { - log.Log.Error("onvif.ConnectToOnvifDevice(): " + err.Error()) - } else { - log.Log.Debug("onvif.ConnectToOnvifDevice(): capabilities.") - } - } - - log.Log.Info("onvif.ConnectToOnvifDevice(): successfully connected to device") - } - log.Log.Debug("onvif.ConnectToOnvifDevice(): finished") - return dev, capabilities, err + log.Log.Debug("ConnectToOnvifDevice: finished") + return device, err } -func GetTokenFromProfile(device *onvif.Device, profileId int) (xsdonvif.ReferenceToken, error) { +func GetTokenFromProfile(device *onvif.Device, profileId int) (xsd.ReferenceToken, error) { // We aim to receive a profile token from the server - var profileToken xsdonvif.ReferenceToken + var profileToken xsd.ReferenceToken // Get Profiles resp, err := device.CallMethod(media.GetProfiles{}) if err == nil { + defer resp.Body.Close() b, err := io.ReadAll(resp.Body) if err == nil { stringBody := string(b) - resp.Body.Close() // Ensure the response body is closed decodedXML, et, err := getXMLNode(stringBody, "GetProfilesResponse") if err != nil { - log.Log.Debug("onvif.GetTokenFromProfile(): " + err.Error()) + log.Log.Error("GetTokenFromProfile: " + err.Error()) return profileToken, err } else { // Decode the profiles from the server var mProfilesResp media.GetProfilesResponse if err := decodedXML.DecodeElement(&mProfilesResp, et); err != nil { - log.Log.Debug("onvif.GetTokenFromProfile(): " + err.Error()) + log.Log.Error("GetTokenFromProfile: " + err.Error()) } // We'll try to get the token from a preferred profile @@ -285,33 +219,31 @@ func GetPTZConfigurationsFromDevice(device *onvif.Device) (ptz.GetConfigurations // Get the PTZ configurations from the device resp, err := device.CallMethod(ptz.GetConfigurations{}) - var b []byte - if resp != nil { - b, err = io.ReadAll(resp.Body) - resp.Body.Close() // Ensure the response body is closed - } - if err == nil { - stringBody := string(b) - decodedXML, et, err := getXMLNode(stringBody, "GetConfigurationsResponse") - if err != nil { - log.Log.Debug("onvif.GetPTZConfigurationsFromDevice(): " + err.Error()) - return configurations, err - } else { - if err := decodedXML.DecodeElement(&configurations, et); err != nil { - log.Log.Debug("onvif.GetPTZConfigurationsFromDevice(): " + err.Error()) + defer resp.Body.Close() + b, err := io.ReadAll(resp.Body) + if err == nil { + stringBody := string(b) + decodedXML, et, err := getXMLNode(stringBody, "GetConfigurationsResponse") + if err != nil { + log.Log.Error("GetPTZConfigurationsFromDevice: " + err.Error()) return configurations, err + } else { + if err := decodedXML.DecodeElement(&configurations, et); err != nil { + log.Log.Error("GetPTZConfigurationsFromDevice: " + err.Error()) + return configurations, err + } } } } return configurations, err } -func GetPositionFromDevice(configuration models.Configuration) (xsdonvif.PTZVector, error) { - var position xsdonvif.PTZVector +func GetPositionFromDevice(configuration models.Configuration) (xsd.PTZVector, error) { + var position xsd.PTZVector // Connect to Onvif device cameraConfiguration := configuration.Config.Capture.IPCamera - device, _, err := ConnectToOnvifDevice(&cameraConfiguration) + device, err := ConnectToOnvifDevice(&cameraConfiguration) if err == nil { // Get token from the first profile @@ -320,57 +252,45 @@ func GetPositionFromDevice(configuration models.Configuration) (xsdonvif.PTZVect // Get the PTZ configurations from the device position, err := GetPosition(device, token) if err == nil { - if position.PanTilt != nil && position.Zoom != nil { - // float to string - x := strconv.FormatFloat(position.PanTilt.X, 'f', 6, 64) - y := strconv.FormatFloat(position.PanTilt.Y, 'f', 6, 64) - z := strconv.FormatFloat(position.Zoom.X, 'f', 6, 64) - log.Log.Info("onvif.GetPositionFromDevice(): successfully got position (" + x + ", " + y + ", " + z + ")") - return position, err - } else { - log.Log.Debug("onvif.GetPositionFromDevice(): position is nil") - return position, errors.New("position is nil") - } + return position, err } else { - log.Log.Debug("onvif.GetPositionFromDevice(): " + err.Error()) + log.Log.Error("GetPositionFromDevice: " + err.Error()) return position, err } } else { - log.Log.Debug("onvif.GetPositionFromDevice(): " + err.Error()) + log.Log.Error("GetPositionFromDevice: " + err.Error()) return position, err } } else { - log.Log.Debug("onvif.GetPositionFromDevice(): " + err.Error()) + log.Log.Error("GetPositionFromDevice: " + err.Error()) return position, err } } -func GetPosition(device *onvif.Device, token xsdonvif.ReferenceToken) (xsdonvif.PTZVector, error) { +func GetPosition(device *onvif.Device, token xsd.ReferenceToken) (xsd.PTZVector, error) { // We'll try to receive the PTZ configurations from the server var status ptz.GetStatusResponse - var position xsdonvif.PTZVector + var position xsd.PTZVector // Get the PTZ configurations from the device resp, err := device.CallMethod(ptz.GetStatus{ ProfileToken: token, }) - var b []byte - if resp != nil { - b, err = io.ReadAll(resp.Body) - resp.Body.Close() // Ensure the response body is closed - } - if err == nil { - stringBody := string(b) - decodedXML, et, err := getXMLNode(stringBody, "GetStatusResponse") - if err != nil { - log.Log.Error("GetPositionFromDevice: " + err.Error()) - return position, err - } else { - if err := decodedXML.DecodeElement(&status, et); err != nil { + defer resp.Body.Close() + b, err := io.ReadAll(resp.Body) + if err == nil { + stringBody := string(b) + decodedXML, et, err := getXMLNode(stringBody, "GetStatusResponse") + if err != nil { log.Log.Error("GetPositionFromDevice: " + err.Error()) return position, err + } else { + if err := decodedXML.DecodeElement(&status, et); err != nil { + log.Log.Error("GetPositionFromDevice: " + err.Error()) + return position, err + } } } } @@ -378,36 +298,33 @@ func GetPosition(device *onvif.Device, token xsdonvif.ReferenceToken) (xsdonvif. return position, err } -func AbsolutePanTiltMove(device *onvif.Device, configuration ptz.GetConfigurationsResponse, token xsdonvif.ReferenceToken, pan float64, tilt float64, zoom float64) error { +func AbsolutePanTiltMove(device *onvif.Device, configuration ptz.GetConfigurationsResponse, token xsd.ReferenceToken, pan float64, tilt float64, zoom float64) error { - absolutePantiltVector := xsdonvif.Vector2D{ + absolutePantiltVector := xsd.Vector2D{ X: pan, Y: tilt, - Space: configuration.PTZConfiguration[0].DefaultAbsolutePantTiltPositionSpace, + Space: configuration.PTZConfiguration.DefaultAbsolutePantTiltPositionSpace, } - absoluteZoomVector := xsdonvif.Vector1D{ + absoluteZoomVector := xsd.Vector1D{ X: zoom, - Space: configuration.PTZConfiguration[0].DefaultAbsoluteZoomPositionSpace, + Space: configuration.PTZConfiguration.DefaultAbsoluteZoomPositionSpace, } - resp, err := device.CallMethod(ptz.AbsoluteMove{ + res, err := device.CallMethod(ptz.AbsoluteMove{ ProfileToken: token, - Position: xsdonvif.PTZVector{ - PanTilt: &absolutePantiltVector, - Zoom: &absoluteZoomVector, + Position: xsd.PTZVector{ + PanTilt: absolutePantiltVector, + Zoom: absoluteZoomVector, }, }) - var b []byte - if resp != nil { - b, err = io.ReadAll(resp.Body) - resp.Body.Close() - } if err != nil { log.Log.Error("AbsoluteMove: " + err.Error()) } - log.Log.Info("AbsoluteMove: " + string(b)) + + bs, _ := ioutil.ReadAll(res.Body) + log.Log.Info("AbsoluteMove: " + string(bs)) return err } @@ -415,7 +332,7 @@ func AbsolutePanTiltMove(device *onvif.Device, configuration ptz.GetConfiguratio // This function will simulate the AbsolutePanTiltMove function. // However the AboslutePanTiltMove function is not working on all cameras. // So we'll use the ContinuousMove function to simulate the AbsolutePanTiltMove function using the position polling. -func AbsolutePanTiltMoveFake(device *onvif.Device, configuration ptz.GetConfigurationsResponse, token xsdonvif.ReferenceToken, pan float64, tilt float64, zoom float64) error { +func AbsolutePanTiltMoveFake(device *onvif.Device, configuration ptz.GetConfigurationsResponse, token xsd.ReferenceToken, pan float64, tilt float64, zoom float64) error { position, err := GetPosition(device, token) if position.PanTilt.X >= pan-0.01 && position.PanTilt.X <= pan+0.01 && position.PanTilt.Y >= tilt-0.01 && position.PanTilt.Y <= tilt+0.01 && position.Zoom.X >= zoom-0.01 && position.Zoom.X <= zoom+0.01 { log.Log.Debug("AbsolutePanTiltMoveFake: already at position") @@ -444,22 +361,18 @@ func AbsolutePanTiltMoveFake(device *onvif.Device, configuration ptz.GetConfigur return err } -func ZoomOutCompletely(device *onvif.Device, configuration ptz.GetConfigurationsResponse, token xsdonvif.ReferenceToken) error { +func ZoomOutCompletely(device *onvif.Device, configuration ptz.GetConfigurationsResponse, token xsd.ReferenceToken) error { // Zoom out completely!!! - zoomOut := xsdonvif.Vector1D{ + zoomOut := xsd.Vector1D{ X: -1, - Space: configuration.PTZConfiguration[0].DefaultContinuousZoomVelocitySpace, + Space: configuration.PTZConfiguration.DefaultContinuousZoomVelocitySpace, } _, err := device.CallMethod(ptz.ContinuousMove{ - ProfileToken: &token, - Velocity: xsdonvif.PTZSpeedZoom{ + ProfileToken: token, + Velocity: xsd.PTZSpeedZoom{ Zoom: zoomOut, }, }) - if err != nil { - log.Log.Error("ZoomOutCompletely: " + err.Error()) - } - for { position, _ := GetPosition(device, token) if position.Zoom.X == 0 { @@ -468,17 +381,14 @@ func ZoomOutCompletely(device *onvif.Device, configuration ptz.GetConfigurations time.Sleep(250 * time.Millisecond) } - _, err = device.CallMethod(ptz.Stop{ + device.CallMethod(ptz.Stop{ ProfileToken: token, Zoom: true, }) - if err != nil { - log.Log.Error("ZoomOutCompletely: " + err.Error()) - } return err } -func PanUntilPosition(device *onvif.Device, configuration ptz.GetConfigurationsResponse, token xsdonvif.ReferenceToken, pan float64, zoom 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 { @@ -492,27 +402,24 @@ func PanUntilPosition(device *onvif.Device, configuration ptz.GetConfigurationsR directionX = speed * -1 } - panTiltVector := xsdonvif.Vector2D{ + panTiltVector := xsd.Vector2D{ X: directionX, Y: 0, - Space: configuration.PTZConfiguration[0].DefaultContinuousPanTiltVelocitySpace, + Space: configuration.PTZConfiguration.DefaultContinuousPanTiltVelocitySpace, } - resp, err := device.CallMethod(ptz.ContinuousMove{ - ProfileToken: &token, - Velocity: xsdonvif.PTZSpeedPanTilt{ + res, err := device.CallMethod(ptz.ContinuousMove{ + ProfileToken: token, + Velocity: xsd.PTZSpeedPanTilt{ PanTilt: panTiltVector, }, }) - var b []byte - if resp != nil { - b, err = io.ReadAll(resp.Body) - resp.Body.Close() - } if err != nil { log.Log.Error("ContinuousPanTiltMove (Pan): " + err.Error()) } - log.Log.Debug("ContinuousPanTiltMove (Pan): " + string(b)) + + bs, _ := ioutil.ReadAll(res.Body) + log.Log.Debug("ContinuousPanTiltMove (Pan): " + string(bs)) // While moving we'll check if we reached the desired position. // or if we overshot the desired position. @@ -530,20 +437,20 @@ func PanUntilPosition(device *onvif.Device, configuration ptz.GetConfigurationsR time.Sleep(wait) } - _, err = device.CallMethod(ptz.Stop{ + _, errStop := device.CallMethod(ptz.Stop{ ProfileToken: token, PanTilt: true, Zoom: true, }) - if err != nil { - log.Log.Error("ContinuousPanTiltMove (Pan): " + err.Error()) + if errStop != nil { + log.Log.Error("ContinuousPanTiltMove (Pan): " + errStop.Error()) } } return err } -func TiltUntilPosition(device *onvif.Device, configuration ptz.GetConfigurationsResponse, token xsdonvif.ReferenceToken, tilt float64, zoom 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.005 && position.PanTilt.Y <= tilt+0.005 { @@ -557,31 +464,24 @@ func TiltUntilPosition(device *onvif.Device, configuration ptz.GetConfigurations directionY = speed * -1 } - panTiltVector := xsdonvif.Vector2D{ + panTiltVector := xsd.Vector2D{ X: 0, Y: directionY, - Space: configuration.PTZConfiguration[0].DefaultContinuousPanTiltVelocitySpace, - } - - velocity := xsdonvif.PTZSpeedPanTilt{ - PanTilt: panTiltVector, + Space: configuration.PTZConfiguration.DefaultContinuousPanTiltVelocitySpace, } - - resp, err := device.CallMethod(ptz.ContinuousMove{ - ProfileToken: &token, - Velocity: velocity, + res, err := device.CallMethod(ptz.ContinuousMove{ + ProfileToken: token, + Velocity: xsd.PTZSpeedPanTilt{ + PanTilt: panTiltVector, + }, }) - var b []byte - if resp != nil { - b, err = io.ReadAll(resp.Body) - resp.Body.Close() - } - if err != nil { log.Log.Error("ContinuousPanTiltMove (Tilt): " + err.Error()) } - log.Log.Debug("ContinuousPanTiltMove (Tilt) " + string(b)) + + bs, _ := ioutil.ReadAll(res.Body) + log.Log.Debug("ContinuousPanTiltMove (Tilt) " + string(bs)) // While moving we'll check if we reached the desired position. // or if we overshot the desired position. @@ -599,20 +499,20 @@ func TiltUntilPosition(device *onvif.Device, configuration ptz.GetConfigurations time.Sleep(wait) } - _, err = device.CallMethod(ptz.Stop{ + _, errStop := device.CallMethod(ptz.Stop{ ProfileToken: token, PanTilt: true, Zoom: true, }) - if err != nil { - log.Log.Error("ContinuousPanTiltMove (Tilt): " + err.Error()) + if errStop != nil { + log.Log.Error("ContinuousPanTiltMove (Tilt): " + errStop.Error()) } } return err } -func ZoomUntilPosition(device *onvif.Device, configuration ptz.GetConfigurationsResponse, token xsdonvif.ReferenceToken, zoom float64, speed float64, wait time.Duration) error { +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.005 && position.Zoom.X <= zoom+0.005 { @@ -626,27 +526,23 @@ func ZoomUntilPosition(device *onvif.Device, configuration ptz.GetConfigurations directionZ = speed * -1 } - zoomVector := xsdonvif.Vector1D{ + zoomVector := xsd.Vector1D{ X: directionZ, - Space: configuration.PTZConfiguration[0].DefaultContinuousZoomVelocitySpace, + Space: configuration.PTZConfiguration.DefaultContinuousZoomVelocitySpace, } - resp, err := device.CallMethod(ptz.ContinuousMove{ - ProfileToken: &token, - Velocity: xsdonvif.PTZSpeedZoom{ + res, err := device.CallMethod(ptz.ContinuousMove{ + ProfileToken: token, + Velocity: xsd.PTZSpeedZoom{ Zoom: zoomVector, }, }) - var b []byte - if resp != nil { - b, err = io.ReadAll(resp.Body) - resp.Body.Close() - } if err != nil { log.Log.Error("ContinuousPanTiltMove (Zoom): " + err.Error()) } - log.Log.Debug("ContinuousPanTiltMove (Zoom) " + string(b)) + bs, _ := ioutil.ReadAll(res.Body) + log.Log.Debug("ContinuousPanTiltMove (Zoom) " + string(bs)) // While moving we'll check if we reached the desired position. // or if we overshot the desired position. @@ -664,110 +560,103 @@ func ZoomUntilPosition(device *onvif.Device, configuration ptz.GetConfigurations time.Sleep(wait) } - _, err = device.CallMethod(ptz.Stop{ + _, errStop := device.CallMethod(ptz.Stop{ ProfileToken: token, PanTilt: true, Zoom: true, }) - if err != nil { - log.Log.Error("ContinuousPanTiltMove (Zoom): " + err.Error()) + if errStop != nil { + log.Log.Error("ContinuousPanTiltMove (Zoom): " + errStop.Error()) } } return err } -func ContinuousPanTilt(device *onvif.Device, configuration ptz.GetConfigurationsResponse, token xsdonvif.ReferenceToken, pan float64, tilt float64) error { +func ContinuousPanTilt(device *onvif.Device, configuration ptz.GetConfigurationsResponse, token xsd.ReferenceToken, pan float64, tilt float64) error { - panTiltVector := xsdonvif.Vector2D{ + panTiltVector := xsd.Vector2D{ X: pan, Y: tilt, - Space: configuration.PTZConfiguration[0].DefaultContinuousPanTiltVelocitySpace, + Space: configuration.PTZConfiguration.DefaultContinuousPanTiltVelocitySpace, } - resp, err := device.CallMethod(ptz.ContinuousMove{ - ProfileToken: &token, - Velocity: xsdonvif.PTZSpeedPanTilt{ + res, err := device.CallMethod(ptz.ContinuousMove{ + ProfileToken: token, + Velocity: xsd.PTZSpeedPanTilt{ PanTilt: panTiltVector, }, }) - var b []byte - if resp != nil { - b, err = io.ReadAll(resp.Body) - resp.Body.Close() - } if err != nil { log.Log.Error("ContinuousPanTiltMove: " + err.Error()) } - log.Log.Debug("ContinuousPanTiltMove: " + string(b)) + bs, _ := ioutil.ReadAll(res.Body) + log.Log.Debug("ContinuousPanTiltMove: " + string(bs)) time.Sleep(200 * time.Millisecond) - resp, err = device.CallMethod(ptz.Stop{ + res, errStop := device.CallMethod(ptz.Stop{ ProfileToken: token, PanTilt: true, }) - b = []byte{} - if resp != nil { - b, err = io.ReadAll(resp.Body) - resp.Body.Close() + if errStop != nil { + log.Log.Error("ContinuousPanTiltMove: " + errStop.Error()) } - if err != nil { - log.Log.Error("ContinuousPanTiltMove: " + err.Error()) + if errStop == nil { + return err + } else { + return errStop } - - return err } -func ContinuousZoom(device *onvif.Device, configuration ptz.GetConfigurationsResponse, token xsdonvif.ReferenceToken, zoom float64) error { +func ContinuousZoom(device *onvif.Device, configuration ptz.GetConfigurationsResponse, token xsd.ReferenceToken, zoom float64) error { - zoomVector := xsdonvif.Vector1D{ + zoomVector := xsd.Vector1D{ X: zoom, - Space: configuration.PTZConfiguration[0].DefaultContinuousZoomVelocitySpace, - } - - velocity := xsdonvif.PTZSpeedZoom{ - Zoom: zoomVector, + Space: configuration.PTZConfiguration.DefaultContinuousZoomVelocitySpace, } - resp, err := device.CallMethod(ptz.ContinuousMove{ - ProfileToken: &token, - Velocity: &velocity, + res, err := device.CallMethod(ptz.ContinuousMove{ + ProfileToken: token, + Velocity: xsd.PTZSpeedZoom{ + Zoom: zoomVector, + }, }) - var b []byte - if resp != nil { - b, err = io.ReadAll(resp.Body) - resp.Body.Close() - } if err != nil { - log.Log.Error("onvif.main.ContinuousZoom(): " + err.Error()) + log.Log.Error("ContinuousPanTiltZoom: " + err.Error()) } - log.Log.Debug("onvif.main.ContinuousZoom(): " + string(b)) + bs, _ := ioutil.ReadAll(res.Body) + log.Log.Debug("ContinuousPanTiltZoom: " + string(bs)) + time.Sleep(500 * time.Millisecond) - _, err = device.CallMethod(ptz.Stop{ + res, errStop := device.CallMethod(ptz.Stop{ ProfileToken: token, Zoom: true, }) - if err != nil { - log.Log.Error("onvif.main.ContinuousZoom(): " + err.Error()) + if errStop != nil { + log.Log.Error("ContinuousPanTiltZoom: " + errStop.Error()) } - return err + if errStop == nil { + return err + } else { + return errStop + } } -func GetCapabilitiesFromDevice(dev *onvif.Device) []string { +func GetCapabilitiesFromDevice(device *onvif.Device) []string { var capabilities []string - services := dev.GetServices() + services := device.GetServices() for key, _ := range services { - log.Log.Debug("onvif.main.GetCapabilitiesFromDevice(): has key: " + key) + log.Log.Debug("GetCapabilitiesFromDevice: has key: " + key) if key != "" { keyParts := strings.Split(key, "/") if len(keyParts) > 0 { @@ -789,41 +678,37 @@ func GetPresetsFromDevice(device *onvif.Device) ([]models.OnvifActionPreset, err resp, err := device.CallMethod(ptz.GetPresets{ ProfileToken: token, }) - var b []byte - if resp != nil { - b, err = io.ReadAll(resp.Body) - resp.Body.Close() // Ensure the response body is closed - } + + 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("onvif.main.GetPresetsFromDevice(): " + err.Error()) + log.Log.Error("GetPresetsFromDevice: " + err.Error()) return presets, err } else { if err := decodedXML.DecodeElement(&presetsResponse, et); err != nil { - log.Log.Error("onvif.main.GetPresetsFromDevice(): " + err.Error()) + log.Log.Error("GetPresetsFromDevice: " + err.Error()) return presets, err } - presetsList := "" for _, preset := range presetsResponse.Preset { p := models.OnvifActionPreset{ Name: string(preset.Name), Token: string(preset.Token), } - presetsList += string(preset.Name) + " (" + string(preset.Token) + "), " + presets = append(presets, p) } - log.Log.Debug("onvif.main.GetPresetsFromDevice(): " + presetsList) return presets, err } } else { - log.Log.Error("onvif.main.GetPresetsFromDevice(): " + err.Error()) + log.Log.Error("GetPresetsFromDevice: " + err.Error()) } } else { - log.Log.Error("onvif.main.GetPresetsFromDevice(): " + err.Error()) + log.Log.Error("GetPresetsFromDevice: " + err.Error()) } return presets, err @@ -835,34 +720,32 @@ func GoToPresetFromDevice(device *onvif.Device, presetName string) error { // Get token from the first profile token, err := GetTokenFromProfile(device, 0) if err == nil { - preset := xsdonvif.ReferenceToken(presetName) + resp, err := device.CallMethod(ptz.GotoPreset{ - ProfileToken: &token, - PresetToken: &preset, + ProfileToken: token, + PresetToken: xsd.ReferenceToken(presetName), }) - var b []byte - if resp != nil { - b, err = io.ReadAll(resp.Body) - resp.Body.Close() // Ensure the response body is closed - } + + 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("onvif.main.GoToPresetFromDevice(): " + err.Error()) + log.Log.Error("GoToPresetFromDevice: " + err.Error()) return err } else { if err := decodedXML.DecodeElement(&goToPresetResponse, et); err != nil { - log.Log.Error("onvif.main.GoToPresetFromDevice(): " + err.Error()) + log.Log.Error("GoToPresetFromDevice: " + err.Error()) return err } return err } } else { - log.Log.Error("onvif.main.GoToPresetFromDevice(): " + err.Error()) + log.Log.Error("GoToPresetFromDevice: " + err.Error()) } } else { - log.Log.Error("onvif.main.GoToPresetFromDevice(): " + err.Error()) + log.Log.Error("GoToPresetFromDevice: " + err.Error()) } return err @@ -873,34 +756,34 @@ func GetPTZFunctionsFromDevice(configurations ptz.GetConfigurationsResponse) ([] canZoom := false canPanTilt := false - if configurations.PTZConfiguration[0].DefaultAbsolutePantTiltPositionSpace != nil { + if configurations.PTZConfiguration.DefaultAbsolutePantTiltPositionSpace != "" { functions = append(functions, "AbsolutePanTiltMove") canPanTilt = true } - if configurations.PTZConfiguration[0].DefaultAbsoluteZoomPositionSpace != nil { + if configurations.PTZConfiguration.DefaultAbsoluteZoomPositionSpace != "" { functions = append(functions, "AbsoluteZoomMove") canZoom = true } - if configurations.PTZConfiguration[0].DefaultRelativePanTiltTranslationSpace != nil { + if configurations.PTZConfiguration.DefaultRelativePanTiltTranslationSpace != "" { functions = append(functions, "RelativePanTiltMove") canPanTilt = true } - if configurations.PTZConfiguration[0].DefaultRelativeZoomTranslationSpace != nil { + if configurations.PTZConfiguration.DefaultRelativeZoomTranslationSpace != "" { functions = append(functions, "RelativeZoomMove") canZoom = true } - if configurations.PTZConfiguration[0].DefaultContinuousPanTiltVelocitySpace != nil { + if configurations.PTZConfiguration.DefaultContinuousPanTiltVelocitySpace != "" { functions = append(functions, "ContinuousPanTiltMove") canPanTilt = true } - if configurations.PTZConfiguration[0].DefaultContinuousZoomVelocitySpace != nil { + if configurations.PTZConfiguration.DefaultContinuousZoomVelocitySpace != "" { functions = append(functions, "ContinuousZoomMove") canZoom = true } - if configurations.PTZConfiguration[0].DefaultPTZSpeed != nil { + if configurations.PTZConfiguration.DefaultPTZSpeed != nil { functions = append(functions, "PTZSpeed") } - if configurations.PTZConfiguration[0].DefaultPTZTimeout != nil { + if configurations.PTZConfiguration.DefaultPTZTimeout != "" { functions = append(functions, "PTZTimeout") } @@ -908,407 +791,57 @@ func GetPTZFunctionsFromDevice(configurations ptz.GetConfigurationsResponse) ([] } // VerifyOnvifConnection godoc -// @Router /api/camera/onvif/verify [post] +// @Router /api/onvif/verify [post] // @ID verify-onvif // @Security Bearer // @securityDefinitions.apikey Bearer // @in header // @name Authorization -// @Tags onvif -// @Param config body models.OnvifCredentials true "OnvifCredentials" +// @Tags config +// @Param cameraConfig body models.IPCamera true "Camera Config" // @Summary Will verify the ONVIF connectivity. // @Description Will verify the ONVIF connectivity. // @Success 200 {object} models.APIResponse func VerifyOnvifConnection(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, capabilities, err := ConnectToOnvifDevice(&cameraConfiguration) + var cameraConfig models.IPCamera + err := c.BindJSON(&cameraConfig) + if err == nil { + device, err := ConnectToOnvifDevice(&cameraConfig) if err == nil { - // Get token from the first profile - token, err := GetTokenFromProfile(device, 0) + // Get the list of configurations + configurations, err := GetPTZConfigurationsFromDevice(device) if err == nil { - c.JSON(200, gin.H{ - "device": device, - "capabilities": capabilities, - "token": token, + + // Check if can zoom and/or pan/tilt is supported + ptzFunctions, canZoom, canPanTilt := GetPTZFunctionsFromDevice(configurations) + c.JSON(200, models.APIResponse{ + Data: device, + PTZFunctions: ptzFunctions, + CanZoom: canZoom, + CanPanTilt: canPanTilt, }) } else { - c.JSON(400, gin.H{ - "data": "Something went wrong: " + err.Error(), + c.JSON(400, models.APIResponse{ + Message: "Something went wrong while getting the configurations " + err.Error(), }) } } else { - c.JSON(400, gin.H{ - "data": "Something went wrong: " + err.Error(), + c.JSON(400, models.APIResponse{ + Message: "Something went wrong while verifying the ONVIF connection " + err.Error(), }) } } else { - c.JSON(400, gin.H{ - "data": "Something went wrong: " + err.Error(), + c.JSON(400, models.APIResponse{ + Message: "Something went wrong while receiving the config " + err.Error(), }) } } -type ONVIFEvents struct { - Key string - Type string - Value string - Timestamp int64 -} - -// Create PullPointSubscription -func CreatePullPointSubscription(dev *onvif.Device) (string, error) { - - // We'll create a subscription to the device - // This will allow us to receive events from the device - var createPullPointSubscriptionResponse event.CreatePullPointSubscriptionResponse - var pullPointAdress string - var err error - - // For the time being we are just interested in the digital inputs and outputs, therefore - // we have set the topic to the followin filter. - terminate := xsd.String("PT60S") - if dev == nil { - return pullPointAdress, errors.New("dev is nil, ONVIF was not able to connect to the device") - } - - resp, err := dev.CallMethod(event.CreatePullPointSubscription{ - InitialTerminationTime: &terminate, - - Filter: &event.FilterType{ - TopicExpression: &event.TopicExpressionType{ - Dialect: xsd.String("http://www.onvif.org/ver10/tev/topicExpression/ConcreteSet"), - TopicKinds: "tns1:Device/Trigger//.", // -> This works for Avigilon, Hanwa, Hikvision - // TopicKinds: "//.", -> This works for Axis, but throws other errors. - }, - }, - }) - var b2 []byte - if resp != nil { - b2, err = io.ReadAll(resp.Body) - resp.Body.Close() // Ensure the response body is closed - if err == nil { - stringBody := string(b2) - decodedXML, et, err := getXMLNode(stringBody, "CreatePullPointSubscriptionResponse") - if err != nil { - log.Log.Debug("onvif.main.CreatePullPointSubscription(): " + err.Error()) - } else { - if err := decodedXML.DecodeElement(&createPullPointSubscriptionResponse, et); err != nil { - log.Log.Error("onvif.main.CreatePullPointSubscription(): " + err.Error()) - } else { - pullPointAdress = string(createPullPointSubscriptionResponse.SubscriptionReference.Address) - } - } - } - } - return pullPointAdress, err -} - -func UnsubscribePullPoint(dev *onvif.Device, pullPointAddress string) error { - - // Unsubscribe from the device - unsubscribe := event.Unsubscribe{} - requestBody, err := xml.Marshal(unsubscribe) - if err != nil { - log.Log.Error("onvif.main.UnsubscribePullPoint(): " + err.Error()) - } - - res, err := dev.SendSoap(pullPointAddress, string(requestBody)) - if err != nil { - log.Log.Error("onvif.main.UnsubscribePullPoint(): " + err.Error()) - } - if res != nil { - b, err := io.ReadAll(res.Body) - res.Body.Close() // Ensure the response body is closed - if err == nil { - stringBody := string(b) - log.Log.Debug("onvif.main.UnsubscribePullPoint(): " + stringBody) - } - if err != nil { - log.Log.Error("onvif.main.UnsubscribePullPoint(): " + err.Error()) - } - } - return err -} - -// Look for Source of input and output -// Creat a map of the source and the value -// We'll use this map to determine if the value has changed. -// If the value has changed we'll send an event to the frontend. -var inputOutputDeviceMap = make(map[string]*ONVIFEvents) - -func GetInputOutputs() ([]ONVIFEvents, error) { - var eventsArray []ONVIFEvents - // We have some odd behaviour for inputs: the logical state is set to false even if circuit is closed. However we do see repeated events (looks like heartbeats). - // We are assuming that if we do not receive an event for 15 seconds the input is inactive, otherwise we set to active. - for key, value := range inputOutputDeviceMap { - if time.Now().Unix()-value.Timestamp < 15 && value.Value == "false" { - value.Value = "true" - } - inputOutputDeviceMap[key] = value - eventsArray = append(eventsArray, *value) - } - for _, value := range eventsArray { - log.Log.Debug("onvif.main.GetInputOutputs(): " + value.Key + " - " + value.Value + " (" + strconv.FormatInt(value.Timestamp, 10) + ")") - } - return eventsArray, nil -} - -// ONVIF has a specific profile that requires a subscription to receive events. -// These events can show if an input or output is active or inactive, and also other events. -// For the time being we are only interested in the input and output events, but this can be extended in the future. -func GetEventMessages(dev *onvif.Device, pullPointAddress string) ([]ONVIFEvents, error) { - - var eventsArray []ONVIFEvents - var err error - - if pullPointAddress != "" { - // We were able to create a subscription to the device. Now pull some messages from the subscription. - subscriptionURI := pullPointAddress - if subscriptionURI == "" { - log.Log.Error("onvif.main.GetEventMessages(): subscriptionURI is empty") - } else { - // Pull message - pullMessage := event.PullMessages{ - Timeout: xsd.Duration("PT5S"), - MessageLimit: 10, - } - requestBody, err := xml.Marshal(pullMessage) - if err != nil { - log.Log.Error("onvif.main.GetEventMessages(pullMessages): " + err.Error()) - return eventsArray, err - } - res, err := dev.SendSoap(string(subscriptionURI), string(requestBody)) - if err != nil { - log.Log.Error("onvif.main.GetEventMessages(pullMessages): " + err.Error()) - return eventsArray, err - } - - var pullMessagesResponse event.PullMessagesResponse - if res != nil { - bs, err := io.ReadAll(res.Body) - res.Body.Close() // Ensure the response body is closed - if err == nil { - stringBody := string(bs) - decodedXML, et, err := getXMLNode(stringBody, "PullMessagesResponse") - if err != nil { - log.Log.Error("onvif.main.GetEventMessages(pullMessages): " + err.Error()) - return eventsArray, err - } else { - if err := decodedXML.DecodeElement(&pullMessagesResponse, et); err != nil { - log.Log.Error("onvif.main.GetEventMessages(pullMessages): " + err.Error()) - return eventsArray, err - } - } - } - } - - for _, message := range pullMessagesResponse.NotificationMessage { - log.Log.Debug("onvif.main.GetEventMessages(pullMessages): " + string(message.Topic.TopicKinds)) - //if len(message.Message.Message.Data.SimpleItem) > 0 { - // log.Log.Debug("onvif.main.GetEventMessages(pullMessages): " + string(message.Message.Message.Data.SimpleItem[0].Name) + " " + string(message.Message.Message.Data.SimpleItem[0].Value)) - //} - if message.Topic.TopicKinds == "tns1:Device/Trigger/Relay" || - message.Topic.TopicKinds == "tns1:Device/tns1:Trigger/tns1:Relay" { // This is for avigilon cameras - if len(message.Message.Message.Data.SimpleItem) > 0 { - if message.Message.Message.Data.SimpleItem[0].Name == "LogicalState" || - message.Message.Message.Data.SimpleItem[0].Name == "RelayLogicalState" { // On avigilon it's called RelayLogicalState - key := string(message.Message.Message.Source.SimpleItem[0].Value) - value := string(message.Message.Message.Data.SimpleItem[0].Value) - propertyOperation := string(message.Message.Message.PropertyOperation) - log.Log.Debug("onvif.main.GetEventMessages(pullMessages) output: " + key + " " + value + " (" + propertyOperation + ")") - - // Depending on the onvif library they might use different values for active and inactive. - if value == "active" || value == "1" { - value = "true" - } else if value == "inactive" || value == "0" { - value = "false" - } - - // Check if key exists in map - // If it does not exist we'll add it to the map otherwise we'll update the value. - if _, ok := inputOutputDeviceMap[key+"-output"]; !ok { - inputOutputDeviceMap[key+"-output"] = &ONVIFEvents{ - Key: key + "-output", - Type: "output", - Value: value, - Timestamp: 0, - } - } else if propertyOperation == "Changed" { - inputOutputDeviceMap[key+"-output"].Value = value - inputOutputDeviceMap[key+"-output"].Timestamp = time.Now().Unix() - } else if propertyOperation == "Initialized" { - inputOutputDeviceMap[key+"-output"].Value = value - } - } - } - } else if message.Topic.TopicKinds == "tns1:Device/Trigger/DigitalInput" || - message.Topic.TopicKinds == "tns1:Device/tns1:Trigger/tnssamsung:DigitalInput" { // This is for avigilon's camera - if len(message.Message.Message.Data.SimpleItem) > 0 { - if message.Message.Message.Data.SimpleItem[0].Name == "LogicalState" || - message.Message.Message.Data.SimpleItem[0].Name == "Level" { // On avigilon it's called level - key := string(message.Message.Message.Source.SimpleItem[0].Value) - value := string(message.Message.Message.Data.SimpleItem[0].Value) - propertyOperation := string(message.Message.Message.PropertyOperation) - log.Log.Debug("onvif.main.GetEventMessages(pullMessages) input: " + key + " " + value + " (" + propertyOperation + ")") - - // Depending on the onvif library they might use different values for active and inactive. - if value == "active" || value == "1" { - value = "true" - } else if value == "inactive" || value == "0" { - value = "false" - } - - // Check if key exists in map - // If it does not exist we'll add it to the map otherwise we'll update the value. - if _, ok := inputOutputDeviceMap[key+"-input"]; !ok { - inputOutputDeviceMap[key+"-input"] = &ONVIFEvents{ - Key: key + "-input", - Type: "input", - Value: value, - Timestamp: 0, - } - } else if propertyOperation == "Changed" { - inputOutputDeviceMap[key+"-input"].Value = value - inputOutputDeviceMap[key+"-input"].Timestamp = time.Now().Unix() - } else if propertyOperation == "Initialized" { - inputOutputDeviceMap[key+"-input"].Value = value - } - } - } - } - } - } - } - - eventsArray, _ = GetInputOutputs() - return eventsArray, err -} - -// This method will get the digital inputs from the device. -// But will not give any status information. -func GetDigitalInputs(dev *onvif.Device) (device.GetDigitalInputsResponse, error) { - - // We'll try to receive the relay outputs from the server - var digitalinputs device.GetDigitalInputsResponse - - var b []byte - resp, err := dev.CallMethod(deviceio.GetDigitalInputs{}) - if resp != nil { - b, err = io.ReadAll(resp.Body) - resp.Body.Close() // Ensure the response body is closed - } - - if err == nil { - if err == nil { - stringBody := string(b) - decodedXML, et, err := getXMLNode(stringBody, "GetDigitalInputsResponse") - if err != nil { - log.Log.Error("onvif.main.GetDigitalInputs(): " + err.Error()) - return digitalinputs, err - } else { - if err := decodedXML.DecodeElement(&digitalinputs, et); err != nil { - log.Log.Debug("onvif.main.GetDigitalInputs(): " + err.Error()) - return digitalinputs, err - } - } - } - } - return digitalinputs, err -} - -// This method will get the relay outputs from the device. -// But will not give any status information. -func GetRelayOutputs(dev *onvif.Device) (device.GetRelayOutputsResponse, error) { - // We'll try to receive the relay outputs from the server - var relayoutputs device.GetRelayOutputsResponse - - // Get the PTZ configurations from the device - resp, err := dev.CallMethod(device.GetRelayOutputs{}) - var b []byte - if resp != nil { - b, err = io.ReadAll(resp.Body) - resp.Body.Close() // Ensure the response body is closed - } - - if err == nil { - stringBody := string(b) - decodedXML, et, err := getXMLNode(stringBody, "GetRelayOutputsResponse") - if err != nil { - log.Log.Error("onvif.main.GetRelayOutputs(): " + err.Error()) - return relayoutputs, err - } else { - if err := decodedXML.DecodeElement(&relayoutputs, et); err != nil { - log.Log.Debug("onvif.main.GetRelayOutputs(): " + err.Error()) - return relayoutputs, err - } - } - } - - return relayoutputs, err -} - -func TriggerRelayOutput(dev *onvif.Device, output string) (err error) { - err = nil - - // Get all outputs - relayoutputs, err := GetRelayOutputs(dev) - - // For the moment we expect a single output - // However in theory there might be multiple outputs. We might need to change - // this in the future "kerberos-io/onvif" library. - if err == nil { - token := relayoutputs.RelayOutputs[0].Token - if output == string(token+"-output") { - outputState := device.SetRelayOutputState{ - RelayOutputToken: token, - LogicalState: "active", - } - - resp, errResp := dev.CallMethod(outputState) - var b []byte - if errResp != nil { - b, err = io.ReadAll(resp.Body) - resp.Body.Close() // Ensure the response body is closed - } - stringBody := string(b) - if err == nil && resp.StatusCode == 200 { - log.Log.Info("onvif.main.TriggerRelayOutput(): triggered relay output (" + string(token) + ")") - } else { - log.Log.Error("onvif.main.TriggerRelayOutput(): " + stringBody) - } - } else { - log.Log.Error("onvif.main.TriggerRelayOutput(): could not find relay output (" + output + ")") - } - } else { - log.Log.Error("onvif.main.TriggerRelayOutput(): something went wrong while getting the relay outputs " + err.Error()) - } - return -} - func getXMLNode(xmlBody string, nodeName string) (*xml.Decoder, *xml.StartElement, error) { xmlBytes := bytes.NewBufferString(xmlBody) decodedXML := xml.NewDecoder(xmlBytes) - var token xml.Token - var err error for { - token, err = decodedXML.Token() + token, err := decodedXML.Token() if err != nil { break } @@ -1319,12 +852,5 @@ func getXMLNode(xmlBody string, nodeName string) (*xml.Decoder, *xml.StartElemen } } } - - // Check for authorisation error - // - The action requested requires authorization and the sender is not authorized - if strings.Contains(xmlBody, "not authorized") { - return nil, nil, errors.New("getXMLNode(): not authorized, make sure you have the correct credentials") - } else { - return nil, nil, errors.New("getXMLNode(): " + err.Error()) - } -} + return nil, nil, errors.New("error in NodeName - username and password might be wrong") +} \ No newline at end of file diff --git a/machinery/src/routers/http/methods.go b/machinery/src/routers/http/methods.go index b8d0aa1b..7c0e572c 100644 --- a/machinery/src/routers/http/methods.go +++ b/machinery/src/routers/http/methods.go @@ -2,7 +2,6 @@ package http import ( "github.com/gin-gonic/gin" - "github.com/kerberos-io/agent/machinery/src/log" "github.com/kerberos-io/agent/machinery/src/models" "github.com/kerberos-io/agent/machinery/src/onvif" ) @@ -44,15 +43,14 @@ func LoginToOnvif(c *gin.Context) { } cameraConfiguration := configuration.Config.Capture.IPCamera - device, capabilities, err := onvif.ConnectToOnvifDevice(&cameraConfiguration) + device, err := onvif.ConnectToOnvifDevice(&cameraConfiguration) if err == nil { // Get token from the first profile token, err := onvif.GetTokenFromProfile(device, 0) if err == nil { c.JSON(200, gin.H{ - "device": device, - "capabilities": capabilities, - "token": token, + "device": device, + "token": token, }) } else { c.JSON(400, gin.H{ @@ -98,11 +96,9 @@ func GetOnvifCapabilities(c *gin.Context) { } cameraConfiguration := configuration.Config.Capture.IPCamera - _, capabilities, err := onvif.ConnectToOnvifDevice(&cameraConfiguration) + _, err := onvif.ConnectToOnvifDevice(&cameraConfiguration) if err == nil { - c.JSON(200, gin.H{ - "capabilities": capabilities, - }) + c.JSON(200, gin.H{}) } else { c.JSON(400, gin.H{ "data": "Something went wrong: " + err.Error(), @@ -142,7 +138,7 @@ func DoOnvifPanTilt(c *gin.Context) { } cameraConfiguration := configuration.Config.Capture.IPCamera - device, _, err := onvif.ConnectToOnvifDevice(&cameraConfiguration) + device, err := onvif.ConnectToOnvifDevice(&cameraConfiguration) if err == nil { // Get token from the first profile @@ -216,7 +212,7 @@ func DoOnvifZoom(c *gin.Context) { } cameraConfiguration := configuration.Config.Capture.IPCamera - device, _, err := onvif.ConnectToOnvifDevice(&cameraConfiguration) + device, err := onvif.ConnectToOnvifDevice(&cameraConfiguration) if err == nil { // Get token from the first profile @@ -289,7 +285,7 @@ func GetOnvifPresets(c *gin.Context) { } cameraConfiguration := configuration.Config.Capture.IPCamera - device, _, err := onvif.ConnectToOnvifDevice(&cameraConfiguration) + device, err := onvif.ConnectToOnvifDevice(&cameraConfiguration) if err == nil { presets, err := onvif.GetPresetsFromDevice(device) if err == nil { @@ -340,7 +336,7 @@ func GoToOnvifPreset(c *gin.Context) { } cameraConfiguration := configuration.Config.Capture.IPCamera - device, _, err := onvif.ConnectToOnvifDevice(&cameraConfiguration) + device, err := onvif.ConnectToOnvifDevice(&cameraConfiguration) if err == nil { err := onvif.GoToPresetFromDevice(device, onvifPreset.Preset) if err == nil { @@ -377,7 +373,7 @@ func GoToOnvifPreset(c *gin.Context) { // @Description Will get the digital inputs from the ONVIF device. // @Success 200 {object} models.APIResponse func DoGetDigitalInputs(c *gin.Context) { - var onvifCredentials models.OnvifCredentials + /*var onvifCredentials models.OnvifCredentials err := c.BindJSON(&onvifCredentials) if err == nil && onvifCredentials.ONVIFXAddr != "" { @@ -395,7 +391,7 @@ func DoGetDigitalInputs(c *gin.Context) { } cameraConfiguration := configuration.Config.Capture.IPCamera - device, _, err := onvif.ConnectToOnvifDevice(&cameraConfiguration) + device, err := onvif.ConnectToOnvifDevice(&cameraConfiguration) onvifInputs, _ := onvif.GetDigitalInputs(device) if err == nil { @@ -450,7 +446,7 @@ func DoGetDigitalInputs(c *gin.Context) { c.JSON(400, gin.H{ "data": "Something went wrong: " + err.Error(), }) - } + }*/ } // DoGetRelayOutputs godoc @@ -466,7 +462,7 @@ func DoGetDigitalInputs(c *gin.Context) { // @Description Will get the relay outputs from the ONVIF device. // @Success 200 {object} models.APIResponse func DoGetRelayOutputs(c *gin.Context) { - var onvifCredentials models.OnvifCredentials + /*var onvifCredentials models.OnvifCredentials err := c.BindJSON(&onvifCredentials) if err == nil && onvifCredentials.ONVIFXAddr != "" { @@ -484,7 +480,7 @@ func DoGetRelayOutputs(c *gin.Context) { } cameraConfiguration := configuration.Config.Capture.IPCamera - _, _, err := onvif.ConnectToOnvifDevice(&cameraConfiguration) + _, err := onvif.ConnectToOnvifDevice(&cameraConfiguration) if err == nil { // Get the digital inputs and outputs from the device inputOutputs, err := onvif.GetInputOutputs() @@ -519,7 +515,7 @@ func DoGetRelayOutputs(c *gin.Context) { c.JSON(400, gin.H{ "data": "Something went wrong: " + err.Error(), }) - } + }*/ } // DoTriggerRelayOutput godoc @@ -536,7 +532,7 @@ func DoGetRelayOutputs(c *gin.Context) { // @Description Will trigger the relay output from the ONVIF device. // @Success 200 {object} models.APIResponse func DoTriggerRelayOutput(c *gin.Context) { - var onvifCredentials models.OnvifCredentials + /*var onvifCredentials models.OnvifCredentials err := c.BindJSON(&onvifCredentials) // Get the output from the url @@ -586,5 +582,5 @@ func DoTriggerRelayOutput(c *gin.Context) { c.JSON(400, gin.H{ "data": msg, }) - } + }*/ } diff --git a/machinery/src/routers/mqtt/main.go b/machinery/src/routers/mqtt/main.go index 957fd3cf..1013b092 100644 --- a/machinery/src/routers/mqtt/main.go +++ b/machinery/src/routers/mqtt/main.go @@ -534,7 +534,7 @@ func HandleNavigatePTZ(mqttClient mqtt.Client, hubKey string, payload models.Pay } func HandleTriggerRelay(mqttClient mqtt.Client, hubKey string, payload models.Payload, configuration *models.Configuration, communication *models.Communication) { - value := payload.Value + /*value := payload.Value jsonData, _ := json.Marshal(value) var triggerRelayPayload models.TriggerRelay json.Unmarshal(jsonData, &triggerRelayPayload) @@ -561,7 +561,7 @@ func HandleTriggerRelay(mqttClient mqtt.Client, hubKey string, payload models.Pa } else { log.Log.Info("routers.mqtt.main.HandleTriggerRelay(): received trigger, but camera is not connected.") } - } + }*/ } func DisconnectMQTT(mqttClient mqtt.Client, config *models.Config) {