I spent a bit of time looking at XML/Soap messages 'onvif_zeep' exchanges with the camera. You can work around the broken event example, but you get another problem: the 'zeep' XML module cannot fully parse an XML alarm message and leaves out important fields (you can compare 'm' to 'm1' to see what is left out). You can however intercept the original XML response from camera and parse it manually like this:
Python:
## Override transport to capture xml:
from onvif import ONVIFCamera
from datetime import timedelta, datetime
from zeep import transports
import xmltodict
class Transport(transports.Transport):
def post(self, address, message, headers):
self.xml_request = message.decode('utf-8')
response = super().post(address, message, headers)
self.response = response
return response
expired = True
while True:
# Subscribe every 5 min:
if expired:
mycam = ONVIFCamera('192.168.1.10, 80, 'admin', 'pass', transport=Transport())
mycam.create_pullpoint_service()
service = mycam.pullpoint.zeep_client._get_service('EventService')
port = mycam.pullpoint.zeep_client._get_port(service, 'PullPointSubscription')
port.binding_options['address'] = mycam.xaddrs['http://www.onvif.org/ver10/events/wsdl/PullPointSubscription']
plp = mycam.pullpoint.zeep_client.bind('EventService', 'PullPointSubscription')
sub_start = datetime.now()
# Pull messages
m=plp.PullMessages(Timeout=timedelta(seconds=20), MessageLimit=100)
m1 = xmltodict.parse(mycam.transport.response.text)
try:
source= m1['env:Envelope']['env:Body']['tev:PullMessagesResponse']['wsnt:NotificationMessage']['wsnt:Topic']['#text']
state = m1['env:Envelope']['env:Body']['tev:PullMessagesResponse']['wsnt:NotificationMessage']['wsnt:Message']['tt:Message']['tt:Data']['tt:SimpleItem']['@Value']
print(datetime.now(), source, state)
except Exception as err:
print (datetime.now(), m1['env:Envelope']['env:Body']['tev:PullMessagesResponse'])
# Check if sub expired
expired = datetime.now() - sub_start > timedelta(seconds=300)
####
On my camera, I am getting this during motion:
2019-10-28 12:50:09.860072 OrderedDict([('tev:CurrentTime', '2019-10-28T17:50:09Z'), ('tev:TerminationTime', '2019-10-28T17:58:05Z')])
2019-10-28 12:50:19.887846 OrderedDict([('tev:CurrentTime', '2019-10-28T17:50:19Z'), ('tev:TerminationTime', '2019-10-28T17:58:05Z')])
2019-10-28 12:50:29.916845 OrderedDict([('tev:CurrentTime', '2019-10-28T17:50:29Z'), ('tev:TerminationTime', '2019-10-28T17:58:05Z')])
2019-10-28 12:50:39.970835 OrderedDict([('tev:CurrentTime', '2019-10-28T17:50:39Z'), ('tev:TerminationTime', '2019-10-28T17:58:05Z')])
2019-10-28 12:50:49.885414 OrderedDict([('tev:CurrentTime', '2019-10-28T17:50:49Z'), ('tev:TerminationTime', '2019-10-28T17:58:05Z')])
2019-10-28 12:50:59.846146 OrderedDict([('tev:CurrentTime', '2019-10-28T17:50:59Z'), ('tev:TerminationTime', '2019-10-28T17:58:05Z')])
2019-10-28 12:51:05.885580 tns1:VideoSource/MotionAlarm true
2019-10-28 12:51:05.938045 tns1:RuleEngine/CellMotionDetector/Motion true
2019-10-28 12:51:06.972172 tns1:VideoSource/MotionAlarm true
2019-10-28 12:51:07.873399 tns1:VideoSource/MotionAlarm true
2019-10-28 12:51:07.926991 tns1:RuleEngine/CellMotionDetector/Motion true
2019-10-28 12:51:08.957086 tns1:VideoSource/MotionAlarm true
2019-10-28 12:51:08.969518 tns1:RuleEngine/CellMotionDetector/Motion true
2019-10-28 12:51:09.997373 tns1:VideoSource/MotionAlarm true
2019-10-28 12:51:11.082327 tns1:VideoSource/MotionAlarm true
2019-10-28 12:51:12.004689 tns1:VideoSource/MotionAlarm false
2019-10-28 12:51:12.014676 tns1:RuleEngine/CellMotionDetector/Motion false
2019-10-28 12:51:12.925665 tns1:VideoSource/MotionAlarm false
2019-10-28 12:51:12.934068 tns1:RuleEngine/CellMotionDetector/Motion false
2019-10-28 12:51:13.865547 tns1:VideoSource/MotionAlarm false
2019-10-28 12:51:13.921019 tns1:RuleEngine/CellMotionDetector/Motion false
2019-10-28 12:51:14.912318 tns1:VideoSource/MotionAlarm false
2019-10-28 12:51:14.964042 tns1:RuleEngine/CellMotionDetector/Motion false
2019-10-28 12:51:15.903087 tns1:VideoSource/MotionAlarm false
2019-10-28 12:51:15.954571 tns1:RuleEngine/CellMotionDetector/Motion false
2019-10-28 12:51:26.966563 OrderedDict([('tev:CurrentTime', '2019-10-28T17:51:26Z'), ('tev:TerminationTime', '2019-10-28T17:58:05Z')])
2019-10-28 12:51:36.871524 OrderedDict([('tev:CurrentTime', '2019-10-28T17:51:36Z'), ('tev:TerminationTime', '2019-10-28T17:58:05Z')])
2019-10-28 12:51:47.024532 OrderedDict([('tev:CurrentTime', '2019-10-28T17:51:46Z'), ('tev:TerminationTime', '2019-10-28T17:58:05Z')])
2019-10-28 12:51:56.970599 OrderedDict([('tev:CurrentTime', '2019-10-28T17:51:56Z'), ('tev:TerminationTime', '2019-10-28T17:58:05Z')])
A subscription expires after 10 min. The python module does not offer the 'Renew' call as requested by the ONVIF standard call so you have re-subscribe every < 10min manually.
To run it, you need to install 'onvif_zeep' (
FalkTannhaeuser/python-onvif-zeep), 'xmltodict', 'utils'. It should be easy to add mqtt calls if desired. Perhaps, someone more motivated and less averse to looking at SOAP messages can improve the original library.