public DataDescription[] GetSubItems()
        {
            Log.Debug($"GetSubItems called on path {Path}");

            if (Path == null || Path == OPCEventFlowBehavior.SNAPSHOT_DATA) // If we're at the top, just return all server names:
            {
                return(opcServerOrm.Fetch()
                       .Select(x => new DataDescription(typeof(OPCDataProvider), x.GetEntity().EntityName, false)
                {
                    NestedVariableName = x.GetEntity().EntityName
                }).ToArray());
            }

            string[] pathSplit = Path.Split(new char[] { '.' }, 2); // {Server Name}.{remaining.tag.path}

            DynamicORM orm = new DynamicORM();

            HashSet <string>       nextPaths = new HashSet <string>();
            List <DataDescription> dds       = new List <DataDescription>();

            foreach (string key in OPCEngine.mostRecentValues.Keys) // keys are like "<guid>|Channel1.Device1.Tag1"
            {
                string[] keySplit   = key.Split('|');
                string   eventId    = keySplit[0];
                string   keyTagPath = keySplit[1];
                OPCEvent ev         = orm.Fetch(typeof(OPCEvent), eventId) as OPCEvent;
                if (ev == null)
                {
                    throw new Exception("OPCEvent not found with id " + eventId);
                }
                string serverName = (orm.Fetch(typeof(Folder), ev.EntityFolderID) as Folder)?.EntityName;
                if (string.IsNullOrEmpty(serverName))
                {
                    throw new Exception("Server name not found");
                }

                if (serverName != pathSplit[0])
                {
                    continue;
                }

                if (pathSplit.Length == 1) // This is the node for the server, so include everything under it:
                {
                    nextPaths.Add(keyTagPath.Split('.')[0]);
                }
                else
                {
                    // If "Channel1.Device1.Tag1" starts with "Channel1.Device1", for example:
                    if (keyTagPath.StartsWith(pathSplit[1]))
                    {
                        string   remainingPath  = keyTagPath.Substring(pathSplit[1].Length + 1); // "Tag1"
                        string[] splitRemaining = remainingPath.Split('.');
                        if (splitRemaining.Length == 1)                                          // This is a tag, so find its type
                        {
                            BaseTagValue tagValue;
                            if (!OPCEngine.mostRecentValues.TryGetValue(key, out tagValue))
                            {
                                throw new Exception("Could not find type for tag " + key);
                            }

                            if (dds.Any(d => d.Name == splitRemaining[0])) // Don't create duplicates - most recent value will be used.
                            {
                                continue;
                            }

                            DataDescription dd = TagValueUtils.GetDataDescriptionFromTagType(tagValue.GetType(), splitRemaining[0]);
                            dd.NestedVariableName = $"{this.Path}.{splitRemaining[0]}";
                            dds.Add(dd);
                        }
                        else
                        {
                            nextPaths.Add(splitRemaining[0]);
                        }
                    }
                }
            }

            foreach (string nextPath in nextPaths)
            {
                dds.Add(new DataDescription(typeof(OPCDataProvider), nextPath, false)
                {
                    NestedVariableName = $"{this.Path}.{nextPath}"
                });
            }

            return(dds.ToArray());
        }
Example #2
0
        private void SetValues(string opcServerUrl, string eventId, BaseTagValueWrapper valuesWrapper)
        {
            BaseTagValue[] values = valuesWrapper.Values;
            using (UserContextHolder.Register(new SystemUserContext()))
            {
                Folder configFolder = EntityCache <OPCServerFolderBehaviorData> .GetCache().AllEntities.FirstOrDefault(s => s.Url == opcServerUrl)?.GetEntity() as Folder;

                if (configFolder == null)
                {
                    return;
                }

                Array.ForEach(values, tagValue => { LOG.Debug($"Value Change: {tagValue.Path} - {TagValueUtils.GetObjectValueFromTag(tagValue)}"); });

                // put values in last cache
                foreach (var v in values)
                {
                    string       key = eventId + "|" + v.Path;
                    BaseTagValue priorValue;
                    OPCEngine.mostRecentValues.TryGetValue(key, out priorValue);

                    OPCEngine.mostRecentValues[key] = v;

                    if (priorValue == null)
                    {
                        OPCEngine.priorValues[key] = v;
                    }
                    else
                    {
                        OPCEngine.priorValues[key] = priorValue;
                    }
                }

                OPCEvent opcEvent = opcEventOrm.Fetch(eventId);
                if (opcEvent == null || opcEvent.Disabled)
                {
                    return;
                }

                bool runIt = false;
                // see if this event is interested in this change
                foreach (var v in opcEvent.EventValues)
                {
                    if (values.FirstOrDefault(changedValue => changedValue.Path == v.PathToValue) != null)
                    {
                        runIt = true;
                        break;
                    }
                }

                if (runIt)
                {
                    try
                    {
                        List <DataPair> inputs = new List <DataPair>();

                        foreach (var v in opcEvent.EventValues)
                        {
                            string       key   = eventId + "|" + v.PathToValue;
                            BaseTagValue value = null;

                            OPCEngine.mostRecentValues.TryGetValue(key, out value);

                            inputs.Add(new DataPair(v.Name, value));

                            BaseTagValue priorvalue = null;

                            OPCEngine.priorValues.TryGetValue(key, out priorvalue);

                            inputs.Add(new DataPair("Last " + v.Name, priorvalue));
                        }

                        inputs.Add(new DataPair("LastWorkflowRun", opcEvent.LastRun));

                        // check rule to see if it matches
                        var ruleResult = RuleEngine.RunRule(opcEvent.Rule, inputs.ToArray());

                        if (ruleResult != null && ruleResult is bool)
                        {
                            if (((bool)ruleResult) == true)
                            {
                                new Log("OPC").Error("Value Changed And Rule Returned True - running flow");
                                FlowEngine.Start(FlowEngine.LoadFlowByID(opcEvent.Flow, false, true),
                                                 new FlowStateData(inputs.ToArray()));
                            }
                            else
                            {
                                new Log("OPC").Error("Value Changed But Rule Returned False");
                            }
                        }
                        else
                        {
                            new Log("OPC").Error("Value Changed But Rule Returned False");
                        }
                    }
                    catch (Exception except)
                    {
                        new Log("OPC").Error(except, "Error running flow from event");
                    }
                }
            }
        }