如何在 C# 中为 PLCnext Control gRPC 服务器创建客户端
固件版本 2022.0 LTS 在 AXC F 1152 和 AXC F 2152 设备上引入了 gRPC 服务器。此 gRPC 服务器为客户端应用程序提供了一种访问 PLCnext 控制设备上的 RSC 服务的方法。客户端应用程序可以是:
- 以任何支持 gRPC 的语言编写。
- 在任何地方运行 - 在 PLCnext 控制设备上本地运行,或在远程机器上运行*。
- 托管在 OCI 容器中。
(* 远程访问将从固件版本 2022.3 开始提供)
PLCnext 控制设备中 gRPC 服务器的一般信息可在 PLCnext 信息中心获得。
本文介绍如何使用 C# 创建一个简单的 gRPC 客户端应用程序,在 PLCnext 控制设备上运行。
先决条件
下面的程序使用:
- AXC F 2152 运行固件版本 2022.0.3 LTS 或更高版本。
- PLCnext Engineer 版本 2022.0.1 LTS 或更高版本。
- Visual Studio 2019(任何版本)。
- 此 Makers 博客文章中介绍的概念:如何使用 C# 创建简单的 PLCnext 控制台应用程序
- gRPC 服务器的 protobuf 定义文件,位于 PLCnext/gRPC Github 存储库的 protobuf 目录中。
- 设备状态 RSC 服务。
- 数据访问 RSC 服务。
程序
1. 使用Web管理页面,确认名为GRPC LOCAL SERVER的服务已启动。
2. 为您的目标设备创建一个新的 PLCnext Engineer 项目。这个项目应该有:
- 一个程序,其 OUT 端口变量称为 AI1,类型为 INT。
- 该程序的一个实例,称为 MainInstance1。
3.将PLCnext Engineer工程发送到目标设备。
4. 在 Visual Studio 中,按照之前 Makers 博客文章中描述的步骤 1-3 创建一个空的 C# 控制台应用程序。
5. 在 Project => Property 窗口中,将项目 Target framework 设置为“.NET 5.0”。
6. 在解决方案资源管理器中,右键单击解决方案,选择“Manage NuGet Packages for Solution...”,然后安装以下 NuGet 包:
- Grpc.Tools
- Grpc.Net.Client
- Google.Protobuf
7. 将包含 protobuf 定义文件的 protobuf 文件夹复制到项目源文件夹中。 Protobuf 是用于描述 gRPC 服务的接口定义语言 (IDL)。
8. 在项目配置文件中,为将在项目中使用的服务添加对 .proto 文件的引用。项目配置的 ItemGroup 部分现在看起来像这样:
9. 用这段代码替换项目.cs文件的内容(可能需要改命名空间名):
using System; using System.Net; using System.Net.Http; using System.Net.Sockets; using System.Threading; using System.Threading.Tasks; using System.IO; using Grpc.Net.Client; using Arp.Device.Interface.Services.Grpc; using Arp.Plc.Gds.Services.Grpc; namespace ConsoleApp1 { class Program { static void Main() { // The code to connect to a Unix Domain Socket is from: // https://docs.microsoft.com/en-us/aspnet/core/grpc/interprocess?view=aspnetcore-6.0 var udsEndPoint = new UnixDomainSocketEndPoint("/run/plcnext/grpc.sock"); var connectionFactory = new UnixDomainSocketConnectionFactory(udsEndPoint); var socketsHttpHandler = new SocketsHttpHandler { ConnectCallback = connectionFactory.ConnectAsync }; // Create a gRPC channel to the PLCnext unix socket using var channel = GrpcChannel.ForAddress("http://localhost", new GrpcChannelOptions { HttpHandler = socketsHttpHandler }); // Create a gRPC client for the Device Status Service on that channel var grpc_status_client = new IDeviceStatusService.IDeviceStatusServiceClient(channel); // Create a gRPC client for the Data Access Service on that channel var grpc_data_client = new IDataAccessService.IDataAccessServiceClient(channel); // Create an item to get from the Device Status Service // Item identifiers are listed in the PLCnext Info Center: // https://www.plcnext.help/te/Service_Components/Remote_Service_Calls_RSC/RSC_device_interface_services.htm#IDeviceStatusService var item = new IDeviceStatusServiceGetItemRequest(); item.Identifier = "Status.Board.Temperature.Centigrade"; // Create a variable to get from the Data Access Service var data = new IDataAccessServiceReadSingleRequest(); data.PortName = "Arp.Plc.Eclr/MainInstance1.AI1"; // Response variables IDeviceStatusServiceGetItemResponse grpc_status_response; IDataAccessServiceReadSingleResponse grpc_data_response; // Endless loop while (true) { // Request the item from the Device Status Service grpc_status_response = grpc_status_client.GetItem(item); // Request data from the Data Access Service grpc_data_response = grpc_data_client.ReadSingle(data); // Report the results var temperature = grpc_status_response.ReturnValue.Int8Value; var ai1 = grpc_data_response.ReturnValue.Value.Int16Value; Console.WriteLine("Board Temperature = " + temperature + "°C"); Console.WriteLine("MainInstance1.AI1 = " + ai1); // Wait for 1 second Thread.Sleep(1000); } } } public class UnixDomainSocketConnectionFactory { private readonly EndPoint _endPoint; public UnixDomainSocketConnectionFactory(EndPoint endPoint) { _endPoint = endPoint; } public async ValueTask<Stream> ConnectAsync(SocketsHttpConnectionContext _, CancellationToken cancellationToken = default) { var socket = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified); try { await socket.ConnectAsync(_endPoint, cancellationToken).ConfigureAwait(false); return new NetworkStream(socket, true); } catch { socket.Dispose(); throw; } } } }
10. 在解决方案资源管理器中,右键单击解决方案并打开终端。
11. 在终端中,执行以下命令:
dotnet build ConsoleApp1.csproj dotnet publish -c RELEASE -r linux-arm .\ConsoleApp1.csproj -o MyApp
... 其中 ConsoleApp1 是解决方案的名称,MyApp 是应用程序将发布到的输出目录的名称。如果需要,应用程序也可以在 DEBUG 模式下发布。
12. 使用(例如)scp 或 WinSCP 将输出目录及其所有内容复制到 PLC。
scp -r MyApp [email protected]:~
13. 使用(例如)ssh 或 PuTTY 在 PLC 上打开一个 shell 会话。
14.确保可执行文件有执行权限:
$ chmod a+x /opt/plcnext/MyApp/ConsoleApp1
15. 运行应用程序:
$ /opt/plcnext/MyApp/ConsoleApp1
输出应该类似于:
Board Temperature = 50°C MainInstance1.AI1 = 0 Board Temperature = 50°C MainInstance1.AI1 = 0 Board Temperature = 50°C MainInstance1.AI1 = 0 Board Temperature = 50°C MainInstance1.AI1 = 0
16. 在 PLCnext Engineer 中,上线并更改 AI1 变量的值。应用报告的值应该会改变。
参考资料和其他资源
1. .NET Core ❤ gRPC
2. 使用.NET客户端调用gRPC服务
3. gRPC 有用资源的精选列表
工业技术