agsh / onvif

ONVIF node.js implementation
https://onvif.pages.dev
MIT License
703 stars 240 forks source link

Eventing #24

Closed nayrnet closed 4 years ago

nayrnet commented 8 years ago

feature request to add support to list and subscribe to ONVIF events, ie motion detection.

carl689 commented 8 years ago

:+1:

agsh commented 8 years ago

Hello guys! Subscription on events is experimental. Cause I haven't got events support in my cam. It describes here http://agsh.github.io/onvif/Cam_.html#event:event and sources are here https://github.com/agsh/onvif/blob/master/lib/events.js It uses PullPointSubscription. So you can use something like that

var cam = Cam({});
cam.on('event', function(camMessage){console.log(camMessage)});

Please try it and perhaps make some chages if you want.

carl689 commented 8 years ago

I got an "Optional Action Not Implemented" soap fault, which looks to be from the device when testing out the events code. This is odd as I know of people who user ONVIF with motion on this particular camera .

I ended up solving my immediate issue by accessing the cameras xml api directly.

agsh commented 8 years ago

Can you send your xmls?

carl689 commented 8 years ago

Are you asking me for the request/response xml generated using your event class or the xml I used to work around? I tried doing a .rawResponse on the cam object but got null, I probably missed something in the docs for pulling the raw request/response.

My workaround was not using Onvif, but the cameras proprietary xml api

bluet commented 8 years ago

Anyone has success?

agsh commented 8 years ago

If anyone grant me an access to cam with events, I'll can debug existing event module

agsh commented 8 years ago

@BlueT can you test event module?

bluet commented 8 years ago

@agsh all (3) of my onvif cams are broken at the moment. I hope I can have a working device to test it soon.

sousandrei commented 8 years ago

@agsh @BlueT still needing cams? i can allocate one for us

agsh commented 8 years ago

Sure! Please e-mail me it address. Does it push events often?

duncanks commented 8 years ago

@agsh Hi, I have been having problems with events too. I think I have identified the issue affecting me at least. The various methods in events.js aren't defining service in the call to _request. e.g. getEventProperties is returning "Optional Action Not Implemented". If I modify it like this it works:

Cam.prototype.getEventProperties = function(callback) { this._request({ **service: 'events' ,** body: this._envelopeHeader() +

RogerHardiman commented 8 years ago

Thank you @duncanks for the bug report in events.js. without the service:'events' line the ONVIF message would go to the default Xaddr of /onvif/device_service and not to the Xaddr for events listed in GetCapabilities.

bluet commented 8 years ago

@agsh @sousandrei has this been tested? Or still need help?

sousandrei commented 8 years ago

it was almost there when I was talking with @agsh. maybe he changed something, but I can send you the changes

bluet commented 8 years ago

@sousandrei thanks. I think maybe wait for @agsh 's confirm, to avoid duplicated works. :-)

tetherit commented 8 years ago

Hi there, when I run "cam.on('event'... " I get the following. This is a Lilin camera. Any ideas?

> cam.on('event', function(camMessage){console.log(camMessage)});
Cam {
  hostname: '192.168.88.14',
  username: 'admin',
  password: 'pass',
  port: 80,
  path: '/onvif/device_service',
  timeout: 120000,
  preserveAddress: false,
  events: { timeout: 30000, messageLimit: 1 },
  timeShift: -398828304488,
  capabilities: 
   { device: 
      { XAddr: 'http://192.168.88.14/onvif/device_service',
        network: [Object],
        system: [Object],
        IO: [Object],
        security: [Object] },
     events: 
      { XAddr: 'http://192.168.88.14/onvif/device_service',
        WSSubscriptionPolicySupport: false,
        WSPullPointSupport: false,
        WSPausableSubscriptionManagerInterfaceSupport: false },
     imaging: { XAddr: 'http://192.168.88.14/onvif/Imaging' },
     media: 
      { XAddr: 'http://192.168.88.14/onvif/device_service',
        streamingCapabilities: [Object] } },
  uri: 
   { media: 
      Url {
        protocol: 'http:',
        slashes: true,
        auth: null,
        host: '192.168.88.14',
        port: null,
        hostname: '192.168.88.14',
        hash: null,
        search: null,
        query: null,
        pathname: '/onvif/device_service',
        path: '/onvif/device_service',
        href: 'http://192.168.88.14/onvif/device_service' },
     imaging: 
      Url {
        protocol: 'http:',
        slashes: true,
        auth: null,
        host: '192.168.88.14',
        port: null,
        hostname: '192.168.88.14',
        hash: null,
        search: null,
        query: null,
        pathname: '/onvif/Imaging',
        path: '/onvif/Imaging',
        href: 'http://192.168.88.14/onvif/Imaging' },
     events: 
      Url {
        protocol: 'http:',
        slashes: true,
        auth: null,
        host: '192.168.88.14',
        port: null,
        hostname: '192.168.88.14',
        hash: null,
        search: null,
        query: null,
        pathname: '/onvif/device_service',
        path: '/onvif/device_service',
        href: 'http://192.168.88.14/onvif/device_service' },
     device: 
      Url {
        protocol: 'http:',
        slashes: true,
        auth: null,
        host: '192.168.88.14',
        port: null,
        hostname: '192.168.88.14',
        hash: null,
        search: null,
        query: null,
        pathname: '/onvif/device_service',
        path: '/onvif/device_service',
        href: 'http://192.168.88.14/onvif/device_service' } },
  profiles: 
   [ { '$': [Object],
       name: 'H2641080P',
       videoSourceConfiguration: [Object],
       audioSourceConfiguration: [Object],
       videoEncoderConfiguration: [Object],
       audioEncoderConfiguration: [Object] },
     { '$': [Object],
       name: 'JPEG720P',
       videoSourceConfiguration: [Object],
       audioSourceConfiguration: [Object],
       videoEncoderConfiguration: [Object],
       audioEncoderConfiguration: [Object] },
     { '$': [Object],
       name: 'H264480P',
       videoSourceConfiguration: [Object],
       audioSourceConfiguration: [Object],
       videoEncoderConfiguration: [Object],
       audioEncoderConfiguration: [Object] } ],
  videoSources: 
   [ { '$': [Object],
       framerate: 20,
       resolution: [Object],
       imaging: [Object],
       extension: '' } ],
  defaultProfiles: 
   [ { '$': [Object],
       name: 'H2641080P',
       videoSourceConfiguration: [Object],
       audioSourceConfiguration: [Object],
       videoEncoderConfiguration: [Object],
       audioEncoderConfiguration: [Object] } ],
  activeSources: 
   [ { sourceToken: 0,
       profileToken: 'H2641080P',
       encoding: 'H264',
       width: 1920,
       height: 1080,
       fps: undefined,
       bitrate: 3072 } ],
  defaultProfile: 
   { '$': { token: 'H2641080P', fixed: true },
     name: 'H2641080P',
     videoSourceConfiguration: 
      { '$': [Object],
        name: 'user0',
        useCount: 4,
        sourceToken: 0,
        bounds: [Object] },
     audioSourceConfiguration: { '$': [Object], name: 'user0', useCount: 4, sourceToken: 0 },
     videoEncoderConfiguration: 
      { '$': [Object],
        name: 'H2641080P',
        useCount: 1,
        encoding: 'H264',
        resolution: [Object],
        quality: 20,
        rateControl: [Object],
        H264: [Object],
        multicast: [Object],
        sessionTimeout: 'PT0S' },
     audioEncoderConfiguration: 
      { '$': [Object],
        name: 'user0',
        useCount: 4,
        encoding: 'G711',
        bitrate: 16000,
        sampleRate: 8000,
        multicast: [Object],
        sessionTimeout: 'PT60S' } },
  activeSource: 
   { sourceToken: 0,
     profileToken: 'H2641080P',
     encoding: 'H264',
     width: 1920,
     height: 1080,
     fps: undefined,
     bitrate: 3072 },
  _eventsCount: 2 }
> TypeError: response.currentTime.getTime is not a function
    at _terminationTime (/Users/Library/Mobile Documents/com~apple~CloudDocs/Development/node-onvif/node_modules/onvif/lib/events.js:162:52)
    at Cam.<anonymous> (/Users/Library/Mobile Documents/com~apple~CloudDocs/Development/node-onvif/node_modules/onvif/lib/events.js:98:34)
    at /Users/Library/Mobile Documents/com~apple~CloudDocs/Development/node-onvif/node_modules/onvif/lib/utils.js:94:5
    at Parser.<anonymous> (/Users/Library/Mobile Documents/com~apple~CloudDocs/Development/node-onvif/node_modules/xml2js/lib/xml2js.js:489:18)
    at emitOne (events.js:96:13)
    at Parser.emit (events.js:188:7)
    at Object.onclosetag (/Users/Library/Mobile Documents/com~apple~CloudDocs/Development/node-onvif/node_modules/xml2js/lib/xml2js.js:447:26)
    at emit (/Users/Library/Mobile Documents/com~apple~CloudDocs/Development/node-onvif/node_modules/sax/lib/sax.js:640:35)
    at emitNode (/Users/Library/Mobile Documents/com~apple~CloudDocs/Development/node-onvif/node_modules/sax/lib/sax.js:645:5)
    at closeTag (/Users/Library/Mobile Documents/com~apple~CloudDocs/Development/node-onvif/node_modules/sax/lib/sax.js:905:7)
tetherit commented 8 years ago

On an Avigilon camera, when I run I get a loop of these messages coming in a few per second:

{ subscriptionReference: { address: 'http://192.168.5.57/onvif/subscription?idx=0' },
  topic: 
   { _: 'tns1:Device/tnsavg:Logs',
     '$': { Dialect: 'http://www.onvif.org/ver10/tev/topicExpression/ConcreteSet' } },
  message: { message: { '$': [Object], source: '', data: [Object] } } }
{ subscriptionReference: { address: 'http://192.168.5.57/onvif/subscription?idx=0' },
  topic: 
   { _: 'tns1:Device/tnsavg:Logs',
     '$': { Dialect: 'http://www.onvif.org/ver10/tev/topicExpression/ConcreteSet' } },
  message: { message: { '$': [Object], source: '', data: [Object] } } }
{ subscriptionReference: { address: 'http://192.168.5.57/onvif/subscription?idx=0' },
  topic: 
   { _: 'tns1:Device/tnsavg:Logs',
     '$': { Dialect: 'http://www.onvif.org/ver10/tev/topicExpression/ConcreteSet' } },
  message: { message: { '$': [Object], source: '', data: [Object] } } }
{ subscriptionReference: { address: 'http://192.168.5.57/onvif/subscription?idx=0' },
  topic: 
   { _: 'tns1:Device/tnsavg:Logs',
     '$': { Dialect: 'http://www.onvif.org/ver10/tev/topicExpression/ConcreteSet' } },
  message: { message: { '$': [Object], source: '', data: [Object] } } }

Not sure if that's right?

EDIT: If I stringify it looks like this. Not quite sure why it's flooding this:

 {"subscriptionReference":{"address":"http://192.168.5.57/onvif/subscription?idx=1"},"topic":{"_":"tns1:Device/tnsavg:Logs","$":{"Dialect":"http://www.onvif.org/ver10/tev/topicExpression/ConcreteSet"}},"message":{"message":{"$":{"UtcTime":"2011-01-11T20:55:09.831Z"},"source":"","data":{"simpleItem":[{"$":{"Name":"BaseId","Value":2828682735}},{"$":{"Name":"BootCount","Value":1078}},{"$":{"Name":"SystemLogId","Value":3814}},{"$":{"Name":"AccessLogId","Value":65502}}]}}}}
Gielert commented 8 years ago

I have a dahua ip-camera, and I'm trying to catch motion events. But when the event fires on the camera, the response object doesn't contain a subscription reference (see output below). So it will just crash because the subscriptionReference is undefined. Any ideas?

<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<s:Envelope         >
    <s:Header/>
    <s:Body>
        <tev:PullMessagesResponse>
            <tev:CurrentTime>2016-11-01T13:08:45Z</tev:CurrentTime>
            <tev:TerminationTime>2038-01-19T01:14:07Z</tev:TerminationTime>
            <wsnt:NotificationMessage>
                <wsnt:Topic Dialect="http://www.onvif.org/ver10/tev/topicExpression/ConcreteSet">tns1:VideoSource/MotionAlarm</wsnt:Topic>
                <wsnt:Message>
                    <tt:Message UtcTime="2016-11-01T13:08:45Z" PropertyOperation="Changed">
                        <tt:Source>
                            <tt:SimpleItem Name="Source" Value="000"/>
                        </tt:Source>
                        <tt:Data>
                            <tt:SimpleItem Name="State" Value="true"/>
                        </tt:Data>
                    </tt:Message>
                </wsnt:Message>
            </wsnt:NotificationMessage>
        </tev:PullMessagesResponse>
    </s:Body>
</s:Envelope>
bluet commented 7 years ago

@xanview Your stringified sample log shows that 192.168.5.57 booted the 1078 times at "UtcTime":"2011-01-11T20:55:09.831Z. Is that correct?

@Gielert You want to avoid the crash even when you got malformed packet, or....?

strarsis commented 5 years ago

No event events are emitted at all for a Hikvision IPcam 😿 .

RogerHardiman commented 5 years ago

@Gielert - Several other people have noticed that some cameras do not return a subscriptionReference in the PullMessageResponse.

I've read the ONVIF Core Specification and am making a code change to take out the check for subscriptionReference.

The ONVIF Core Spec defines two ways to receive events. Method 1 (Basic Notifications) is to register with the camera and wait for the camera to send a 'Notify' message to the client. (Core Spec v2.6.1, Section 9.3.1). In this case I'd expect the Notify message to include a subscriptionReference so the client knows exactly which subscription it relates to. This method does not work well with NAT routers.

Method 2 is to use Pull requests. The client polls the camera over and over requesting details of any new events. In this case the client knows exactly which subscription the PullMessageResponse relates to (it is the reply to to the outgoing SOAP message) so there is no need for the reply to include the subscriptionReference. This Method works well with NAT and firewalls.

The ONVIF WSDL states that the subscriptionReference has a minOccures=0 which means it is optional.

Elsewhere other users have forked this project and removed the check for a subscriptionReference in the PullMessageResponse and I'm happy that as this library uses Method 2 - Pull Requests then we don't want to check the subscriptionReference in the PullMessageResponse

RogerHardiman commented 5 years ago

@strarsis I've added example6.js to the project which connects to a camera and prints out the Events received. It requires you to get the latest onvif library code out of git as removes the subscriptionReference. example6.js receives events from the HikVision static camera I have

Can you test it please with your camera?

RogerHardiman commented 4 years ago

This is a very old issue report and Events have just had a major rewrite. So I am going to close this issue and as that people with problems check the latest code and open new issues if they still have problems