├── _config.yml ├── libs ├── Opc.Ua.Core.dll ├── OpcComRcw.dll ├── OpcNetApi.dll ├── Opc.Ua.Client.dll ├── OpcNetApi.Com.dll └── Opc.Ua.Configuration.dll ├── odenwald-architecture.jpg ├── Odenwald.Common ├── packages.config ├── Opc │ ├── MeasurementDto.cs │ ├── OpcMetric.cs │ ├── OpcPluginConfig.cs │ └── OpcHelper.cs ├── Properties │ └── AssemblyInfo.cs ├── Util.cs └── Odenwald.Common.csproj ├── Odenwald.ConsolePlugin ├── packages.config ├── ConsolePlugin.cs ├── Properties │ └── AssemblyInfo.cs └── Odenwald.ConsolePlugin.csproj ├── Odenwald.OpcDaPlugin ├── packages.config ├── OpcDa.config ├── Properties │ └── AssemblyInfo.cs ├── Odenwald.OpcDaPlugin.csproj └── OpcDaPlugin.cs ├── Odenwald.InfluxDbPlugin ├── InfluxDb.config ├── packages.config ├── Properties │ └── AssemblyInfo.cs ├── InfluxDbPluginConfig.cs ├── InfluxDbPlugin.cs └── Odenwald.InfluxDbPlugin.csproj ├── Odenwald.KafkaConsumerPlugin ├── KafkaConsumer.config ├── packages.config ├── Properties │ └── AssemblyInfo.cs ├── KafkaConsumerPluginConfig.cs ├── KafkaConsumerPlugin.cs └── Odenwald.KafkaConsumerPlugin.csproj ├── Odenwald.KafkaProducerPlugin ├── KafkaProducer.config ├── packages.config ├── Properties │ └── AssemblyInfo.cs ├── KafkaProducerPluginConfig.cs ├── KafkaProducerPlugin.cs └── Odenwald.KafkaProducerPlugin.csproj ├── Odenwald ├── packages.config ├── Util.cs ├── Interface │ ├── IMetricsWritePlugin.cs │ ├── IMetricsReadPlugin.cs │ └── IMetricsPlugin.cs ├── Config │ ├── log4net.config │ ├── Odenwald.config │ └── OdenwaldConfig.cs ├── Odenwald.licenseheader ├── app.config ├── Properties │ └── AssemblyInfo.cs ├── PluginRegistry.cs ├── Odenwald.csproj ├── MetricValue.cs ├── Type │ ├── Types.cs │ └── types.db └── Aggregator.cs ├── Odenwald.OpcUaPlugin ├── packages.config ├── opcua.config ├── Properties │ └── AssemblyInfo.cs └── Odenwald.OpcUaPlugin.csproj ├── Odenwald.App ├── packages.config ├── OdenwaldService.Designer.cs ├── OdenwaldService.cs ├── Program.cs ├── Properties │ └── AssemblyInfo.cs ├── app.config └── Odenwald.App.csproj ├── Odenwald.Service ├── packages.config ├── OdenwaldService.Designer.cs ├── OdenwaldService.cs ├── Program.cs ├── Properties │ └── AssemblyInfo.cs ├── app.config └── Odenwald.Service.csproj ├── LICENSE ├── Tests └── Odenwald.OpcUaPluginTest │ ├── packages.config │ ├── Properties │ └── AssemblyInfo.cs │ ├── Odenwald.OpcUaPluginTest.csproj │ └── OpcUaClientTest.cs ├── README.md ├── .gitattributes ├── .gitignore ├── Odenwald.WindowsPerformanceCounterPlugin └── Config │ └── WindowsPerformanceCounterPluginConfig.cs └── Odenwald.sln /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-cayman -------------------------------------------------------------------------------- /libs/Opc.Ua.Core.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinson/Odenwald/HEAD/libs/Opc.Ua.Core.dll -------------------------------------------------------------------------------- /libs/OpcComRcw.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinson/Odenwald/HEAD/libs/OpcComRcw.dll -------------------------------------------------------------------------------- /libs/OpcNetApi.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinson/Odenwald/HEAD/libs/OpcNetApi.dll -------------------------------------------------------------------------------- /libs/Opc.Ua.Client.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinson/Odenwald/HEAD/libs/Opc.Ua.Client.dll -------------------------------------------------------------------------------- /libs/OpcNetApi.Com.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinson/Odenwald/HEAD/libs/OpcNetApi.Com.dll -------------------------------------------------------------------------------- /odenwald-architecture.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinson/Odenwald/HEAD/odenwald-architecture.jpg -------------------------------------------------------------------------------- /libs/Opc.Ua.Configuration.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/robinson/Odenwald/HEAD/libs/Opc.Ua.Configuration.dll -------------------------------------------------------------------------------- /Odenwald.Common/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Odenwald.ConsolePlugin/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Odenwald.OpcDaPlugin/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /Odenwald.InfluxDbPlugin/InfluxDb.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /Odenwald.KafkaConsumerPlugin/KafkaConsumer.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Odenwald.KafkaProducerPlugin/KafkaProducer.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Odenwald/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Odenwald.OpcUaPlugin/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Odenwald.KafkaConsumerPlugin/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Odenwald.KafkaProducerPlugin/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /Odenwald.App/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Odenwald.Service/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 [Robinson (https://github.com/robinson)] 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /Odenwald.InfluxDbPlugin/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Tests/Odenwald.OpcUaPluginTest/packages.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /Odenwald/Util.cs: -------------------------------------------------------------------------------- 1 | 2 | // ---------------------------------------------------------------------------- 3 | // Copyright (C) 2017 Robinson. 4 | // https://github.com/robinson 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | using log4net; 15 | using System; 16 | using System.Net; 17 | using System.Net.Sockets; 18 | 19 | namespace Odenwald 20 | { 21 | 22 | } 23 | -------------------------------------------------------------------------------- /Odenwald.OpcUaPlugin/opcua.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Odenwald.Common/Opc/MeasurementDto.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | 7 | namespace Odenwald.Common.Opc 8 | { 9 | public class MeasurementDto 10 | { 11 | public string Name { get; set; } 12 | 13 | public string DataType { get; set; } 14 | public string AttributeId { get; set; } 15 | public string Path { get; set; } 16 | public int DeadbandAbsolute { get; set; } 17 | public decimal DeadbandRelative { get; set; } 18 | public object LastValue { get; set; } 19 | public string LastOpcstatus { get; set; } 20 | public Dictionary Tags { get; set; } 21 | } 22 | public class MonitoredMeasurement : MeasurementDto 23 | { 24 | public int MonitorResolution { get; set; } 25 | } 26 | public class PolledMeasurement : MeasurementDto 27 | { 28 | public int PollInterval { get; set; } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /Odenwald.OpcDaPlugin/OpcDa.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /Odenwald/Interface/IMetricsWritePlugin.cs: -------------------------------------------------------------------------------- 1 | 2 | // ---------------------------------------------------------------------------- 3 | // Copyright (C) 2017 Robinson. 4 | // https://github.com/robinson 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | using System.Collections.Generic; 15 | using System.Threading.Tasks; 16 | 17 | namespace Odenwald 18 | { 19 | public interface IMetricsWritePlugin : IMetricsPlugin 20 | { 21 | void Write(MetricValue metric); 22 | void Flush(); 23 | 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /Odenwald/Interface/IMetricsReadPlugin.cs: -------------------------------------------------------------------------------- 1 | 2 | // ---------------------------------------------------------------------------- 3 | // Copyright (C) 2017 Robinson. 4 | // https://github.com/robinson 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | using System; 15 | using System.Collections.Generic; 16 | using System.Linq; 17 | using System.Text; 18 | using System.Threading.Tasks; 19 | 20 | namespace Odenwald 21 | { 22 | public interface IMetricsReadPlugin : IMetricsPlugin 23 | { 24 | IList Read(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /Odenwald/Interface/IMetricsPlugin.cs: -------------------------------------------------------------------------------- 1 | 2 | // ---------------------------------------------------------------------------- 3 | // Copyright (C) 2017 Robinson. 4 | // https://github.com/robinson 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | using System; 15 | using System.Collections.Generic; 16 | using System.Linq; 17 | using System.Text; 18 | using System.Threading.Tasks; 19 | 20 | namespace Odenwald 21 | { 22 | public interface IMetricsPlugin 23 | { 24 | void Configure(); 25 | void Start(); 26 | void Stop(); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Odenwald.ConsolePlugin/ConsolePlugin.cs: -------------------------------------------------------------------------------- 1 | using log4net; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Odenwald.ConsolePlugin 9 | { 10 | public class ConsolePlugin : IMetricsWritePlugin 11 | { 12 | static ILog l_logger = LogManager.GetLogger(typeof(ConsolePlugin)); 13 | 14 | 15 | public void Configure() 16 | { 17 | l_logger.Info("console runner output configured"); 18 | } 19 | 20 | public void Flush() 21 | { 22 | Console.WriteLine("console runner output flushing"); 23 | } 24 | 25 | public void Start() 26 | { 27 | l_logger.Info("console runner output started"); 28 | } 29 | 30 | public void Stop() 31 | { 32 | l_logger.Info("console runner output stopped"); 33 | } 34 | 35 | public void Write(MetricValue metric) 36 | { 37 | l_logger.InfoFormat("console runner output {0}", metric.GetJsonString()); 38 | Console.WriteLine("console runner output {0}", metric.GetJsonString()); 39 | } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /Odenwald.App/OdenwaldService.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Odenwald.App 2 | { 3 | partial class OdenwaldService 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Component Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | components = new System.ComponentModel.Container(); 32 | this.ServiceName = "OdenwaldService"; 33 | } 34 | 35 | #endregion 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Odenwald.Service/OdenwaldService.Designer.cs: -------------------------------------------------------------------------------- 1 | namespace Odenwald.Runner 2 | { 3 | partial class OdenwaldService 4 | { 5 | /// 6 | /// Required designer variable. 7 | /// 8 | private System.ComponentModel.IContainer components = null; 9 | 10 | /// 11 | /// Clean up any resources being used. 12 | /// 13 | /// true if managed resources should be disposed; otherwise, false. 14 | protected override void Dispose(bool disposing) 15 | { 16 | if (disposing && (components != null)) 17 | { 18 | components.Dispose(); 19 | } 20 | base.Dispose(disposing); 21 | } 22 | 23 | #region Component Designer generated code 24 | 25 | /// 26 | /// Required method for Designer support - do not modify 27 | /// the contents of this method with the code editor. 28 | /// 29 | private void InitializeComponent() 30 | { 31 | components = new System.ComponentModel.Container(); 32 | this.ServiceName = "OdenwaldService"; 33 | } 34 | 35 | #endregion 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /Odenwald/Config/log4net.config: -------------------------------------------------------------------------------- 1 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /Odenwald.App/OdenwaldService.cs: -------------------------------------------------------------------------------- 1 | using log4net; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.Data; 6 | using System.Diagnostics; 7 | using System.Linq; 8 | using System.ServiceProcess; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | 12 | namespace Odenwald.App 13 | { 14 | partial class OdenwaldService : ServiceBase 15 | { 16 | static ILog l_logger = LogManager.GetLogger(typeof(OdenwaldService)); 17 | private MetricsCollector l_metricCollector; 18 | public OdenwaldService() 19 | { 20 | InitializeComponent(); 21 | } 22 | 23 | protected override void OnStart(string[] args) 24 | { 25 | StartService(args); 26 | } 27 | 28 | protected override void OnStop() 29 | { 30 | StopService(); 31 | } 32 | public virtual void StartService(params string[] args) 33 | { 34 | l_logger.Debug("StartService() begin"); 35 | l_metricCollector = new MetricsCollector(); 36 | l_metricCollector.ConfigureAll(); 37 | l_metricCollector.StartAll(); 38 | l_logger.Debug("StartService() return"); 39 | } 40 | 41 | // public accessibility for running as a console application 42 | public virtual void StopService() 43 | { 44 | l_logger.Debug("StopService() begin"); 45 | l_metricCollector.StopAll(); 46 | l_logger.Debug("StopService() return"); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Odenwald.Common/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Odenwald.Common")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Odenwald.Common")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("fef57f91-04c1-4d42-ba2e-737697ab26c1")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Odenwald.Service/OdenwaldService.cs: -------------------------------------------------------------------------------- 1 | using log4net; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.ComponentModel; 5 | using System.Data; 6 | using System.Diagnostics; 7 | using System.Linq; 8 | using System.ServiceProcess; 9 | using System.Text; 10 | using System.Threading.Tasks; 11 | 12 | namespace Odenwald.Runner 13 | { 14 | partial class OdenwaldService : ServiceBase 15 | { 16 | static ILog l_logger = LogManager.GetLogger(typeof(OdenwaldService)); 17 | private MetricsCollector l_metricCollector; 18 | public OdenwaldService() 19 | { 20 | InitializeComponent(); 21 | } 22 | 23 | protected override void OnStart(string[] args) 24 | { 25 | StartService(args); 26 | } 27 | 28 | protected override void OnStop() 29 | { 30 | StopService(); 31 | } 32 | public virtual void StartService(params string[] args) 33 | { 34 | l_logger.Debug("StartService() begin"); 35 | l_metricCollector = new MetricsCollector(); 36 | l_metricCollector.ConfigureAll(); 37 | l_metricCollector.StartAll(); 38 | l_logger.Debug("StartService() return"); 39 | } 40 | 41 | // public accessibility for running as a console application 42 | public virtual void StopService() 43 | { 44 | l_logger.Debug("StopService() begin"); 45 | l_metricCollector.StopAll(); 46 | l_logger.Debug("StopService() return"); 47 | } 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Odenwald.OpcDaPlugin/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Odenwald.OpcDaPlugin")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Odenwald.OpcDaPlugin")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("3c3fd86f-220d-418f-b964-3c4590824fce")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Odenwald.OpcUaPlugin/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Odenwald.OpcUaPlugin")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Odenwald.OpcUaPlugin")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("63e03daa-660e-4c89-ba28-e1f6b72f854a")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Odenwald.ConsolePlugin/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Odenwald.ConsolePlugin")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Odenwald.ConsolePlugin")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("e7092227-fb5b-40e9-882c-9f636335afb7")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Odenwald.InfluxDbPlugin/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Odenwald.InfluxDbPlugin")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Odenwald.InfluxDbPlugin")] 13 | [assembly: AssemblyCopyright("Copyright © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("084be120-923f-4517-850c-17d1d5590ac9")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Tests/Odenwald.OpcUaPluginTest/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Odenwald.OpcUaPluginTest")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Odenwald.OpcUaPluginTest")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("c46f6932-ab4c-4a49-a3ba-1f9690015a48")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Odenwald.Common/Opc/OpcMetric.cs: -------------------------------------------------------------------------------- 1 | using log4net; 2 | using Newtonsoft.Json; 3 | using System; 4 | using System.Collections.Generic; 5 | using System.Linq; 6 | using System.Text; 7 | using System.Threading.Tasks; 8 | 9 | namespace Odenwald.Common.Opc 10 | { 11 | public class OpcMetric 12 | { 13 | #region Attribute 14 | static ILog l_logger = LogManager.GetLogger(typeof(OpcMetric)); 15 | private readonly IDictionary l_meta = new SortedDictionary(); 16 | #endregion 17 | 18 | 19 | public object OpcValue { get; set; } 20 | public MeasurementDto Measurement { get; set; } 21 | 22 | public DateTime Timestamp { get; set; } 23 | public string Opcstatus { get; set; } 24 | 25 | public string JsonString() 26 | { 27 | object opcObject = new 28 | { 29 | OpcValue = OpcValue, 30 | Timestamp = Timestamp, 31 | Opcstatus = Opcstatus, 32 | Name = Measurement.Name, 33 | DataType = Measurement.DataType, 34 | AttributeId = Measurement.AttributeId, 35 | Path = Measurement.Path, 36 | DeadbandAbsolute = Measurement.DeadbandAbsolute, 37 | DeadbandRelative = Measurement.DeadbandRelative, 38 | LastValue = Measurement.LastValue, 39 | LastOpcstatus = Measurement.LastOpcstatus, 40 | Tags = Measurement.Tags 41 | }; 42 | return (JsonConvert.SerializeObject(opcObject)); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Odenwald.KafkaConsumerPlugin/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Odenwald.KafkaConsumerPlugin")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Odenwald.KafkaConsumerPlugin")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("b9a8e446-db9f-46e9-bfcd-916a3d8424aa")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Odenwald.KafkaProducerPlugin/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Odenwald.KafkaProducerPlugin")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Odenwald.KafkaProducerPlugin")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("eec9106e-6812-444b-9a5e-59cdf4022d4a")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /Odenwald.App/Program.cs: -------------------------------------------------------------------------------- 1 | using log4net; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Configuration; 5 | using System.Linq; 6 | using System.ServiceProcess; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace Odenwald.App 11 | { 12 | public static class Program 13 | { 14 | static ILog l_logger = LogManager.GetLogger(typeof(Program)); 15 | public static void Main(string[] args) 16 | { 17 | 18 | var config = ConfigurationManager.GetSection("Odenwald") as OdenwaldConfig; 19 | if (config == null) 20 | { 21 | l_logger.Error("Main(): cannot get configuration section"); 22 | return; 23 | } 24 | var odenWaldService = new OdenwaldService(); 25 | 26 | if (Array.Find(args, s => s.Equals(@"app")) != null) 27 | { 28 | Console.WriteLine("*** Starting OdenwaldApp in console mode***"); 29 | // run as a console application for testing and debugging purpose 30 | odenWaldService.StartService(); 31 | Console.WriteLine("*** Enter Ctrl-C to exit: ***"); 32 | Console.ReadLine(); 33 | odenWaldService.StopService(); 34 | } 35 | else 36 | { 37 | // run as a windows service 38 | ServiceBase[] servicesToRun = { odenWaldService }; 39 | ServiceBase.Run(servicesToRun); 40 | } 41 | l_logger.Error("OdenwaldService: exiting ..."); 42 | } 43 | 44 | 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Odenwald.App/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Odenwald.App")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Odenwald.App")] 13 | [assembly: AssemblyCopyright("Copyright Odenwald © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | 18 | // Setting ComVisible to false makes the types in this assembly not visible 19 | // to COM components. If you need to access a type in this assembly from 20 | // COM, set the ComVisible attribute to true on that type. 21 | [assembly: ComVisible(false)] 22 | 23 | // The following GUID is for the ID of the typelib if this project is exposed to COM 24 | [assembly: Guid("ad130047-5631-4f12-b357-82b45e671c83")] 25 | 26 | // Version information for an assembly consists of the following four values: 27 | // 28 | // Major Version 29 | // Minor Version 30 | // Build Number 31 | // Revision 32 | // 33 | // You can specify all the values or you can default the Build and Revision Numbers 34 | // by using the '*' as shown below: 35 | // [assembly: AssemblyVersion("1.0.*")] 36 | [assembly: AssemblyVersion("1.0.0.0")] 37 | [assembly: AssemblyFileVersion("1.0.0.0")] 38 | 39 | [assembly: log4net.Config.XmlConfigurator(Watch = true)] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Updating... 2 | TO BE UPDATING... 3 | # Summary 4 | Odenwald is a tool which switch the data from points to destination, and supports following plugins: 5 | - OPC UA 6 | - OPC DA (opc classic) 7 | - InfluxDB 8 | - Kafka 9 | - Console 10 | 11 | # Disclaimer 12 | The following binaries belong to the OPC Foundation (https://opcfoundation.org/): 13 | 14 | - OPC.Ua.Client.dll 15 | - OPC.Ua.Core.dll 16 | - OPC.Ua.Configuration.dll 17 | - OpcComRcw.dll 18 | - OpcNetApi.Com.dll 19 | - OpcNetApi.dll 20 | 21 | You should become a registered user in order to use. 22 | 23 | Beside some popular packages as thousands opensouces (such as: log4net, newtonsoft.json, etc.), Odenwald use: 24 | - InfluxDB.Net-Main 25 | - kafka-net 26 | 27 | # Reference 28 | In order to test with OPC UA you should register and get the sample OPC UA server as (https://github.com/OPCFoundation/UA-.NET/tree/master/SampleApplications/Samples/Server) 29 | In case of OPC DA testing, you are able to use OPC Classic Demo server from Softing (of course before using it, you should register as a user, althought that is a free of charge software), 30 | http://industrial.softing.com/en/products/software/opc-development-toolkits/opc-classic-development-toolkits/opc-classic-da-ae-xml-da-client-and-server-toolkit-for-windows.html 31 | 32 | Besides, Odenwald refers from these systems: 33 | - collectd (https://github.com/collectd/collectd) 34 | - CollectdWin (https://github.com/bloomberg/collectdwin) 35 | 36 | # TODO 37 | - Installation package use wix toolset. 38 | - A small web app to monitor the service. 39 | - MongoDB plugin. 40 | - Update document. 41 | - Recode MetricData 42 | 43 | 44 | -------------------------------------------------------------------------------- /Odenwald.Service/Program.cs: -------------------------------------------------------------------------------- 1 | using log4net; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Configuration; 5 | using System.Linq; 6 | using System.ServiceProcess; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace Odenwald.Runner 11 | { 12 | public static class Program 13 | { 14 | static ILog l_logger = LogManager.GetLogger(typeof(Program)); 15 | public static void Main(string[] args) 16 | { 17 | 18 | var config = ConfigurationManager.GetSection("Odenwald") as OdenwaldConfig; 19 | if (config == null) 20 | { 21 | l_logger.Error("Main(): cannot get configuration section"); 22 | return; 23 | } 24 | var odenWaldService = new OdenwaldService(); 25 | 26 | if (Array.Find(args, s => s.Equals(@"console")) != null) 27 | { 28 | Console.WriteLine("*** Starting OdenwaldService in console mode***"); 29 | // run as a console application for testing and debugging purpose 30 | odenWaldService.StartService(); 31 | Console.WriteLine("*** Enter Ctrl-C to exit: ***"); 32 | Console.ReadLine(); 33 | odenWaldService.StopService(); 34 | } 35 | else 36 | { 37 | // run as a windows service 38 | ServiceBase[] servicesToRun = { odenWaldService }; 39 | ServiceBase.Run(servicesToRun); 40 | } 41 | l_logger.Error("OdenwaldService: exiting ..."); 42 | } 43 | 44 | 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /Odenwald.Service/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("Odenwald.Service")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("Odenwald.Service")] 13 | [assembly: AssemblyCopyright("Copyright Odenwald © 2016")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | 18 | // Setting ComVisible to false makes the types in this assembly not visible 19 | // to COM components. If you need to access a type in this assembly from 20 | // COM, set the ComVisible attribute to true on that type. 21 | [assembly: ComVisible(false)] 22 | 23 | // The following GUID is for the ID of the typelib if this project is exposed to COM 24 | [assembly: Guid("ad130047-5631-4f12-b357-82b45e671c83")] 25 | 26 | // Version information for an assembly consists of the following four values: 27 | // 28 | // Major Version 29 | // Minor Version 30 | // Build Number 31 | // Revision 32 | // 33 | // You can specify all the values or you can default the Build and Revision Numbers 34 | // by using the '*' as shown below: 35 | // [assembly: AssemblyVersion("1.0.*")] 36 | [assembly: AssemblyVersion("1.0.0.0")] 37 | [assembly: AssemblyFileVersion("1.0.0.0")] 38 | 39 | [assembly: log4net.Config.XmlConfigurator(Watch = true)] -------------------------------------------------------------------------------- /Odenwald/Odenwald.licenseheader: -------------------------------------------------------------------------------- 1 | extensions: designer.cs generated.cs 2 | extensions: .cs .cpp .h 3 | 4 | // ---------------------------------------------------------------------------- 5 | // Copyright (C) 2017 Robinson. 6 | // https://github.com/robinson 7 | // Licensed under the Apache License, Version 2.0 (the "License"); 8 | // you may not use this file except in compliance with the License. 9 | // You may obtain a copy of the License at 10 | // http://www.apache.org/licenses/LICENSE-2.0 11 | // Unless required by applicable law or agreed to in writing, software 12 | // distributed under the License is distributed on an "AS IS" BASIS, 13 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | // See the License for the specific language governing permissions and 15 | // limitations under the License. 16 | extensions: .aspx .ascx 17 | <%-- 18 | Copyright (c) 2011 rubicon IT GmbH 19 | --%> 20 | extensions: .vb 21 | 'Sample license text. 22 | extensions: .xml .config .xsd 23 | -------------------------------------------------------------------------------- /Odenwald.KafkaConsumerPlugin/KafkaConsumerPluginConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Odenwald.KafkaConsumerPlugin 9 | { 10 | public class KafkaConsumerPluginConfig : ConfigurationSection 11 | { 12 | public static KafkaConsumerPluginConfig GetConfig() 13 | { 14 | return (KafkaConsumerPluginConfig)ConfigurationManager.GetSection("KafkaConsumer") ?? new KafkaConsumerPluginConfig(); 15 | } 16 | [ConfigurationProperty("Settings", IsRequired = true)] 17 | public SettingsConfig Settings 18 | { 19 | get { return (SettingsConfig)base["Settings"]; } 20 | set { base["Settings"] = value; } 21 | } 22 | } 23 | public sealed class SettingsConfig : ConfigurationElement 24 | { 25 | [ConfigurationProperty("Url", IsRequired = true)] 26 | public string Url 27 | { 28 | get { return (string)base["Url"]; } 29 | set { base["Url"] = value; } 30 | } 31 | [ConfigurationProperty("Topic", IsRequired = true)] 32 | public string Topic 33 | { 34 | get { return (string)base["Topic"]; } 35 | set { base["Topic"] = value; } 36 | } 37 | [ConfigurationProperty("BatchDelayTime")] 38 | public int BatchDelayTime 39 | { 40 | get { return (int)base["BatchDelayTime"]; } 41 | set { base["BatchDelayTime"] = value; } 42 | } 43 | [ConfigurationProperty("BatchSize")] 44 | public int BatchSize 45 | { 46 | get { return (int)base["BatchSize"]; } 47 | set { base["BatchSize"] = value; } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /Odenwald/app.config: -------------------------------------------------------------------------------- 1 | 2 | 15 | 16 | 17 | 18 |
19 |
20 | 21 | 22 | 30 | 31 | 32 | 34 | 35 | 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /Odenwald.Common/Util.cs: -------------------------------------------------------------------------------- 1 | using log4net; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Net; 6 | using System.Net.Sockets; 7 | using System.Text; 8 | using System.Threading.Tasks; 9 | 10 | namespace Odenwald.Common 11 | { 12 | public static class Util 13 | { 14 | static ILog l_logger = LogManager.GetLogger(typeof(Util)); 15 | 16 | public static double GetNow() 17 | { 18 | TimeSpan t = DateTime.UtcNow - new DateTime(1970, 1, 1); 19 | double epoch = t.TotalMilliseconds / 1000; 20 | double now = Math.Round(epoch, 3); 21 | return (now); 22 | } 23 | 24 | public static string GetHostName() 25 | { 26 | string hostname = Environment.MachineName.ToLower(); 27 | try 28 | { 29 | hostname = Dns.GetHostEntry("localhost").HostName.ToLower(); 30 | } 31 | catch (SocketException) 32 | { 33 | l_logger.WarnFormat("Unable to resolve hostname, using MachineName: {0}", hostname); 34 | } 35 | return hostname; 36 | } 37 | public static bool IsNumber(this object value) 38 | { 39 | return value is sbyte 40 | || value is byte 41 | || value is short 42 | || value is ushort 43 | || value is int 44 | || value is uint 45 | || value is long 46 | || value is ulong 47 | || value is float 48 | || value is double 49 | || value is decimal; 50 | } 51 | public static bool IsBoolean(this object value) 52 | { 53 | return value is bool; 54 | } 55 | public static bool IsString(this object value) 56 | { 57 | return value is string; 58 | } 59 | 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /Odenwald.InfluxDbPlugin/InfluxDbPluginConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Odenwald.InfluxDbPlugin 9 | { 10 | public sealed class InfluxDbPluginConfig : ConfigurationSection 11 | { 12 | public static InfluxDbPluginConfig GetConfig() 13 | { 14 | return (InfluxDbPluginConfig)ConfigurationManager.GetSection("InfluxDb") ?? new InfluxDbPluginConfig(); 15 | } 16 | [ConfigurationProperty("Settings", IsRequired = true)] 17 | public SettingsConfig Settings 18 | { 19 | get { return (SettingsConfig)base["Settings"]; } 20 | set { base["Settings"] = value; } 21 | } 22 | } 23 | public sealed class SettingsConfig : ConfigurationElement 24 | { 25 | [ConfigurationProperty("Interval", IsRequired = true)] 26 | public int Interval 27 | { 28 | get { return (int)base["Interval"]; } 29 | set { base["Interval"] = value; } 30 | } 31 | [ConfigurationProperty("Url", IsRequired = true)] 32 | public string Url 33 | { 34 | get { return (string)base["Url"]; } 35 | set { base["Url"] = value; } 36 | } 37 | [ConfigurationProperty("Database", IsRequired = true)] 38 | public string Database 39 | { 40 | get { return (string)base["Database"]; } 41 | set { base["Database"] = value; } 42 | } 43 | [ConfigurationProperty("Username")] 44 | public string Username 45 | { 46 | get { return (string)base["Username"]; } 47 | set { base["Username"] = value; } 48 | } 49 | [ConfigurationProperty("Password")] 50 | public string Password 51 | { 52 | get { return (string)base["Password"]; } 53 | set { base["Password"] = value; } 54 | } 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /Odenwald.KafkaProducerPlugin/KafkaProducerPluginConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Odenwald.KafkaProducerPlugin 9 | { 10 | public class KafkaProducerPluginConfig : ConfigurationSection 11 | { 12 | public static KafkaProducerPluginConfig GetConfig() 13 | { 14 | return (KafkaProducerPluginConfig)ConfigurationManager.GetSection("KafkaProducer") ?? new KafkaProducerPluginConfig(); 15 | } 16 | [ConfigurationProperty("Settings", IsRequired = true)] 17 | public SettingsConfig Settings 18 | { 19 | get { return (SettingsConfig)base["Settings"]; } 20 | set { base["Settings"] = value; } 21 | } 22 | } 23 | public sealed class SettingsConfig : ConfigurationElement 24 | { 25 | //[ConfigurationProperty("Interval", IsRequired = true)] 26 | //public int Interval 27 | //{ 28 | // get { return (int)base["Interval"]; } 29 | // set { base["Interval"] = value; } 30 | //} 31 | [ConfigurationProperty("Url", IsRequired = true)] 32 | public string Url 33 | { 34 | get { return (string)base["Url"]; } 35 | set { base["Url"] = value; } 36 | } 37 | [ConfigurationProperty("Topic", IsRequired = true)] 38 | public string Topic 39 | { 40 | get { return (string)base["Topic"]; } 41 | set { base["Topic"] = value; } 42 | } 43 | [ConfigurationProperty("BatchDelayTime")] 44 | public int BatchDelayTime 45 | { 46 | get { return (int)base["BatchDelayTime"]; } 47 | set { base["BatchDelayTime"] = value; } 48 | } 49 | [ConfigurationProperty("BatchSize")] 50 | public int BatchSize 51 | { 52 | get { return (int)base["BatchSize"]; } 53 | set { base["BatchSize"] = value; } 54 | } 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /Odenwald/Config/Odenwald.config: -------------------------------------------------------------------------------- 1 | 14 | 15 | 16 | 17 | 18 | 19 | 21 | 23 | 25 | 27 | 29 | 31 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | -------------------------------------------------------------------------------- /Odenwald/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | 2 | // ---------------------------------------------------------------------------- 3 | // Copyright (C) 2017 Robinson. 4 | // https://github.com/robinson 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | using System.Reflection; 15 | using System.Runtime.CompilerServices; 16 | using System.Runtime.InteropServices; 17 | 18 | // General Information about an assembly is controlled through the following 19 | // set of attributes. Change these attribute values to modify the information 20 | // associated with an assembly. 21 | [assembly: AssemblyTitle("Odenwald")] 22 | [assembly: AssemblyDescription("")] 23 | [assembly: AssemblyConfiguration("")] 24 | [assembly: AssemblyCompany("")] 25 | [assembly: AssemblyProduct("Odenwald")] 26 | [assembly: AssemblyCopyright("Copyright © 2016")] 27 | [assembly: AssemblyTrademark("")] 28 | [assembly: AssemblyCulture("")] 29 | 30 | // Setting ComVisible to false makes the types in this assembly not visible 31 | // to COM components. If you need to access a type in this assembly from 32 | // COM, set the ComVisible attribute to true on that type. 33 | [assembly: ComVisible(false)] 34 | 35 | // The following GUID is for the ID of the typelib if this project is exposed to COM 36 | [assembly: Guid("bb7a7712-cc11-4d95-83dc-a0ab28714860")] 37 | 38 | // Version information for an assembly consists of the following four values: 39 | // 40 | // Major Version 41 | // Minor Version 42 | // Build Number 43 | // Revision 44 | // 45 | // You can specify all the values or you can default the Build and Revision Numbers 46 | // by using the '*' as shown below: 47 | // [assembly: AssemblyVersion("1.0.*")] 48 | [assembly: AssemblyVersion("1.0.0.0")] 49 | [assembly: AssemblyFileVersion("1.0.0.0")] 50 | 51 | [assembly: log4net.Config.XmlConfigurator(Watch = true)] 52 | -------------------------------------------------------------------------------- /Odenwald/PluginRegistry.cs: -------------------------------------------------------------------------------- 1 | 2 | // ---------------------------------------------------------------------------- 3 | // Copyright (C) 2017 Robinson. 4 | // https://github.com/robinson 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | using log4net; 15 | using System; 16 | using System.Collections.Generic; 17 | using System.Configuration; 18 | using System.Linq; 19 | using System.Text; 20 | using System.Threading.Tasks; 21 | 22 | 23 | namespace Odenwald 24 | { 25 | internal class PluginRegistry 26 | { 27 | static ILog l_logger = LogManager.GetLogger(typeof(PluginRegistry)); 28 | 29 | private readonly Dictionary _registry = new Dictionary(); 30 | 31 | public PluginRegistry() 32 | { 33 | var config = ConfigurationManager.GetSection("Odenwald") as OdenwaldConfig; 34 | if (config == null) 35 | { 36 | l_logger.ErrorFormat("Cannot get configuration section : Odenwald"); 37 | return; 38 | } 39 | foreach ( 40 | OdenwaldConfig.PluginConfig pluginConfig in 41 | config.Plugins.Cast() 42 | .Where(pluginConfig => pluginConfig.Enable)) 43 | { 44 | _registry[pluginConfig.Name] = pluginConfig.Class; 45 | } 46 | } 47 | 48 | public IList CreatePlugins() 49 | { 50 | IList plugins = new List(); 51 | foreach (var entry in _registry) 52 | { 53 | Type classType = Type.GetType(entry.Value); 54 | if (classType == null) 55 | { 56 | l_logger.ErrorFormat("Cannot create plugin:{0}, class:{1}", entry.Key, entry.Value); 57 | continue; 58 | } 59 | var plugin = (IMetricsPlugin)Activator.CreateInstance(classType); 60 | plugins.Add(plugin); 61 | } 62 | return (plugins); 63 | } 64 | } 65 | } 66 | 67 | 68 | 69 | -------------------------------------------------------------------------------- /Odenwald.KafkaProducerPlugin/KafkaProducerPlugin.cs: -------------------------------------------------------------------------------- 1 | using KafkaNet; 2 | using KafkaNet.Model; 3 | using KafkaNet.Protocol; 4 | using log4net; 5 | using System; 6 | using System.Configuration; 7 | using System.Linq; 8 | 9 | namespace Odenwald.KafkaProducerPlugin 10 | { 11 | public class KafkaProducerPlugin : IMetricsWritePlugin, IDisposable 12 | { 13 | #region attributes 14 | static ILog l_logger = LogManager.GetLogger(typeof(KafkaProducerPlugin)); 15 | KafkaProducerPluginConfig l_kafkaProducerConfig; 16 | Producer l_kafkaProducer; 17 | #endregion 18 | public void Configure() 19 | { 20 | l_kafkaProducerConfig = KafkaProducerPluginConfig.GetConfig(); 21 | if (l_kafkaProducerConfig == null) 22 | { 23 | throw new Exception("Cannot get configuration section : KafkaProducer"); 24 | } 25 | 26 | } 27 | 28 | public void Flush() 29 | { 30 | l_logger.Info("kafka producer flushed!"); 31 | } 32 | 33 | public void Start() 34 | { 35 | var urls = l_kafkaProducerConfig.Settings.Url.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries) 36 | .Select(x => new Uri(x)); 37 | 38 | var options = new KafkaOptions(urls.ToArray()) 39 | { 40 | Log = new DefaultTraceLog() 41 | }; 42 | var batchDelayTime = l_kafkaProducerConfig.Settings.BatchDelayTime == 0 ? 2000 : l_kafkaProducerConfig.Settings.BatchDelayTime; 43 | var batchSize = l_kafkaProducerConfig.Settings.BatchSize == 0 ? 100 : l_kafkaProducerConfig.Settings.BatchSize; 44 | l_kafkaProducer = new Producer(new BrokerRouter(options)) 45 | { 46 | BatchDelayTime = TimeSpan.FromMilliseconds(batchDelayTime), 47 | BatchSize = batchSize 48 | }; 49 | } 50 | 51 | public void Stop() 52 | { 53 | l_kafkaProducer.Stop(); 54 | } 55 | 56 | public void Write(MetricValue metric) 57 | { 58 | var produceResponse = l_kafkaProducer.SendMessageAsync(l_kafkaProducerConfig.Settings.Topic, new[] { new Message(metric.GetJsonString()) }); 59 | if (produceResponse.IsFaulted || produceResponse.IsCanceled) 60 | { 61 | l_logger.ErrorFormat("kafka producer write false: {0}", produceResponse.Exception); 62 | } 63 | } 64 | 65 | public void Dispose() 66 | { 67 | if (l_kafkaProducer != null) 68 | l_kafkaProducer.Dispose(); 69 | GC.SuppressFinalize(this); 70 | } 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | ############################################################################### 2 | # Set default behavior to automatically normalize line endings. 3 | ############################################################################### 4 | * text=auto 5 | 6 | ############################################################################### 7 | # Set default behavior for command prompt diff. 8 | # 9 | # This is need for earlier builds of msysgit that does not have it on by 10 | # default for csharp files. 11 | # Note: This is only used by command line 12 | ############################################################################### 13 | #*.cs diff=csharp 14 | 15 | ############################################################################### 16 | # Set the merge driver for project and solution files 17 | # 18 | # Merging from the command prompt will add diff markers to the files if there 19 | # are conflicts (Merging from VS is not affected by the settings below, in VS 20 | # the diff markers are never inserted). Diff markers may cause the following 21 | # file extensions to fail to load in VS. An alternative would be to treat 22 | # these files as binary and thus will always conflict and require user 23 | # intervention with every merge. To do so, just uncomment the entries below 24 | ############################################################################### 25 | #*.sln merge=binary 26 | #*.csproj merge=binary 27 | #*.vbproj merge=binary 28 | #*.vcxproj merge=binary 29 | #*.vcproj merge=binary 30 | #*.dbproj merge=binary 31 | #*.fsproj merge=binary 32 | #*.lsproj merge=binary 33 | #*.wixproj merge=binary 34 | #*.modelproj merge=binary 35 | #*.sqlproj merge=binary 36 | #*.wwaproj merge=binary 37 | 38 | ############################################################################### 39 | # behavior for image files 40 | # 41 | # image files are treated as binary by default. 42 | ############################################################################### 43 | #*.jpg binary 44 | #*.png binary 45 | #*.gif binary 46 | 47 | ############################################################################### 48 | # diff behavior for common document formats 49 | # 50 | # Convert binary document formats to text before diffing them. This feature 51 | # is only available from the command line. Turn it on by uncommenting the 52 | # entries below. 53 | ############################################################################### 54 | #*.doc diff=astextplain 55 | #*.DOC diff=astextplain 56 | #*.docx diff=astextplain 57 | #*.DOCX diff=astextplain 58 | #*.dot diff=astextplain 59 | #*.DOT diff=astextplain 60 | #*.pdf diff=astextplain 61 | #*.PDF diff=astextplain 62 | #*.rtf diff=astextplain 63 | #*.RTF diff=astextplain 64 | -------------------------------------------------------------------------------- /Odenwald.App/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 38 | 40 | 42 | 44 | 46 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /Odenwald.Service/app.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 38 | 40 | 42 | 44 | 46 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /Odenwald.InfluxDbPlugin/InfluxDbPlugin.cs: -------------------------------------------------------------------------------- 1 | using InfluxDB.Net; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Configuration; 5 | using System.Linq; 6 | using InfluxDB.Net.Models; 7 | using log4net; 8 | using Newtonsoft.Json.Linq; 9 | using Newtonsoft.Json; 10 | 11 | namespace Odenwald.InfluxDbPlugin 12 | { 13 | public class InfluxDbPlugin : IMetricsWritePlugin 14 | { 15 | #region attributes 16 | static ILog l_logger = LogManager.GetLogger(typeof(InfluxDbPlugin)); 17 | InfluxDbPluginConfig l_influxDbConfig; 18 | InfluxDb l_influxDbClient; 19 | #endregion 20 | 21 | #region IOutputAdapter properties 22 | 23 | public void Configure() 24 | { 25 | l_influxDbConfig = ConfigurationManager.GetSection("InfluxDb") as InfluxDbPluginConfig; 26 | if (l_influxDbConfig == null) 27 | { 28 | throw new Exception("Cannot get configuration section : InfluxDb"); 29 | } 30 | } 31 | 32 | public void Flush() 33 | { 34 | l_logger.Info("InfluxDbAdapter flushed!"); 35 | } 36 | 37 | public void Start() 38 | { 39 | l_influxDbClient = new InfluxDb(l_influxDbConfig.Settings.Url, l_influxDbConfig.Settings.Username, l_influxDbConfig.Settings.Password); 40 | 41 | } 42 | 43 | public void Stop() 44 | { 45 | l_logger.Info("InfluxDbAdapter stopped!"); 46 | } 47 | 48 | 49 | public void Write(MetricValue metric) 50 | { 51 | if (metric.Extension.Equals("")) // no extension, nothing to write 52 | return; 53 | var extension = JObject.Parse(metric.Extension); 54 | if (extension["OpcValue"] == null) // no OpcValue, nothing to write 55 | return; 56 | var opcValue = extension["OpcValue"]; 57 | var opcName = extension["Name"].ToString(); 58 | var timeStamp = extension["Timestamp"] != null ? (DateTime)extension["Timestamp"] : DateTime.Now; 59 | Dictionary tags = extension["Tags"] != null ? 60 | JsonConvert.DeserializeObject>(extension["Tags"].ToString()) : null; 61 | 62 | var p = new Point() 63 | { 64 | Measurement = opcName, 65 | Precision = InfluxDB.Net.Enums.TimeUnit.Seconds, 66 | Fields = new Dictionary() 67 | { 68 | {"Value",opcValue}, 69 | {"Timestamp", timeStamp} 70 | }, 71 | Tags = tags// tags.ToDictionary(k => k.Key, k => k.Value == "" || k.Value == null ? null : (object)k.Value)// metric.MetaData.ToDictionary(k => k.Key, k => k.Value == "" || k.Value == null ? null : (object)k.Value) 72 | }; 73 | var writeResponse = l_influxDbClient.WriteAsync(l_influxDbConfig.Settings.Database, p); 74 | 75 | if (writeResponse.IsFaulted || writeResponse.IsCanceled) 76 | l_logger.ErrorFormat("InfluxDb write false: {0}", writeResponse.Exception); 77 | } 78 | #endregion 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /Odenwald.KafkaConsumerPlugin/KafkaConsumerPlugin.cs: -------------------------------------------------------------------------------- 1 | using KafkaNet; 2 | using KafkaNet.Common; 3 | using KafkaNet.Model; 4 | using log4net; 5 | using Newtonsoft.Json; 6 | using System; 7 | using System.Collections.Concurrent; 8 | using System.Collections.Generic; 9 | using System.Linq; 10 | using System.Threading.Tasks; 11 | 12 | namespace Odenwald.KafkaConsumerPlugin 13 | { 14 | public class KafkaConsumerPlugin : IMetricsReadPlugin, IDisposable 15 | { 16 | #region attributes 17 | static ILog l_logger = LogManager.GetLogger(typeof(KafkaConsumerPlugin)); 18 | KafkaConsumerPluginConfig l_kafkaConsumerConfig; 19 | Consumer l_kafkaConsumer; 20 | BlockingCollection l_metricCollection; 21 | #endregion 22 | public void Configure() 23 | { 24 | l_kafkaConsumerConfig = KafkaConsumerPluginConfig.GetConfig(); 25 | if (l_kafkaConsumerConfig == null) 26 | { 27 | throw new Exception("Cannot get configuration section : KafkaConsumer"); 28 | } 29 | } 30 | 31 | public IList Read() 32 | { 33 | if (l_metricCollection.Count <= 0) 34 | return null; 35 | List metricList = new List(); 36 | while (l_metricCollection.Count > 0) 37 | { 38 | 39 | string data = null; 40 | try 41 | { 42 | data = l_metricCollection.Take(); 43 | } 44 | catch (InvalidOperationException) { } 45 | 46 | if (data != null) 47 | { 48 | var metricValue = JsonConvert.DeserializeObject(data);//this is not a good practice, review later 49 | 50 | metricList.Add(metricValue); 51 | } 52 | } 53 | l_logger.DebugFormat("Read {0} items.", metricList.Count); 54 | return metricList; 55 | } 56 | 57 | public void Start() 58 | { 59 | var urls = l_kafkaConsumerConfig.Settings.Url.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries) 60 | .Select(x => new Uri(x)); 61 | 62 | var options = new KafkaOptions(urls.ToArray()) 63 | { 64 | Log = new DefaultTraceLog() 65 | }; 66 | l_metricCollection = new BlockingCollection(); 67 | Task.Run(() => 68 | { 69 | l_kafkaConsumer = new Consumer(new ConsumerOptions(l_kafkaConsumerConfig.Settings.Topic, new BrokerRouter(options)) { Log = new DefaultTraceLog() }); 70 | foreach (var message in l_kafkaConsumer.Consume()) 71 | { 72 | var value = message.Value.ToUtf8String(); 73 | 74 | l_metricCollection.Add(value); 75 | } 76 | }); 77 | } 78 | 79 | public void Stop() 80 | { 81 | l_logger.Info("KafkaConsumer plugin stopped."); 82 | } 83 | public void Dispose() 84 | { 85 | if (l_kafkaConsumer != null) 86 | l_kafkaConsumer.Dispose(); 87 | GC.SuppressFinalize(this); 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Odenwald.ConsolePlugin/Odenwald.ConsolePlugin.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {BA07862A-586A-47AC-9069-7D1904973A83} 8 | Library 9 | Properties 10 | Odenwald.ConsolePlugin 11 | Odenwald.ConsolePlugin 12 | v4.6 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | ..\packages\log4net.2.0.7\lib\net45-full\log4net.dll 35 | True 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | {bb7a7712-cc11-4d95-83dc-a0ab28714860} 53 | Odenwald 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 71 | -------------------------------------------------------------------------------- /Odenwald.Common/Odenwald.Common.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {FEF57F91-04C1-4D42-BA2E-737697AB26C1} 8 | Library 9 | Properties 10 | Odenwald.Common 11 | Odenwald.Common 12 | v4.6 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | ..\packages\log4net.2.0.7\lib\net45-full\log4net.dll 35 | True 36 | 37 | 38 | False 39 | ..\Odenwald.OpcUaPlugin\bin\Debug\Newtonsoft.Json.dll 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 70 | -------------------------------------------------------------------------------- /Odenwald.KafkaProducerPlugin/Odenwald.KafkaProducerPlugin.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {EEC9106E-6812-444B-9A5E-59CDF4022D4A} 8 | Library 9 | Properties 10 | Odenwald.KafkaProducerPlugin 11 | Odenwald.KafkaProducerPlugin 12 | v4.6 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | ..\packages\kafka-net.0.9.0.65\lib\net45\kafka-net.dll 35 | True 36 | 37 | 38 | ..\packages\log4net.2.0.7\lib\net45-full\log4net.dll 39 | True 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | PreserveNewest 59 | 60 | 61 | 62 | 63 | 64 | {BB7A7712-CC11-4D95-83DC-A0AB28714860} 65 | Odenwald 66 | 67 | 68 | 69 | 76 | -------------------------------------------------------------------------------- /Odenwald.OpcDaPlugin/Odenwald.OpcDaPlugin.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {3C3FD86F-220D-418F-B964-3C4590824FCE} 8 | Library 9 | Properties 10 | Odenwald.OpcDaPlugin 11 | Odenwald.OpcDaPlugin 12 | v4.6 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | ..\packages\log4net.2.0.7\lib\net45-full\log4net.dll 35 | True 36 | 37 | 38 | False 39 | ..\libs\OpcComRcw.dll 40 | 41 | 42 | ..\libs\OpcNetApi.dll 43 | 44 | 45 | ..\libs\OpcNetApi.Com.dll 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | {FEF57F91-04C1-4D42-BA2E-737697AB26C1} 64 | Odenwald.Common 65 | 66 | 67 | {bb7a7712-cc11-4d95-83dc-a0ab28714860} 68 | Odenwald 69 | 70 | 71 | 72 | 73 | PreserveNewest 74 | 75 | 76 | 77 | 78 | 85 | -------------------------------------------------------------------------------- /Odenwald.KafkaConsumerPlugin/Odenwald.KafkaConsumerPlugin.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {B9A8E446-DB9F-46E9-BFCD-916A3D8424AA} 8 | Library 9 | Properties 10 | Odenwald.KafkaConsumerPlugin 11 | Odenwald.KafkaConsumerPlugin 12 | v4.6 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | ..\packages\kafka-net.0.9.0.65\lib\net45\kafka-net.dll 35 | True 36 | 37 | 38 | ..\packages\log4net.2.0.7\lib\net45-full\log4net.dll 39 | True 40 | 41 | 42 | False 43 | ..\Odenwald.OpcUaPlugin\bin\Debug\Newtonsoft.Json.dll 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | PreserveNewest 63 | 64 | 65 | 66 | 67 | 68 | {FEF57F91-04C1-4D42-BA2E-737697AB26C1} 69 | Odenwald.Common 70 | 71 | 72 | {BB7A7712-CC11-4D95-83DC-A0AB28714860} 73 | Odenwald 74 | 75 | 76 | 77 | 84 | -------------------------------------------------------------------------------- /Odenwald/Odenwald.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {BB7A7712-CC11-4D95-83DC-A0AB28714860} 8 | Library 9 | Properties 10 | Odenwald 11 | Odenwald 12 | v4.6 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | ..\packages\log4net.2.0.7\lib\net45-full\log4net.dll 35 | True 36 | 37 | 38 | ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll 39 | True 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | PreserveNewest 72 | 73 | 74 | 75 | 76 | {FEF57F91-04C1-4D42-BA2E-737697AB26C1} 77 | Odenwald.Common 78 | 79 | 80 | 81 | 88 | -------------------------------------------------------------------------------- /Odenwald/MetricValue.cs: -------------------------------------------------------------------------------- 1 | 2 | // ---------------------------------------------------------------------------- 3 | // Copyright (C) 2017 Robinson. 4 | // https://github.com/robinson 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | using log4net; 15 | using Newtonsoft.Json; 16 | using System; 17 | using System.Collections.Generic; 18 | using System.Linq; 19 | using System.Text; 20 | using System.Threading.Tasks; 21 | 22 | namespace Odenwald 23 | { 24 | public class MetricValue 25 | { 26 | #region Attribute 27 | static ILog l_logger = LogManager.GetLogger(typeof(MetricValue)); 28 | private readonly IDictionary l_meta = new SortedDictionary(); 29 | #endregion 30 | 31 | #region Properties 32 | public string PluginName { get; set; } 33 | public string PluginInstanceName { get; set; } 34 | 35 | public string HostName { get; set; } 36 | 37 | public IDictionary MetaData { get { return l_meta; } } 38 | 39 | public string TypeName { get; set; } 40 | public string TypeInstanceName { get; set; } 41 | 42 | public double[] Values { get; set; } 43 | 44 | public double Epoch { get { return DateTimeOffset.Now.ToUnixTimeSeconds(); } } 45 | 46 | public int Interval { get; set; } 47 | 48 | public IList DsTypes { get; set; } 49 | 50 | public IList DsNames { get; set; } 51 | 52 | public string Key 53 | { 54 | get 55 | { 56 | return (HostName + "." + PluginName + "." + PluginName + "." + TypeName + "." + TypeInstanceName); 57 | } 58 | } 59 | 60 | public void AddMetaData(IDictionary meta) 61 | { 62 | if (meta == null) 63 | { 64 | return; 65 | } 66 | 67 | foreach (var tag in meta) 68 | { 69 | l_meta[tag.Key] = tag.Value; 70 | } 71 | } 72 | 73 | public void AddMetaData(string tagName, string tagValue) 74 | { 75 | l_meta[tagName] = tagValue; 76 | } 77 | public string Extension { get; set; } //extension will be a json string 78 | 79 | public MetricValue DeepCopy() 80 | { 81 | var other = (MetricValue)MemberwiseClone(); 82 | other.HostName = String.Copy(HostName); 83 | other.PluginName = String.Copy(PluginName); 84 | other.PluginInstanceName = String.Copy(PluginInstanceName); 85 | other.TypeName = String.Copy(TypeName); 86 | other.TypeInstanceName = String.Copy(TypeInstanceName); 87 | other.Values = (double[])Values.Clone(); 88 | return (other); 89 | } 90 | 91 | public string GetJsonString() 92 | { 93 | IList dsList = DataSetCollection.Instance.GetDataSource(TypeName); 94 | DsNames = new List(); 95 | DsTypes = new List(); 96 | if (dsList == null) 97 | { 98 | l_logger.DebugFormat("Invalid type : {0}, not found in types.db", TypeName); 99 | } 100 | else 101 | { 102 | foreach (DataSource ds in dsList) 103 | { 104 | DsNames.Add(ds.Name); 105 | DsTypes.Add(ds.Type.ToString().ToLower()); 106 | } 107 | } 108 | var jsonString = ""; 109 | try 110 | { 111 | jsonString = JsonConvert.SerializeObject(this); 112 | } 113 | catch (Exception ex) 114 | { 115 | l_logger.ErrorFormat("Got exception in json conversion : {0}", ex); 116 | } 117 | return (jsonString); 118 | } 119 | #endregion 120 | 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /Odenwald.OpcUaPlugin/Odenwald.OpcUaPlugin.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {712B2914-BF62-4278-BFE2-EB6925760839} 8 | Library 9 | Properties 10 | Odenwald.OpcUaPlugin 11 | Odenwald.OpcUaPlugin 12 | v4.6 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | ..\packages\log4net.2.0.7\lib\net45-full\log4net.dll 35 | True 36 | 37 | 38 | ..\..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll 39 | True 40 | 41 | 42 | False 43 | ..\libs\Opc.Ua.Client.dll 44 | 45 | 46 | False 47 | ..\libs\Opc.Ua.Configuration.dll 48 | 49 | 50 | False 51 | ..\libs\Opc.Ua.Core.dll 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | Designer 71 | PreserveNewest 72 | 73 | 74 | 75 | 76 | 77 | {fef57f91-04c1-4d42-ba2e-737697ab26c1} 78 | Odenwald.Common 79 | 80 | 81 | {bb7a7712-cc11-4d95-83dc-a0ab28714860} 82 | Odenwald 83 | 84 | 85 | 86 | 93 | -------------------------------------------------------------------------------- /Odenwald.Common/Opc/OpcPluginConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Odenwald.Common.Opc 9 | { 10 | public sealed class OpcPluginConfig : ConfigurationSection 11 | { 12 | public static OpcPluginConfig GetConfig(string rootElement) 13 | { 14 | return (OpcPluginConfig)ConfigurationManager.GetSection(rootElement) ?? new OpcPluginConfig(); 15 | } 16 | [ConfigurationProperty("Settings", IsRequired = true)] 17 | public SettingsConfig Settings 18 | { 19 | get { return (SettingsConfig)base["Settings"]; } 20 | set { base["Settings"] = value; } 21 | } 22 | [ConfigurationProperty("Measurements", IsRequired = true)] 23 | [ConfigurationCollection(typeof(MeasurementCollection), AddItemName = "Measurement")] 24 | public MeasurementCollection Measurements 25 | { 26 | get { return (MeasurementCollection)base["Measurements"]; } 27 | set { base["Measurements"] = value; } 28 | } 29 | } 30 | public sealed class SettingsConfig : ConfigurationElement 31 | { 32 | [ConfigurationProperty("FailoverTimeout", IsRequired = true)] 33 | public int FailoverTimeout 34 | { 35 | get { return (int)base["FailoverTimeout"]; } 36 | set { base["FailoverTimeout"] = value; } 37 | } 38 | [ConfigurationProperty("Url", IsRequired = true)] 39 | public string Url 40 | { 41 | get { return (string)base["Url"]; } 42 | set { base["Url"] = value; } 43 | } 44 | } 45 | public sealed class MeasurementCollection : ConfigurationElementCollection 46 | { 47 | protected override ConfigurationElement CreateNewElement() 48 | { 49 | return new MeasurementConfig(); 50 | } 51 | 52 | protected override object GetElementKey(ConfigurationElement element) 53 | { 54 | return (((MeasurementConfig)element).UniqueId); 55 | } 56 | } 57 | public sealed class MeasurementConfig : ConfigurationElement 58 | { 59 | internal Guid UniqueId { get; set; } 60 | public MeasurementConfig() 61 | { 62 | UniqueId = Guid.NewGuid(); 63 | } 64 | [ConfigurationProperty("Name", IsRequired = true)] 65 | public string Name 66 | { 67 | get { return (string)base["Name"]; } 68 | set { base["Name"] = value; } 69 | } 70 | [ConfigurationProperty("DataType", IsRequired = true)] 71 | public string DataType 72 | { 73 | get { return (string)base["DataType"]; } 74 | set { base["DataType"] = value; } 75 | } 76 | 77 | [ConfigurationProperty("Path", IsRequired = true)] 78 | public string Path 79 | { 80 | get { return (string)base["Path"]; } 81 | set { base["Path"] = value; } 82 | } 83 | //[ConfigurationProperty("NodeId", IsRequired = true)] 84 | //public string NodeId 85 | //{ 86 | // get { return (string)base["NodeId"]; } 87 | // set { base["NodeId"] = value; } 88 | //} 89 | [ConfigurationProperty("CollectionType", IsRequired = true)] 90 | public string CollectionType 91 | { 92 | get { return (string)base["CollectionType"]; } 93 | set { base["CollectionType"] = value; } 94 | } 95 | [ConfigurationProperty("PollInterval")] 96 | public int PollInterval 97 | { 98 | get { return (int)base["PollInterval"]; } 99 | set { base["PollInterval"] = value; } 100 | } 101 | [ConfigurationProperty("MonitorResolution")] 102 | public int MonitorResolution 103 | { 104 | get { return (int)base["MonitorResolution"]; } 105 | set { base["MonitorResolution"] = value; } 106 | } 107 | [ConfigurationProperty("DeadbandAbsolute", IsRequired = true)] 108 | public int DeadbandAbsolute 109 | { 110 | get { return (int)base["DeadbandAbsolute"]; } 111 | set { base["DeadbandAbsolute"] = value; } 112 | } 113 | [ConfigurationProperty("DeadbandRelative", IsRequired = true)] 114 | public decimal DeadbandRelative 115 | { 116 | get { return (decimal)base["DeadbandRelative"]; } 117 | set { base["DeadbandRelative"] = value; } 118 | } 119 | [ConfigurationProperty("Tags")] 120 | public string Tags 121 | { 122 | get { return (string)base["Tags"]; } 123 | set { base["Tags"] = value; } 124 | } 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /Odenwald.InfluxDbPlugin/Odenwald.InfluxDbPlugin.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {084BE120-923F-4517-850C-17D1D5590AC9} 8 | Library 9 | Properties 10 | Odenwald.InfluxDbPlugin 11 | Odenwald.InfluxDbPlugin 12 | v4.6 13 | 512 14 | 15 | 16 | true 17 | full 18 | false 19 | bin\Debug\ 20 | DEBUG;TRACE 21 | prompt 22 | 4 23 | 24 | 25 | pdbonly 26 | true 27 | bin\Release\ 28 | TRACE 29 | prompt 30 | 4 31 | 32 | 33 | 34 | ..\packages\InfluxDB.Net-Main.1.0.20\lib\net45\InfluxDB.Net.dll 35 | 36 | 37 | ..\packages\log4net.2.0.7\lib\net45-full\log4net.dll 38 | True 39 | 40 | 41 | False 42 | ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | {bb7a7712-cc11-4d95-83dc-a0ab28714860} 64 | Odenwald 65 | 66 | 67 | 68 | 69 | PreserveNewest 70 | 71 | 72 | Designer 73 | 74 | 75 | 76 | 81 | 88 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ## Ignore Visual Studio temporary files, build results, and 2 | ## files generated by popular Visual Studio add-ons. 3 | 4 | # User-specific files 5 | *.suo 6 | *.user 7 | *.userosscache 8 | *.sln.docstates 9 | 10 | # User-specific files (MonoDevelop/Xamarin Studio) 11 | *.userprefs 12 | 13 | # Build results 14 | [Dd]ebug/ 15 | [Dd]ebugPublic/ 16 | [Rr]elease/ 17 | [Rr]eleases/ 18 | [Xx]64/ 19 | [Xx]86/ 20 | [Bb]uild/ 21 | bld/ 22 | [Bb]in/ 23 | [Oo]bj/ 24 | 25 | # Visual Studio 2015 cache/options directory 26 | .vs/ 27 | # Uncomment if you have tasks that create the project's static files in wwwroot 28 | #wwwroot/ 29 | 30 | # MSTest test Results 31 | [Tt]est[Rr]esult*/ 32 | [Bb]uild[Ll]og.* 33 | 34 | # NUNIT 35 | *.VisualState.xml 36 | TestResult.xml 37 | 38 | # Build Results of an ATL Project 39 | [Dd]ebugPS/ 40 | [Rr]eleasePS/ 41 | dlldata.c 42 | 43 | # DNX 44 | project.lock.json 45 | artifacts/ 46 | 47 | *_i.c 48 | *_p.c 49 | *_i.h 50 | *.ilk 51 | *.meta 52 | *.obj 53 | *.pch 54 | *.pdb 55 | *.pgc 56 | *.pgd 57 | *.rsp 58 | *.sbr 59 | *.tlb 60 | *.tli 61 | *.tlh 62 | *.tmp 63 | *.tmp_proj 64 | *.log 65 | *.vspscc 66 | *.vssscc 67 | .builds 68 | *.pidb 69 | *.svclog 70 | *.scc 71 | 72 | # Chutzpah Test files 73 | _Chutzpah* 74 | 75 | # Visual C++ cache files 76 | ipch/ 77 | *.aps 78 | *.ncb 79 | *.opendb 80 | *.opensdf 81 | *.sdf 82 | *.cachefile 83 | *.VC.db 84 | 85 | # Visual Studio profiler 86 | *.psess 87 | *.vsp 88 | *.vspx 89 | *.sap 90 | 91 | # TFS 2012 Local Workspace 92 | $tf/ 93 | 94 | # Guidance Automation Toolkit 95 | *.gpState 96 | 97 | # ReSharper is a .NET coding add-in 98 | _ReSharper*/ 99 | *.[Rr]e[Ss]harper 100 | *.DotSettings.user 101 | 102 | # JustCode is a .NET coding add-in 103 | .JustCode 104 | 105 | # TeamCity is a build add-in 106 | _TeamCity* 107 | 108 | # DotCover is a Code Coverage Tool 109 | *.dotCover 110 | 111 | # NCrunch 112 | _NCrunch_* 113 | .*crunch*.local.xml 114 | nCrunchTemp_* 115 | 116 | # MightyMoose 117 | *.mm.* 118 | AutoTest.Net/ 119 | 120 | # Web workbench (sass) 121 | .sass-cache/ 122 | 123 | # Installshield output folder 124 | [Ee]xpress/ 125 | 126 | # DocProject is a documentation generator add-in 127 | DocProject/buildhelp/ 128 | DocProject/Help/*.HxT 129 | DocProject/Help/*.HxC 130 | DocProject/Help/*.hhc 131 | DocProject/Help/*.hhk 132 | DocProject/Help/*.hhp 133 | DocProject/Help/Html2 134 | DocProject/Help/html 135 | 136 | # Click-Once directory 137 | publish/ 138 | 139 | # Publish Web Output 140 | *.[Pp]ublish.xml 141 | *.azurePubxml 142 | 143 | # TODO: Un-comment the next line if you do not want to checkin 144 | # your web deploy settings because they may include unencrypted 145 | # passwords 146 | #*.pubxml 147 | *.publishproj 148 | 149 | # NuGet Packages 150 | *.nupkg 151 | # The packages folder can be ignored because of Package Restore 152 | **/packages/* 153 | # except build/, which is used as an MSBuild target. 154 | !**/packages/build/ 155 | # Uncomment if necessary however generally it will be regenerated when needed 156 | #!**/packages/repositories.config 157 | # NuGet v3's project.json files produces more ignoreable files 158 | *.nuget.props 159 | *.nuget.targets 160 | 161 | # Microsoft Azure Build Output 162 | csx/ 163 | *.build.csdef 164 | 165 | # Microsoft Azure Emulator 166 | ecf/ 167 | rcf/ 168 | 169 | # Microsoft Azure ApplicationInsights config file 170 | ApplicationInsights.config 171 | 172 | # Windows Store app package directory 173 | AppPackages/ 174 | BundleArtifacts/ 175 | 176 | # Visual Studio cache files 177 | # files ending in .cache can be ignored 178 | *.[Cc]ache 179 | # but keep track of directories ending in .cache 180 | !*.[Cc]ache/ 181 | 182 | # Others 183 | ClientBin/ 184 | [Ss]tyle[Cc]op.* 185 | ~$* 186 | *~ 187 | *.dbmdl 188 | *.dbproj.schemaview 189 | *.pfx 190 | *.publishsettings 191 | node_modules/ 192 | orleans.codegen.cs 193 | 194 | # RIA/Silverlight projects 195 | Generated_Code/ 196 | 197 | # Backup & report files from converting an old project file 198 | # to a newer Visual Studio version. Backup files are not needed, 199 | # because we have git ;-) 200 | _UpgradeReport_Files/ 201 | Backup*/ 202 | UpgradeLog*.XML 203 | UpgradeLog*.htm 204 | 205 | # SQL Server files 206 | *.mdf 207 | *.ldf 208 | 209 | # Business Intelligence projects 210 | *.rdl.data 211 | *.bim.layout 212 | *.bim_*.settings 213 | 214 | # Microsoft Fakes 215 | FakesAssemblies/ 216 | 217 | # GhostDoc plugin setting file 218 | *.GhostDoc.xml 219 | 220 | # Node.js Tools for Visual Studio 221 | .ntvs_analysis.dat 222 | 223 | # Visual Studio 6 build log 224 | *.plg 225 | 226 | # Visual Studio 6 workspace options file 227 | *.opt 228 | 229 | # Visual Studio LightSwitch build output 230 | **/*.HTMLClient/GeneratedArtifacts 231 | **/*.DesktopClient/GeneratedArtifacts 232 | **/*.DesktopClient/ModelManifest.xml 233 | **/*.Server/GeneratedArtifacts 234 | **/*.Server/ModelManifest.xml 235 | _Pvt_Extensions 236 | 237 | # LightSwitch generated files 238 | GeneratedArtifacts/ 239 | ModelManifest.xml 240 | 241 | # Paket dependency manager 242 | .paket/paket.exe 243 | 244 | # FAKE - F# Make 245 | .fake/ -------------------------------------------------------------------------------- /Tests/Odenwald.OpcUaPluginTest/Odenwald.OpcUaPluginTest.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Debug 7 | AnyCPU 8 | {C46F6932-AB4C-4A49-A3BA-1F9690015A48} 9 | Library 10 | Properties 11 | Odenwald.OpcUaPluginTest 12 | Odenwald.OpcUaPluginTest 13 | v4.6 14 | 512 15 | 16 | 17 | 18 | 19 | true 20 | full 21 | false 22 | bin\Debug\ 23 | DEBUG;TRACE 24 | prompt 25 | 4 26 | 27 | 28 | pdbonly 29 | true 30 | bin\Release\ 31 | TRACE 32 | prompt 33 | 4 34 | 35 | 36 | 37 | ..\..\libs\Opc.Ua.Client.dll 38 | 39 | 40 | ..\..\libs\Opc.Ua.Core.dll 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | ..\..\packages\xunit.abstractions.2.0.0\lib\net35\xunit.abstractions.dll 52 | True 53 | 54 | 55 | ..\..\packages\xunit.assert.2.1.0\lib\dotnet\xunit.assert.dll 56 | True 57 | 58 | 59 | ..\..\packages\xunit.extensibility.core.2.1.0\lib\dotnet\xunit.core.dll 60 | True 61 | 62 | 63 | ..\..\packages\xunit.extensibility.execution.2.1.0\lib\net45\xunit.execution.desktop.dll 64 | True 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | {712b2914-bf62-4278-bfe2-eb6925760839} 77 | Odenwald.OpcUaPlugin 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. 87 | 88 | 89 | 90 | 97 | -------------------------------------------------------------------------------- /Odenwald.WindowsPerformanceCounterPlugin/Config/WindowsPerformanceCounterPluginConfig.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Configuration; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Odenwald.WindowsPerformanceCounterPlugin 9 | { 10 | public class WindowsPerformanceCounterPluginConfig : ConfigurationSection 11 | { 12 | [ConfigurationProperty("RefreshInstancesConfiguration", IsRequired = true)] 13 | public RefreshInstancesConfigurationConfig RefreshInstancesConfiguration 14 | { 15 | get { return (RefreshInstancesConfigurationConfig)base["RefreshInstancesConfiguration"]; } 16 | set { base["RefreshInstancesConfiguration"] = value; } 17 | } 18 | 19 | public sealed class RefreshInstancesConfigurationConfig : ConfigurationElement 20 | { 21 | [ConfigurationProperty("Enable", IsRequired = true)] 22 | public bool Enable 23 | { 24 | get { return (bool)base["Enable"]; } 25 | set { base["Enable"] = value; } 26 | } 27 | 28 | [ConfigurationProperty("Interval", IsRequired = true)] 29 | public int Interval 30 | { 31 | get { return (int)base["Interval"]; } 32 | set { base["Interval"] = value; } 33 | } 34 | } 35 | 36 | [ConfigurationProperty("Counters", IsRequired = false)] 37 | [ConfigurationCollection(typeof(CounterConfigCollection), AddItemName = "Counter")] 38 | public CounterConfigCollection Counters 39 | { 40 | get { return (CounterConfigCollection)base["Counters"]; } 41 | set { base["Counters"] = value; } 42 | } 43 | 44 | public static WindowsPerformanceCounterPluginConfig GetConfig() 45 | { 46 | return 47 | (WindowsPerformanceCounterPluginConfig) 48 | ConfigurationManager.GetSection("WindowsPerformanceCounterPlugin") ?? 49 | new WindowsPerformanceCounterPluginConfig(); 50 | } 51 | 52 | public sealed class CounterConfig : ConfigurationElement 53 | { 54 | [ConfigurationProperty("Transformer", IsRequired = false, DefaultValue = "")] 55 | public string Transformer 56 | { 57 | get { return (string)base["Transformer"]; } 58 | set { base["Transformer"] = value; } 59 | } 60 | 61 | [ConfigurationProperty("TransformerParameters", IsRequired = false)] 62 | public string TransformerParameters 63 | { 64 | get { return (string)base["TransformerParameters"]; } 65 | set { base["TransformerParameters"] = value; } 66 | } 67 | 68 | [ConfigurationProperty("Category", IsRequired = true)] 69 | public string Category 70 | { 71 | get { return (string)base["Category"]; } 72 | set { base["Category"] = value; } 73 | } 74 | 75 | [ConfigurationProperty("Name", IsRequired = true)] 76 | public string Name 77 | { 78 | get { return (string)base["Name"]; } 79 | set { base["Name"] = value; } 80 | } 81 | 82 | 83 | [ConfigurationProperty("Instance", IsRequired = false)] 84 | public string Instance 85 | { 86 | get { return (string)base["Instance"]; } 87 | set { base["Instance"] = value; } 88 | } 89 | 90 | [ConfigurationProperty("CollectdPlugin", IsRequired = true)] 91 | public string CollectdPlugin 92 | { 93 | get { return (string)base["CollectdPlugin"]; } 94 | set { base["CollectdPlugin"] = value; } 95 | } 96 | 97 | [ConfigurationProperty("CollectdPluginInstance", IsRequired = false)] 98 | public string CollectdPluginInstance 99 | { 100 | get { return (string)base["CollectdPluginInstance"]; } 101 | set { base["CollectdPluginInstance"] = value; } 102 | } 103 | 104 | [ConfigurationProperty("CollectdType", IsRequired = true)] 105 | public string CollectdType 106 | { 107 | get { return (string)base["CollectdType"]; } 108 | set { base["CollectdType"] = value; } 109 | } 110 | 111 | [ConfigurationProperty("CollectdTypeInstance", IsRequired = true)] 112 | public string CollectdTypeInstance 113 | { 114 | get { return (string)base["CollectdTypeInstance"]; } 115 | set { base["CollectdTypeInstance"] = value; } 116 | } 117 | } 118 | 119 | public sealed class CounterConfigCollection : ConfigurationElementCollection 120 | { 121 | protected override ConfigurationElement CreateNewElement() 122 | { 123 | return new CounterConfig(); 124 | } 125 | 126 | protected override object GetElementKey(ConfigurationElement element) 127 | { 128 | var counterConfig = (CounterConfig)element; 129 | return (counterConfig.CollectdPlugin + "_" + counterConfig.CollectdPluginInstance + "_" + counterConfig.CollectdType + "_" + counterConfig.CollectdTypeInstance); 130 | } 131 | } 132 | } 133 | } 134 | -------------------------------------------------------------------------------- /Tests/Odenwald.OpcUaPluginTest/OpcUaClientTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.Text; 5 | using System.Threading.Tasks; 6 | using Xunit; 7 | 8 | 9 | using Opc.Ua.Client; 10 | using Opc.Ua; 11 | using Odenwald.OpcUaPlugin; 12 | 13 | namespace Odenwald.OpcUaPluginTest 14 | { 15 | public class OpcUaClientTest 16 | { 17 | [Fact] 18 | public void TestFindNode() 19 | { 20 | ApplicationConfiguration l_applicationConfig = new ApplicationConfiguration() 21 | { 22 | 23 | ApplicationName = "OdenwaldUnitTest", 24 | ApplicationType = ApplicationType.Client, 25 | SecurityConfiguration = new SecurityConfiguration 26 | { 27 | ApplicationCertificate = new CertificateIdentifier 28 | { 29 | StoreType = @"Windows", 30 | StorePath = @"CurrentUser\My", 31 | SubjectName = Utils.Format(@"CN={0}, DC={1}", 32 | "Odenwald", 33 | System.Net.Dns.GetHostName()) 34 | }, 35 | TrustedPeerCertificates = new CertificateTrustList 36 | { 37 | StoreType = @"Windows", 38 | StorePath = @"CurrentUser\TrustedPeople", 39 | }, 40 | NonceLength = 32, 41 | AutoAcceptUntrustedCertificates = true 42 | }, 43 | TransportConfigurations = new TransportConfigurationCollection(), 44 | TransportQuotas = new TransportQuotas { OperationTimeout = 15000 }, 45 | ClientConfiguration = new ClientConfiguration { DefaultSessionTimeout = 60000 } 46 | }; 47 | l_applicationConfig.Validate(ApplicationType.Client); 48 | if (l_applicationConfig.SecurityConfiguration.AutoAcceptUntrustedCertificates) 49 | { 50 | l_applicationConfig.CertificateValidator.CertificateValidation += (s, e) => 51 | { e.Accept = (e.Error.StatusCode == StatusCodes.BadCertificateUntrusted); }; 52 | } 53 | 54 | Session l_session = Session.Create(l_applicationConfig, new ConfiguredEndpoint(null, new EndpointDescription("opc.tcp://ac-l32-m7-lth1:51210/UA/SampleServer")), true, "OdenwaldUnitTest", 60000, null, null);//EndpointDescription need to be changed according to your OPC server 55 | var nodeId = OpcUaHelper.GetReadValueIdCollection("Data.Dynamic.Scalar.Int32Value", Attributes.Value, l_session); 56 | Assert.Equal(nodeId[0].NodeId.ToString(), "ns=2;i=10849"); 57 | } 58 | [Fact] 59 | public void OpcUaHelperTest() 60 | { 61 | //config 62 | ApplicationConfiguration l_applicationConfig = new ApplicationConfiguration() 63 | { 64 | 65 | ApplicationName = "OdenwaldUnitTest", 66 | ApplicationType = ApplicationType.Client, 67 | SecurityConfiguration = new SecurityConfiguration 68 | { 69 | ApplicationCertificate = new CertificateIdentifier 70 | { 71 | StoreType = @"Windows", 72 | StorePath = @"CurrentUser\My", 73 | SubjectName = Utils.Format(@"CN={0}, DC={1}", 74 | "Odenwald", 75 | System.Net.Dns.GetHostName()) 76 | }, 77 | TrustedPeerCertificates = new CertificateTrustList 78 | { 79 | StoreType = @"Windows", 80 | StorePath = @"CurrentUser\TrustedPeople", 81 | }, 82 | NonceLength = 32, 83 | AutoAcceptUntrustedCertificates = true 84 | }, 85 | TransportConfigurations = new TransportConfigurationCollection(), 86 | TransportQuotas = new TransportQuotas { OperationTimeout = 15000 }, 87 | ClientConfiguration = new ClientConfiguration { DefaultSessionTimeout = 60000 } 88 | }; 89 | l_applicationConfig.Validate(ApplicationType.Client); 90 | if (l_applicationConfig.SecurityConfiguration.AutoAcceptUntrustedCertificates) 91 | { 92 | l_applicationConfig.CertificateValidator.CertificateValidation += (s, e) => 93 | { e.Accept = (e.Error.StatusCode == StatusCodes.BadCertificateUntrusted); }; 94 | } 95 | 96 | Session l_session = Session.Create(l_applicationConfig, new ConfiguredEndpoint(null, new EndpointDescription("opc.tcp://ac-l32-m7-lth1:51210/UA/SampleServer")), true, "OdenwaldUnitTest", 60000, null, null);//EndpointDescription need to be changed according to your OPC server 97 | 98 | string[] browsePaths = new string[] 99 | { 100 | "2:Data/2:Dynamic/2:Scalar/2:Int32Value" 101 | }; 102 | 103 | string nodeRelativePath = "Data.Dynamic.Scalar.Int32Value"; 104 | 105 | var nsCount = l_session.NamespaceUris.Count; 106 | string[] relativePaths = { "Objects/Data/Dynamic/Scalar/Int32Value/" }; 107 | relativePaths = nodeRelativePath.Split('.'); 108 | 109 | var nodeList = OpcUaHelper.TranslateBrowsePaths(l_session, ObjectIds.ObjectsFolder, l_session.NamespaceUris, browsePaths); 110 | 111 | Assert.NotNull(nodeList); 112 | Assert.Equal(1, nodeList.Count); 113 | 114 | } 115 | } 116 | } 117 | -------------------------------------------------------------------------------- /Odenwald.Common/Opc/OpcHelper.cs: -------------------------------------------------------------------------------- 1 | using log4net; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Linq; 5 | using System.Text; 6 | using System.Threading.Tasks; 7 | 8 | namespace Odenwald.Common.Opc 9 | { 10 | public static class OpcHelper 11 | { 12 | static ILog l_logger = LogManager.GetLogger(typeof(OpcHelper)); 13 | public static bool QualifyMetric(ref OpcMetric metric, Dictionary cache ) 14 | { 15 | if (PointHasGoodOrDifferentBadStatus(metric)) 16 | { 17 | if (!cache.ContainsKey(metric.Measurement.Name)) 18 | { 19 | cache.Add(metric.Measurement.Name, metric.OpcValue); 20 | metric.Measurement.LastOpcstatus = metric.Opcstatus; 21 | metric.Measurement.LastValue = metric.OpcValue; 22 | } 23 | else 24 | { 25 | object lastvalue; 26 | cache.TryGetValue(metric.Measurement.Name, out lastvalue); 27 | metric.Measurement.LastValue = lastvalue; 28 | } 29 | 30 | 31 | if (!PointIsValid(metric) || !PointMatchesType(metric)) 32 | { 33 | // Set de default value for the type specified 34 | l_logger.ErrorFormat("Invalid point: measurement.name<{0}>, measurement.path<{1}>, metric.value<{2}>", metric.Measurement.Name, metric.Measurement.Path, metric.OpcValue.ToString()); 35 | switch (metric.Measurement.DataType) 36 | { 37 | case "number": 38 | metric.OpcValue = 0; 39 | break; 40 | case "boolean": 41 | metric.OpcValue = false; 42 | break; 43 | case "string": 44 | metric.OpcValue = ""; 45 | break; 46 | default: 47 | l_logger.Error("No valid datatype, ignoring point"); 48 | break; 49 | } 50 | return false; 51 | } 52 | } 53 | // Check for deadband 54 | if (PointIsWithinDeadband(metric)) return false; 55 | if (!PointMatchesType(metric)) 56 | { 57 | l_logger.ErrorFormat("Invalid type returned from OPC. Ignoring point {0}", metric.Measurement.Name); 58 | return false; 59 | } 60 | return true; 61 | } 62 | 63 | static bool PointMatchesType(OpcMetric metric) 64 | { 65 | var match = (metric.OpcValue.IsNumber() && metric.Measurement.DataType == "number") 66 | || metric.OpcValue.IsBoolean() && metric.Measurement.DataType == "boolean" 67 | || metric.OpcValue.IsString() && metric.Measurement.DataType == "string"; 68 | 69 | if (!match) 70 | { 71 | //log here 72 | 73 | } 74 | return match; 75 | } 76 | static bool PointIsValid(OpcMetric p) 77 | { 78 | // check if the value is a type that we can handle (number or a bool). 79 | return (p.OpcValue != null && (p.OpcValue.IsBoolean() || p.OpcValue.IsNumber())) || p.OpcValue.IsString(); 80 | 81 | } 82 | static bool PointHasGoodOrDifferentBadStatus(OpcMetric p) 83 | { 84 | var curr = p.Opcstatus; 85 | var prev = p.Measurement.LastOpcstatus; 86 | 87 | if (curr == "Good" || curr != prev || curr == "S_OK") return true; 88 | return false; 89 | } 90 | 91 | 92 | static bool PointIsWithinDeadband(OpcMetric metric) 93 | { 94 | // some vars for shorter statements later on. 95 | var curr = metric.OpcValue; 96 | var prev = metric.Measurement.LastValue; 97 | var dba = metric.Measurement.DeadbandAbsolute; 98 | var dbr = metric.Measurement.DeadbandRelative; 99 | 100 | // return early if the type of the previous value is not the same as the current. 101 | // this will also return when this is the first value and prev is still undefined. 102 | if (curr.GetType() != prev.GetType()) return false; 103 | 104 | // calculate deadbands based on value type. For numbers, make the 105 | // calculations for both absolute and relative if they are set. For bool, 106 | // just check if a deadband has been set and if the value has changed. 107 | 108 | if (curr.IsNumber()) 109 | { 110 | 111 | if (dba > 0 && Math.Abs(System.Convert.ToDecimal(curr) - System.Convert.ToDecimal(prev)) < dba) 112 | { 113 | return true; 114 | } 115 | if (dbr > 0 && Math.Abs(System.Convert.ToDecimal(curr) - System.Convert.ToDecimal(prev)) < Math.Abs(System.Convert.ToDecimal(prev)) * dbr) 116 | { 117 | // console.log("New value is within relative deadband.", p); 118 | return true; 119 | 120 | } 121 | } 122 | else if (curr.IsBoolean()) 123 | { 124 | if (dba > 0 && prev == curr) 125 | // console.log("New value is within bool deadband.", p); 126 | return true; 127 | 128 | } 129 | else if (curr.IsString()) 130 | return true; 131 | return false; 132 | 133 | } 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /Odenwald/Config/OdenwaldConfig.cs: -------------------------------------------------------------------------------- 1 | 2 | // ---------------------------------------------------------------------------- 3 | // Copyright (C) 2017 Robinson. 4 | // https://github.com/robinson 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | using System; 15 | using System.Collections.Generic; 16 | using System.Configuration; 17 | 18 | namespace Odenwald 19 | { 20 | 21 | public class OdenwaldConfigHelper 22 | { 23 | public static IDictionary GetMetaData() 24 | { 25 | IDictionary metaData = new Dictionary(); 26 | 27 | var coreConfig = ConfigurationManager.GetSection("Odenwald") as OdenwaldConfig; 28 | if (coreConfig == null) 29 | { 30 | throw new Exception("Cannot get configuration section : Odenwald"); 31 | } 32 | foreach (OdenwaldConfig.TagConfig tagConfig in coreConfig.MetaData) 33 | { 34 | metaData[tagConfig.Name] = tagConfig.Value; 35 | } 36 | return (metaData); 37 | } 38 | } 39 | 40 | public class OdenwaldConfig : ConfigurationSection 41 | { 42 | [ConfigurationProperty("GeneralSettings", IsRequired = true)] 43 | public GeneralSettingsConfig GeneralSettings 44 | { 45 | get { return (GeneralSettingsConfig)base["GeneralSettings"]; } 46 | set { base["GeneralSettings"] = value; } 47 | } 48 | 49 | [ConfigurationProperty("Plugins", IsRequired = true)] 50 | [ConfigurationCollection(typeof(PluginCollection), AddItemName = "Plugin")] 51 | public PluginCollection Plugins 52 | { 53 | get { return (PluginCollection)base["Plugins"]; } 54 | set { base["Plugins"] = value; } 55 | } 56 | 57 | [ConfigurationProperty("MetaData", IsRequired = false)] 58 | [ConfigurationCollection(typeof(TagCollection), AddItemName = "Tag")] 59 | public TagCollection MetaData 60 | { 61 | get { return (TagCollection)base["MetaData"]; } 62 | set { base["MetaData"] = value; } 63 | } 64 | 65 | public static OdenwaldConfigHelper GetConfig() 66 | { 67 | return (OdenwaldConfigHelper)ConfigurationManager.GetSection("OdenwaldConfig") ?? new OdenwaldConfigHelper(); 68 | } 69 | 70 | public sealed class GeneralSettingsConfig : ConfigurationElement 71 | { 72 | [ConfigurationProperty("Interval", IsRequired = true)] 73 | public int Interval 74 | { 75 | get { return (int)base["Interval"]; } 76 | set { base["Interval"] = value; } 77 | } 78 | 79 | [ConfigurationProperty("Timeout", IsRequired = true)] 80 | public int Timeout 81 | { 82 | get { return (int)base["Timeout"]; } 83 | set { base["Timeout"] = value; } 84 | } 85 | 86 | [ConfigurationProperty("StoreRates", IsRequired = true)] 87 | public bool StoreRates 88 | { 89 | get { return (bool)base["StoreRates"]; } 90 | set { base["StoreRates"] = value; } 91 | } 92 | } 93 | 94 | public sealed class PluginCollection : ConfigurationElementCollection 95 | { 96 | protected override ConfigurationElement CreateNewElement() 97 | { 98 | return new PluginConfig(); 99 | } 100 | 101 | protected override object GetElementKey(ConfigurationElement element) 102 | { 103 | return (((PluginConfig)element).UniqueId); 104 | } 105 | } 106 | 107 | public sealed class PluginConfig : ConfigurationElement 108 | { 109 | public PluginConfig() 110 | { 111 | UniqueId = Guid.NewGuid(); 112 | } 113 | 114 | internal Guid UniqueId { get; set; } 115 | 116 | [ConfigurationProperty("Name", IsRequired = true)] 117 | public string Name 118 | { 119 | get { return (string)base["Name"]; } 120 | set { base["Name"] = value; } 121 | } 122 | 123 | [ConfigurationProperty("Class", IsRequired = true)] 124 | public string Class 125 | { 126 | get { return (string)base["Class"]; } 127 | set { base["Class"] = value; } 128 | } 129 | 130 | [ConfigurationProperty("Enable", IsRequired = true)] 131 | public bool Enable 132 | { 133 | get { return (bool)base["Enable"]; } 134 | set { base["Enable"] = value; } 135 | } 136 | } 137 | 138 | public sealed class TagCollection : ConfigurationElementCollection 139 | { 140 | protected override ConfigurationElement CreateNewElement() 141 | { 142 | return new TagConfig(); 143 | } 144 | 145 | protected override object GetElementKey(ConfigurationElement element) 146 | { 147 | return (((TagConfig)element).UniqueId); 148 | } 149 | } 150 | public sealed class TagConfig : ConfigurationElement 151 | { 152 | public TagConfig() 153 | { 154 | UniqueId = Guid.NewGuid(); 155 | } 156 | 157 | internal Guid UniqueId { get; set; } 158 | 159 | [ConfigurationProperty("Name", IsRequired = true)] 160 | public string Name 161 | { 162 | get { return (string)base["Name"]; } 163 | set { base["Name"] = value; } 164 | } 165 | 166 | [ConfigurationProperty("Value", IsRequired = true)] 167 | public string Value 168 | { 169 | get { return (string)base["Value"]; } 170 | set { base["Value"] = value; } 171 | } 172 | } 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /Odenwald.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Odenwald", "Odenwald\Odenwald.csproj", "{BB7A7712-CC11-4D95-83DC-A0AB28714860}" 7 | EndProject 8 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{BC6D364C-E228-46F3-B0DC-36E10395334B}" 9 | EndProject 10 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Plugins", "Plugins", "{5256FABB-EEFB-4508-A51C-EAC828656DE7}" 11 | EndProject 12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Odenwald.ConsolePlugin", "Odenwald.ConsolePlugin\Odenwald.ConsolePlugin.csproj", "{BA07862A-586A-47AC-9069-7D1904973A83}" 13 | EndProject 14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Odenwald.OpcUaPlugin", "Odenwald.OpcUaPlugin\Odenwald.OpcUaPlugin.csproj", "{712B2914-BF62-4278-BFE2-EB6925760839}" 15 | EndProject 16 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Odenwald.OpcUaPluginTest", "Tests\Odenwald.OpcUaPluginTest\Odenwald.OpcUaPluginTest.csproj", "{C46F6932-AB4C-4A49-A3BA-1F9690015A48}" 17 | EndProject 18 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Odenwald.InfluxDbPlugin", "Odenwald.InfluxDbPlugin\Odenwald.InfluxDbPlugin.csproj", "{084BE120-923F-4517-850C-17D1D5590AC9}" 19 | EndProject 20 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Odenwald.OpcDaPlugin", "Odenwald.OpcDaPlugin\Odenwald.OpcDaPlugin.csproj", "{3C3FD86F-220D-418F-B964-3C4590824FCE}" 21 | EndProject 22 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Odenwald.Common", "Odenwald.Common\Odenwald.Common.csproj", "{FEF57F91-04C1-4D42-BA2E-737697AB26C1}" 23 | EndProject 24 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Odenwald.KafkaProducerPlugin", "Odenwald.KafkaProducerPlugin\Odenwald.KafkaProducerPlugin.csproj", "{EEC9106E-6812-444B-9A5E-59CDF4022D4A}" 25 | EndProject 26 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Odenwald.KafkaConsumerPlugin", "Odenwald.KafkaConsumerPlugin\Odenwald.KafkaConsumerPlugin.csproj", "{B9A8E446-DB9F-46E9-BFCD-916A3D8424AA}" 27 | EndProject 28 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Odenwald.App", "Odenwald.App\Odenwald.App.csproj", "{AD130047-5631-4F12-B357-82B45E671C83}" 29 | EndProject 30 | Global 31 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 32 | Debug|Any CPU = Debug|Any CPU 33 | Release|Any CPU = Release|Any CPU 34 | EndGlobalSection 35 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 36 | {BB7A7712-CC11-4D95-83DC-A0AB28714860}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 37 | {BB7A7712-CC11-4D95-83DC-A0AB28714860}.Debug|Any CPU.Build.0 = Debug|Any CPU 38 | {BB7A7712-CC11-4D95-83DC-A0AB28714860}.Release|Any CPU.ActiveCfg = Release|Any CPU 39 | {BB7A7712-CC11-4D95-83DC-A0AB28714860}.Release|Any CPU.Build.0 = Release|Any CPU 40 | {BA07862A-586A-47AC-9069-7D1904973A83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 41 | {BA07862A-586A-47AC-9069-7D1904973A83}.Debug|Any CPU.Build.0 = Debug|Any CPU 42 | {BA07862A-586A-47AC-9069-7D1904973A83}.Release|Any CPU.ActiveCfg = Release|Any CPU 43 | {BA07862A-586A-47AC-9069-7D1904973A83}.Release|Any CPU.Build.0 = Release|Any CPU 44 | {712B2914-BF62-4278-BFE2-EB6925760839}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 45 | {712B2914-BF62-4278-BFE2-EB6925760839}.Debug|Any CPU.Build.0 = Debug|Any CPU 46 | {712B2914-BF62-4278-BFE2-EB6925760839}.Release|Any CPU.ActiveCfg = Release|Any CPU 47 | {712B2914-BF62-4278-BFE2-EB6925760839}.Release|Any CPU.Build.0 = Release|Any CPU 48 | {C46F6932-AB4C-4A49-A3BA-1F9690015A48}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 49 | {C46F6932-AB4C-4A49-A3BA-1F9690015A48}.Debug|Any CPU.Build.0 = Debug|Any CPU 50 | {C46F6932-AB4C-4A49-A3BA-1F9690015A48}.Release|Any CPU.ActiveCfg = Release|Any CPU 51 | {C46F6932-AB4C-4A49-A3BA-1F9690015A48}.Release|Any CPU.Build.0 = Release|Any CPU 52 | {084BE120-923F-4517-850C-17D1D5590AC9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 53 | {084BE120-923F-4517-850C-17D1D5590AC9}.Debug|Any CPU.Build.0 = Debug|Any CPU 54 | {084BE120-923F-4517-850C-17D1D5590AC9}.Release|Any CPU.ActiveCfg = Release|Any CPU 55 | {084BE120-923F-4517-850C-17D1D5590AC9}.Release|Any CPU.Build.0 = Release|Any CPU 56 | {3C3FD86F-220D-418F-B964-3C4590824FCE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 57 | {3C3FD86F-220D-418F-B964-3C4590824FCE}.Debug|Any CPU.Build.0 = Debug|Any CPU 58 | {3C3FD86F-220D-418F-B964-3C4590824FCE}.Release|Any CPU.ActiveCfg = Release|Any CPU 59 | {3C3FD86F-220D-418F-B964-3C4590824FCE}.Release|Any CPU.Build.0 = Release|Any CPU 60 | {FEF57F91-04C1-4D42-BA2E-737697AB26C1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 61 | {FEF57F91-04C1-4D42-BA2E-737697AB26C1}.Debug|Any CPU.Build.0 = Debug|Any CPU 62 | {FEF57F91-04C1-4D42-BA2E-737697AB26C1}.Release|Any CPU.ActiveCfg = Release|Any CPU 63 | {FEF57F91-04C1-4D42-BA2E-737697AB26C1}.Release|Any CPU.Build.0 = Release|Any CPU 64 | {EEC9106E-6812-444B-9A5E-59CDF4022D4A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 65 | {EEC9106E-6812-444B-9A5E-59CDF4022D4A}.Debug|Any CPU.Build.0 = Debug|Any CPU 66 | {EEC9106E-6812-444B-9A5E-59CDF4022D4A}.Release|Any CPU.ActiveCfg = Release|Any CPU 67 | {EEC9106E-6812-444B-9A5E-59CDF4022D4A}.Release|Any CPU.Build.0 = Release|Any CPU 68 | {B9A8E446-DB9F-46E9-BFCD-916A3D8424AA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 69 | {B9A8E446-DB9F-46E9-BFCD-916A3D8424AA}.Debug|Any CPU.Build.0 = Debug|Any CPU 70 | {B9A8E446-DB9F-46E9-BFCD-916A3D8424AA}.Release|Any CPU.ActiveCfg = Release|Any CPU 71 | {B9A8E446-DB9F-46E9-BFCD-916A3D8424AA}.Release|Any CPU.Build.0 = Release|Any CPU 72 | {AD130047-5631-4F12-B357-82B45E671C83}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 73 | {AD130047-5631-4F12-B357-82B45E671C83}.Debug|Any CPU.Build.0 = Debug|Any CPU 74 | {AD130047-5631-4F12-B357-82B45E671C83}.Release|Any CPU.ActiveCfg = Release|Any CPU 75 | {AD130047-5631-4F12-B357-82B45E671C83}.Release|Any CPU.Build.0 = Release|Any CPU 76 | EndGlobalSection 77 | GlobalSection(SolutionProperties) = preSolution 78 | HideSolutionNode = FALSE 79 | EndGlobalSection 80 | GlobalSection(NestedProjects) = preSolution 81 | {BA07862A-586A-47AC-9069-7D1904973A83} = {5256FABB-EEFB-4508-A51C-EAC828656DE7} 82 | {712B2914-BF62-4278-BFE2-EB6925760839} = {5256FABB-EEFB-4508-A51C-EAC828656DE7} 83 | {C46F6932-AB4C-4A49-A3BA-1F9690015A48} = {BC6D364C-E228-46F3-B0DC-36E10395334B} 84 | {084BE120-923F-4517-850C-17D1D5590AC9} = {5256FABB-EEFB-4508-A51C-EAC828656DE7} 85 | {3C3FD86F-220D-418F-B964-3C4590824FCE} = {5256FABB-EEFB-4508-A51C-EAC828656DE7} 86 | {EEC9106E-6812-444B-9A5E-59CDF4022D4A} = {5256FABB-EEFB-4508-A51C-EAC828656DE7} 87 | {B9A8E446-DB9F-46E9-BFCD-916A3D8424AA} = {5256FABB-EEFB-4508-A51C-EAC828656DE7} 88 | EndGlobalSection 89 | EndGlobal 90 | -------------------------------------------------------------------------------- /Odenwald/Type/Types.cs: -------------------------------------------------------------------------------- 1 | 2 | // ---------------------------------------------------------------------------- 3 | // Copyright (C) 2017 Robinson. 4 | // https://github.com/robinson 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | using log4net; 15 | using System; 16 | using System.Collections.Generic; 17 | using System.IO; 18 | using System.Text; 19 | using System.Text.RegularExpressions; 20 | 21 | namespace Odenwald 22 | { 23 | public enum DsType 24 | { 25 | Absolute, 26 | Counter, 27 | Derive, 28 | Gauge 29 | }; 30 | 31 | public enum Status 32 | { 33 | Success, 34 | Failure 35 | }; 36 | 37 | public class DataSource 38 | { 39 | public DataSource(string name, DsType type, double min, double max) 40 | { 41 | Name = name; 42 | Type = type; 43 | Min = min; 44 | Max = max; 45 | } 46 | 47 | public string Name { get; set; } 48 | public DsType Type { get; set; } 49 | public double Min { get; set; } 50 | public double Max { get; set; } 51 | } 52 | 53 | internal class DataSetCollection 54 | { 55 | private static ILog m_logger = LogManager.GetLogger(typeof(DataSetCollection)); 56 | private static volatile DataSetCollection _instance; 57 | private static readonly object SyncRoot = new Object(); 58 | 59 | private readonly Dictionary> _dataSetMap; 60 | // 61 | 62 | private DataSetCollection() 63 | { 64 | _dataSetMap = new Dictionary>(); 65 | } 66 | 67 | public static DataSetCollection Instance 68 | { 69 | get 70 | { 71 | if (_instance == null) 72 | { 73 | lock (SyncRoot) 74 | { 75 | if (_instance == null) 76 | { 77 | _instance = new DataSetCollection(); 78 | _instance.Load(); 79 | } 80 | } 81 | } 82 | return _instance; 83 | } 84 | } 85 | 86 | private static Status GetDouble(string dstr, out double val) 87 | { 88 | if (dstr == "u" || dstr == "U") 89 | { 90 | val = Double.NaN; 91 | return (Status.Success); 92 | } 93 | try 94 | { 95 | val = Double.Parse(dstr); 96 | } 97 | catch (Exception) 98 | { 99 | val = Double.NaN; 100 | return (Status.Failure); 101 | } 102 | return (Status.Success); 103 | } 104 | 105 | public void Print() 106 | { 107 | var sb = new StringBuilder(); 108 | foreach (var entry in _dataSetMap) 109 | { 110 | sb.Append(string.Format("\n[{0}] ==>", entry.Key)); 111 | foreach (DataSource ds in entry.Value) 112 | { 113 | sb.Append(string.Format(" [{0}:{1}:{2}:{3}]", ds.Name, ds.Type, ds.Min, ds.Max)); 114 | } 115 | } 116 | Console.WriteLine(sb.ToString()); 117 | } 118 | 119 | public void Load() 120 | { 121 | const string dataSetPattern = @"[\s\t]*(\w+)[\s\t]*(.*)$"; 122 | const string dataSourcePattern = @"(\w+):(ABSOLUTE|COUNTER|DERIVE|GAUGE):([+-]?\w+):([+-]?\w+)[,]?\s*"; 123 | 124 | var dataSetRegex = new Regex(dataSetPattern, RegexOptions.IgnoreCase); 125 | var dataSourceRegex = new Regex(dataSourcePattern, RegexOptions.IgnoreCase); 126 | 127 | string fileName = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, @"Type\types.db"); 128 | string[] lines = File.ReadAllLines(fileName); 129 | 130 | foreach (string line in lines) 131 | { 132 | // skip comments and blank lines 133 | if (line.StartsWith("#") || line.Trim() == string.Empty) 134 | { 135 | continue; 136 | } 137 | Match match = dataSetRegex.Match(line); 138 | if (match.Groups.Count < 3) 139 | { 140 | m_logger.ErrorFormat("types.db: invalid data set [{0}]", line); 141 | continue; 142 | } 143 | string dataSetName = match.Groups[1].Value; 144 | MatchCollection matches = dataSourceRegex.Matches(line); 145 | if (matches.Count < 1) 146 | { 147 | m_logger.ErrorFormat("types.db: invalid data source [{0}]", line); 148 | continue; 149 | } 150 | var dataSourceList = new List(); 151 | foreach (Match m in matches) 152 | { 153 | if (m.Groups.Count != 5) 154 | { 155 | m_logger.ErrorFormat("types.db: cannot parse data source [{0}]", line); 156 | dataSourceList.Clear(); 157 | break; 158 | } 159 | 160 | string dsName = m.Groups[1].Value; 161 | var dstype = (DsType)Enum.Parse(typeof(DsType), m.Groups[2].Value, true); 162 | 163 | double min, max; 164 | 165 | if (GetDouble(m.Groups[3].Value, out min) != Status.Success) 166 | { 167 | m_logger.Error(string.Format("types.db: invalid Min value [{0}]", line)); 168 | dataSourceList.Clear(); 169 | break; 170 | } 171 | 172 | if (GetDouble(m.Groups[4].Value, out max) != Status.Success) 173 | { 174 | m_logger.Error(string.Format("types.db: invalid Max value [{0}]", line)); 175 | dataSourceList.Clear(); 176 | break; 177 | } 178 | 179 | var ds = new DataSource(dsName, dstype, min, max); 180 | dataSourceList.Add(ds); 181 | } 182 | if (dataSourceList.Count > 0) 183 | { 184 | _dataSetMap[dataSetName] = dataSourceList; 185 | } 186 | } 187 | } 188 | 189 | public IList GetDataSource(string dataSetName) 190 | { 191 | IList dataSourceList; 192 | return (_dataSetMap.TryGetValue(dataSetName, out dataSourceList) ? (dataSourceList) : (null)); 193 | } 194 | } 195 | } 196 | -------------------------------------------------------------------------------- /Odenwald/Aggregator.cs: -------------------------------------------------------------------------------- 1 | 2 | // ---------------------------------------------------------------------------- 3 | // Copyright (C) 2017 Robinson. 4 | // https://github.com/robinson 5 | // Licensed under the Apache License, Version 2.0 (the "License"); 6 | // you may not use this file except in compliance with the License. 7 | // You may obtain a copy of the License at 8 | // http://www.apache.org/licenses/LICENSE-2.0 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | using log4net; 15 | using Odenwald.Common; 16 | using System; 17 | using System.Collections.Generic; 18 | using System.Linq; 19 | using System.Text; 20 | using System.Threading.Tasks; 21 | 22 | namespace Odenwald 23 | { 24 | internal class CacheEntry 25 | { 26 | public MetricValue MetricRate; 27 | public double[] RawValues; 28 | 29 | public CacheEntry(MetricValue metricValue) 30 | { 31 | MetricRate = metricValue; 32 | RawValues = (double[])metricValue.Values.Clone(); 33 | } 34 | } 35 | public class Aggregator 36 | { 37 | static ILog l_logger = LogManager.GetLogger(typeof(Aggregator)); 38 | readonly Dictionary l_cache; 39 | readonly Object l_cacheLock; 40 | readonly bool l_storeRates; 41 | readonly int l_timeoutSeconds; 42 | public Aggregator(int timeoutSeconds, bool storeRates) 43 | { 44 | l_cache = new Dictionary(); 45 | l_cacheLock = new object(); 46 | l_timeoutSeconds = timeoutSeconds; 47 | l_storeRates = storeRates; 48 | } 49 | 50 | 51 | 52 | 53 | public void Aggregate(ref MetricValue metric) 54 | { 55 | // If rates are not stored then there is nothing to aggregate 56 | if (!l_storeRates) 57 | { 58 | return; 59 | } 60 | IList dsl = DataSetCollection.Instance.GetDataSource(metric.TypeName); 61 | if (dsl == null || metric.Values.Length != dsl.Count) 62 | { 63 | return; 64 | } 65 | double now = Util.GetNow(); 66 | lock (l_cacheLock) 67 | { 68 | CacheEntry cEntry; 69 | string key = metric.Key; 70 | 71 | if (!(l_cache.TryGetValue(key, out cEntry))) 72 | { 73 | cEntry = new CacheEntry(metric.DeepCopy()); 74 | for (int i = 0; i < metric.Values.Length; i++) 75 | { 76 | if (dsl[i].Type == DsType.Derive || 77 | dsl[i].Type == DsType.Absolute || 78 | dsl[i].Type == DsType.Counter) 79 | { 80 | metric.Values[i] = double.NaN; 81 | cEntry.MetricRate.Values[i] = double.NaN; 82 | } 83 | } 84 | l_cache[key] = cEntry; 85 | return; 86 | } 87 | for (int i = 0; i < metric.Values.Length; i++) 88 | { 89 | double rawValNew = metric.Values[i]; 90 | double rawValOld = cEntry.RawValues[i]; 91 | double rawValDiff = rawValNew - rawValOld; 92 | double timeDiff = cEntry.MetricRate.Epoch - DateTimeOffset.Now.ToUnixTimeSeconds(); 93 | 94 | double rateNew = rawValDiff / timeDiff; 95 | 96 | switch (dsl[i].Type) 97 | { 98 | case DsType.Gauge: 99 | // no rates calculations are done, values are stored as-is for gauge 100 | cEntry.RawValues[i] = rawValNew; 101 | cEntry.MetricRate.Values[i] = rawValNew; 102 | break; 103 | 104 | case DsType.Absolute: 105 | // similar to gauge, except value will be divided by time diff 106 | cEntry.MetricRate.Values[i] = rawValNew / timeDiff; 107 | cEntry.RawValues[i] = rawValNew; 108 | metric.Values[i] = cEntry.MetricRate.Values[i]; 109 | break; 110 | 111 | case DsType.Derive: 112 | cEntry.RawValues[i] = rawValNew; 113 | cEntry.MetricRate.Values[i] = rateNew; 114 | metric.Values[i] = rateNew; 115 | 116 | break; 117 | 118 | case DsType.Counter: 119 | // Counters are very simlar to derive except when counter wraps around 120 | if (rawValNew < rawValOld) 121 | { 122 | // counter has wrapped around 123 | cEntry.MetricRate.Values[i] = rawValNew / timeDiff; 124 | cEntry.RawValues[i] = rawValNew; 125 | metric.Values[i] = cEntry.MetricRate.Values[i]; 126 | } 127 | else 128 | { 129 | cEntry.MetricRate.Values[i] = rateNew; 130 | cEntry.RawValues[i] = rawValNew; 131 | metric.Values[i] = rateNew; 132 | } 133 | break; 134 | } 135 | // range checks 136 | if (Convert.ToDouble(metric.Values[i]) < dsl[i].Min) 137 | { 138 | metric.Values[i] = dsl[i].Min; 139 | cEntry.RawValues[i] = metric.Values[i]; 140 | } 141 | if (Convert.ToDouble(metric.Values[i]) > dsl[i].Max) 142 | { 143 | metric.Values[i] = dsl[i].Max; 144 | cEntry.RawValues[i] = metric.Values[i]; 145 | } 146 | } 147 | } 148 | } 149 | 150 | public void RemoveExpiredEntries() 151 | {//TODO: consider about remove expired entries in the cache 152 | // If rates are not stored then there is nothing to remove 153 | if (!l_storeRates) 154 | { 155 | return; 156 | } 157 | double now = Util.GetNow(); 158 | double expirationTime = now - l_timeoutSeconds; 159 | var removeList = new List(); 160 | 161 | lock (l_cacheLock) 162 | { 163 | removeList.AddRange(from pair in l_cache 164 | let cEntry = pair.Value 165 | where cEntry.MetricRate.Epoch < expirationTime 166 | select pair.Key); 167 | if (removeList.Count > 0) 168 | l_logger.DebugFormat("Removing expired entries: {0}", removeList.Count); 169 | foreach (string key in removeList) 170 | { 171 | l_cache.Remove(key); 172 | } 173 | } 174 | } 175 | } 176 | } 177 | -------------------------------------------------------------------------------- /Odenwald.OpcDaPlugin/OpcDaPlugin.cs: -------------------------------------------------------------------------------- 1 | using log4net; 2 | using Odenwald.Common.Opc; 3 | using Opc; 4 | using System; 5 | using System.Collections.Concurrent; 6 | using System.Collections.Generic; 7 | using System.Linq; 8 | using System.Threading.Tasks; 9 | 10 | using Factory = OpcCom.Factory; 11 | using OpcDa = Opc.Da; 12 | 13 | namespace Odenwald.OpcDaPlugin 14 | { 15 | public class OpcDaPlugin : IMetricsReadPlugin, IDisposable 16 | { 17 | #region attributes 18 | static ILog l_logger = LogManager.GetLogger(typeof(OpcDaPlugin)); 19 | List PolledMeasurements; 20 | List MonitoredMeasurements; 21 | static Dictionary l_cache = new Dictionary(); 22 | BlockingCollection l_metricCollection; 23 | OpcPluginConfig l_opcDaPluginConfig; 24 | OpcDa.Server l_server; 25 | 26 | #endregion 27 | 28 | #region IMetricsReadPlugin 29 | public void Configure() 30 | { 31 | l_opcDaPluginConfig = OpcPluginConfig.GetConfig("OpcDa"); 32 | if (l_opcDaPluginConfig == null) 33 | { 34 | throw new Exception("Cannot get configuration section : OpcUa"); 35 | } 36 | 37 | } 38 | 39 | public IList Read() 40 | { 41 | if (l_metricCollection.Count <= 0) 42 | return null; 43 | List metricList = new List(); 44 | 45 | while (l_metricCollection.Count > 0) 46 | { 47 | 48 | OpcMetric data = null; 49 | try 50 | { 51 | data = l_metricCollection.Take(); 52 | } 53 | catch (InvalidOperationException) { } 54 | 55 | if (data != null) 56 | { 57 | MetricValue metricValue = new MetricValue() 58 | { 59 | TypeName = "gauge", 60 | TypeInstanceName = "gauge", 61 | //Interval = data.Measurement.mo 62 | HostName = "localhost", 63 | PluginInstanceName = "OpcDaPluginInstance", 64 | PluginName = "OpcDaPlugin", 65 | Extension = data.JsonString() 66 | }; 67 | metricList.Add(metricValue); 68 | } 69 | } 70 | l_logger.DebugFormat("Read {0} items.", metricList.Count); 71 | return metricList; 72 | } 73 | 74 | public void Start() 75 | { 76 | InitializeMeasurements(); 77 | Uri serverUri = new Uri(l_opcDaPluginConfig.Settings.Url); 78 | var opcServerUrl = new URL(serverUri.ToString()) 79 | { 80 | Scheme = serverUri.Scheme, 81 | HostName = serverUri.Host 82 | }; 83 | l_server = new OpcDa.Server(new Factory(), opcServerUrl); 84 | l_server.Connect(); 85 | 86 | l_metricCollection = new BlockingCollection(); 87 | StartMonitoring(); 88 | StartPolling(); 89 | } 90 | 91 | public void Stop() 92 | { 93 | if (l_server != null) 94 | l_server.Dispose(); 95 | } 96 | #endregion 97 | 98 | #region methods 99 | void InitializeMeasurements() 100 | { 101 | MonitoredMeasurements = new List(); 102 | PolledMeasurements = new List(); 103 | foreach (MeasurementConfig item in l_opcDaPluginConfig.Measurements) 104 | { 105 | Dictionary tags = null; 106 | if (!item.Tags.Equals("")) 107 | tags = item.Tags.Split(new[] { ';' }, StringSplitOptions.RemoveEmptyEntries) 108 | .Select(part => part.Split(':')) 109 | .ToDictionary(split => split[0], split => split[1]); 110 | switch (item.CollectionType) 111 | { 112 | case "monitored": 113 | 114 | var monitoredpoint = new MonitoredMeasurement() 115 | { 116 | Name = item.Name, 117 | Path = item.Path, 118 | MonitorResolution = item.MonitorResolution > 0 ? item.MonitorResolution : 0, 119 | DeadbandAbsolute = item.DeadbandAbsolute > 0 ? item.DeadbandAbsolute : 0, 120 | DeadbandRelative = item.DeadbandRelative > 0 ? item.DeadbandRelative : 0, 121 | DataType = item.DataType, 122 | Tags = tags 123 | 124 | }; 125 | 126 | MonitoredMeasurements.Add(monitoredpoint); 127 | break; 128 | case "polled": 129 | var polledPoint = new PolledMeasurement() 130 | { 131 | Name = item.Name, 132 | Path = item.Path, 133 | DeadbandAbsolute = item.DeadbandAbsolute > 0 ? item.DeadbandAbsolute : 0, 134 | DeadbandRelative = item.DeadbandRelative > 0 ? item.DeadbandRelative : 0, 135 | PollInterval = item.PollInterval, 136 | DataType = item.DataType, 137 | Tags = tags 138 | }; 139 | 140 | PolledMeasurements.Add(polledPoint); 141 | 142 | break; 143 | default: 144 | //no collection type, log 145 | l_logger.DebugFormat("no collection type at: {0}", item.Name); 146 | break; 147 | } 148 | } 149 | 150 | } 151 | void StartMonitoring() 152 | { 153 | foreach (var item in MonitoredMeasurements) 154 | { 155 | var subItem = new OpcDa.SubscriptionState 156 | { 157 | Name = item.Name, 158 | Active = true, 159 | UpdateRate = item.MonitorResolution 160 | }; 161 | var sub = l_server.CreateSubscription(subItem); 162 | sub.DataChanged += (handle, requestHandle, values) => 163 | { 164 | var p = values[0]; 165 | MonitorData(item, p); 166 | }; 167 | sub.AddItems(new[] { new OpcDa.Item { ItemName = item.Path } }); 168 | sub.SetEnabled(true); 169 | } 170 | } 171 | 172 | private void MonitorData(MonitoredMeasurement measurement, OpcDa.ItemValueResult p) 173 | { 174 | OpcMetric metric = new OpcMetric() 175 | { 176 | Timestamp = p.Timestamp, 177 | OpcValue = p.Value, 178 | Opcstatus = p.ResultID.ToString(), 179 | Measurement = (MeasurementDto)measurement 180 | }; 181 | l_metricCollection.Add(metric); 182 | } 183 | 184 | void StartPolling() 185 | { 186 | foreach (var item in PolledMeasurements) 187 | { 188 | var task = Task.Factory.StartNew((Func)(async () => // <- marked async 189 | { 190 | do 191 | { 192 | ReadMeasurement(item); 193 | await Task.Delay(TimeSpan.FromMilliseconds(item.PollInterval)); 194 | } while (true); 195 | })); 196 | } 197 | } 198 | void ReadMeasurement(PolledMeasurement measurement) 199 | { 200 | var item = new OpcDa.Item { ItemName = measurement.Path }; 201 | if (l_server == null || l_server.GetStatus().ServerState != OpcDa.serverState.running) 202 | { 203 | l_logger.ErrorFormat(string.Format("Server not connected. Cannot read path {0}.", measurement.Name)); 204 | throw new Exception(string.Format("Server not connected. Cannot read path {0}.",measurement.Name)); 205 | } 206 | var result = l_server.Read(new[] { item })[0]; 207 | if (result == null) 208 | { 209 | l_logger.Error("the server replied with an empty response!!!"); 210 | throw new Exception("the server replied with an empty response");//if any item cannot read, throw exeption 211 | } 212 | if (result.ResultID.ToString() != "S_OK") 213 | { 214 | l_logger.ErrorFormat(string.Format("Invalid response from the server. (Response Status: {0}, Opc Tag: {1})", result.ResultID, measurement.Path)); 215 | throw new Exception(string.Format("Invalid response from the server. (Response Status: {0}, Opc Tag: {1})", result.ResultID, measurement.Path)); 216 | } 217 | 218 | OpcMetric metric = new OpcMetric() 219 | { 220 | Measurement = measurement, 221 | Opcstatus = result.ResultID.ToString(), 222 | OpcValue = result.Value, 223 | Timestamp = result.Timestamp 224 | 225 | }; 226 | if (OpcHelper.QualifyMetric(ref metric, l_cache)) 227 | { 228 | l_cache[metric.Measurement.Name] = metric.OpcValue; 229 | l_metricCollection.Add(metric); 230 | } 231 | } 232 | 233 | public void Dispose() 234 | { 235 | if (l_server != null) 236 | l_server.Dispose(); 237 | GC.SuppressFinalize(this); 238 | } 239 | #endregion 240 | } 241 | } 242 | -------------------------------------------------------------------------------- /Odenwald.App/Odenwald.App.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {AD130047-5631-4F12-B357-82B45E671C83} 8 | Exe 9 | Properties 10 | Odenwald.App 11 | Odenwald.App 12 | v4.6 13 | 512 14 | publish\ 15 | true 16 | Disk 17 | false 18 | Foreground 19 | 7 20 | Days 21 | false 22 | false 23 | true 24 | 0 25 | 1.0.0.%2a 26 | false 27 | false 28 | true 29 | 30 | 31 | true 32 | full 33 | false 34 | bin\Debug\ 35 | DEBUG;TRACE 36 | prompt 37 | 4 38 | false 39 | 40 | 41 | pdbonly 42 | true 43 | bin\Release\ 44 | TRACE 45 | prompt 46 | 4 47 | 48 | 49 | 50 | 51 | 52 | 53 | ..\packages\log4net.2.0.7\lib\net45-full\log4net.dll 54 | True 55 | 56 | 57 | ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll 58 | True 59 | 60 | 61 | ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll 62 | True 63 | 64 | 65 | ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll 66 | True 67 | 68 | 69 | ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll 70 | True 71 | 72 | 73 | 74 | 75 | 76 | 77 | ..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Extensions.dll 78 | True 79 | 80 | 81 | ..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Primitives.dll 82 | True 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | Component 96 | 97 | 98 | OdenwaldService.cs 99 | 100 | 101 | 102 | 103 | 104 | 105 | {bb7a7712-cc11-4d95-83dc-a0ab28714860} 106 | Odenwald 107 | 108 | 109 | 110 | 111 | Designer 112 | 113 | 114 | 115 | 116 | 117 | False 118 | Microsoft .NET Framework 4.6 %28x86 and x64%29 119 | true 120 | 121 | 122 | False 123 | .NET Framework 3.5 SP1 124 | false 125 | 126 | 127 | 128 | 129 | xcopy "$(SolutionDir)Odenwald.ConsolePlugin\bin\$(ConfigurationName)\*.dll" .\*.* /Y 130 | xcopy "$(SolutionDir)Odenwald.ConsolePlugin\bin\$(ConfigurationName)\*.pdb" .\*.* /Y 131 | xcopy "$(SolutionDir)Odenwald.WindowsPerformanceCounterPlugin\bin\$(ConfigurationName)\*.dll" .\*.* /Y 132 | xcopy "$(SolutionDir)Odenwald.WindowsPerformanceCounterPlugin\bin\$(ConfigurationName)\*.pdb" .\*.* /Y 133 | xcopy "$(SolutionDir)Odenwald.WindowsPerformanceCounterPlugin\bin\$(ConfigurationName)\*.config" .\Config\*.* /Y 134 | xcopy "$(SolutionDir)Odenwald.OpcUaPlugin\bin\$(ConfigurationName)\*.dll" .\*.* /Y 135 | xcopy "$(SolutionDir)Odenwald.OpcUaPlugin\bin\$(ConfigurationName)\*.pdb" .\*.* /Y 136 | xcopy "$(SolutionDir)Odenwald.OpcUaPlugin\bin\$(ConfigurationName)\*.config" .\Config\*.* /Y 137 | xcopy "$(SolutionDir)Odenwald.OpcDaPlugin\bin\$(ConfigurationName)\*.dll" .\*.* /Y 138 | xcopy "$(SolutionDir)Odenwald.OpcDaPlugin\bin\$(ConfigurationName)\*.pdb" .\*.* /Y 139 | xcopy "$(SolutionDir)Odenwald.OpcDaPlugin\bin\$(ConfigurationName)\*.config" .\Config\*.* /Y 140 | xcopy "$(SolutionDir)Odenwald.InfluxDbPlugin\bin\$(ConfigurationName)\*.dll" .\*.* /Y 141 | xcopy "$(SolutionDir)Odenwald.InfluxDbPlugin\bin\$(ConfigurationName)\*.pdb" .\*.* /Y 142 | xcopy "$(SolutionDir)Odenwald.InfluxDbPlugin\bin\$(ConfigurationName)\*.config" .\Config\*.* /Y 143 | xcopy "$(SolutionDir)Odenwald.KafkaProducerPlugin\bin\$(ConfigurationName)\*.dll" .\*.* /Y 144 | xcopy "$(SolutionDir)Odenwald.KafkaProducerPlugin\bin\$(ConfigurationName)\*.pdb" .\*.* /Y 145 | xcopy "$(SolutionDir)Odenwald.KafkaProducerPlugin\bin\$(ConfigurationName)\*.config" .\Config\*.* /Y 146 | xcopy "$(SolutionDir)Odenwald.KafkaConsumerPlugin\bin\$(ConfigurationName)\*.dll" .\*.* /Y 147 | xcopy "$(SolutionDir)Odenwald.KafkaConsumerPlugin\bin\$(ConfigurationName)\*.pdb" .\*.* /Y 148 | xcopy "$(SolutionDir)Odenwald.KafkaConsumerPlugin\bin\$(ConfigurationName)\*.config" .\Config\*.* /Y 149 | 150 | 151 | del "$(SolutionDir)Odenwald.App\bin\*.*" /Q /F 152 | 153 | 154 | 155 | 156 | 157 | 158 | 165 | -------------------------------------------------------------------------------- /Odenwald.Service/Odenwald.Service.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {AD130047-5631-4F12-B357-82B45E671C83} 8 | Exe 9 | Properties 10 | Odenwald.Service 11 | Odenwald.Service 12 | v4.6 13 | 512 14 | publish\ 15 | true 16 | Disk 17 | false 18 | Foreground 19 | 7 20 | Days 21 | false 22 | false 23 | true 24 | 0 25 | 1.0.0.%2a 26 | false 27 | false 28 | true 29 | 30 | 31 | true 32 | full 33 | false 34 | bin\Debug\ 35 | DEBUG;TRACE 36 | prompt 37 | 4 38 | false 39 | 40 | 41 | pdbonly 42 | true 43 | bin\Release\ 44 | TRACE 45 | prompt 46 | 4 47 | 48 | 49 | 50 | 51 | 52 | 53 | ..\packages\log4net.2.0.7\lib\net45-full\log4net.dll 54 | True 55 | 56 | 57 | ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.dll 58 | True 59 | 60 | 61 | ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.dll 62 | True 63 | 64 | 65 | ..\packages\Microsoft.Bcl.Async.1.0.168\lib\net40\Microsoft.Threading.Tasks.Extensions.Desktop.dll 66 | True 67 | 68 | 69 | ..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll 70 | True 71 | 72 | 73 | 74 | 75 | 76 | 77 | ..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Extensions.dll 78 | True 79 | 80 | 81 | ..\packages\Microsoft.Net.Http.2.2.28\lib\net45\System.Net.Http.Primitives.dll 82 | True 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | Component 96 | 97 | 98 | OdenwaldService.cs 99 | 100 | 101 | 102 | 103 | 104 | 105 | {bb7a7712-cc11-4d95-83dc-a0ab28714860} 106 | Odenwald 107 | 108 | 109 | 110 | 111 | Designer 112 | 113 | 114 | 115 | 116 | 117 | False 118 | Microsoft .NET Framework 4.6 %28x86 and x64%29 119 | true 120 | 121 | 122 | False 123 | .NET Framework 3.5 SP1 124 | false 125 | 126 | 127 | 128 | 129 | xcopy "$(SolutionDir)Odenwald.ConsolePlugin\bin\$(ConfigurationName)\*.dll" .\*.* /Y 130 | xcopy "$(SolutionDir)Odenwald.ConsolePlugin\bin\$(ConfigurationName)\*.pdb" .\*.* /Y 131 | xcopy "$(SolutionDir)Odenwald.WindowsPerformanceCounterPlugin\bin\$(ConfigurationName)\*.dll" .\*.* /Y 132 | xcopy "$(SolutionDir)Odenwald.WindowsPerformanceCounterPlugin\bin\$(ConfigurationName)\*.pdb" .\*.* /Y 133 | xcopy "$(SolutionDir)Odenwald.WindowsPerformanceCounterPlugin\bin\$(ConfigurationName)\*.config" .\Config\*.* /Y 134 | xcopy "$(SolutionDir)Odenwald.OpcUaPlugin\bin\$(ConfigurationName)\*.dll" .\*.* /Y 135 | xcopy "$(SolutionDir)Odenwald.OpcUaPlugin\bin\$(ConfigurationName)\*.pdb" .\*.* /Y 136 | xcopy "$(SolutionDir)Odenwald.OpcUaPlugin\bin\$(ConfigurationName)\*.config" .\Config\*.* /Y 137 | xcopy "$(SolutionDir)Odenwald.OpcDaPlugin\bin\$(ConfigurationName)\*.dll" .\*.* /Y 138 | xcopy "$(SolutionDir)Odenwald.OpcDaPlugin\bin\$(ConfigurationName)\*.pdb" .\*.* /Y 139 | xcopy "$(SolutionDir)Odenwald.OpcDaPlugin\bin\$(ConfigurationName)\*.config" .\Config\*.* /Y 140 | xcopy "$(SolutionDir)Odenwald.InfluxDbPlugin\bin\$(ConfigurationName)\*.dll" .\*.* /Y 141 | xcopy "$(SolutionDir)Odenwald.InfluxDbPlugin\bin\$(ConfigurationName)\*.pdb" .\*.* /Y 142 | xcopy "$(SolutionDir)Odenwald.InfluxDbPlugin\bin\$(ConfigurationName)\*.config" .\Config\*.* /Y 143 | xcopy "$(SolutionDir)Odenwald.KafkaProducerPlugin\bin\$(ConfigurationName)\*.dll" .\*.* /Y 144 | xcopy "$(SolutionDir)Odenwald.KafkaProducerPlugin\bin\$(ConfigurationName)\*.pdb" .\*.* /Y 145 | xcopy "$(SolutionDir)Odenwald.KafkaProducerPlugin\bin\$(ConfigurationName)\*.config" .\Config\*.* /Y 146 | xcopy "$(SolutionDir)Odenwald.KafkaConsumerPlugin\bin\$(ConfigurationName)\*.dll" .\*.* /Y 147 | xcopy "$(SolutionDir)Odenwald.KafkaConsumerPlugin\bin\$(ConfigurationName)\*.pdb" .\*.* /Y 148 | xcopy "$(SolutionDir)Odenwald.KafkaConsumerPlugin\bin\$(ConfigurationName)\*.config" .\Config\*.* /Y 149 | 150 | 151 | del "$(SolutionDir)Odenwald.Service\bin\*.*" /Q /F 152 | 153 | 154 | 155 | 156 | 157 | 158 | 165 | -------------------------------------------------------------------------------- /Odenwald/Type/types.db: -------------------------------------------------------------------------------- 1 | # 2 | # types.db - Data-set specifications for the system statistics collection daemon collectd 3 | # This file is a copy from following URL: 4 | # https://raw.githubusercontent.com/collectd/collectd/master/src/types.db 5 | # 6 | # The types.db file contains one line for each data-set specification. Each 7 | # line consists of two fields delimited by spaces and/or horizontal tabs. 8 | # The first field defines the name of the data-set, while the second field 9 | # defines a list of data-source specifications, delimited by spaces and, 10 | # optionally, a comma (",") right after each list-entry. 11 | # 12 | # The format of the data-source specification has been inspired by RRDtool's 13 | # data-source specification. Each data-source is defined by a quadruple made 14 | # up of the data-source name, type, minimal and maximal values, delimited by 15 | # colons (":"): ds-name:ds-type:min:max. ds-type may be either ABSOLUTE, 16 | # COUNTER, DERIVE, or GAUGE. min and max define the range of valid values for 17 | # data stored for this data-source. If U is specified for either the min or 18 | # max value, it will be set to unknown, meaning that no range checks will 19 | # happen. See rrdcreate(1) for more details. 20 | # 21 | # 22 | absolute value:ABSOLUTE:0:U 23 | apache_bytes value:DERIVE:0:U 24 | apache_connections value:GAUGE:0:65535 25 | apache_idle_workers value:GAUGE:0:65535 26 | apache_requests value:DERIVE:0:U 27 | apache_scoreboard value:GAUGE:0:65535 28 | ath_nodes value:GAUGE:0:65535 29 | ath_stat value:DERIVE:0:U 30 | backends value:GAUGE:0:65535 31 | bitrate value:GAUGE:0:4294967295 32 | blocked_clients value:GAUGE:0:U 33 | bytes value:GAUGE:0:U 34 | cache_eviction value:DERIVE:0:U 35 | cache_operation value:DERIVE:0:U 36 | cache_ratio value:GAUGE:0:100 37 | cache_result value:DERIVE:0:U 38 | cache_size value:GAUGE:0:U 39 | ceph_bytes value:GAUGE:U:U 40 | ceph_latency value:GAUGE:U:U 41 | ceph_rate value:DERIVE:0:U 42 | changes_since_last_save value:GAUGE:0:U 43 | charge value:GAUGE:0:U 44 | compression_ratio value:GAUGE:0:2 45 | compression uncompressed:DERIVE:0:U, compressed:DERIVE:0:U 46 | connections value:DERIVE:0:U 47 | conntrack value:GAUGE:0:4294967295 48 | contextswitch value:DERIVE:0:U 49 | count value:GAUGE:0:U 50 | counter value:COUNTER:U:U 51 | cpufreq value:GAUGE:0:U 52 | cpu value:DERIVE:0:U 53 | current_connections value:GAUGE:0:U 54 | current_sessions value:GAUGE:0:U 55 | current value:GAUGE:U:U 56 | delay value:GAUGE:-1000000:1000000 57 | derive value:DERIVE:0:U 58 | df_complex value:GAUGE:0:U 59 | df_inodes value:GAUGE:0:U 60 | df used:GAUGE:0:1125899906842623, free:GAUGE:0:1125899906842623 61 | disk_latency read:GAUGE:0:U, write:GAUGE:0:U 62 | disk_merged read:DERIVE:0:U, write:DERIVE:0:U 63 | disk_octets read:DERIVE:0:U, write:DERIVE:0:U 64 | disk_ops_complex value:DERIVE:0:U 65 | disk_ops read:DERIVE:0:U, write:DERIVE:0:U 66 | disk_time read:DERIVE:0:U, write:DERIVE:0:U 67 | disk_io_time io_time:DERIVE:0:U, weighted_io_time:DERIVE:0:U 68 | dns_answer value:DERIVE:0:U 69 | dns_notify value:DERIVE:0:U 70 | dns_octets queries:DERIVE:0:U, responses:DERIVE:0:U 71 | dns_opcode value:DERIVE:0:U 72 | dns_qtype_cached value:GAUGE:0:4294967295 73 | dns_qtype value:DERIVE:0:U 74 | dns_query value:DERIVE:0:U 75 | dns_question value:DERIVE:0:U 76 | dns_rcode value:DERIVE:0:U 77 | dns_reject value:DERIVE:0:U 78 | dns_request value:DERIVE:0:U 79 | dns_resolver value:DERIVE:0:U 80 | dns_response value:DERIVE:0:U 81 | dns_transfer value:DERIVE:0:U 82 | dns_update value:DERIVE:0:U 83 | dns_zops value:DERIVE:0:U 84 | drbd_resource value:DERIVE:0:U 85 | duration seconds:GAUGE:0:U 86 | email_check value:GAUGE:0:U 87 | email_count value:GAUGE:0:U 88 | email_size value:GAUGE:0:U 89 | entropy value:GAUGE:0:4294967295 90 | expired_keys value:GAUGE:0:U 91 | fanspeed value:GAUGE:0:U 92 | file_size value:GAUGE:0:U 93 | files value:GAUGE:0:U 94 | flow value:GAUGE:0:U 95 | fork_rate value:DERIVE:0:U 96 | frequency_offset value:GAUGE:-1000000:1000000 97 | frequency value:GAUGE:0:U 98 | fscache_stat value:DERIVE:0:U 99 | gauge value:GAUGE:U:U 100 | hash_collisions value:DERIVE:0:U 101 | http_request_methods value:DERIVE:0:U 102 | http_requests value:DERIVE:0:U 103 | http_response_codes value:DERIVE:0:U 104 | humidity value:GAUGE:0:100 105 | if_collisions value:DERIVE:0:U 106 | if_dropped rx:DERIVE:0:U, tx:DERIVE:0:U 107 | if_errors rx:DERIVE:0:U, tx:DERIVE:0:U 108 | if_multicast value:DERIVE:0:U 109 | if_octets rx:DERIVE:0:U, tx:DERIVE:0:U 110 | if_packets rx:DERIVE:0:U, tx:DERIVE:0:U 111 | if_rx_errors value:DERIVE:0:U 112 | if_rx_octets value:DERIVE:0:U 113 | if_tx_errors value:DERIVE:0:U 114 | if_tx_octets value:DERIVE:0:U 115 | invocations value:DERIVE:0:U 116 | io_octets rx:DERIVE:0:U, tx:DERIVE:0:U 117 | io_packets rx:DERIVE:0:U, tx:DERIVE:0:U 118 | ipt_bytes value:DERIVE:0:U 119 | ipt_packets value:DERIVE:0:U 120 | irq value:DERIVE:0:U 121 | latency value:GAUGE:0:U 122 | links value:GAUGE:0:U 123 | load shortterm:GAUGE:0:5000, midterm:GAUGE:0:5000, longterm:GAUGE:0:5000 124 | md_disks value:GAUGE:0:U 125 | memcached_command value:DERIVE:0:U 126 | memcached_connections value:GAUGE:0:U 127 | memcached_items value:GAUGE:0:U 128 | memcached_octets rx:DERIVE:0:U, tx:DERIVE:0:U 129 | memcached_ops value:DERIVE:0:U 130 | memory value:GAUGE:0:281474976710656 131 | memory_lua value:GAUGE:0:281474976710656 132 | multimeter value:GAUGE:U:U 133 | mutex_operations value:DERIVE:0:U 134 | mysql_commands value:DERIVE:0:U 135 | mysql_handler value:DERIVE:0:U 136 | mysql_locks value:DERIVE:0:U 137 | mysql_log_position value:DERIVE:0:U 138 | mysql_octets rx:DERIVE:0:U, tx:DERIVE:0:U 139 | mysql_bpool_pages value:GAUGE:0:U 140 | mysql_bpool_bytes value:GAUGE:0:U 141 | mysql_bpool_counters value:DERIVE:0:U 142 | mysql_innodb_data value:DERIVE:0:U 143 | mysql_innodb_dblwr value:DERIVE:0:U 144 | mysql_innodb_log value:DERIVE:0:U 145 | mysql_innodb_pages value:DERIVE:0:U 146 | mysql_innodb_row_lock value:DERIVE:0:U 147 | mysql_innodb_rows value:DERIVE:0:U 148 | mysql_select value:DERIVE:0:U 149 | mysql_sort value:DERIVE:0:U 150 | nfs_procedure value:DERIVE:0:U 151 | nginx_connections value:GAUGE:0:U 152 | nginx_requests value:DERIVE:0:U 153 | node_octets rx:DERIVE:0:U, tx:DERIVE:0:U 154 | node_rssi value:GAUGE:0:255 155 | node_stat value:DERIVE:0:U 156 | node_tx_rate value:GAUGE:0:127 157 | objects value:GAUGE:0:U 158 | operations value:DERIVE:0:U 159 | packets value:DERIVE:0:U 160 | pending_operations value:GAUGE:0:U 161 | percent value:GAUGE:0:100.1 162 | percent_bytes value:GAUGE:0:100.1 163 | percent_inodes value:GAUGE:0:100.1 164 | pf_counters value:DERIVE:0:U 165 | pf_limits value:DERIVE:0:U 166 | pf_source value:DERIVE:0:U 167 | pf_states value:GAUGE:0:U 168 | pf_state value:DERIVE:0:U 169 | pg_blks value:DERIVE:0:U 170 | pg_db_size value:GAUGE:0:U 171 | pg_n_tup_c value:DERIVE:0:U 172 | pg_n_tup_g value:GAUGE:0:U 173 | pg_numbackends value:GAUGE:0:U 174 | pg_scan value:DERIVE:0:U 175 | pg_xact value:DERIVE:0:U 176 | ping_droprate value:GAUGE:0:100 177 | ping_stddev value:GAUGE:0:65535 178 | ping value:GAUGE:0:65535 179 | players value:GAUGE:0:1000000 180 | power value:GAUGE:0:U 181 | pressure value:GAUGE:0:U 182 | protocol_counter value:DERIVE:0:U 183 | ps_code value:GAUGE:0:9223372036854775807 184 | ps_count processes:GAUGE:0:1000000, threads:GAUGE:0:1000000 185 | ps_cputime user:DERIVE:0:U, syst:DERIVE:0:U 186 | ps_data value:GAUGE:0:9223372036854775807 187 | ps_disk_octets read:DERIVE:0:U, write:DERIVE:0:U 188 | ps_disk_ops read:DERIVE:0:U, write:DERIVE:0:U 189 | ps_pagefaults minflt:DERIVE:0:U, majflt:DERIVE:0:U 190 | ps_rss value:GAUGE:0:9223372036854775807 191 | ps_stacksize value:GAUGE:0:9223372036854775807 192 | ps_state value:GAUGE:0:65535 193 | ps_vm value:GAUGE:0:9223372036854775807 194 | pubsub value:GAUGE:0:U 195 | queue_length value:GAUGE:0:U 196 | records value:GAUGE:0:U 197 | requests value:GAUGE:0:U 198 | response_time value:GAUGE:0:U 199 | response_code value:GAUGE:0:U 200 | route_etx value:GAUGE:0:U 201 | route_metric value:GAUGE:0:U 202 | routes value:GAUGE:0:U 203 | segments value:GAUGE:0:65535 204 | serial_octets rx:DERIVE:0:U, tx:DERIVE:0:U 205 | signal_noise value:GAUGE:U:0 206 | signal_power value:GAUGE:U:0 207 | signal_quality value:GAUGE:0:U 208 | smart_poweron value:GAUGE:0:U 209 | smart_powercycles value:GAUGE:0:U 210 | smart_badsectors value:GAUGE:0:U 211 | smart_temperature value:GAUGE:-300:300 212 | smart_attribute current:GAUGE:0:255, worst:GAUGE:0:255, threshold:GAUGE:0:255, pretty:GAUGE:0:U 213 | snr value:GAUGE:0:U 214 | spam_check value:GAUGE:0:U 215 | spam_score value:GAUGE:U:U 216 | spl value:GAUGE:U:U 217 | swap_io value:DERIVE:0:U 218 | swap value:GAUGE:0:1099511627776 219 | tcp_connections value:GAUGE:0:4294967295 220 | temperature value:GAUGE:U:U 221 | threads value:GAUGE:0:U 222 | time_dispersion value:GAUGE:-1000000:1000000 223 | timeleft value:GAUGE:0:U 224 | time_offset value:GAUGE:-1000000:1000000 225 | total_bytes value:DERIVE:0:U 226 | total_connections value:DERIVE:0:U 227 | total_objects value:DERIVE:0:U 228 | total_operations value:DERIVE:0:U 229 | total_requests value:DERIVE:0:U 230 | total_sessions value:DERIVE:0:U 231 | total_threads value:DERIVE:0:U 232 | total_time_in_ms value:DERIVE:0:U 233 | total_values value:DERIVE:0:U 234 | uptime value:GAUGE:0:4294967295 235 | users value:GAUGE:0:65535 236 | vcl value:GAUGE:0:65535 237 | vcpu value:GAUGE:0:U 238 | virt_cpu_total value:DERIVE:0:U 239 | virt_vcpu value:DERIVE:0:U 240 | vmpage_action value:DERIVE:0:U 241 | vmpage_faults minflt:DERIVE:0:U, majflt:DERIVE:0:U 242 | vmpage_io in:DERIVE:0:U, out:DERIVE:0:U 243 | vmpage_number value:GAUGE:0:4294967295 244 | volatile_changes value:GAUGE:0:U 245 | voltage_threshold value:GAUGE:U:U, threshold:GAUGE:U:U 246 | voltage value:GAUGE:U:U 247 | vs_memory value:GAUGE:0:9223372036854775807 248 | vs_processes value:GAUGE:0:65535 249 | vs_threads value:GAUGE:0:65535 250 | 251 | # 252 | # Legacy types 253 | # (required for the v5 upgrade target) 254 | # 255 | arc_counts demand_data:COUNTER:0:U, demand_metadata:COUNTER:0:U, prefetch_data:COUNTER:0:U, prefetch_metadata:COUNTER:0:U 256 | arc_l2_bytes read:COUNTER:0:U, write:COUNTER:0:U 257 | arc_l2_size value:GAUGE:0:U 258 | arc_ratio value:GAUGE:0:U 259 | arc_size current:GAUGE:0:U, target:GAUGE:0:U, minlimit:GAUGE:0:U, maxlimit:GAUGE:0:U 260 | mysql_qcache hits:COUNTER:0:U, inserts:COUNTER:0:U, not_cached:COUNTER:0:U, lowmem_prunes:COUNTER:0:U, queries_in_cache:GAUGE:0:U 261 | mysql_threads running:GAUGE:0:U, connected:GAUGE:0:U, cached:GAUGE:0:U, created:COUNTER:0:U 262 | --------------------------------------------------------------------------------