public override bool CreateUX() { if (mIsUXInitCalled) { return(false); } mIsUXInitCalled = true; base.CreateUXBase("Mesh Receiver"); if (MyForm != null) { MyForm.DeleteByOrder(11); MyForm.DeleteByOrder(24); //Removes the ADDRES Field from the Form //TheNMIEngine.AddSmartControl(MyBaseThing, MyForm, eFieldType.CollapsibleGroup, 40, 2, 0xC0, "Advanced Configurations...", null, ThePropertyBag.Create(new nmiCtrlCollapsibleGroup() { DoClose = true }));//() { "TileWidth=6", "Format=Advanced Configurations", "Style=font-size:26px;text-align: left" }); //TheNMIEngine.AddSmartControl(MyBaseThing, MyForm, eFieldType.Password, 41, 7, 0xC0, "Connection String", TheAzureConnectionHelper.strConnectionString, new ThePropertyBag() { "ParentFld=40", "TileWidth=6", "TileHeight=1", "HideMTL=true" }); //TheNMIEngine.AddSmartControl(MyBaseThing, MyForm, eFieldType.SingleEnded, 42, 7, 0xC0, "Event Hub Name", TheAzureConnectionHelper.strEventHubName, new ThePropertyBag() { "ParentFld=40", "TileWidth=6", "TileHeight=1" }); //TheNMIEngine.AddSmartControl(MyBaseThing, MyForm, eFieldType.SingleEnded, 43, 0, 0xC0, "Event Hub Address:", "Address", new ThePropertyBag() { "ParentFld=40", "TileHeight=1", "TileWidth=6" }); //TheNMIEngine.AddSmartControl(MyBaseThing, MyForm, eFieldType.SingleEnded, 44, 7, 0xC0, "Consumer Group", strConsumerGroup, new ThePropertyBag() { "ParentFld=40", "TileWidth=6", "TileHeight=1" }); //TheNMIEngine.AddSmartControl(MyBaseThing, MyForm, eFieldType.Password, 45, 7, 0xC0, "Storage Connection String (Checkpoints)", strStorageConnectionString, new ThePropertyBag() { "ParentFld=40", "TileWidth=6", "TileHeight=1", "HideMTL=true" }); //TheNMIEngine.AddSmartControl(MyBaseThing, tMyForm, eFieldType.SingleCheck, 46, 3, 0xC0, "Preserve Order for all Things", "PreserveSendOrderAllThings", new ThePropertyBag() { "TileWidth=6", "TileHeight=1" }); TheNMIEngine.AddSmartControl(MyBaseThing, MyForm, eFieldType.ComboBox, 24, 2, 0xC0, "Receiver Event Converter", nameof(ReceiverEventConverter), new nmiCtrlComboBox { ParentFld = 20, DefaultValue = TheEventConverters.GetDisplayName(typeof(JSonObjectEventConverter)), Options = TheEventConverters.GetDisplayNamesAsSemicolonSeperatedList() }); TheNMIEngine.AddSmartControl(MyBaseThing, MyForm, eFieldType.SingleEnded, 30, 2, 0xC0, "Property for Sender Time:", nameof(SenderTimePropertyName), new ThePropertyBag() { "ParentFld=20", "TileHeight=1", "TileWidth=6" }); TheNMIEngine.AddSmartControl(MyBaseThing, MyForm, eFieldType.SingleEnded, 40, 2, 0xC0, "Property for Time Drift:", nameof(TimeDriftPropertyName), new ThePropertyBag() { "ParentFld=20", "TileHeight=1", "TileWidth=6" }); #if CDEPUBSUB TheNMIEngine.AddSmartControl(MyBaseThing, MyForm, eFieldType.SingleEnded, 45, 2, 0xC0, "PubSub Topic", nameof(PubSubTopic), new ThePropertyBag() { "ParentFld=20", "TileHeight=1", "TileWidth=6" }); #endif //TheNMIEngine.AddSmartControl(MyBaseThing, MyForm, eFieldType.Number, 310, 0, 0, "Last Received", nameof(LastReceiveTime), new ThePropertyBag() { "ParentFld=300", "TileHeight=1", "TileWidth=6", "FldWidth=4" }); mIsUXInitialized = true; return(true); } return(false); }
public override void CreateUXBase(string formTitle) { base.CreateUXBase(formTitle); // KPI Form //tKPIForm = new TheFormInfo(TheThing.GetSafeThingGuid(MyBaseThing, "AzureKPI_ID"), eEngineName.NMIService, "Azure Receiver: KPIs", tDataSource) { IsNotAutoLoading = true }; //var tFlds = TheNMIEngine.AddStandardForm(MyBaseThing, MyBaseThing.FriendlyName, 18, "AzureKPI_ID"); //var tKPIForm = tFlds["Form"] as TheFormInfo; //(tFlds["DashIcon"] as TheDashPanelInfo).PropertyBag=new ThePropertyBag() { "Visibility=false" }; TheNMIEngine.AddSmartControl(MyBaseThing, MyForm, eFieldType.CollapsibleGroup, 300, 2, 0, String.Format("Receiver KPIs: {0}", MyBaseThing.FriendlyName), null, new nmiCtrlCollapsibleGroup() { DoClose = true, ParentFld = 3, TileWidth = 6, IsSmall = true }); TheNMIEngine.AddFields(MyConnectionThingsForm, new List <TheFieldInfo> { new TheFieldInfo() { FldOrder = 13, DataItem = "EventFormat", Flags = 2, Type = eFieldType.ComboBox, Header = "Data Serializer", FldWidth = 3, PropertyBag = new ThePropertyBag() { "Options=" + TheEventConverters.GetDisplayNamesAsSemicolonSeperatedList() } }, }); TheNMIEngine.AddSmartControl(MyBaseThing, MyForm, eFieldType.Number, 308, 0, 0, "Events Received", nameof(ReceiveCount), new ThePropertyBag() { "ParentFld=300", "TileHeight=1", "TileWidth=6", "FldWidth=4" }); TheNMIEngine.AddSmartControl(MyBaseThing, MyForm, eFieldType.DateTime, 309, 0, 0, "Last Receive", nameof(LastReceiveTime), new ThePropertyBag() { "ParentFld=300", "TileHeight=1", "TileWidth=6", "FldWidth=4" }); TheNMIEngine.AddSmartControl(MyBaseThing, MyForm, eFieldType.Number, 310, 0, 0, "Receive Errors", nameof(ReceiveErrorCount), new ThePropertyBag() { "ParentFld=300", "TileHeight=1", "TileWidth=6", "FldWidth=4" }); // Add link to KPIs to AzureConnection form //TheNMIEngine.AddSmartControl(MyBaseThing, MyForm , eFieldType.TileButton, 12, 2, 0xF0, "Show KPIs", null, new nmiCtrlTileButton() { ParentFld=3, NoTE=true, OnClick=$"TTS:{tKPIForm.cdeMID}", ClassName="cdeTransitButton" }); }
private bool ProcessMessage(string correlationToken, string eventConverterName, DateTimeOffset messageTime, string messagePayload, string originator, bool bIsTargetedMessage, out string error, out bool bSendAck) { bool bSuccess = false; bSendAck = true; if (bIsTargetedMessage) { if (_nodeOwnerManager.RegisterOwnerCandidate(correlationToken, originator, TheBaseAssets.MyServiceHostInfo.MyDeviceInfo.DeviceID.ToString(), true)) { var notification = new TSM(MyBaseEngine.GetEngineName(), $"MESHRECEIVER_ACK_NOTIFY:;:{correlationToken}:;:{originator}:;:{bIsTargetedMessage}"); TheCommCore.PublishCentral(notification, false); } } else { if (_nodeOwnerManager.CheckOwner(originator, TheBaseAssets.MyServiceHostInfo.MyDeviceInfo.DeviceID.ToString()) != true) { _nodeOwnerManager.RequestOwnership(correlationToken, originator, TheBaseAssets.MyServiceHostInfo.MyDeviceInfo.DeviceID.ToString()); } } IEventConverter eventConverter = null; if (!string.IsNullOrEmpty(eventConverterName)) { eventConverter = TheEventConverters.GetEventConverter(eventConverterName); if (eventConverter == null) { TheBaseAssets.MySYSLOG.WriteToLog(180001, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("Mesh Receiver", $"Unknown event converter in incoming MESHSENDER_DATA {this.MyBaseThing.FriendlyName}: {eventConverterName}", eMsgLevel.l1_Error, TSM.L(eDEBUG_LEVELS.OFF) ? null : messagePayload)); } } else { eventConverter = TheEventConverters.GetEventConverter(ReceiverEventConverter); if (eventConverter == null) { TheBaseAssets.MySYSLOG.WriteToLog(180002, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("Mesh Receiver", $"Unknown default event converter {this.MyBaseThing.FriendlyName}: {ReceiverEventConverter}", eMsgLevel.l1_Error)); } } //if (EnableDataLogging) //{ // try // { // lock (dataLoggerLock) // { // System.IO.File.AppendAllText("meshreceiverdata.log", $"{{\"TimeReceived\":\"{DateTimeOffset.Now:O}\", \"PLS\": {pMsg.Message.PLS},\"TXT\":{pMsg.Message.TXT}}},\r\n"); // } // } // catch (Exception e) // { // TheBaseAssets.MySYSLOG.WriteToLog(180003, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM("Mongo Writer", $"Unable to log data to file: {this.MyBaseThing.FriendlyName}", eMsgLevel.l3_ImportantMessage, e.ToString())); // } //} if (eventConverter == null) { error = "Unknown event converter"; } else { if (IsConnected) { try { var now = DateTimeOffset.Now; if (!string.IsNullOrEmpty(TimeDriftPropertyName)) { // Calculate time difference (in minutes) between the sender and this node var timeDrift = now - messageTime; timeDrift = TimeSpan.FromMinutes(timeDrift.TotalMinutes > 0 ? Math.Floor(timeDrift.TotalMinutes) : Math.Ceiling(timeDrift.TotalMinutes)); if (eventConverter.StaticPropsToAdd == null) { eventConverter.StaticPropsToAdd = new Dictionary <string, object>(); } eventConverter.StaticPropsToAdd[TimeDriftPropertyName] = System.Xml.XmlConvert.ToString(timeDrift); } if (!string.IsNullOrEmpty(SenderTimePropertyName)) { if (eventConverter.StaticPropsToAdd == null) { eventConverter.StaticPropsToAdd = new Dictionary <string, object>(); } eventConverter.StaticPropsToAdd[SenderTimePropertyName] = messageTime; } bool bDetectedOtherOwner = false; // TODO Support picking a thing for formats that don't carry a thing id eventConverter.NewThingCallback = async(t) => { if (await _nodeOwnerManager.CheckOwnerAsync(correlationToken, originator, TheBaseAssets.MyServiceHostInfo.MyDeviceInfo.DeviceID.ToString()).ConfigureAwait(false) == false) { bDetectedOtherOwner = true; return(false); } return(true); }; error = eventConverter.ProcessEventData(null, messagePayload, now); if (bDetectedOtherOwner) { error = "Detected other receiver"; bSendAck = false; bSuccess = false; } else { if (String.IsNullOrEmpty(error)) { ReceiveCount++; bSuccess = true; } else { TheBaseAssets.MySYSLOG.WriteToLog(180004, new TSM("Mesh Receiver", "Error processing data", eMsgLevel.l1_Error, error)); ReceiveErrorCount++; } LastReceiveTime = now; } } catch (Exception e) { error = "Error parsing data: " + e.Message; TheBaseAssets.MySYSLOG.WriteToLog(180005, new TSM("Mesh Receiver", "Error processing data", eMsgLevel.l1_Error, e.ToString())); bSuccess = false; ReceiveErrorCount++; } if (bSuccess) { MyBaseThing.StatusLevel = 1; } } else { error = "Not connected"; } } return(bSuccess); }
private async Task PlaybackLoop(TheThing tThingOverride, CancellationToken cancelToken, IEnumerable <object> updatesToPlay, TimeSpan startupDelayRange, bool bFromAutoStart) { var lastItemTime = DateTimeOffset.MaxValue; var previousUpdateTime = DateTimeOffset.Now; if (bFromAutoStart && AutoStartDelay > 0 && tThingOverride.FriendlyName != "ignored") // hack to delay only for real things { TheBaseAssets.MySYSLOG.WriteToLog(700, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM(MyBaseThing.EngineName, $"Playback loop for {tThingOverride?.FriendlyName} holding for {AutoStartDelay} ms.", eMsgLevel.l6_Debug)); await TheCommonUtils.TaskDelayOneEye(AutoStartDelay, 100); } TheBaseAssets.MySYSLOG.WriteToLog(700, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM(MyBaseThing.EngineName, $"Playback loop started for {tThingOverride?.FriendlyName}", eMsgLevel.l6_Debug)); if (startupDelayRange > TimeSpan.Zero) { var startupDelayInMs = (uint)startupDelayRange.TotalMilliseconds; var randomDelay = TheCommonUtils.GetRandomUInt(0, startupDelayInMs); await TheCommonUtils.TaskDelayOneEye((int)randomDelay, 100, cancelToken).ConfigureAwait(false); } var eventconverter = TheEventConverters.GetEventConverter("JSON Things", true) as JSonThingEventConverter; // These get set in the callback from ProcessEventData so we can process them afterwards List <Tuple <TheThing, TheThingStore> > updatesProcessed = new List <Tuple <TheThing, TheThingStore> >(); eventconverter.ApplyUpdateCallback = (thing, update) => { updatesProcessed.Add(Tuple.Create(thing, update)); return(false); }; eventconverter.eventDecoder = (o => o.ToString()); do { foreach (var updateObj in updatesToPlay) { updatesProcessed.Clear(); eventconverter.ProcessEventData(tThingOverride, updateObj, DateTimeOffset.Now); if (IsDisabled) { //How can a cacnel token be set? break; } if (cancelToken.IsCancellationRequested) { break; } foreach (var updateAndThing in updatesProcessed) { TimeSpan timeToWait = TimeSpan.Zero; var tThingProcessed = updateAndThing.Item1; var tThingUpdateProcessed = updateAndThing.Item2; if (PlaybackSpeedFactor > 0) { var now = DateTimeOffset.Now; var timeSinceLastUpdate = now - previousUpdateTime; var timeToNextItem = tThingUpdateProcessed.cdeCTIM - lastItemTime; if (timeToNextItem > TimeSpan.Zero && timeSinceLastUpdate < timeToNextItem) { timeToWait = timeToNextItem - timeSinceLastUpdate; if (timeToWait > TimeSpan.Zero) { if (PlaybackSpeedFactor != 1) { timeToWait = new TimeSpan(0, 0, 0, 0, (int)(timeToWait.TotalMilliseconds / PlaybackSpeedFactor)); } if (MaxItemDelay > 0 && timeToWait.TotalMilliseconds > MaxItemDelay) { timeToWait = new TimeSpan(0, 0, 0, 0, MaxItemDelay); } } else { // falling behind! } } } else if (PlaybackItemDelay > 0) { timeToWait = new TimeSpan(0, 0, 0, 0, PlaybackItemDelay); } if (timeToWait > TimeSpan.Zero) { await TheCommonUtils.TaskDelayOneEye((int)timeToWait.TotalMilliseconds, 100, cancelToken).ConfigureAwait(false); } if (cancelToken.IsCancellationRequested) { break; } lastItemTime = tThingUpdateProcessed.cdeCTIM; { var now = DateTimeOffset.Now; previousUpdateTime = now; var timeToSend = AdjustTimestamps ? now : tThingUpdateProcessed.cdeCTIM; if (tThingOverride != null) { if (tThingUpdateProcessed.PB.ContainsKey("FriendlyName")) { tThingUpdateProcessed.PB["FriendlyName"] = tThingOverride.FriendlyName; } if (tThingUpdateProcessed.PB.ContainsKey("ID")) { tThingUpdateProcessed.PB["ID"] = tThingOverride.FriendlyName; } if (tThingUpdateProcessed.PB.ContainsKey("EngineName")) { tThingUpdateProcessed.PB["EngineName"] = tThingOverride.EngineName; } if (tThingUpdateProcessed.PB.ContainsKey("DeviceType")) { tThingUpdateProcessed.PB["DeviceType"] = tThingOverride.DeviceType; } if (tThingUpdateProcessed.PB.ContainsKey("DeviceType")) { tThingUpdateProcessed.PB["DeviceType"] = tThingOverride.DeviceType; } } tThingProcessed.SetProperties(tThingUpdateProcessed.PB, timeToSend); Interlocked.Add(ref _propertyCounter, tThingUpdateProcessed.PB.Count); _lastSendTime = timeToSend; } } } } while (RestartPlayback && !cancelToken.IsCancellationRequested && !IsDisabled); TheBaseAssets.MySYSLOG.WriteToLog(700, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM(MyBaseThing.EngineName, $"Playback loop stopped for {tThingOverride?.FriendlyName}", eMsgLevel.l6_Debug)); }