RegisterReceiver to be able to react when camera is enabled or/and disabled

Is it possible to register receiver to be able to handle situation when camera changes status from disabled to enabled and vice versa?

I have been trying with various Filters but non of them worked in a way I want.

messageReceiver = EnvironmentManager.Instance.RegisterReceiver(CameraConfigChangedHandler, new MessageIdFilter....  or KindFilter(Kind.Camera) ...etc

Also, is there a way of registering receiver for a TabPlugin, so when I change something in UI of TabPlugin proper action can be taken …

We tested following code and it worked in background class running in the Smart Client;

    ServerId serverId = EnvironmentManager.Instance.MasterSite.ServerId;
    MessageCommunicationManager.Start(serverId);
    _messageCommunication = MessageCommunicationManager.Get(serverId);
    _obj = _messageCommunication.RegisterCommunicationFilter(configChangedHandler, new VideoOS.Platform.Messaging.CommunicationIdFilter(VideoOS.Platform.Messaging.MessageId.System.SystemConfigurationChangedIndication));

It is important to understand that Smart Client does not get any information from device enable/disable automatically. If a new camera is added (or a camera that was disabled is enabled (which is the same thing from the client’s point of view)) the new camera is not available in the Smart Client.

NOTE: When you add or remove a camera (or enable/disable), Smart Client does not know what’s happened because Smart Client gets a configuration when it starts. This means that Smart Client need to be refreshed via a new login or reload configuration in order to see new cameras or remove deleted or disabled cameras.

I have tried with CommunicationFilter, but it doesn’t give me enough information. I forgot to mention in my previous post that I am interesting in “events” that occurs when you enable or disable camera in management client only. So, the idea is to register receiver in background plugin(event service) that allows me to handle events that are triggered only when camera is being enabled or disabled in management client by user.

I have tabPlugin in management client that gives additional properties to camera (associated properties), and background plugin uses those information but I need to update background part if some camera becomes disabled or enabled.

Initially, I will build a list of all items of Kind.Camera that are enabled, but if user enable/disable some camera I must update List and so on…

I don’t want to pull and iterate trough every recording server and every camera and compare,..if I can subscribe/register to receive events.

Also in a handler I need to extract data that holds i.e. FQID of item that has been enabled/disabled.

private object CameraConfigChangedHandler(Message message, FQID dest, FQID sender)

Using your suggestion I couldn’t get that information. Only message contains some date but non of that holds reference to camera that has been changed.

I played a little bit with code you provided and I got needed info.

I just build a list of FQIDs from message.Data and got ObjectId of changing item.

List<FQID> fqids = message.Data as List<FQID>;

I have to wait some time because of ConfigurationChangedDelayThread, up to 60sec if not incremented by some other changes but that’s ok - preventing changes in plugin to happen too often.

Thanks for help.

Hi Branislav,

Another option is to listen to the Server.NewEventIndication MessageId. In the video below you can see some of the events that are fired after enabling/disabling the hardware and/or camera channels. There are messages with the string “Enabled” and “Disabled” along with the camera name/ID. But as you can see, there are a lot more messages than that so you would need to filter out many more messages than you are interested in, if all you need is to know whether something is enabled/disabled.

https://youtu.be/uSwzchh4ULE

Here’s the source for the Trace-Events cmdlet shown in that video for reference. Line 78 is where you can see the NewEventIndication message being translated into the object shown in PowerShell so you can see there how the Message and source information is retrieved from the BaseEvent.EventHeader property.

using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Management.Automation;
using VideoOS.Platform;
using VideoOS.Platform.ConfigurationItems;
using VideoOS.Platform.Data;
using VideoOS.Platform.Messaging;
 
namespace MilestonePSTools.EventCommands
{
    [Cmdlet(VerbsDiagnostic.Trace, "Events")]
    [OutputType(typeof(TraceEventsMessage))]
    public class TraceEvents : ConfigApiCmdlet
    {
        private readonly BlockingCollection<Message> _messageQueue = new BlockingCollection<Message>();
 
        [Parameter]
        public SwitchParameter IncludeConfigurationChanged { get; set; }
        [Parameter]
        public SwitchParameter IncludeFailover { get; set; }
        [Parameter]
        public SwitchParameter ExcludeNewEventIndication { get; set; }
        [Parameter]
        public SwitchParameter TraceAllSites { get; set; }
        [Parameter]
        public SwitchParameter UseLocalTimestamps { get; set; }
 
        protected override void ProcessRecord()
        {
            var filters = new Dictionary<ServerId, List<object>>();
            var serverIds = new List<ServerId>();
            var commManagers = new List<MessageCommunication>();
            var messages = new List<string>();
            if (!ExcludeNewEventIndication) messages.Add(MessageId.Server.NewEventIndication);
            if (IncludeConfigurationChanged) messages.AddRange(new []{MessageId.Server.ConfigurationChangedIndication, MessageId.System.SystemConfigurationChangedIndication});
            if (IncludeFailover) messages.Add(MessageId.Server.RecorderFQIDChangedIndication);
            
            if (TraceAllSites)
            {
                serverIds.AddRange(Connection.GetSites().Select(s => s.FQID.ServerId));
            }
            else
            {
                serverIds.Add(Connection.CurrentSite.FQID.ServerId);
            }
            try
            {
                serverIds.ForEach(serverId =>
                {
                    MessageCommunicationManager.Start(serverId);
                    var msg = MessageCommunicationManager.Get(serverId);
                    commManagers.Add(msg);
                    filters.Add(serverId, new List<object>());
                    messages.ForEach(messageId => filters[serverId].Add(msg.RegisterCommunicationFilter(Receiver, new CommunicationIdFilter(messageId))));
                });
 
                Listen();
            }
            finally
            {
                foreach (var mgr in commManagers)
                {
                    filters[mgr.ServerId].ForEach(mgr.UnRegisterCommunicationFilter);
                    MessageCommunicationManager.Stop(mgr.ServerId);
                }
            }
        }
 
        private void Listen()
        {
            foreach (var message in _messageQueue.GetConsumingEnumerable())
            {
                if (_messageQueue.IsAddingCompleted) continue;
                switch (message.MessageId)
                {
                    case MessageId.Server.NewEventIndication:
                        {
                            var e = (message.Data as BaseEvent)?.EventHeader;
                            if (e == null) break;
                            var msg = new TraceEventsMessage
                            {
                                Timestamp = UseLocalTimestamps ? e.Timestamp.ToLocalTime() : e.Timestamp,
                                Message = e.Message,
                                MessageId = message.MessageId,
                                SourceId = e.Source.FQID.ObjectId,
                                SourceName = e.Source.Name
                            };
                            try
                            {
                                msg.SourceUri = e.Source.FQID.ServerId.Uri;
                            }
                            catch (UriFormatException)
                            {
                                WriteVerbose($"{nameof(UriFormatException)}: Invalid URI on {msg.Message} event.");
                            }
 
                            WriteObject(msg);
                            break;
                        }
                    case MessageId.Server.ConfigurationChangedIndication:
                        {
                            var item = Configuration.Instance.GetItem(message.RelatedFQID);
                            if (item == null) break;
                            var msg = new TraceEventsMessage
                            {
                                Timestamp = UseLocalTimestamps ? DateTime.Now : DateTime.UtcNow,
                                Message = "ConfigurationChangedIndication",
                                MessageId = message.MessageId,
                                SourceId = item.FQID.ObjectId,
                                SourceName = item.Name,
                                SourceUri = item.FQID.ServerId.Uri
                            };
                            WriteObject(msg);
                            break;
                        }
                    case "System.SystemConfigurationChangedIndication":
                        {
                            var item = Configuration.Instance.GetItem(message.RelatedFQID);
                            if (item == null) break;
                            var msg = new TraceEventsMessage
                            {
                                Timestamp = UseLocalTimestamps ? DateTime.Now : DateTime.UtcNow,
                                Message = "SystemConfigurationChangedIndication",
                                MessageId = message.MessageId,
                                SourceId = item.FQID.ObjectId,
                                SourceName = item.Name,
                                SourceUri = item.FQID.ServerId.Uri
                            };
                            WriteObject(msg);
                            break;
                        }
                    case MessageId.Server.RecorderFQIDChangedIndication:
                        {
                            var msg = new TraceEventsMessage
                            {
                                Timestamp = UseLocalTimestamps ? DateTime.Now : DateTime.UtcNow,
                                Message = "Failover",
                                MessageId = message.MessageId,
                                SourceId = message.RelatedFQID.ServerId.Id,
                            };
                            try
                            {
                                msg.SourceUri = message.RelatedFQID.ServerId.Uri;
                                var recorder = new RecordingServer(message.RelatedFQID.ServerId,
                                    $"RecordingServer[{message.RelatedFQID.ServerId.Id}]");
                                msg.SourceName = recorder.Name;
                            }
                            catch (UriFormatException)
                            {
                                WriteVerbose($"{nameof(UriFormatException)}: Invalid URI on {msg.Message} event.");
                            }
                            catch (Exception)
                            {
                                msg.SourceName = "Unknown";
                            }
                            WriteObject(msg);
                            break;
                        }
                    default:
                        {
                            var msg = new TraceEventsMessage
                            {
                                Timestamp = UseLocalTimestamps ? DateTime.Now : DateTime.UtcNow,
                                Message = message.MessageId,
                                MessageId = message.MessageId,
                                SourceId = message.RelatedFQID.ServerId.Id,
                            };
                            try
                            {
                                msg.SourceUri = message.RelatedFQID.ServerId.Uri;
                            }
                            catch (UriFormatException)
                            {
                                WriteVerbose($"{nameof(UriFormatException)}: Invalid URI on {msg.Message} event.");
                            }
                            WriteObject(msg);
                            break;
                        }
                }
            }
        }
 
        private object Receiver(Message message, FQID destination, FQID sender)
        {
            _messageQueue.Add(message);
            return null;
        }
 
        protected override void StopProcessing()
        {
            _messageQueue.CompleteAdding();
        }
    }
}

Hi Joshua,

Thank you for code, it really helped me a lot, now I implemented part of plugin in a way I initially wanted.

Best regards,

B.

That’s great, I’m glad to hear it!​