Search code examples
c#onvif

How to switch the state of a relay-output using the Onvif protocol


I'm currently trying to switch the state of a relay-output on several test cameras (all Onvif compliant). The confusion starts when trying to retrieve the list of relay-outputs for an Hikvision PTZ camera. I can successfully get the relay-output(it only has 1) and ask for its 'RelayLogicalState' which can be either open or closed.

For switching the relay-output I use the 'SetRelayOutputState', its parameters are the token of the relay-output to switch and a 'RelayLogicalState'. Since there is only 1 relay-output I can only send that token, the 'RelayLogicalState' is an enum of 2 items (active or inactive) not much to do wrong here. I can switch the state of the relay-output but when calling 'GetrelayOutputs' again to check its state this function will always set the input to 'inactive'.

For BOSCH I can retrieve the relay-output again only 1 is present but calling 'SetRelayOutputState' does nothing with either of the 2 'RelayLogicalState' when called.

For reference: http://www.onvif.org/ver10/deviceio.wsdl

Both cameras have the latest firmware installed and according to the Onvif Device Manager both use Onvif version 2.0.

    private void OutputLowButton_Click(object sender, EventArgs e)
    {
        if (relayOutputs != null)
        {
            //only 1 present so we take the first for this example
            var output = relayOutputs.First();
            execute(() => IOClient.SetRelayOutputState(output.token, RelayLogicalState.inactive));
        }
    }
    private void OutputHighButton_Click(object sender, EventArgs e)
    {
        if (relayOutputs != null)
        {
            //only 1 present so we take the first for this example
            var output = relayOutputs.First();
            execute(() => IOClient.SetRelayOutputState(output.token, RelayLogicalState.active)); 
        }
    }
    private void OutputStateButton_Click(object sender, EventArgs e)
    {
        //only 1 present so we take the first for this example
        var relayOutputs = execute(() => IOClient.GetRelayOutputs());
        if(relayOutputs != null)
            MessageBox.Show(relayOutputs.First().Properties.IdleState.ToString());
    }

EDIT

Eventually I got it working in the following manner:

 relayOutput.Properties.Mode = Onv_Device_Management.RelayMode.Bistable;
            relayOutput.Properties.IdleState = Onv_Device_Management.RelayIdleState.open;
            TryCatch(() => deviceClient.SetRelayOutputSettingsAsync(relayOutput.token, relayOutput.Properties));
            TryCatch(() => deviceClient.SetRelayOutputState(relayOutput.token, Onv_Device_Management.RelayLogicalState.active));

Solution

  • I had some problem with that too. There is another onvif function called SetRelayOutputSettings. You have couple of settings there:

    idleState
    open/close
    delayTime
    time when if mode is "monostable" it will come back to idleState
    Mode
    bistable - you have to handle changing state by yourself
    monostable - after you set state, it will come back to idleState after "delayTime"

    Of course you have to deliver Token there also. Still to solve problem I had to call functions in this sequence(pseudocode I am not c#):

    void SetState(string token, bool bOpen) // true if high, false if low
    {
       SetRelayOutputSettings(token, bOpen, "bistable", 20);
       SetRelayOutputState(token, "active");
       SetRelayOutputState(token, "inactive");
    }
    

    Hope that help you.