Exemplo n.º 1
0
        /// <summary>
        /// Sends the Observations to the MQTT broker
        /// </summary>
        /// <param name="sendAdditionalProperties">If true, the 'Writeable' and 'Forceable' properties will be sent in the Observation</param>
        /// <returns></returns>
        private async Task <bool> UpdateValues(SubscriptionReader si, ReadResult <SubscriptionResultItem> results, bool sendAdditionalProperties = false)
        {
            if (!results.Success)
            {
                Prompts.AddRange(results.Prompts);
                return(false);
            }

            var devices = results.DataRead.GroupBy(a => a.ValueItemChangeEvent.Id.Remove(a.ValueItemChangeEvent.Id.LastIndexOf('/')).Remove(0, 2));

            foreach (var device in devices)
            {
                var observations  = new List <Observation>();
                var deviceMessage = new IotEdgeMessage
                {
                    Format       = "rec2.3",
                    Observations = observations,
                    DeviceId     = device.Key
                };

                AddUpdatedValuesToMessage(observations, device.Key, device.ToList(), si.CachedSubscribedItems, sendAdditionalProperties);

                var messageBuilder = new MqttApplicationMessageBuilder();
                var message        = messageBuilder.WithRetainFlag().WithAtLeastOnceQoS().WithTopic(ValuePushTopic).WithPayload(deviceMessage.ToJson()).Build();
                Logger.LogTrace(LogCategory.Processor, this.Name, $"Sending Message to MQTT Broker: {deviceMessage.ToJson()}");
                await ManagedMqttClient.PublishAsync(message);
            }

            return(true);
        }
Exemplo n.º 2
0
 /// <summary>
 /// It is possible that if there is an internal timeout on the Subscription in EBO, that subscription read requests will end up returned with errors and
 /// an empty value. This attempts to resolve this, by manually getting the value of those points.
 /// </summary>
 /// <param name="si"></param>
 /// <param name="results"></param>
 private void CheckAndRetryValuesWithError(SubscriptionReader si, ReadResult <SubscriptionResultItem> results)
 {
     try
     {
         var erroredValuesToRetry = results.DataRead.Where(a => a.ValueItemChangeEvent.State == EwsValueStateEnum.Error);
         Logger.LogInfo(LogCategory.Processor, this.Name, $"Manually fetching values for {erroredValuesToRetry.Count()} objects.");
         var getValuesResponse = si.EwsConnection.GetValues(si, erroredValuesToRetry.Select(a => a.ValueItemChangeEvent.Id).ToArray());
         foreach (var value in getValuesResponse.GetValuesItems)
         {
             var resultToEdit = results.DataRead.FirstOrDefault(a => a.ValueItemChangeEvent.Id == value.Id);
             if (resultToEdit == null)
             {
                 continue;
             }
             var stateCorrect = Enum.TryParse(value.State, out EwsValueStateEnum ewsValueStateEnum);
             resultToEdit.ValueItemChangeEvent.State = stateCorrect ? ewsValueStateEnum : EwsValueStateEnum.Error;
             resultToEdit.ValueItemChangeEvent.Value = value.Value;
         }
     }
     catch (Exception ex)
     {
         Logger.LogError(LogCategory.Processor, this.Name, ex.ToJSON());
         // Intentionally doing nothing here, we don't wanna stop the processor, let's just continue.
     }
 }
Exemplo n.º 3
0
        public INamedChannelReader <T> Subscribe(string name)
        {
            lock (_channel)
            {
                if (_closed)
                {
                    throw new ChannelClosedException("Write end closed. Impossible to subscribe.");
                }

                INamedChannelReader <T> ch = new SubscriptionReader <T>(Name, name);

                return(ch);
            }
        }
Exemplo n.º 4
0
        /// <summary>
        /// Sends the Observations to the MQTT broker
        /// </summary>
        /// <param name="sendAdditionalProperties">If true, the 'Writeable' and 'Forceable' properties will be sent in the Observation</param>
        /// <returns></returns>
        private async Task <bool> UpdateValues(SubscriptionReader si, ReadResult <SubscriptionResultItem> results, bool sendAdditionalProperties = false)
        {
            if (!results.Success)
            {
                Prompts.AddRange(results.Prompts);
                return(false);
            }

            if (results.DataRead.Any(a => a.ValueItemChangeEvent.State == EwsValueStateEnum.Error))
            {
                CheckAndRetryValuesWithError(si, results);
            }

            var signalChanges = results.DataRead.GroupBy(a => a.ValueItemChangeEvent.Id.Remove(a.ValueItemChangeEvent.Id.LastIndexOf('/')).Remove(0, 2)).ToList();
            var devices       = _tempSignals.GroupBy(a => a.DatabasePath.Remove(a.DatabasePath.LastIndexOf('/')));

            foreach (var device in devices)
            {
                var observations  = new List <Observation>();
                var deviceMessage = new IotEdgeMessage
                {
                    Format       = "rec2.3",
                    Observations = observations,
                    DeviceId     = device.Key
                };
                var signalChangesForDevice = signalChanges.FirstOrDefault(a => a.Key == device.Key);
                AddUpdatedValuesToMessage(observations, device.Key, signalChangesForDevice == null || !signalChangesForDevice.ToList().Any() ? new List <SubscriptionResultItem>() : signalChangesForDevice.ToList(), si.CachedSubscribedItems, sendAdditionalProperties);

                if (deviceMessage.Observations != null && deviceMessage.Observations.Count > 0)
                {
                    var messageBuilder        = new MqttApplicationMessageBuilder();
                    var managedMessageBuilder = new ManagedMqttApplicationMessageBuilder();
                    var message = messageBuilder.WithRetainFlag().WithAtLeastOnceQoS().WithTopic(ValuePushTopic).WithPayload(deviceMessage.ToJson()).Build();
                    Logger.LogTrace(LogCategory.Processor, this.Name, $"Sending Message to MQTT Broker: {deviceMessage.ToJson()}");
                    await ManagedMqttClient.PublishAsync(managedMessageBuilder.WithApplicationMessage(message).Build());
                }
            }

            return(true);
        }
Exemplo n.º 5
0
        private async Task <bool> ReadExistingSubscriptions(List <Signal> signals)
        {
            Logger.LogTrace(LogCategory.Processor, this.Name, $"Reading existing subscriptions..");

            var activeSubscriptions          = Cache.RetrieveItem($"ActiveSubscriptions", () => new List <string>(), CacheTenantId, 0) as List <string>;
            var activeSubscriptionsToIterate = activeSubscriptions.ToList();

            foreach (var sub in activeSubscriptionsToIterate)
            {
                if (IsCancellationRequested)
                {
                    return(false);
                }
                var subscription = Cache.RetrieveItem($"ActiveSubscriptions#{sub}", CacheTenantId);
                Logger.LogDebug(LogCategory.Processor, $"Reading existing subscription: {sub}");
                try
                {
                    CheckCancellationToken();

                    var si = new SubscriptionReader
                    {
                        Address  = EboEwsSettings.Address,
                        UserName = EboEwsSettings.UserName,
                        Password = EboEwsSettings.Password,
                        SubscriptionEventType = EwsSubscriptionEventTypeEnum.ValueItemChanged,
                        SubscriptionId        = sub
                    };
                    var results = si.ReadData();
                    // Attempt to update the values by reading the subscription, if this fails return all Prompts
                    if (!await UpdateValues(si, results))
                    {
                        if (!si.IsResubscribeRequired)
                        {
                            return(false);
                        }
                        activeSubscriptions.Remove(sub);
                        Cache.DeleteItem($"ActiveSubscriptions#{sub}", CacheTenantId);
                    }

                    // It's possible that the subscription id has changed if it failed to be renewed/ updated... reset it here
                    if (si.SubsciptionChanged)
                    {
                        Logger.LogDebug(LogCategory.Processor, $"Subscription Id {sub} has changed to {si.SubscriptionId}, updating cache values to represent this");
                        activeSubscriptions.Remove(sub);
                        activeSubscriptions.Add(si.SubscriptionId);
                        Cache.DeleteItem($"ActiveSubscriptions#{sub}", CacheTenantId);
                        Cache.AddOrUpdateItem(subscription, $"ActiveSubscriptions#{si.SubscriptionId}", CacheTenantId, 0);
                    }
                }

                catch (Exception)
                {
                    activeSubscriptions.Remove(sub);
                    Cache.DeleteItem($"ActiveSubscriptions#{sub}", CacheTenantId);
                }
            }

            // Save any changes to cache
            Cache.AddOrUpdateItem(activeSubscriptions, $"ActiveSubscriptions", CacheTenantId, 0);
            return(true);
        }
Exemplo n.º 6
0
        private async Task <bool> SubscribeAndReadNew(List <Signal> signals)
        {
            Logger.LogTrace(LogCategory.Processor, this.Name, $"Creating and reading new subscriptions..");
            var activeSubscriptions = Cache.RetrieveItem($"ActiveSubscriptions", () => new List <string>(), CacheTenantId, 0) as List <string>;

            var subscribedIds = new List <string>();

            foreach (var subscription in activeSubscriptions)
            {
                var itemsToAdd = Cache.RetrieveItem <List <string> >($"ActiveSubscriptions#{subscription}", null, CacheTenantId);
                if (itemsToAdd != null)
                {
                    subscribedIds.AddRange(itemsToAdd);
                }
            }

            var unsubscribedIds = signals.Select(a => a.EwsId).Where(a => !subscribedIds.Contains(a)).ToList();

            Logger.LogDebug(LogCategory.Processor, this.Name, $"Found {unsubscribedIds.Count} points that are not currently subscribed to.");
            Logger.LogTrace(LogCategory.Processor, this.Name, $"Unsubscribed Point Ids: {unsubscribedIds.ToJSON()}");

            while (unsubscribedIds.Any())
            {
                if (IsCancellationRequested)
                {
                    return(false);
                }
                try
                {
                    var idsToSubscribeTo = unsubscribedIds.Take(MaxItemsPerSubscription).ToList();
                    CheckCancellationToken();
                    var si = new SubscriptionReader
                    {
                        Address  = EboEwsSettings.Address,
                        UserName = EboEwsSettings.UserName,
                        Password = EboEwsSettings.Password,
                        SubscriptionEventType = EwsSubscriptionEventTypeEnum.ValueItemChanged,
                        Ids = idsToSubscribeTo
                    };

                    // Attempt to update the values by reading the subscription, if this fails return all false as this could go on forever.
                    var results = si.ReadData();
                    // If all the ids we subscribed to failed, just continue on.. nothing to see here..
                    if (si.FailedSubscribedItems.Count == idsToSubscribeTo.Count)
                    {
                        return(true);
                    }
                    if (!await UpdateValues(si, results, true))
                    {
                        return(false);
                    }

                    Cache.AddOrUpdateItem(si.SubscribedItems, $"ActiveSubscriptions#{si.SubscriptionId}", CacheTenantId, 0);
                    unsubscribedIds = unsubscribedIds.Skip(MaxItemsPerSubscription).ToList();

                    activeSubscriptions.Add(si.SubscriptionId);
                    Cache.AddOrUpdateItem(activeSubscriptions, $"ActiveSubscriptions", CacheTenantId, 0);

                    // Add any prompts generated from reader to the list of prompts
                    Prompts.AddRange(si.ReadData().Prompts);

                    if (si.FailedSubscribedItems.Any())
                    {
                        Logger.LogInfo(LogCategory.Processor, this.Name, $"Some items failed to be subscribed to: {si.FailedSubscribedItems.ToJSON()}");
                    }
                }

                catch (Exception ex)
                {
                    Prompts.Add(ex.ToPrompt());
                    break;
                }
            }

            return(true);

            // TODO: How to handle subscriptions to value items that keep failing?
        }