-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathonvifEventLogger.py
189 lines (148 loc) · 7.03 KB
/
onvifEventLogger.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# This file runs inside the Docker container, grabs the Ip Address, and logs all messages to the database.
import requests
import os
import time
import json
from requests.auth import HTTPDigestAuth
from datetime import datetime, timedelta
from bs4 import BeautifulSoup
from urllib.parse import urlparse
from time import sleep
from globalFunctions import myCursor, myDatabase
# RTSP Credential URL
rtspCredUrl = os.getenv('RTSP_PATHS_CAM1_SOURCE')
cameraName = os.getenv('CAMERA_NAME_SPACE')
# We need to get three things from this string,
# the username, password, and IP address
rtspCredUrlParsed = urlparse(rtspCredUrl)
camera_username = rtspCredUrlParsed.username
camera_password = rtspCredUrlParsed.password
ipAddress = rtspCredUrlParsed.hostname
initialTerminationTime = datetime.utcnow() + timedelta(hours=1)
initialTerminationTime = initialTerminationTime.strftime('%Y-%m-%dT%H:%M:%SZ')
# print(initialTerminationTime)
# Subscribe to an ONVIF Stream
success = False
# structured XML for CreatePullPointSubscription,
# Step 1, create a Event Subscription On Remote Camera, InitialTerminationTime will be now + one hour.
while success == False:
try:
payload = """<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:wsdl="http://www.onvif.org/ver10/events/wsdl">
<soap:Header/>
<soap:Body>
<wsdl:CreatePullPointSubscription>
<!--Optional:-->
<wsdl:Filter>
<!--You may enter ANY elements at this point-->
</wsdl:Filter>
<!--Optional:-->
<wsdl:InitialTerminationTime>""" + initialTerminationTime + """</wsdl:InitialTerminationTime>
<!--Optional:-->
<wsdl:SubscriptionPolicy>
<!--You may enter ANY elements at this point-->
</wsdl:SubscriptionPolicy>
<!--You may enter ANY elements at this point-->
</wsdl:CreatePullPointSubscription>
</soap:Body>
</soap:Envelope>"""
# headers
headers = {
'Content-Type': 'text/xml; charset=utf-8'
}
# POST request
response = requests.request("POST", "http://{0}/onvif/device_serivce".format(ipAddress), headers=headers, data=payload, auth=HTTPDigestAuth(camera_username, camera_password))
# print("Parsing XML Response...")
# print("")
# print("")
# print("")
parsedResponseXML = BeautifulSoup(response.text, 'xml')
subscriptionURL = parsedResponseXML.find_all('wsa5:Address')[0].text
except:
print("Assigning Subscription URL gave an exemption, sending a 'Camera Restart' and waiting for 60 seconds.")
payload = '''<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:wsdl="http://www.onvif.org/ver10/device/wsdl">
<soap:Header/>
<soap:Body>
<wsdl:SystemReboot/>
</soap:Body>
</soap:Envelope>'''
headers = {
'Content-Type': 'text/xml; charset=utf-8'
}
print((requests.request("POST", "http://{0}/onvif/device_serivce".format(ipAddress), headers=headers, data=payload, auth=HTTPDigestAuth(camera_username, camera_password))).text)
i = 0
while i < 80:
print(i)
time.sleep(1)
i = i + 1
else:
success = True
subscriptionResponseTime = parsedResponseXML.find_all('wsnt:CurrentTime')[0].text
subscriptionTerminationTime = parsedResponseXML.find_all('wsnt:TerminationTime')[0].text
subscriptionTerminationTimeObject = datetime.strptime(subscriptionTerminationTime, '%Y-%m-%dT%H:%M:%SZ')
subscriptionTerminationTimeEpoch = (time.mktime(subscriptionTerminationTimeObject.timetuple())) # Time Subscription Ends In Unix EPOCH
currentTimeEpoch = (time.mktime(datetime.utcnow().timetuple()))
# print("Subscription URL: " + subscriptionURL)
# print("Subscription Response Time: " + subscriptionResponseTime)
# print("Subscription Termination Time: " + subscriptionTerminationTime)
# Now we have the Subscription, we'll use the time as a loop condition to check when we should renew the subscription.
# Everytime we loop, we can pull the last 10 Messages, for instance. The Request URL will now be the Subscription URL
# We should pull these into a local DB, for both history and timestamping,
while True:
# structured XML for PullMessages,
# Step 2, get all messages from Subscription, then wait for new messages, including motion events!
payload = """<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:wsdl="http://www.onvif.org/ver10/events/wsdl">
<soap:Header/>
<soap:Body>
<wsdl:PullMessages>
<wsdl:Timeout>0.1</wsdl:Timeout>
<wsdl:MessageLimit>10</wsdl:MessageLimit>
<!--You may enter ANY elements at this point-->
</wsdl:PullMessages>
</soap:Body>
</soap:Envelope>"""
# headers
headers = {
'Content-Type': 'text/xml; charset=utf-8'
}
# POST request
# print("Sending Request For Notification, Waiting For Response...")
response = requests.request("POST", subscriptionURL, headers=headers, data=payload, auth=HTTPDigestAuth(camera_username, camera_password))
# print(response.text)
# print("Got Response, Parsing And Dumping...")
messagesXML = BeautifulSoup(response.text, 'xml')
# With XML Here, we need to break down the response into it's individual messages.
messages = messagesXML.find_all('NotificationMessage')
# Now we have each 'message' seperated, we can run a loop based on this:
for message in messages:
jsonMessage = {}
# Parse Each message to a string, following the format: Topic | Time | Data
# print("==========MESSAGE START===========")
tmpXML = BeautifulSoup(str(message), 'xml')
# print("Raw: " + str(tmpXML))
# Get Topic
thisTopic = tmpXML.find('Topic')
# print("Topic: " + str(thisTopic.text))
# Get Time
thisTime = tmpXML.find('Message', {'UtcTime': True})
thisTime = thisTime.get('UtcTime')
# print("Timestamp: " + str(thisTime))
# Get Data
thisData = tmpXML.find_all('SimpleItem')
# Itterate Over Data
i = 0
for items in thisData:
thisObject = thisData[i].get('Name')
thisValue = thisData[i].get('Value')
# print("Object: " + thisObject + " | Value: " + thisValue)
# We need to add this to a JSON object that then get's passed to the database
# Create the JSON to append:
tmpJSON = {thisObject:thisValue}
# Append It
jsonMessage.update(tmpJSON)
i = i + 1
# print("==========MESSAGE STOP============")
# print("")
# Now that the entire message is parsed, we need to add an entry to the database for this entire message.
# Commit Topic, Time AND Data
myCursor.execute("INSERT INTO cameraevents (name, topic, messagetime, data) VALUES(%s, %s, %s, %s)", (str(cameraName), str(thisTopic.text), str(thisTime), json.dumps(jsonMessage)))
myDatabase.commit()