工业福利!用.NET快速开发物联网扫码器设备的通用扫码功能

net · 浏览次数 : 0

小编点评

```csharp public class ScannerController : ControllerBase { private readonly ICodeReader _reader; public ScannerController(ICodeReader reader) { _reader = reader; } [HttpPost] public IActionResult Connection([FromBody] List clientInfos) { // 创建一个StringBuilder对象用于存储返回的结果信息 var result = new StringBuilder(); try { // 处理每个客户端的信息 foreach (var client in clientInfos) { // 连接到服务器 using (var socket = new Socket(_reader.Client.Address, _reader.Client.Port)) { // 发送命令 socket.Send(client.Command); // 接收响应 var response = socket.Receive(); // 处理响应 switch (client.Brand) { case "Keyence": if (response.Length != 1) { result.Append("Error: Invalid response length from Keyence scanner.\n"); } else { var message = Encoding.UTF8.GetString(response, 0, response.Length); result.Append($"Scan result: {message}\n"); } break; // 其他品牌的处理逻辑 // ... } } } // 所有客户端的处理完成,发送成功信息 result.Append("Scan successful!\n"); } catch (Exception ex) { // 处理异常 result.Append("Error: " + ex.Message + "\n"); } // 返回结果信息 return Ok(result.ToString()); } } public class ReaderClientInfo { public string Command { get; set; } public string Brand { get; set; } // 其他参数,例如 Start、End 等,根据具体品牌需求设置 } ``` **改进说明:** * 使用 `List` 存储客户端信息,可以方便地处理多个客户端。 * 使用 `switch` 语句可以简化处理不同品牌的逻辑。 * 使用 `Exception` 来捕获并处理异常。 * 添加 `[HttpGet]` 和 `[HttpDelete]` 属性,根据需要添加路由。

正文

不管你是用.net framework还是用.net core或者更高版本.net环境,这篇文章也许都能帮到你!因为接下来我会提供一个简单粗暴的方式,来快速实现多款扫码器的通用扫码功能。目前本地测试过的包括基恩士系列、康耐视系列、以及其他支持以太网通信的多款小众厂家等。

下面开始重点操作:

首先,在你的项目里面引用Wesky.Net.OpenTools 包,1.0.7以及以上版本均可。

 

如果你是在.netframework环境下面开放,或者是没有使用依赖注入的项目中使用,使用方式可以直接new一个对象来使用,有关使用如下代码:

ICodeReader reader = new CodeReader();
ReaderClientInfo clientInfo = new ReaderClientInfo(); // 扫码器客户端实例
clientInfo.Ip = IPAddress.Parse("192.168.1.102"); // 扫码器IP
clientInfo.Port = 3000; // 扫码器端口号
clientInfo.Count = 3;  // 没扫到码重试次数
clientInfo.SendTimeOut = 3000; // 请求超时 毫秒
clientInfo.ReceiveTimeOut = 3000; // 接收扫码内容超时 毫秒
clientInfo.Brand = "SR"; // 扫码器品牌
clientInfo.Command = "CMD"; // 扫码器触发指令,指令可通过各个扫码器厂家提供的配置软件,配置为通用的
clientInfo.ReaderNo = 1;  // 扫码器编号,可自定义,例如有10个,就可以配置1-10号
clientInfo.CloseCommand = ""; // 停止触发指令,如果没有则默认空字符串即可
​
ReaderResultInfo res = reader.ReaderConnection(ref clientInfo); // 通信连接,连接扫码器服务端,参数返回客户端实例 以及 标准返回值类型ReaderResultInfo
if (!res.IsSucceed)
{
    Console.WriteLine($"与扫码器建立通信连接失败:{res.Message}");
    return;
}
res = reader.ReaderRead(ref clientInfo); // 传入扫码器客户端实例,进行扫码。并参数内返回最新的扫码器客户端实例
if (!res.IsSucceed)
{
   Console.WriteLine($"扫码异常:{res.Message}");
    return;
}
else
{
    Console.WriteLine($"扫到码:{res.Value}  扫码耗时:{res.ElapsedMilliseconds}");
}
 

当然,强烈建议你们的项目使用.net core或以上环境。毕竟.net core是开源的,还可以跨平台,不管你是在Windows运行还是在Linux,都可以运行。

下面是在.net core或以上环境下的使用。例如我新建一个.net 8的webapi项目,

对ICodeReader接口和CodeReader类进行依赖注入的注册,建议使用瞬时生命周期,可以提高多个扫码器同时存在时的并发扫码效率。

例如:builder.Services.AddTransient<ICodeReader, CodeReader>(); 

 

 

建议新建一个全局实体类属性,用于存储扫码器的所有客户端实例,用于保持实例长连接。

例如:

public class ReaderClients{    public static ReaderClientInfo[] Clients { getset; }=new ReaderClientInfo[0];}

 

 

 

扫码器服务注入和使用.此处为了方便,我直接创建一个api控制器来演示,并对ICodeReader进行了构造函数注入。大佬们请自行根据实际情况进行操作。

 

 

假设有一个方法,或者接口等,传入一批扫码设备的配置信息,例如配置文件读取、数据库读取、或者其他任意方式配置的扫码器集合信息,传给连接接口或者方法等。然后根据传入的配置信息,进行对每个设备通信连接:

 

 

访问扫码函数,进行触发扫码操作。以下案例仅供参考,请根据个人实际情况进行优化或者修改。例如修改扫码次数、扫码成功或失败的其他处理等等。

 

控制器内所有代码如下:

 1  public class ScannerController : ControllerBase
 2  {
 3      private readonly ICodeReader _reader;
 4      public ScannerController(ICodeReader reader)
 5      {
 6          _reader = reader;
 7      }
 8  9      [HttpPost]
10      public IActionResult Connection([FromBody] List<ReaderClientInfo> clientInfos)
11      {
12          // 创建一个StringBuilder对象用于存储返回的结果信息
13          var result = new StringBuilder();
14          try
15          {
16              if (clientInfos == null || clientInfos.Count == 0)
17              {
18                  return Ok("没有可用客户连接信息"); // No available client connection info.
19              }
20 21              // 为全局静态数组分配空间
22              ReaderClients.Clients = new ReaderClientInfo[clientInfos.Count];
23 24              // 用于追踪失败的连接,以便存储到全局数组中
25              for (int i = 0; i < clientInfos.Count; i++)
26              {
27                  var clientInfo = clientInfos[i];
28                  // 尝试与读卡器设备建立连接
29                  var res = _reader.ReaderConnection(ref clientInfo);
30                  if (res.IsSucceed)
31                  {
32                      // 连接成功,记录成功信息
33                      result.AppendLine($"{DateTime.Now:yyyy/MM/dd HH:mm:ss}>>>与扫码器设备通信连接成功:{res.Message}");
34                  }
35                  else
36                  {
37                      // 连接失败,记录失败信息并将客户端信息存储到全局静态数组中
38                      ReaderClients.Clients[i] = clientInfo;
39                      result.AppendLine($"{DateTime.Now:yyyy/MM/dd HH:mm:ss}>>>通信连接失败");
40                  }
41              }
42 43              // 返回所有连接结果
44              return Ok(result.ToString());
45          }
46          catch (Exception ex)
47          {
48              // 异常处理,返回异常信息
49              return Ok($"{DateTime.Now:yyyy/MM/dd HH:mm:ss}>>>通信连接失败: {ex.Message}");
50          }
51      }
52 53      [HttpPost]
54      public IActionResult BeginScanner(int count)
55      {
56          const string timeFormat = "yyyy/MM/dd HH:mm:ss";
57          StringBuilder result = new StringBuilder();
58          if (ReaderClients.Clients == null || !ReaderClients.Clients.Any())
59          {
60              return Ok($"{DateTime.Now.ToString(timeFormat)} >>> 没有可连接的扫码器客户端,无法启动扫描功能。");
61          }
62          try
63          {
64              for (int now = 1; now <= count; now++)
65              {
66                  var res = _reader.ReaderRead(ref ReaderClients.Clients[0]); // 假设第一个客户端已连接。下标0代表第一个扫码器,请根据实际情况修改。
67                  if (res.IsSucceed)
68                  {
69                      result.AppendLine($"{DateTime.Now.ToString(timeFormat)} >>> 第{now}次扫码,扫码结果:{res.Message}");
70                  }
71                  else
72                  {
73                      result.AppendLine($"{DateTime.Now.ToString(timeFormat)} >>> 第{now}次扫码,扫码失败:{res.Value} 扫码耗时:{res.ElapsedMilliseconds}毫秒");
74                  }
75              }
76          }
77          catch (Exception ex)
78          {
79              result.AppendLine($"{DateTime.Now.ToString(timeFormat)} >>> 扫码异常:{ex.Message}");
80          }
81          return Ok(result.ToString());
82      }
83  }

 

其他介绍:扫码器配置参数和通用返回值参数对应实体类说明。

扫码器客户端配置实体类:

 1 /// <summary>
 2 /// Represents the client configuration for a scanner.
 3 /// 表示扫描器的客户端配置。
 4 /// </summary>
 5 public class ReaderClientInfo
 6 {
 7     /// <summary>
 8     /// The IP address of the scanner.
 9     /// 扫描器的IP地址。
10     /// </summary>
11     public IPAddress Ip { get; set; }
12 13     /// <summary>
14     /// The port number for the scanner connection.
15     /// 扫描器连接的端口号。
16     /// </summary>
17     public int Port { get; set; }
18 19     /// <summary>
20     /// Number of retry attempts if no code is scanned.
21     /// 如果没有扫描到码的重试次数。
22     /// </summary>
23     public short Count { get; set; }
24 25     /// <summary>
26     /// The socket connection to the scanner.
27     /// 扫描器的Socket连接。
28     /// </summary>
29     public Socket Client { get; set; }
30 31     /// <summary>
32     /// The identifier number of the scanner.
33     /// 扫描器的编号。
34     /// </summary>
35     public ushort ReaderNo { get; set; }
36 37     /// <summary>
38     /// Timeout in milliseconds for sending requests.
39     /// 发送请求的超时时间(毫秒)。
40     /// </summary>
41     public int SendTimeOut { get; set; } = 3000;
42 43     /// <summary>
44     /// Timeout in milliseconds for receiving responses.
45     /// 接收响应的超时时间(毫秒)。
46     /// </summary>
47     public int ReceiveTimeOut { get; set; } = 3000;
48 49     /// <summary>
50     /// The brand of the scanner, such as Keyence, Cognex, OPT, etc.
51     /// 扫描器的品牌,例如基恩士、康耐视、OPT等等。
52     /// </summary>
53     public string Brand { get; set; }
54 55     /// <summary>
56     /// Command to trigger the scan.
57     /// 触发扫描的命令。
58     /// </summary>
59     public string Command { get; set; }
60 61     /// <summary>
62     /// Command to stop triggering the scanner (used by Keyence).
63     /// 停止触发扫描器的命令(基恩士使用)。
64     /// </summary>
65     public string CloseCommand { get; set; }
66 67     /// <summary>
68     /// Start character for commands, if applicable (empty string if none).
69     /// 命令的起始字符(如果有),没有则为空字符串。
70     /// </summary>
71     public string Start { get; set; } = string.Empty;
72 73     /// <summary>
74     /// End character for commands, such as '\r\n' for Keyence; empty if not used.
75     /// 命令的结束字符,如基恩士使用的'\r\n';如果不使用则为空字符串。
76     /// </summary>
77     public string End { get; set; } = string.Empty;
78 }

 

 

返回值实体类:

 1   /// <summary>
 2   /// Represents the result information from a scanner.
 3   /// 表示扫描器的结果信息。
 4   /// </summary>
 5   public class ReaderResultInfo
 6   {
 7       /// <summary>
 8       /// Indicates whether the scan was successful.
 9       /// 指示扫描是否成功。
10       /// </summary>
11       public bool IsSucceed { get; set; } = false;
12 13       /// <summary>
14       /// The error message if the scan failed.
15       /// 如果扫描失败,错误信息。
16       /// </summary>
17       public string Message { get; set; } = string.Empty;
18 19       /// <summary>
20       /// The result of the scan.
21       /// 扫描结果。
22       /// </summary>
23       public string Value { get; set; } = string.Empty;
24 25       /// <summary>
26       /// The time taken for the scan in milliseconds.
27       /// 扫描所耗费的时间(毫秒)。
28       /// </summary>
29       public long ElapsedMilliseconds { get; set; } = 0;
30 31       /// <summary>
32       /// The number identifying the scanner.
33       /// 扫描器编号。
34       /// </summary>
35       public ushort ReaderNo { get; set; } = 0;
36 37       /// <summary>
38       /// The brand of the scanner.
39       /// 扫描器品牌。
40       /// </summary>
41       public string Brand { get; set; } = string.Empty;
42     }  

 

如果觉得有帮助,欢迎点赞、分享​。

​不介意也可关注个人公众号:Dotnet Dancer

 

不管你是用.net framework还是用.net core或者更高版本.net环境,这篇文章也许都能帮到你!因为接下来我会提供一个简单粗暴的方式,来快速实现多款扫码器的通用扫码功能。目前本地测试过的包括基恩士系列、康耐视系列、以及其他支持以太网通信的多款小众厂家等。

下面开始重点操作:

首先,在你的项目里面引用Wesky.Net.OpenTools 包,1.0.7以及以上版本均可。

如果你是在.netframework环境下面开放,或者是没有使用依赖注入的项目中使用,使用方式可以直接new一个对象来使用,有关使用如下代码:

ICodeReader reader = new CodeReader();ReaderClientInfo clientInfo = new ReaderClientInfo(); // 扫码器客户端实例clientInfo.Ip = IPAddress.Parse("192.168.1.102"); // 扫码器IPclientInfo.Port = 3000; // 扫码器端口号clientInfo.Count = 3;  // 没扫到码重试次数clientInfo.SendTimeOut = 3000; // 请求超时 毫秒clientInfo.ReceiveTimeOut = 3000; // 接收扫码内容超时 毫秒clientInfo.Brand = "SR"; // 扫码器品牌clientInfo.Command = "CMD"; // 扫码器触发指令,指令可通过各个扫码器厂家提供的配置软件,配置为通用的clientInfo.ReaderNo = 1;  // 扫码器编号,可自定义,例如有10个,就可以配置1-10号clientInfo.CloseCommand = ""; // 停止触发指令,如果没有则默认空字符串即可ReaderResultInfo res = reader.ReaderConnection(ref clientInfo); // 通信连接,连接扫码器服务端,参数返回客户端实例 以及 标准返回值类型ReaderResultInfoif (!res.IsSucceed){    Console.WriteLine($"与扫码器建立通信连接失败:{res.Message}");    return;}res = reader.ReaderRead(ref clientInfo); // 传入扫码器客户端实例,进行扫码。并参数内返回最新的扫码器客户端实例if (!res.IsSucceed){   Console.WriteLine($"扫码异常:{res.Message}");    return;}else{    Console.WriteLine($"扫到码:{res.Value}  扫码耗时:{res.ElapsedMilliseconds}");}

 

当然,强烈建议你们的项目使用.net core或以上环境。毕竟.net core是开源的,还可以跨平台,不管你是在Windows运行还是在Linux,都可以运行。

下面是在.net core或以上环境下的使用。例如我新建一个.net 8的webapi项目,

对ICodeReader接口和CodeReader类进行依赖注入的注册,建议使用瞬时生命周期,可以提高多个扫码器同时存在时的并发扫码效率。

例如:builder.Services.AddTransient<ICodeReader, CodeReader>(); 

 

 

建议新建一个全局实体类属性,用于存储扫码器的所有客户端实例,用于保持实例长连接。

例如:

public class ReaderClients{    public static ReaderClientInfo[] Clients { getset; }=new ReaderClientInfo[0];}

 

 

扫码器服务注入和使用.此处为了方便,我直接创建一个api控制器来演示,并对ICodeReader进行了构造函数注入。大佬们请自行根据实际情况进行操作。

 

假设有一个方法,或者接口等,传入一批扫码设备的配置信息,例如配置文件读取、数据库读取、或者其他任意方式配置的扫码器集合信息,传给连接接口或者方法等。然后根据传入的配置信息,进行对每个设备通信连接:

 

访问扫码函数,进行触发扫码操作。以下案例仅供参考,请根据个人实际情况进行优化或者修改。例如修改扫码次数、扫码成功或失败的其他处理等等。

控制器内所有代码如下:

 public class ScannerController : ControllerBase {     private readonly ICodeReader _reader;     public ScannerController(ICodeReader reader)     {         _reader = reader;     }     [HttpPost]     public IActionResult Connection([FromBody] List<ReaderClientInfo> clientInfos)     {         // 创建一个StringBuilder对象用于存储返回的结果信息         var result = new StringBuilder();         try         {             if (clientInfos == null || clientInfos.Count == 0)             {                 return Ok("没有可用客户连接信息"); // No available client connection info.             }             // 为全局静态数组分配空间             ReaderClients.Clients = new ReaderClientInfo[clientInfos.Count];             // 用于追踪失败的连接,以便存储到全局数组中             for (int i = 0; i < clientInfos.Count; i++)             {                 var clientInfo = clientInfos[i];                 // 尝试与读卡器设备建立连接                 var res = _reader.ReaderConnection(ref clientInfo);                 if (res.IsSucceed)                 {                     // 连接成功,记录成功信息                     result.AppendLine($"{DateTime.Now:yyyy/MM/dd HH:mm:ss}>>>与扫码器设备通信连接成功:{res.Message}");                 }                 else                 {                     // 连接失败,记录失败信息并将客户端信息存储到全局静态数组中                     ReaderClients.Clients[i] = clientInfo;                     result.AppendLine($"{DateTime.Now:yyyy/MM/dd HH:mm:ss}>>>通信连接失败");                 }             }             // 返回所有连接结果             return Ok(result.ToString());         }         catch (Exception ex)         {             // 异常处理,返回异常信息             return Ok($"{DateTime.Now:yyyy/MM/dd HH:mm:ss}>>>通信连接失败: {ex.Message}");         }     }     [HttpPost]     public IActionResult BeginScanner(int count)     {         const string timeFormat = "yyyy/MM/dd HH:mm:ss";         StringBuilder result = new StringBuilder();         if (ReaderClients.Clients == null || !ReaderClients.Clients.Any())         {             return Ok($"{DateTime.Now.ToString(timeFormat)} >>> 没有可连接的扫码器客户端,无法启动扫描功能。");         }         try         {             for (int now = 1; now <= count; now++)             {                 var res = _reader.ReaderRead(ref ReaderClients.Clients[0]); // 假设第一个客户端已连接。下标0代表第一个扫码器,请根据实际情况修改。                 if (res.IsSucceed)                 {                     result.AppendLine($"{DateTime.Now.ToString(timeFormat)} >>> 第{now}次扫码,扫码结果:{res.Message}");                 }                 else                 {                     result.AppendLine($"{DateTime.Now.ToString(timeFormat)} >>> 第{now}次扫码,扫码失败:{res.Value} 扫码耗时:{res.ElapsedMilliseconds}毫秒");                 }             }         }         catch (Exception ex)         {             result.AppendLine($"{DateTime.Now.ToString(timeFormat)} >>> 扫码异常:{ex.Message}");         }         return Ok(result.ToString());     } }

其他介绍:扫码器配置参数和通用返回值参数对应实体类说明。

扫码器客户端配置实体类:

/// <summary>/// Represents the client configuration for a scanner./// 表示扫描器的客户端配置。/// </summary>public class ReaderClientInfo{    /// <summary>    /// The IP address of the scanner.    /// 扫描器的IP地址。    /// </summary>    public IPAddress Ip { get; set; }    /// <summary>    /// The port number for the scanner connection.    /// 扫描器连接的端口号。    /// </summary>    public int Port { get; set; }    /// <summary>    /// Number of retry attempts if no code is scanned.    /// 如果没有扫描到码的重试次数。    /// </summary>    public short Count { get; set; }    /// <summary>    /// The socket connection to the scanner.    /// 扫描器的Socket连接。    /// </summary>    public Socket Client { get; set; }    /// <summary>    /// The identifier number of the scanner.    /// 扫描器的编号。    /// </summary>    public ushort ReaderNo { get; set; }    /// <summary>    /// Timeout in milliseconds for sending requests.    /// 发送请求的超时时间(毫秒)。    /// </summary>    public int SendTimeOut { get; set; } = 3000;    /// <summary>    /// Timeout in milliseconds for receiving responses.    /// 接收响应的超时时间(毫秒)。    /// </summary>    public int ReceiveTimeOut { get; set; } = 3000;    /// <summary>    /// The brand of the scanner, such as Keyence, Cognex, OPT, etc.    /// 扫描器的品牌,例如基恩士、康耐视、OPT等等。    /// </summary>    public string Brand { get; set; }    /// <summary>    /// Command to trigger the scan.    /// 触发扫描的命令。    /// </summary>    public string Command { get; set; }    /// <summary>    /// Command to stop triggering the scanner (used by Keyence).    /// 停止触发扫描器的命令(基恩士使用)。    /// </summary>    public string CloseCommand { get; set; }    /// <summary>    /// Start character for commands, if applicable (empty string if none).    /// 命令的起始字符(如果有),没有则为空字符串。    /// </summary>    public string Start { get; set; } = string.Empty;    /// <summary>    /// End character for commands, such as '\r\n' for Keyence; empty if not used.    /// 命令的结束字符,如基恩士使用的'\r\n';如果不使用则为空字符串。    /// </summary>    public string End { get; set; } = string.Empty;}

 

返回值实体类:

  /// <summary>  /// Represents the result information from a scanner.  /// 表示扫描器的结果信息。  /// </summary>  public class ReaderResultInfo  {      /// <summary>      /// Indicates whether the scan was successful.      /// 指示扫描是否成功。      /// </summary>      public bool IsSucceed { get; set; } = false;      /// <summary>      /// The error message if the scan failed.      /// 如果扫描失败,错误信息。      /// </summary>      public string Message { get; set; } = string.Empty;      /// <summary>      /// The result of the scan.      /// 扫描结果。      /// </summary>      public string Value { get; set; } = string.Empty;      /// <summary>      /// The time taken for the scan in milliseconds.      /// 扫描所耗费的时间(毫秒)。      /// </summary>      public long ElapsedMilliseconds { get; set; } = 0;      /// <summary>      /// The number identifying the scanner.      /// 扫描器编号。      /// </summary>      public ushort ReaderNo { get; set; } = 0;      /// <summary>      /// The brand of the scanner.      /// 扫描器品牌。      /// </summary>      public string Brand { get; set; } = string.Empty;    }  

 

如果觉得有帮助,欢迎点赞、分享​。

​不介意也可关注个人公众号:Dotnet Dancer

 

与工业福利!用.NET快速开发物联网扫码器设备的通用扫码功能相似的内容:

工业福利!用.NET快速开发物联网扫码器设备的通用扫码功能

不管你是用.net framework还是用.net core或者更高版本.net环境,这篇文章也许都能帮到你!因为接下来我会提供一个简单粗暴的方式,来快速实现多款扫码器的通用扫码功能。目前本地测试过的包括基恩士系列、康耐视系列、以及其他支持以太网通信的多款小众厂家等。 下面开始重点操作: 首先,在

真·生产力「GitHub 热点速览」

这些工具真的能极大提高生产力,节约你的时间来自(摸)我(鱼)增(划)值(水)。先别提 style2paints,你给它随意画个草图,就能给你一个能交付给甲方爸爸的成品插画。如果提升 30%-40% 传输速度的 kcp 不够惊艳,还有想象力匮乏程序员的福音——rerun,直接让你带入计算机视角看待那些

基于工业互联网平台智能制造方案【工业互联网甄选联盟】

工业互联网甄选联盟自发布委员会管理制度以来,得到了广大朋友的支撑。经过反复沟通和酝酿,最终形成《基于工业互联网平台智能制造方案》。在今后的实践过程中会不断完善本方案。现在入选4家会员单位,后续再不断择优选取脚踏实地为生产企业服务的公司。

工业数据分析为什么要用FusionInsight MRS IoTDB?

摘要:MRS IoTDB,它是华为FusionInsight MRS大数据套件中的时序数据库产品,在深度参与Apache IoTDB社区开源版的基础上推出的高性能企业级时序数据库产品。 本文分享自华为云社区《工业数据分析为什么要用FusionInsight MRS IoTDB?》,作者:高深广 。

工业互联网:加速从“中国制造”迈向“中国智造”

摘要:在推进制造业智能化的过程中,除设备本身数字化外,基于工业互联网实现设备互联和全流程智能化已成为最重要方向之一。 本文分享自华为云社区《【华为云Stack】【大架光临】第18期:工业互联网:加速从“中国制造”迈向“中国智造”》,作者:华为云Stack 制造行业总经理 崔新。 随着全球数字化浪潮的

30万奖金池鼓励工控人,AIRIOT智慧物联应用场景创新大赛等你来战!

随着工业和智慧领域数智化发展步伐的逐步加快,智慧物联应用场景越来越广泛,涵盖了智慧城市、智能园区、智慧能源、智慧电力、智能制造、工业物联网等多个领域。航天科技控股集团股份有限公司举办【AIRIOT智慧物联应用场景创新大赛】,30万奖金池鼓励智慧项目应用场景创新与落地!邀请工控工程师、智慧项目运维工程

iNeuOS工业互联网操作系统,增加电力IEC104协议

IEC60870-5-104 是一种电力自动化系统中常用的通信协议,使用 TCP/IP 协议作为底层通信协议,用于监视和控制电力系统中的各种设备,如变电站、发电机、开关等。

时代在发展,做信息化的思维也要变

最近,跟踪了15个月的项目,预算2000万,最终投标失败。投标价是倒数第二低,中标方是投标价倒数第一低,中标价基本是预算的50%左右,中标单位还是一个行业内有名的企业。 最近群友交流,反馈也是比较难做,如下图: 我们回顾过去,原来的程序员开发程序按代码行数收费,原来会OFFICE就可以找到工作,原来

iNeuOS工业互联网操作系统,民爆远程运维平台案例

民爆生产厂区有地面站和民爆车,现场地面站的控制系统为西门子PLC和欧姆龙PLC,民爆车为三菱PLC,地面站通过光纤与本地机房进行数据交互,民爆车的位置及其他数据通过4G与本地机房进行数据交互。本地机房与北京运维中心进行数据交互,实现民爆行业的综合运维平台。

记一次 .NET某工业设计软件 崩溃分析

一:背景 1. 讲故事 前些天有位朋友找到我,说他的软件在客户那边不知道什么原因崩掉了,从windows事件日志看崩溃在 clr 里,让我能否帮忙定位下,dump 也抓到了,既然dump有了,接下来就上 windbg 分析吧。 二:WinDbg 分析 1. 为什么崩溃在 clr 一般来说崩溃在clr