public override DataDescription[] ProcessInputDeclaration(Rule flow, DataDescription[] inputData) { var id = flow.Source?.ComponentRegistrationId?.Split('.').FirstOrDefault(); if (id != null) { ORM <OPCEvent> orm = new ORM <OPCEvent>(); var e = orm.Fetch(id); if (e != null) { List <DataDescription> output = new List <DataDescription>(); foreach (var ev in e.EventValues) { Type tagType = TagValueUtils.GetTagValueType(TypeUtilities.FindTypeByFullName(ev.TypeName)); output.Add(new DataDescription(tagType, ev.Name)); output.Add(new DataDescription(tagType, "Last " + ev.Name)); } output.Add(new DataDescription(typeof(DateTime), "LastWorkflowRun")); output.AddRange(base.ProcessInputDeclaration(flow, inputData)); return(output.ToArray()); } } return(base.ProcessInputDeclaration(flow, inputData)); }
public ResultData Run(StepStartData data) { object value = data.Data[VALUE_INPUT]; OPCTag tag; string serverUrl; if (chooseTagAtRuntime) { string tagPath = data.Data[TAG_INPUT] as string; serverUrl = data.Data[SERVER_URL_INPUT] as string; if (string.IsNullOrEmpty(tagPath)) { throw new Exception("No tag specified"); } if (string.IsNullOrEmpty(serverUrl)) { throw new Exception("No server URL specified"); } tag = EntityCache <OPCTag> .GetCache().AllEntities.FirstOrDefault(x => x.Path == tagPath && x.ServerUrl == serverUrl); if (tag == null) { throw new Exception($"No tag found at '{tagPath}' on server '{serverUrl}'"); } } else { tag = EntityCache <OPCTag> .GetCache().GetById(tagId); if (tag == null) { throw new Exception($"Tag '{tagId}' not found"); } serverUrl = tag.ServerUrl; } BaseTagValue tagValue = TagValueUtils.GetTagWithValue(TypeUtilities.FindTypeByFullName(tag.TypeName), value); tagValue.Path = tag.Path; OPCServerFolderBehaviorData folderExt = EntityCache <OPCServerFolderBehaviorData> .GetCache().AllEntities.FirstOrDefault(s => s.Url == serverUrl); Folder folder = folderExt?.GetEntity() as Folder; if (folder == null) { throw new Exception($"No server folder configured for URL '{serverUrl}'."); } OPCEngine.SetTagValues(serverUrl, folderExt.AgentId, new BaseTagValue[] { tagValue }); return(new ResultData(PATH_DONE, new KeyValuePair <string, object>[] { })); }
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()); }
public object GetValue(string name) { Log.Debug($"GetValue called on path {Path}"); if (Path == null || !Path.Contains(".")) { // If at the top, or at a server, the next part can't be a tag: string nextPath = (Path == null) ? name : $"{Path}.{name}"; return(new OPCDataProvider { Path = nextPath, Snapshot = this.Snapshot }); } string[] pathSplit = Path.Split(new char[] { '.' }, 2); // {Server Name}.{remaining.tag.path} Folder folder = opcServerOrm.Fetch().Select(ext => ext.GetEntity()).FirstOrDefault(f => f.EntityName == pathSplit[0]) as Folder; if (folder == null) { throw new Exception($"Could not find server named {pathSplit[0]}"); } string[] eventIds = FolderService.GetFolderEntities <OPCEvent>(folder.FolderID).Select(e => e.Id).ToArray(); BaseTagValue mostRecentTag = null; IDictionary <string, BaseTagValue> sourceDict = ((Snapshot as IDictionary <string, BaseTagValue>) ?? OPCEngine.mostRecentValues); foreach (string eventId in eventIds) { string key = $"{eventId}|{pathSplit[1]}.{name}"; BaseTagValue tag; if (sourceDict.TryGetValue(key, out tag)) { if (mostRecentTag == null || mostRecentTag.TimeStamp < tag.TimeStamp) { mostRecentTag = tag; } } } if (mostRecentTag != null) { return(TagValueUtils.GetObjectValueFromTag(mostRecentTag)); } // No current value found, so check folders to see whether this is a folder or a tag: Folder tagDataFolder = folder.GetSubFolder().FirstOrDefault(x => x.EntityName == "Tag Data"); if (tagDataFolder == null) { throw new Exception("Tag data folder not found"); } string[] parts = pathSplit[1].Split('.'); Folder currentFolder = tagDataFolder; for (int i = 0; i < parts.Length; ++i) { // descend for each part, arriving at the folder which should contain the named entity Folder nextFolder = currentFolder.GetSubFolder().FirstOrDefault(x => x.EntityName == parts[i]); if (nextFolder == null) { throw new Exception($"Folder '{parts[i]}' not found in folder '{currentFolder?.EntityName}'."); } currentFolder = nextFolder; } Folder namedFolder = FolderService.GetFolderEntities <Folder>(currentFolder.FolderID).FirstOrDefault(x => x.EntityName == name); if (namedFolder != null) { return new OPCDataProvider { Path = $"{this.Path}.{name}", Snapshot = this.Snapshot } } ; OPCTag namedTag = FolderService.GetFolderEntities <OPCTag>(currentFolder.FolderID).FirstOrDefault(x => x.EntityName == name); if (namedTag != null) { throw new Exception($"Tag '{name}' has no known value"); } else { throw new Exception($"No tag or folder '{name}' found in '{currentFolder.EntityName}'"); } }
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"); } } } }