How to receive data from an Event in a PlugIn?

Good day.

How are you ?

I have been able to send an Event to Milestone

and see that it has been received due to a Rule I implemented to Log it,

so I can see that the event has been received and it worked properly.

Now, I want to expand that rule to send the Event to a PlugIn,

so I can show the data received on that PlugIn interface.

Expanding the rule is easy, but receiving the data in the PlugIn is where I have no clue.

1.- How do I create a function in a PlugIn that receives the Event?

If I receive the Event, with all the XML data, I can extract the data I want from it.

2.- Is there any example that does something similar?

Thank you very much and have a nice day.

Alarm and Event Viewer sample might be helpful, please see this link -

https://doc.developer.milestonesys.com/html/index.html?base=samples/componentsamples/alarmeventviewer/readme.html&tree=tree_2.html

And ref. https://doc.developer.milestonesys.com/html/index.html?base=gettingstarted/intro_events.html&tree=tree_4.html

Good day, Rie Kito.

Thank you very much for your answer.

I was on leave last week, and this is why I am replying this late.

I have tested the Application that you referred to and checked the outcome of the Event I sent to Milestone:

As you can see, I can see that an event has been sent to Milestone,

but I could see that also in the Milestone Log using a rule I created for that:

Even if I switch the name of the tags and in the XML:

MyTypeFaceRecognitionEvent

MyFaceRecognitionAnalyticsEvent0A

CustomTagFromXML01

They do now show up in the application that you mentioned.

My actual goal is being able to recover the data I am sending with this Event.

I am sending a within this XML and I need the data I am sending with it.

That is the data I would like to show to the user.

Also, I would like to show it (the data, the AnalyticsObject) inside Milestone,

in a log or in a Plug-In, for instance.

Not in an external application like the Alarm and Event Vewer.

My goal is making this into a Plug-In.

How can I do that?

How can I show the data from an AnalyticsObject I am sending to Milestone,

or any other data in a tag in XML

or add a custom tag with the data

?

Thank you.

Hi Cristian,

Thank you for the description. Let me introduce another sample, Smart Client Overlay Graph on Event sample, it should fit for your goal. Please see this link -

https://doc.developer.milestonesys.com/html/index.html?base=samples/pluginsamples/scoverlaygraphonevent/readme.html&tree=tree_1.html

The sample will place overlays on cameras displayed in the Smart Client in live mode, when an Analytics Event is received with the camera as source.

In this sample, object would be an overlay and you can see it on Smart Client View. I hope this could be helpful.

NOTE- we will recommend you start a new plugin using MIP SDK template, this is just a sample and I assume that you might not want to use it as it is.

Hello again, Rie.

How are you?

I tried earlier in this test with the Smart Client Overlay Graph on Event I am performing on Milestone to receive the data I am sending to it via an Event.

I have been reading the code in Visual Studio, but I cannot find the function that extracts the data, with the names of the variables of that data, to draw the frame on the Video.

I saw that an Alert Event is the only one that can perform that action, automatically, since I could not find anywhere in the code where the information was received from the event.

It only sends a pre-configured location of the frame and a color.

I have tested adding more boundary boxes / frames to test if several of them can be painted at the same Time on the Video, and the result was positive.

But I want to receive the data I am sending to Milestone via an Event.

I have changed my code to send the coordinates of the points to Milestone using the Analytic Event I have designed.

I receive the Analytic Event in Milestone (Tested with a Rule that writes in the Log that an Event of my type has been received)

But I want to know the part of the code that extracts the data from the XML that is received in the Event in Milestone:

1

2

3

4

5

6

7

8

So I can build the object that creates the boundary box / frame in the video

Where can I find the code that extracts the data from an Analytics Event received by Milestone ?

How can I send the data to a plugin ? (How can a PlugIn receive the data or a complete Event?)

Maybe I should start another Post with these last two questions

EDIT:

Hello again.

Sorry for editing / double posting.

I was looking for the coordinates of the polygon in SCOverlayGraphOnEvent but I could not find them…

So I re-checked my other code and it was, in fact, in the AnalyticsEventTriggerViaLibrary code where I added the two boxes so I could receive them in Milestone.

I still do not understand how the SCOverlayGraphOnEvent extracts the parameters from the Analytics Event that was sent from AnalyticsEvetntTriggerViaLibrary.

In which part of the code does the application handle this reception?

Thank you in advance

I have found these parts of the code in Smart Client Overlay Graph on Event:

Code 1:

private void CreatePlaybackDictionary(ImageViewerAddOn imageViewerAddOn, DateTime videoTime)
        {
            CachedOverlayObjects coo;
            if (!_dicAddOnOverlayObjectsPlayback.TryGetValue(imageViewerAddOn, out coo)
                || coo.StartTime > videoTime
                || coo.EndTime < videoTime
                )
            {
                DateTime startDatetime = videoTime.AddMilliseconds(-_startCache);
                DateTime endDatetime = videoTime.AddMilliseconds(_endCache);
                if (endDatetime > DateTime.Now)
                {
                    endDatetime = DateTime.Now;
                }
 
                EventLine[] analyticsEventLines = GetAnalyticsEventList(startDatetime, endDatetime);
                if (analyticsEventLines.Length == 0)
                {
                    return;
                }
 
                CachedOverlayObjects overlayObjectList = new CachedOverlayObjects();
                overlayObjectList.OverlayObjectList = new List<OverlayObject>();
                overlayObjectList.StartTime = startDatetime;
                overlayObjectList.EndTime = endDatetime;
 
                AlarmClientManager _alarmClientManager = new AlarmClientManager();
                IAlarmClient alarmClient = _alarmClientManager.GetAlarmClient(EnvironmentManager.Instance.MasterSite.ServerId);
 
                foreach (EventLine ev in analyticsEventLines)
                {
                    BaseEvent baseevent = alarmClient.GetEvent(ev.Id);
                    overlayObjectList.OverlayObjectList.Add(new OverlayObject(baseevent, ev.Timestamp));
                }
                if (_dicAddOnOverlayObjectsPlayback.ContainsKey(imageViewerAddOn))
                {
                    _dicAddOnOverlayObjectsPlayback.Remove(imageViewerAddOn);
                }
                _dicAddOnOverlayObjectsPlayback.Add(imageViewerAddOn, overlayObjectList);
            }
        }

Code 2:

/// <summary>
        /// Draw the overlay on one specific imagevieweraddon
        /// </summary>
        /// <param name="addOn"></param>
        private void DrawGraphOverlay(ImageViewerAddOn addOn)
        {
            OverlayObject oo;
            if (!_dicAddOnOverlayObjects.TryGetValue(addOn, out oo))
            {
                return;
            }
 
            ClientControl.Instance.CallOnUiThread(() =>
            {
                List<Shape> shapes = VideoOS.Platform.Util.AnalyticsOverlayBuilder.BuildShapeOverlay(
                addOn.PaintSize.Width,
                addOn.PaintSize.Height,
                (BaseEvent)oo.EventObject
);
 
                UpdateShapeOverlay(addOn, shapes);
            });
        }

Code 3:

private EventLine[] GetAnalyticsEventList(DateTime periodStart, DateTime periodEnd)
        {
            AlarmClientManager _alarmClientManager = new AlarmClientManager();
 
            int eventCount = (int)(_startCache + _endCache) / 500;
            try
            {
                IAlarmClient alarmClient = _alarmClientManager.GetAlarmClient(EnvironmentManager.Instance.MasterSite.ServerId);
                EventLine[] events = alarmClient.GetEventLines(0, eventCount, new VideoOS.Platform.Proxy.Alarm.EventFilter()
                {
                    Conditions = new Condition[] {
                        new Condition() {
                            Operator = Operator.NotEquals,
                            Target = Target.Type,
                            Value = "System Event"
                        },
                        new Condition() {
                            Operator=Operator.LessThan,
                            Target = Target.Timestamp,
                            Value=periodEnd
                        },
                        new Condition() {
                            Operator=Operator.GreaterThan,
                            Target = Target.Timestamp,
                            Value=periodStart
                        }
                    }
                });
                return events;
            }
            catch (Exception ex)
            {
                // this will happen if for instance the Event Server cannot be contacted. Showing error each time is quite intrusive, so let's just log.
                EnvironmentManager.Instance.Log(true, nameof(OverlayGraphOnEventBackgroundPlugin), "Exception thrown: " + ex.Message);
                return new EventLine[] { };
            }
        }

It seems like Code 1 checks wether one of the AnalyticsEvent objects should be analysed and, if it is in the proper Time frame, add it to a dictionary to present it in the Visor

(_dicAddOnOverlayObjectsPlayback.Add(imageViewerAddOn, overlayObjectList):wink:

On Code 2, a new shape is added to a list of the VideoOS.Platform, if there is any value in the list contained by the object addOn.

But also, it defines the Width and the Height of the object as can be seen in Line 15:

    _List<Shape> shapes = VideoOS.Platform.Util.AnalyticsOverlayBuilder.BuildShapeOverlay(_

addOn.PaintSize.Width,

addOn.PaintSize.Height,

(BaseEvent)oo.EventObject

);

It is the only place I have seen that data involving a shape of a box or a frame might be implied

And, inside Code 3, it seems that it recovers the list of Analytic Events but no parameters of them are represented there, only if they are between a Time frame.

I will keep on reading the code trying to understand it, but I still cannot find where the data received from the Analytics Event is handled in Smart Client Overlay Graph on Event to draw the frame on the video, and I feel confused.

Would you mind pointing me in the right direction, please?

Thank you

Edit: Typo

Please put a break point on the line 94 around (see // Break point HERE in below code) in OverlayGraphOnEventBackgroundPlugin.cs

private object NewEventIndicationMessageHandler(VideoOS.Platform.Messaging.Message message, FQID dest, FQID source)
        {
            try
            {
                AnalyticsEvent evAnalyt = message.Data as AnalyticsEvent;
                if (evAnalyt != null)
                {
                    DrawGraphOverlays(evAnalyt);  // Break point HERE
                }
            }

You will see evAnalyt – ObjectList - Items[0] - Polygon.PointList. That is what you can get from an analytics event when you trigger it.

FYI – Maybe you have already known how to debug your plugin but let me add this link -

https://developer.milestonesys.com/s/article/debugging-techniques-for-Smart-Client-plugins

Hello again.

How are you?

I have checked what you mentioned about line 94

If I use the Smart Client Overlay Graph on Event sample with the application AnalyticsEventTriggerViaLibrary , the flow of the program stops in that line as you mentioned, and I can check the data that there is in that ObjectList.

But, when I send a complete XML using my own function:

"<AnalyticsEvent xmlns:i=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns=\"urn:milestone-systems\">
	<EventHeader>
		<ID>00000000-0000-0000-0000-000000000000</ID>
		<Timestamp>123.456</Timestamp>
		<Type>MyTypeFaceRecognitionEvent</Type>
		<!-- Insert Event Message here -->
		<Message>MyAnalyticsEvent01</Message>
		<CustomTag>CustomTagFromXML01</CustomTag>
		<Source>
			<!-- Insert camera URI here, if you don't have the GUID. -->
			<!-- (For multichannel devices, URI may contain channel number after ',') -->
			<Name>192.168.0.199</Name>
		</Source>
	</EventHeader>
 
	<Description>
		Event from my own code
	</Description>
	<Location>
		Event location 2
	</Location>
	<Vendor>
		<Name>My Smart Camera</Name>
	</Vendor>
	<ObjectList>
		<AnalyticsObject>
			<Name>AnalyticsObjectName</Name>
			<AlarmTrigger>AnalyticsObjectAlarmTrigger</AlarmTrigger>
			<Value>AnalyticsObjectValue</Value>
			<Confidence>0.987</Confidence>
			<Description>ABC PepitoGrillo</Description>
			<IdEmpleado>PepitoGrillo</IdEmpleado>
			<IdCamera>ABC</IdCamera>
			<!--\t\t<Facex>AnalyticsObjectFacex</Facex>\t\t<Facey>AnalyticsObjectFacey</Facey>\t\t<Faceheight>AnalyticsObjectFaceheight</Faceheight>\t\t<Facewidth>AnalyticsObjectFacewidth</Facewidth>\t\t-->
			<Polygon>
				<Color>
					<A>255</A>
					<R>0</R>
					<G>255</G>
					<B>255</B>
				</Color>
				<PointList>
					<TPoint>
						<X>0,1875</X>
						<Y>0,375</Y>
					</TPoint>
					<TPoint>
						<X>0,225</X>
						<Y>0,375</Y>
					</TPoint>
					<TPoint>
						<X>0,225</X>
						<Y>0,441666666666667</Y>
					</TPoint>
					<TPoint>
						<X>0,1875</X>
						<Y>0,441666666666667</Y>
					</TPoint>
					<TPoint>
						<X>0,1875</X>
						<Y>0,375</Y>
					</TPoint>
				</PointList>
			</Polygon>
		</AnalyticsObject>
	</ObjectList>
</AnalyticsEvent>"

This is the XML I am sending using the funcition:

string response = SendXmlWithSocket(
                                      myXML, // The String provided in the code before
                                      destinationAddress_param,
                                      Convert.ToInt32(destinationPort_param)
                                  );

And that function is the one that is provided in one of the samples:

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
        private static string SendXmlWithSocket(string xmlMessage, string hostname, int port)
        {
            byte[] receiveData = new byte[1024];
            int length;
            using (Socket socket = ConnectSocket(hostname, port))
            {
                if (socket == null)
                {
                    return "Unable to contact server";
                }
                socket.SendTimeout = 10000;
                socket.ReceiveTimeout = 10000;
 
                // Add HTTP header to Analytics event XML
                string data = string.Format(
                    "POST / HTTP/1.1\r\n" +
                    "Content-Type: text/xml\r\n" +
                    "Content-Length: {0}\r\n" +
                    "Connection: Keep-Alive\r\n\r\n{1}",
                    Encoding.UTF8.GetByteCount(xmlMessage), xmlMessage);
 
                // Send XML
                try
                {
                    length = socket.Send(Encoding.UTF8.GetBytes(data));
                }
                catch (SocketException e)
                {
                    string msg = string.Format("SocketException ({0}): {1}", e.SocketErrorCode, e.Message);
                    if (e.InnerException != null)
                    {
                        msg += Environment.NewLine + "InnerException: " + e.InnerException.Message;
                        //MessageBox.Show("Error sending analytics event to event server: " + msg);
                    }
                    return "Error sending analytics event to event server: " + msg;
                }
 
                try
                {
                    length = socket.Receive(receiveData);
                }
                catch (SocketException e)
                {
                    string msg = string.Format("SocketException ({0}): {1}", e.SocketErrorCode, e.Message);
                    if (e.InnerException != null)
                    {
                        msg += Environment.NewLine + "InnerException: " + e.InnerException.Message;
                    }
                    //MessageBox.Show("Error receiving reply from event server: " + msg);
                    return "Error receiving reply from event server: " + msg;
                }
            }
 
            // Check response
            string contentsSeparator = "\r\n\r\n";
            string response = Encoding.UTF8.GetString(receiveData, 0, length);
            Match headerMatch = Regex.Match(response, @"^HTTP/(?<version>[\d\.]+) (?<code>\d+) (?<message>[\w\s]+)\r\n");
            Match contentMatch = Regex.Match(response, @"^Content-Length: (?<length>\d+)\r\n", RegexOptions.Multiline);
            int responseIdx = response.IndexOf(contentsSeparator);
 
            if (!headerMatch.Success || !contentMatch.Success || responseIdx == -1)
            {
                return "Unknown response: " + response;
            }
 
            int contentLength = Int32.Parse(contentMatch.Groups["length"].Value);
            int returnCode = Int32.Parse(headerMatch.Groups["code"].Value);
            string message = headerMatch.Groups["message"].Value;
            string content = response.Substring(responseIdx + contentsSeparator.Length, contentLength);
 
            switch (returnCode)
            {
                case 200:
                    // Fail on unknown event message. Ignore all other warnings...
                    if (content.Contains("Warning: Event message not known"))
                    {
                    }
                    else
                    {
                    }
                    break;
                case 400:
                    break;
                case 403:
                    break;
                case 500:
                    break;
                default:
                    break;
            }
 
            Debug.WriteLine("Socket receive: " + response);
            return response;
        } // SendXmlWithSocket (END)
        /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

So, I am sending a formatted XML, with the parameters of an Analytics Event to Milestone, but the breakpoint of line 94 of the Plugin SCOverlayGraphOnEvent does not break the flow, so my XML is not being aknowledged as an Analytics Event.

What am I doing wrong?

Thank you very much

Can we get one step back? Can you please verify if you can see your events that you trigger? We would like to know if you can get them properly and can see them on Smart Client.

Please start Smart Client and go to Alarm Manager tab, then you will see all events that you trigger.

Sure thing

No Alarms, no triggers in this screen

But if I call with AnalyticsEventViaLibrary , since I have kept that breakpoint in line 94, it stops there.

Even when I select the Alarm Manager tab, it stops at that same breakpoint.

-

-

-

-

-

Right now, I am trying a different approach:

Instead of using this function to send my XML, that I mentioned in the previous post:

SendXmlWithSocket

I am trying the one in the AnalyticsEventViaLibrary example.

            if (EnvironmentManager.Instance == null)
            {
                VideoOS.Platform.SDK.Environment.Initialize();
            }
 
            EnvironmentManager.Instance.SendMessage(
                new VideoOS.Platform.Messaging.Message(MessageId.Server.NewEventCommand)
                { Data = myAnalyticsEvent });

The object myAnalyticsEvent is an AnalyticsEvent object I am trying to send.

But I believe that the server address is not properly set, so I am not sending the message to where I should send it to.

Where can I configure the address and port so I can send properly the event, please?

Thank you

I have modified the file OverlayGraphOnEventBackgroundPlugin.cs to add other possibilities:

Code Section 1:

private object NewEventIndicationMessageHandler(VideoOS.Platform.Messaging.Message message, FQID dest, FQID source)
        {
            try
            {
                AnalyticsEvent evAnalyt = message.Data as AnalyticsEvent;
                if (evAnalyt != null)
                {
                    DrawGraphOverlays(evAnalyt);
                }
 
                MyAnalyticsEvent myEvAnalyt = message.Data as MyAnalyticsEvent;
                if (myEvAnalyt != null)
                {
                    DrawGraphOverlays(myEvAnalyt);
                }
                BaseEvent baseEvent = message.Data as BaseEvent;
                if (baseEvent != null)
                {
                    // Habría que extraer los datos en caso de que se recibiera un tipo básico de Evento
                    // Esto sucede cuando se manda un XML directamente
                    DrawGraphOverlays(baseEvent);
                }
            }
            catch (Exception ex)
            {
                EnvironmentManager.Instance.ExceptionDialog("NewEventMessageHandler", ex);
            }
            return null;
        }

Because I relized that, when I send the proper XML file that I have generated myself, with the function:

Code Section 2:

string response = SendXmlWithSocket(
                          faceRecognitionXml,
                          destinationAddress_param,
                          Convert.ToInt32(destinationPort_param)
                      );

I receive an object of type BaseEvent in the SCOverlayOnEvent sample for the Client.

But the data received in that function is empty, there is no ObjectList that could contain my custom data, so I cannot access it either

In the Code Section 1, you can see that I have also added the chance of the data being a MyAnalyticsEvent object, which is the one that is an AnalyticsEvent object modified to contain the data I require.

But if I send that object using the function I posted in the previous post:

Code Section 3:

if (EnvironmentManager.Instance == null)
{
    VideoOS.Platform.SDK.Environment.Initialize();
}
 
EnvironmentManager.Instance.SendMessage(
    new VideoOS.Platform.Messaging.Message(MessageId.Server.NewEventCommand)
    { Data = myAnalyticsEvent }
);

Which is the code that is used in the AnalyticsEventViaLibrary sample,

I do not receive anything in the Code Section 1.

I believe there is some configuration in AnalyticsEventViaLibrary sample that configures the addres to which send the object, but I cannot find it nor configure it myself.

How can I set the proper address to where send the EventObject, MyAnalyticsEvent, to the Event server in Milestone, please?

Thank you

Please see this link. In the answer, we explained how to configure Analytics Events and how to see them.

https://developer.milestonesys.com/s/question/0D53X0000Ah8PTPSQ2/i-am-looking-to-create-an-event-in-milestone-and-trigger-it-via-api-sdk-or-other-if-there-is-an-option-the-event-will-need-to-disable-alarms-is-this-possible

Hello again, Rie

How are you?

I followed the instructions in the link you provided; but no Event shows up.

As I have stated in the previous post, when I open the AnalyticsEventTriggerViaLibrary application;

a “popup” window appears that requests the address of the server.

I believe that it configures something in the code to get the address where is sends the message to Milestone Event Server, using the function in the Code Section 3 in the previous post.

Since that code does not appear in the sample, I believe it must be inside a DLL file that it is used by it.

What code lines have been used to configure the server addresss, please?

Hi Christian,

Let’s focus on one thing at a time. Firstly, let’s forget about your code and samples. Please verify that Event functionality works and see the events that you trigger. Otherwise, your code never works.

When looking at your image of Smart Client, it seems to me, you are looking at Alarm list, not Event list.

Please start Smart Client and go to Setup and select Event on the left (see the question link that we provided, there is an image and instructions..)

​If the event list on SC will be still empty when you trigger a test event (on Management Client), then I believe that is not a SDK issue, rather installation/setup issue. However I am not 100% sure if it is not SDK, so again, please read the previous link and follow the instructions there. And please send images that you setup.

I have the application installed in Spanish for consistency with my colleagues at the company

I do not know if it is possible to change the language of the Milestone application while running it to send you screenshots in English.

As I can see, the older the trigger, the lower it is in the list.

First Trigger:

Message: MyAnalyticsEvent01

Source: 192.168.0.199

Generated using the TriggerAnalyticsEventXML application

Second Trigger:

Message: MyAnalyticsEvent01

Source: CAM03

Generated using AnalyticsEventTriggerViaLibrary

Third to Fifth Triggers:

These Elements are generated by my code:

Third Trigger:

Message: External Event

Source: MyType

Fourth Trigger:

Message: External Event

Source: TagFromXML

Fifth Trigger:

Message: External Event

Source: MyFaceRecognitionsAnalyticsEvent01

These three, have those sources (MyType, TagFromXML, MyFaceRecognitionsAnalyticsEvent01) because they are defined in my Generic Events.

But they are not found by SCOverlayGraphOnEvent, even if I added the code for different objects

private object NewEventIndicationMessageHandler(VideoOS.Platform.Messaging.Message message, FQID dest, FQID source)
        {
            try
            {
                AnalyticsEvent evAnalyt = message.Data as AnalyticsEvent;
                MyAnalyticsEvent myEvAnalyt = message.Data as MyAnalyticsEvent;
                BaseEvent baseEvent = message.Data as BaseEvent;
 
                if (evAnalyt != null)
                {
                    DrawGraphOverlays(evAnalyt);
                }
                else if (myEvAnalyt != null)
                {
                    DrawGraphOverlays(myEvAnalyt);
                }
                else if (baseEvent != null)
                {
                    // Habría que extraer los datos en caso de que se recibiera un tipo básico de Evento
                    // Esto sucede cuando se manda un XML directamente
                    DrawGraphOverlays(baseEvent);
                }
            }
            catch (Exception ex)
            {
                EnvironmentManager.Instance.ExceptionDialog("NewEventMessageHandler", ex);
            }
            return null;
        }

It is a bit confusing, because you started mentioning about Generic Events, but we have talked about Analytics Events, haven’t we? So, Generic Events and Analytics events are different, and you cannot extract data from Generic Events.

Please read this documentation, it describes quite well about Analytics events. It might be helpful to get to know about events (and alarms).

https://download.milestonesys.com/MIPSDK/Samples/TriggerAlarmFromExternal-ConceptSolution.pdf

Good day to you all.

As I stated on May 3rd of 2023:

I believe that it configures something in the code to get the address where is sends the message to Milestone Event Server, using the function in the Code Section 3 in the previous post.

It was something related to it.

The server was not configured, so we figured how it should have been done:

VideoOS.Platform.SDK.Environment.Initialize();
ServerId serverId = new ServerId(
          "XPCORS",
          "desktop-12345",
          "7563",
          new Guid("07169210-e7f4-4064-adbe-2378shdgf872")
        );
 
NetworkCredential networkCredential = System.Net.CredentialCache.DefaultNetworkCredentials;
 
string serverUri = "http://X.X.X.X/"; // Server URL, for instance, "http://myserver.com"
 
bool secureOnly = false; // Use HTTPS ?
bool masterOnly = false; // Add Master Server?
 
// Add Server to Environment
VideoOS.Platform.SDK.Environment.AddServer(
          secureOnly,
          new Uri(serverUri),
          networkCredential,
          masterOnly
        );
 
// Initialize Server
VideoOS.Platform.SDK.Environment.Login(new Uri(serverUri));
 
// Check if CurrentSite is configured properly
FQID currentSite44 = EnvironmentManager.Instance.CurrentSite;
 
FQID F = new FQID(serverId);
F.ParentId = new Guid("07169210-e7f4-4064-adbe-327299c2cc88");
F.ObjectId = new Guid("909c57cf-92c6-4f6d-bb91-1b7bf346deab");
F.Kind = new Guid("5135ba21-f1dc-4321-806a-6ce2017343c0");
 
EnvironmentManager.Instance.CurrentSite.ServerId = serverId;
EnvironmentManager.Instance.CurrentSite.ParentId = F.ParentId;
EnvironmentManager.Instance.CurrentSite.ObjectId = F.ParentId;
EnvironmentManager.Instance.CurrentSite.Kind = F.ParentId;
 
EventSource eventSource = new EventSource()
{
  //FQID = null,
  FQID = F,
  // If FQID is null, then the Name can be an IP address, and the event server will make a lookup to find the camera
  //Name = Settings.Default.MilestoneDestinationAddress
  Name = "CAM002"
};

This way, when we send the Analytics Event object to the server:

AnalyticsEvent analyticsEvent = new AnalyticsEvent();
...
EnvironmentManager.Instance.SendMessage(
  new VideoOS.Platform.Messaging.Message
    (MessageId.Server.NewEventCommand)
    { Data = analyticsEvent }
  );

And, as it is received, it is shown in the Client Alarm Management:

But the event is not received on the Milestone Server:

Anyway, now I want to extract the data from the Analytic Event I have received.

I believe I have to do this using a PlugIn.

I want to send an Object inside the Analytic Event with the data I require.

Is there a way of creating a custcom Analytic Event or adding an object inside an Analytic Event object to be sent to the server?

Thank you

Hello again.

How are you ?

Finally, I have been able to send an Analytics Event with my code to Milestone, and Milestone receives it.

How can I receive that Event inside a MIDP PlugIn ?

I mean, what is the code in the PlugIn that will allow me to use the data received inside the Analytics Event?

Thank you.

Please read my previous answer starts with [Please put a break point on the line 94 around….]

Also, this article is helpful when you debug plugins, please read this -

https://developer.milestonesys.com/s/article/debugging-techniques-for-Smart-Client-plugins