package main import ( "context" "time" "lc/common/mqtt" "lc/common/onvif/profiles/event" "lc/common/onvif/soap" "lc/common/protocol" ) type EventActuator struct { parent *LcDevice ctx context.Context cancel context.CancelFunc } func NewEventActuator(parent *LcDevice) *EventActuator { ctx, cancel := context.WithCancel(context.Background()) ea := EventActuator{ parent: parent, ctx: ctx, cancel: cancel, } return &ea } func (o *EventActuator) Cancel() { o.cancel() } func (o *EventActuator) EventHandle(XAddr string) { defer func() { recover() if o.parent.EventActuator != nil { o.parent.EventActuator.Cancel() o.parent.EventActuator = nil } }() Retry: //onvif事件 client := soap.NewClient(soap.WithTimeout(time.Second * 0)) client.AddHeader(soap.NewWSSSecurityHeader(o.parent.onvifDev.User, o.parent.onvifDev.Password)) epy := event.NewEventPortType(client, XAddr) resp0, err0 := epy.GetServiceCapabilities(&event.GetServiceCapabilities{}) if err0 != nil { return } if !resp0.Capabilities.WSPullPointSupport { return } resp1, err1 := epy.GetEventProperties(&event.GetEventProperties{}) if err1 != nil { return } //订阅在onvif.json中Event配置的事件主题 var TopicExpressionDialect event.AnyURI = "https://www.onvif.org/ver10/tev/topicExpression/ConcreteSet" if len(resp1.TopicExpressionDialect) > 0 && len(resp1.TopicExpressionDialect[0]) > 0 { TopicExpressionDialect = event.AnyURI(resp1.TopicExpressionDialect[0]) } cps := event.CreatePullPointSubscription{ Filter: event.FilterType{ TopicExpression: event.TopicExpressionType{ TopicKinds: o.parent.onvifDev.Event, Dialect: TopicExpressionDialect, }, }, } resp2, err2 := epy.CreatePullPointSubscription(&cps) if err2 != nil { return } pps := event.NewPullPointSubscription(client, string(resp2.SubscriptionReference.Address)) pm := event.PullMessages{MessageLimit: resp0.Capabilities.MaxPullPoints} errCnt := 0 for { select { case <-o.ctx.Done(): return default: resp, err := pps.PullMessages(&pm) if err != nil { //发生错误,则停3秒再重试 time.Sleep(3 * time.Second) if errCnt++; errCnt > 5 { goto Retry } break } else { errCnt = 0 } if resp == nil { break } for _, v := range resp.NotificationMessage { //一键告警按键告警,v.Topic.TopicKinds == "tns1:Device/Trigger/tnshik:AlarmIn" t, err := time.Parse("2006-01-02T15:04:05Z", v.Message.Message.UtcTime) if err != nil { continue } ca := protocol.OnvifAlarmInfo{ AlarmTopic: v.Topic.TopicKinds, Time: protocol.ToBJTime(t).Format("2006-01-02 15:04:05"), } if len(v.Message.Message.Source.SimpleItem) > 0 { ca.Source = make(map[string]string) for _, si := range v.Message.Message.Source.SimpleItem { ca.Source[si.Name] = si.Value } } if len(v.Message.Message.Key.SimpleItem) > 0 { ca.Key = make(map[string]string) for _, si := range v.Message.Message.Key.SimpleItem { ca.Key[si.Name] = si.Value } } if len(v.Message.Message.Data.SimpleItem) > 0 { ca.Data = make(map[string]string) for _, si := range v.Message.Message.Data.SimpleItem { ca.Data[si.Name] = si.Value } } seq := GetNextUint64() var obj protocol.Pack_OnvifAlarm if str, err := obj.EnCode(o.parent.onvifDev.Code, appConfig.GID, seq, &ca); err == nil { topic := GetTopic(o.parent.GetDevType(), o.parent.onvifDev.Code, protocol.TP_ONVIF_ALARM) GetMQTTMgr().Publish(topic, str, mqtt.AtMostOnce, ToAll) } switch v.Topic.TopicKinds { case "tns1:Device/Trigger/tnshik:AlarmIn": //海康一键报警 o.HandleDeviceTriggerAlarm(seq, &ca) //录像抓图 case "tns1:RuleEngine/LineDetector/Crossed": //遮挡告警 o.HandleRuleEngineCrossedLinedetector(seq, &ca) } } } } } func (o *EventActuator) HandleRuleEngineCrossedLinedetector(seq uint64, ca *protocol.OnvifAlarmInfo) { go o.parent.Snapshot("") } func (o *EventActuator) HandleDeviceTriggerAlarm(seq uint64, ca *protocol.OnvifAlarmInfo) { if v, ok := ca.Data["State"]; ok && v == "true" { go o.parent.RecordToFLV("", 20) //告警开始,抓拍视频 } go o.parent.Snapshot("") //告警开始或结束,抓拍图片 }