ipc_ptz.go 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291
  1. package main
  2. import (
  3. "errors"
  4. "strconv"
  5. "time"
  6. "github.com/sirupsen/logrus"
  7. "lc/common/mqtt"
  8. "lc/common/onvif/profiles/ptz"
  9. "lc/common/onvif/soap"
  10. "lc/common/protocol"
  11. )
  12. var (
  13. NotSupportPtz = errors.New("不支持云台PTZ")
  14. )
  15. // ContinuousMove direction 0:停止移动;1:向左边;2:向右边;3:向上;4:向下;5:缩小;6:放大
  16. // speed/255.0,speed的范围[0,255]
  17. func (o *LcDevice) ContinuousMove(profileToken string, direction, speed uint8) error {
  18. XAddr, ok := o.endpoints["ptz"]
  19. if !ok {
  20. return NotSupportPtz
  21. }
  22. p := ptz.NewPTZ(o.client, XAddr)
  23. var x float32 = 0.0
  24. var y float32 = 0.0
  25. var z float32 = 0.0
  26. s := float32(speed) / 255
  27. switch direction {
  28. case 0: //停止移动,用初始值,全零
  29. case 1: //向左边移动
  30. x = -s
  31. case 2: //向右边移动
  32. x = s
  33. case 3: //向上移动
  34. y = s
  35. case 4: //向下移动
  36. y = -s
  37. case 5: //缩小
  38. z = -s
  39. case 6: //放大
  40. z = s
  41. }
  42. _, err := p.ContinuousMove(&ptz.ContinuousMove{
  43. ProfileToken: ptz.ReferenceToken(profileToken),
  44. Velocity: ptz.PTZSpeed{
  45. PanTilt: ptz.Vector2D{
  46. X: x,
  47. Y: y,
  48. //Space: "http://www.onvif.org/ver10/tptz/PanTiltSpaces/GenericSpeedSpace",
  49. },
  50. Zoom: ptz.Vector1D{
  51. X: z,
  52. //Space: "http://www.onvif.org/ver10/tptz/ZoomSpaces/ZoomGenericSpeedSpace",
  53. },
  54. },
  55. })
  56. return err
  57. }
  58. // GetProsets 获取所有预置点并上报到平台
  59. func (o *LcDevice) GetProsets(profileToken string, filter bool) ([]protocol.PresetInfo, error) {
  60. XAddr, ok := o.endpoints["ptz"]
  61. if !ok {
  62. return nil, NotSupportPtz
  63. }
  64. //新球机需要重新生成签名dsz 20230704
  65. client := soap.NewClient(soap.WithTimeout(time.Second * 0))
  66. client.AddHeader(soap.NewWSSSecurityHeader(o.onvifDev.User, o.onvifDev.Password))
  67. o.client = client
  68. p := ptz.NewPTZ(o.client, XAddr)
  69. resp, err := p.GetPresets(&ptz.GetPresets{ProfileToken: ptz.ReferenceToken(profileToken)})
  70. if err != nil {
  71. return nil, err
  72. }
  73. var Data []protocol.PresetInfo
  74. for _, v := range resp.Preset {
  75. //海康某球机默认包含300个预置点,需要过滤默认的预置点
  76. if filter {
  77. if v.PTZPosition.PanTilt.X == 0 && v.PTZPosition.PanTilt.Y == 1 && v.PTZPosition.Zoom.X == 0 {
  78. continue
  79. }
  80. }
  81. pi := protocol.PresetInfo{Token: string(v.Token), Name: string(v.Name),
  82. X: v.PTZPosition.PanTilt.Y, Y: v.PTZPosition.PanTilt.Y, Z: v.PTZPosition.Zoom.X}
  83. Data = append(Data, pi)
  84. }
  85. return Data, nil
  86. }
  87. // SetProset 设置预置点
  88. func (o *LcDevice) SetProset(profileToken, presetToken, presetName string) (string, error) {
  89. XAddr, ok := o.endpoints["ptz"]
  90. if !ok {
  91. return "", NotSupportPtz
  92. }
  93. //新球机需要重新生成签名dsz 20230704
  94. client := soap.NewClient(soap.WithTimeout(time.Second * 0))
  95. client.AddHeader(soap.NewWSSSecurityHeader(o.onvifDev.User, o.onvifDev.Password))
  96. o.client = client
  97. p := ptz.NewPTZ(o.client, XAddr)
  98. resp, err := p.SetPreset(&ptz.SetPreset{
  99. ProfileToken: ptz.ReferenceToken(profileToken),
  100. PresetName: presetName,
  101. PresetToken: ptz.ReferenceToken(presetToken),
  102. })
  103. if err != nil {
  104. if _, ok := err.(*soap.SOAPFault); ok { //可能是token错误
  105. resp, err = p.SetPreset(&ptz.SetPreset{
  106. ProfileToken: ptz.ReferenceToken(profileToken),
  107. PresetName: presetName,
  108. })
  109. }
  110. }
  111. if err == nil {
  112. return string(resp.PresetToken), nil
  113. }
  114. return "", err
  115. }
  116. // DeleteProset 删除预置点
  117. func (o *LcDevice) DeleteProset(profileToken, presetToken string) error {
  118. XAddr, ok := o.endpoints["ptz"]
  119. if !ok {
  120. return NotSupportPtz
  121. }
  122. //新球机需要重新生成签名dsz 20230704
  123. client := soap.NewClient(soap.WithTimeout(time.Second * 0))
  124. client.AddHeader(soap.NewWSSSecurityHeader(o.onvifDev.User, o.onvifDev.Password))
  125. o.client = client
  126. p := ptz.NewPTZ(o.client, XAddr)
  127. _, err := p.RemovePreset(&ptz.RemovePreset{
  128. ProfileToken: ptz.ReferenceToken(profileToken),
  129. PresetToken: ptz.ReferenceToken(presetToken),
  130. })
  131. return err
  132. }
  133. // GotoProset 跳转到指定的预置点
  134. func (o *LcDevice) GotoProset(profileToken, presetToken string) error {
  135. XAddr, ok := o.endpoints["ptz"]
  136. if !ok {
  137. return NotSupportPtz
  138. }
  139. //新球机需要重新生成签名dsz 20230704
  140. client := soap.NewClient(soap.WithTimeout(time.Second * 0))
  141. client.AddHeader(soap.NewWSSSecurityHeader(o.onvifDev.User, o.onvifDev.Password))
  142. o.client = client
  143. p := ptz.NewPTZ(o.client, XAddr)
  144. _, err := p.GotoPreset(&ptz.GotoPreset{
  145. ProfileToken: ptz.ReferenceToken(profileToken),
  146. PresetToken: ptz.ReferenceToken(presetToken),
  147. })
  148. return err
  149. }
  150. // SetHomePosition 跳转到指定的预置点
  151. func (o *LcDevice) SetHomePosition(profileToken string) error {
  152. XAddr, ok := o.endpoints["ptz"]
  153. if !ok {
  154. return NotSupportPtz
  155. }
  156. //新球机需要重新生成签名dsz 20230704
  157. client := soap.NewClient(soap.WithTimeout(time.Second * 0))
  158. client.AddHeader(soap.NewWSSSecurityHeader(o.onvifDev.User, o.onvifDev.Password))
  159. o.client = client
  160. p := ptz.NewPTZ(o.client, XAddr)
  161. _, err := p.SetHomePosition(&ptz.SetHomePosition{ProfileToken: ptz.ReferenceToken(profileToken)})
  162. return err
  163. }
  164. // GotoHomePosition 跳转到指定的预置点
  165. func (o *LcDevice) GotoHomePosition(profileToken string) error {
  166. XAddr, ok := o.endpoints["ptz"]
  167. if !ok {
  168. return NotSupportPtz
  169. }
  170. //新球机需要重新生成签名dsz 20230704
  171. client := soap.NewClient(soap.WithTimeout(time.Second * 0))
  172. client.AddHeader(soap.NewWSSSecurityHeader(o.onvifDev.User, o.onvifDev.Password))
  173. o.client = client
  174. p := ptz.NewPTZ(o.client, XAddr)
  175. _, err := p.GotoHomePosition(&ptz.GotoHomePosition{ProfileToken: ptz.ReferenceToken(profileToken)})
  176. return err
  177. }
  178. func (o *LcDevice) HandleTpSPtzComm(m mqtt.Message) {
  179. //新球机需要重新生成签名dsz 20230704
  180. client := soap.NewClient(soap.WithTimeout(time.Second * 0))
  181. client.AddHeader(soap.NewWSSSecurityHeader(o.onvifDev.User, o.onvifDev.Password))
  182. o.client = client
  183. var obj protocol.Pack_PTZCommonInfo
  184. if err := obj.DeCode(m.PayloadString()); err != nil {
  185. return
  186. }
  187. if o.onvifDev.Code != obj.Id {
  188. return
  189. }
  190. profiletoken := o.GetProfileToken(obj.Data.ProfileToken)
  191. //0:获取所有预置点,1:设置预置点,2:删除预置点,3:跳转到预置点,4:设置home点,5:跳转到home点
  192. switch obj.Data.Flag {
  193. case 0:
  194. arrpis, err := o.GetProsets(profiletoken, true)
  195. var ret protocol.Pack_PresetInfo
  196. strRet, err := ret.EnCode(o.onvifDev.Code, appConfig.GID, obj.Seq, err, obj.Data.Flag, arrpis)
  197. GetMQTTMgr().Publish(GetTopic(o.GetDevType(), o.onvifDev.Code, protocol.TP_ONVIF_PRESETS_ACK), strRet, mqtt.AtMostOnce, ToCloud)
  198. case 1:
  199. token, err := o.SetProset(profiletoken, obj.Data.PresetToken, obj.Data.PresetName)
  200. var (
  201. ret protocol.Pack_IPCSetPresetACK
  202. file string
  203. x, y, z float32 = 0, 0, 0
  204. )
  205. if err == nil {
  206. //预置位设置成功,则抓拍一张图片
  207. tmpfile := o.onvifDev.Code + "_" + strconv.FormatUint(obj.Seq, 10) + ".jpg"
  208. err = o.Snapshot2(tmpfile)
  209. if err == nil {
  210. file = tmpfile
  211. }
  212. //获取x,y,z
  213. if arrpis, errx := o.GetProsets(profiletoken, true); errx == nil {
  214. for _, pis := range arrpis {
  215. if pis.Name == obj.Data.PresetName && pis.Token == token {
  216. x = pis.X
  217. y = pis.Y
  218. z = pis.Z
  219. break
  220. }
  221. }
  222. }
  223. }
  224. strRet, err := ret.EnCode(o.onvifDev.Code, appConfig.GID, token, obj.Data.PresetName, file, x, y, z, obj.Seq, err)
  225. GetMQTTMgr().Publish(GetTopic(o.GetDevType(), o.onvifDev.Code, protocol.TP_ONVIF_PRESET_ACK), strRet, mqtt.AtMostOnce, ToAll)
  226. case 2:
  227. err := o.DeleteProset(profiletoken, obj.Data.PresetToken)
  228. var ret protocol.Pack_IPCCommonACK
  229. strRet, err := ret.EnCode(o.onvifDev.Code, appConfig.GID, "", obj.Seq, err)
  230. GetMQTTMgr().Publish(GetTopic(o.GetDevType(), o.onvifDev.Code, protocol.TP_ONVIF_PTZ_COMM_ACK), strRet, mqtt.AtMostOnce, ToAll)
  231. case 3:
  232. err := o.GotoProset(profiletoken, obj.Data.PresetToken)
  233. var ret protocol.Pack_IPCCommonACK
  234. strRet, err := ret.EnCode(o.onvifDev.Code, appConfig.GID, "", obj.Seq, err)
  235. GetMQTTMgr().Publish(GetTopic(o.GetDevType(), o.onvifDev.Code, protocol.TP_ONVIF_PTZ_COMM_ACK), strRet, mqtt.AtMostOnce, ToAll)
  236. case 4:
  237. err := o.SetHomePosition(profiletoken)
  238. var ret protocol.Pack_IPCCommonACK
  239. strRet, err := ret.EnCode(o.onvifDev.Code, appConfig.GID, "", obj.Seq, err)
  240. GetMQTTMgr().Publish(GetTopic(o.GetDevType(), o.onvifDev.Code, protocol.TP_ONVIF_PTZ_COMM_ACK), strRet, mqtt.AtMostOnce, ToAll)
  241. case 5:
  242. err := o.GotoHomePosition(profiletoken)
  243. var ret protocol.Pack_IPCCommonACK
  244. strRet, err := ret.EnCode(o.onvifDev.Code, appConfig.GID, "", obj.Seq, err)
  245. GetMQTTMgr().Publish(GetTopic(o.GetDevType(), o.onvifDev.Code, protocol.TP_ONVIF_PTZ_COMM_ACK), strRet, mqtt.AtMostOnce, ToAll)
  246. case 6:
  247. arrpis, err := o.GetProsets(profiletoken, false)
  248. var ret protocol.Pack_PresetInfo
  249. strRet, err := ret.EnCode(o.onvifDev.Code, appConfig.GID, obj.Seq, err, obj.Data.Flag, arrpis)
  250. GetMQTTMgr().Publish(GetTopic(o.GetDevType(), o.onvifDev.Code, protocol.TP_ONVIF_PRESETS_ACK), strRet, mqtt.AtMostOnce, ToCloud)
  251. default:
  252. logrus.Errorf("Handle_PTZ:不支持的flag[%d]", obj.Data.Flag)
  253. }
  254. }
  255. func (o *LcDevice) HandleTpOnvifPtz(m mqtt.Message) {
  256. var obj protocol.Pack_PTZMoveInfo
  257. if err := obj.DeCode(m.PayloadString()); err != nil {
  258. return
  259. }
  260. if o.onvifDev.Code != obj.Id {
  261. return
  262. }
  263. //新球机需要重新生成签名dsz 20230704
  264. client := soap.NewClient(soap.WithTimeout(time.Second * 0))
  265. client.AddHeader(soap.NewWSSSecurityHeader(o.onvifDev.User, o.onvifDev.Password))
  266. o.client = client
  267. token := o.GetProfileToken(obj.Data.ProfileToken)
  268. err := o.ContinuousMove(token, obj.Data.Direction, obj.Data.Speed)
  269. var ret protocol.Pack_IPCCommonACK
  270. strRet, err := ret.EnCode(o.onvifDev.Code, appConfig.GID, "", obj.Seq, err)
  271. GetMQTTMgr().Publish(GetTopic(o.GetDevType(), o.onvifDev.Code, protocol.TP_ONVIF_PTZ_COMM_ACK), strRet, mqtt.AtMostOnce, ToAll)
  272. }