ipc_ptz.go 9.5 KB

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