[{"server":null,"owner":null,"id":"a77251ad-8ce2-489e-b453-b8378b608ea2","params":{"result":{"value":"","datetime":1688725154,"status":null,"version":0},"hash":{"value":"0C9EXehaTsiYqgCNZ13ybQ==","datetime":1689079136,"status":null,"version":0},"enabled":{"value":false,"datetime":1689078987,"status":null,"version":0},"error_text":{"value":"","datetime":1688984093,"status":null,"version":0},"type":{"value":"EgsScenario","datetime":1689079079,"status":null,"version":0},"settings":{"value":"{\r\n  \"deviceUrl\": \"http://192.168.1.39:9000/onvif/device_service\",\r\n  \"initialTerminationTime\": \"PT10M\",\r\n  \"messageLimit\": 1024,\r\n  \"timeout\": \"PT10S\",\r\n  \"interval\": \"00:00:01\",\r\n  \"prefixId\": \"onvif1_\",\r\n  \"mapping\": {\r\n    \"VideoSurveillanceSystem\": {\r\n      \"type\": \"IpVideoCamera\",\r\n      \"params\": {\r\n        \"Category\": \"category\",\r\n        \"Comment\": \"comment\",\r\n        \"Priority\": \"priority\"\r\n      },\r\n      \"states\": {\r\n        \"ChannelDisconnect\": \"ok.channelDisconnect\",\r\n        \"ChannelConnect\": \"ok.channelConnect\",\r\n        \"RecordTurnOff\": \"ok.archiveStop\",\r\n        \"RecordTurnOn\": \"ok.archiveNormal\",\r\n        \"MotionDetectorTrigger\": \"alarm.motionInZone\"\r\n      }\r\n    },\r\n    \"AccessControl\": {\r\n      \"type\": \"Onvif_AccessControl\",\r\n      \"params\": {\r\n        \"Name\": \"name\",\r\n        \"Comment\": \"comment\",\r\n        \"Place\": \"place\"\r\n      },\r\n      \"states\": {\r\n        \"Accident\": \"alarm.alarm\",\r\n        \"Fault\": \"error.defective\"\r\n      }\r\n    },\r\n    \"FireAlarm\": {\r\n      \"type\": \"LowCurrentFireSensor\",\r\n      \"params\": {\r\n        \"Category\": \"category\",\r\n        \"Zone\": \"zone\",\r\n        \"Comment\": \"comment\"\r\n      },\r\n      \"states\": {\r\n        \"Alarm\": \"alarm.openCase\",\r\n        \"Fire\": \"alarm.alarm\",\r\n        \"Fault\": \"error.defective\"\r\n      }\r\n    },\r\n    \"Introscopy\": {\r\n      \"type\": \"Introscopy\",\r\n      \"params\": {\r\n        \"Account\": \"account\",\r\n        \"Result\": \"result\",\r\n        \"Picture\": \"picture\",\r\n        \"Manufacturer\": \"manufacturer\",\r\n        \"Model\": \"model\",\r\n        \"FirmwareVersion\": \"firmwareVersion\",\r\n        \"SerialNumber\": \"serialNumber\",\r\n        \"HardwareId\": \"hardwareId\"\r\n      },\r\n      \"states\": {\r\n        \"LimitExceeded\": \"alarm.concentrationExceeded\"\r\n      }\r\n    },\r\n    \"GasAnalysis\": {\r\n      \"type\": \"GasAnalysis\",\r\n      \"params\": {\r\n        \"Place\": \"place\",\r\n        \"ConcentrationLimit\": \"concentrationLimit\",\r\n        \"GasType\": \"gasType\",\r\n        \"Concentration\": \"concentration\",\r\n        \"Comment\": \"comment\"\r\n      },\r\n      \"states\": {\r\n        \"ConcentrationExceeded\": \"alarm.alarm\"\r\n      }\r\n    },\r\n    \"RadiationMonitoring\": {\r\n      \"type\": \"RadiationMonitoring\",\r\n      \"params\": {\r\n        \"Category\": \"category\",\r\n        \"Account\": \"account\",\r\n        \"Mesures\": \"mesures\",\r\n        \"Picture\": \"picture\"\r\n      },\r\n      \"states\": {\r\n        \"Detect\": \"alarm.alarm\"\r\n      }\r\n    },\r\n    \"NeutronProbing\": {\r\n      \"type\": \"NeutronProbing\",\r\n      \"params\": {\r\n        \"Place\": \"place\",\r\n        \"ExplosiveType\": \"explosiveType\",\r\n        \"Location\": \"location\",\r\n        \"Comment\": \"comment\"\r\n      },\r\n      \"states\": {\r\n        \"Detect\": \"alarm.alarm\"\r\n      }\r\n    },\r\n    \"MetalDetector\": {\r\n      \"type\": \"MetalDetector\",\r\n      \"params\": {\r\n        \"Account\": \"account\",\r\n        \"Picture\": \"picture\"\r\n      },\r\n      \"states\": {\r\n        \"Detect\": \"alarm.alarm\"\r\n      }\r\n    },\r\n    \"SteamDetector\": {\r\n      \"type\": \"SteamDetector\",\r\n      \"params\": {\r\n        \"Account\": \"account\",\r\n        \"Mesures\": \"mesures\",\r\n        \"Picture\": \"picture\"\r\n      },\r\n      \"states\": {\r\n        \"Detect\": \"alarm.alarm\"\r\n      }\r\n    }\r\n  },\r\n  \"terminationTime\": \"PT10M\"\r\n}","datetime":1689079314,"status":null,"version":0},"state":{"value":"ok.normal","datetime":1688984093,"status":null,"version":0},"script":{"value":"# имя: 'CCTMK Client'\r\n# описание: клиент протокола ССТМК\r\n# тип триггера: 'EgsScenario'\r\n# создан: 2021.09.06 17.43.25, Сельченков Н.Ю.\r\n# изменен: '2023.07.11 16.38.56', Сельченков Н.Ю.\r\n# подробности: https://redmine.integra-s.com:11000/projects/eilyacuario/wiki/CCTMK_Client\r\n\r\nuse System.IO.StringReader\r\nuse System.IO.StringWriter\r\nuse System.IO.Stream\r\nuse System.IO.FileStream\r\nuse System.IO.FileMode\r\nuse System.Xml.Serialization.XmlSerializer\r\nuse System.Xml.XmlElement \r\nuse System.Xml.XmlDocument\r\nuse System.Xml.XmlConvert\r\nuse System.Uri\r\nuse System.Text.RegularExpressions.Regex\r\nuse System.Security.Cryptography.HashAlgorithm\r\nuse System.Text.Encoding\r\nuse System.Convert\r\nuse System.Threading.Tasks.Task\r\nuse System.Exception\r\nuse Newtonsoft.Json.JsonConvert from Newtonsoft.Json\r\nuse acuario2.webserver.soap12.UsernameToken\r\nuse acuario2.webserver.soap12.Security\r\nuse acuario2.webserver.soap12.ReplyTo\r\nuse acuario2.webserver.soap12.Header\r\nuse acuario2.webserver.soap12.Envelope\r\nuse acuario2.webserver.onvif.wsdl.GetSystemDateAndTimeRequest from acuario2.onvif\r\nuse acuario2.webserver.onvif.wsdl.GetSystemDateAndTimeResponse from acuario2.onvif\r\nuse acuario2.webserver.onvif.wsdl.GetDeviceInformationRequest from acuario2.onvif\r\nuse acuario2.webserver.onvif.wsdl.GetDeviceInformationResponse from acuario2.onvif\r\nuse acuario2.webserver.onvif.wsdl.GetScopesRequest from acuario2.onvif\r\nuse acuario2.webserver.onvif.wsdl.GetScopesResponse from acuario2.onvif\r\nuse acuario2.webserver.onvif.wsdl.GetServicesRequest from acuario2.onvif\r\nuse acuario2.webserver.onvif.wsdl.GetServicesResponse from acuario2.onvif\r\nuse acuario2.webserver.onvif.wsdl.CreatePullPointSubscriptionRequest from acuario2.onvif\r\nuse acuario2.webserver.onvif.wsdl.CreatePullPointSubscriptionResponse from acuario2.onvif\r\nuse acuario2.webserver.onvif.wsdl.PullMessagesRequest from acuario2.onvif\r\nuse acuario2.webserver.onvif.wsdl.PullMessagesResponse from acuario2.onvif\r\nuse acuario2.webserver.onvif.wsdl.Renew from acuario2.onvif\r\nuse acuario2.webserver.onvif.wsdl.RenewRequest from acuario2.onvif\r\nuse acuario2.webserver.onvif.wsdl.RenewResponse from acuario2.onvif\r\nuse acuario2.webserver.onvif.wsdl.SeekRequest from acuario2.onvif\r\nuse acuario2.webserver.onvif.wsdl.SeekResponse from acuario2.onvif\r\nuse acuario2.webserver.onvif.wsdl.SeekRequest from acuario2.onvif\r\nuse acuario2.webserver.onvif.wsdl.SeekResponse from acuario2.onvif\r\nuse acuario2.webserver.onvif.wsdl.Unsubscribe from acuario2.onvif\r\nuse acuario2.webserver.onvif.wsdl.UnsubscribeResponse from acuario2.onvif\r\nuse acuario2.webserver.onvif.wsdl.NotificationMessageHolderType from acuario2.onvif\r\nuse acuario2.webserver.onvif.Message\r\nuse System.Collections.Generic.List(NotificationMessageHolderType) as MessageList\r\nuse acuario2.utils.NameValueList(string) as NameValueList\r\n\r\nlet regexFind(text as string, pattern as string) = with Regex(pattern).Match(text) do if Success then Groups[1].Value\r\nlet json(obj as object) = JsonConvert.SerializeObject(obj)    \r\n\r\n### settings ###\r\n\r\nuse json_schema\r\n`\r\n{\r\n    \"type\": \"object\",\r\n    \"properties\":\r\n    {\r\n        \"deviceUrl\":       { \"type\": \"string\", \"default\": \"http://192.168.1.39:9000/onvif/device_service\" },\r\n        \"terminationTime\": { \"type\": \"string\", \"default\": \"PT10M\" },\r\n        \"messageLimit\":    { \"type\": \"integer\",\"default\": 1024 },\r\n        \"timeout\":         { \"type\": \"string\", \"default\": \"PT10S\" },\r\n        \"interval\":        { \"type\": \"string\", \"format\": \"TimeSpan\", \"default\": \"00:00:01\" },\r\n        \"prefixId\":        { \"type\": \"string\", \"default\": \"\" },\r\n        \"mapping\":              \r\n        { \r\n            \"type\": \"object\",\r\n            \"additionalProperties\": \r\n            { \r\n                \"type\": \"object\",\r\n                \"properties\": {\r\n                    \"type\": { \"type\": \"string\" },\r\n                    \"params\": {\r\n                        \"type\": \"object\",\r\n                        \"additionalProperties\": { \"type\": \"string\" }                    \r\n                    },\r\n                    \"states\": {\r\n                        \"type\": \"object\",\r\n                        \"additionalProperties\": { \"type\": \"string\" }                    \r\n                    }\r\n                }\r\n            }\r\n        }, \r\n    }\r\n}\r\n` as SETTINGS\r\n\r\nlet serializer = XmlSerializer(Message)\r\nlet settings   = SETTINGS(this.settings) \r\nlet uri        = null as Uri \r\nlet device     = null as NameValueList \r\nlet header     = Header()\r\n \r\nlet parse(message as NotificationMessageHolderType) = \r\n    let topic  = message.Topic.Any[0].Value\r\n    let type   = regexFind(topic, \".+/(.+)/.+\")\r\n    let event  = regexFind(topic, \".+/.+/(.+)\")\r\n    let reader = StringReader(message.Message.OuterXml)\r\n    let msg    = serializer.Deserialize(reader) as Message\r\n    let source = NameValueList(from msg.Source bind Name to Value)\r\n    let key    = NameValueList(from msg.Key bind Name to Value)\r\n    let data   = NameValueList(from msg.Data bind Name to Value)\r\n    new { type, event, time = msg.UtcTime, source, key, data }\r\nend\r\n\r\nlet report(err as Exception) = \r\n    print err\r\n    this.error_text = string(err)\r\nend\r\n\r\nlet subscribe() =     \r\n    uri      = Uri(settings.deviceUrl)\r\n    let info = await Envelope(GetDeviceInformationRequest(), null, null).Post(GetDeviceInformationResponse, uri)\r\n    \r\n    device = NameValueList()\r\n    device[\"Manufacturer\"]    = info.Manufacturer\r\n    device[\"Model\"]           = info.Model\r\n    device[\"FirmwareVersion\"] = info.FirmwareVersion\r\n    device[\"SerialNumber\"]    = info.SerialNumber\r\n    device[\"HardwareId\"]      = info.HardwareId\r\n    print(\"Device:\", json(device))\r\n     \r\n    let request               = GetServicesRequest() \r\n    request.IncludeCapability = false\r\n    let services              = await Envelope(request, null, null).Post(GetServicesResponse, uri)\r\n    from services.Service do\r\n        let type = regexFind(Namespace, \"http://www.onvif.org/ver10/(.+)/wsdl\")\r\n        if type is \"events\" then \r\n            print(\"EventsUrl:\", XAddr) \r\n            uri = Uri(XAddr)\r\n    now\r\n\r\n    let request                    = CreatePullPointSubscriptionRequest()\r\n    request.InitialTerminationTime = settings.terminationTime\r\n    let envelope                   = Envelope(request, null, null)\r\n    let response                   = await envelope.Post(CreatePullPointSubscriptionResponse, uri)\r\n    header.To                      = response.SubscriptionReference.Address.Value\r\n    print(\"Subscription:\", header.To)    \r\nend\r\n\r\nlet pullMessages() = \r\n    let request             = Renew()\r\n    request.TerminationTime = settings.terminationTime\r\n    let envelope            = Envelope(request, null, null)\r\n    envelope.Header         = header\r\n    let response            = await envelope.Post(RenewResponse, uri)\r\n    let request             = PullMessagesRequest()\r\n    request.MessageLimit    = settings.messageLimit\r\n    request.Timeout         = settings.timeout\r\n    let envelope            = Envelope(request, null, null)\r\n    envelope.Header         = header\r\n    let response            = await envelope.Post(PullMessagesResponse, uri)\r\n    if response.NotificationMessage isnt empty then\r\n        let message = from response.NotificationMessage first\r\n        let parsed  = parse(message)\r\n        let id      = settings.prefixId + parsed.source[\"Id\"]\r\n        print(\"NotificationMessage:\", id, json(parsed))       \r\n        if settings.mapping.ContainsKey(parsed.type) then\r\n            let mapping = settings.mapping[parsed.type]\r\n            let item    = from graph.Find(\"*/\"+mapping.type) of type OnvifItem where onvifId == id try first\r\n            if item isnt null then\r\n                from mapping.params do\r\n                    if parsed.data.ContainsKey(Key) then item[Value].Value = parsed.data[Key]\r\n                    if parsed.key.ContainsKey(Key)  then item[Value].Value = parsed.key[Key]\r\n                    if device.ContainsKey(Key)      then item[Value].Value = device[Key]\r\n                now\r\n                if mapping.states.ContainsKey(parsed.event) then item[\"state\"].Value = mapping.states[parsed.event].Replace('.','_')\r\n                else item[\"state\"].Value = \"none_unknown\"\r\n            end            \r\n        end\r\n    end    \r\n    void()\r\nend \r\n\r\nlet on_timer() = \r\n    try \r\n        if uri is null then await async subscribe()\r\n        await async pullMessages()        \r\n    else    \r\n        uri = null\r\n        print(\"ERROR:\", last_error.Message)\r\n    end\r\nend\r\n\r\nthis.result = \"\"\r\nthis.RunOnTimer(settings.interval.TotalSeconds, on_timer)\r\n\r\n    ","datetime":1689079136,"status":null,"version":0},"name":{"value":"CCTMK Client","datetime":1688711004,"status":null,"version":0}},"entity":"item","operation":"create"}]