We've released an open-source library that makes reading/writing tags to a PLC in C#/VB dead simple. It's available on Github and NuGet.
Contents
- What is a PLC?
- What is libplctag?
- Why was libplctag .NET developed?
- Enough talk, let's see some code!
- What's next?
- All the Thank Yous
- Github Repo
What is a PLC?
For those of us in the industrial automation world we often work with hardware called PLCs (Programmable Logic Controllers). These are the de facto standard for low level control in nearly any manufacturing line whether it's assembling cars, sorting packages, or filling soda bottles. Common brands include Siemens Simatic S7, Rockwell Automation Allen-Bradley CompactLogic/ControlLogix, and Schneider Modicon. The library we're introducing today primarily supports Rockwell Automation's Allen-Bradley line - everything from their oldest models up to the current CompactLogix an ControlLogix offerings.
These PLCs use different and often proprietary methods of communicating over ethernet networks. In order to integrate them with the larger ecosystem of Manufacturing Operations Management it's required a Windows-based server running what's called an OPC server - essentially a protocol converter that reads/writes to the PLC using the proprietary protocol and makes it available to other systems over the standardized OPC protocol. Almost all OPC servers require a per installation license and often a license for the number of variables (tags in PLC lingo) you would like to read/write.
What is libplctag?
The actual low-level library is called libplctag. It's a portable C library with a low memory footprint that runs on Linux/Mac/Windows/Android. At present, the library handles all the low-level encoding and decoding of CIP (Common Industrial Protocol AKA Ethernet/IP) implemented in various Allen-Bradley PLCs. It also handles Modbus TCP and there are plans to include other protocols and PLCs in the future. The library itself has been around since 2012 and is quite stable and used in many applications.
Why was libplctag .NET developed?
While C is a great language and very efficient, most programmers writing native or web applications rely on higher level languages. My language of choice is C#/dotnet these days and I've spent years using it to build programs that connect to PLCs and other industrial control systems. Unfortunately, these connections have always required either a commercially licensed C# library or an OPC server in order to communicate with the PLC. I started looking around for open-source options and came across the libplctag library via a couple of the C# wrappers that were floating around. None of the wrappers were very well documented and many were still using old versions of the lower level library. I reached out to the main C library developer and several of the wrapper maintainers to try to build a bigger community that I could help contribute to. Two of us got together, and with the help of the libplctag developer built a dotnet wrapper that includes all the features we wanted and thought should be expected in a dotnet library.
- Available on Nuget
- Self-contained - C DLL is extracted as part of dotnet DLL
- Compatible with .Net Standard (Core/Framework)
- Cross platform (Windows/Mac/Linux)
- Strongly typed
- Support Async/Await*
- Usable in C# and Visual Basic .NET
* await/async is currently stubbed into the API via Task.Run due to some complexities with the C callback
Enough talk, let's see some code!
We've got quite a few examples in our Github repo, but I'll show a quick example below.
The first thing to understand is that there must be a Mapper
class to convert from the PLC datatype to the dotnet datatype. Luckily, we've included mappers for all the base PLC types (DINT, SINT, STRING, BOOL, etc) and provided an example for building a custom mapper for your own UDTs.
Here's a simple example for reading/writing a DINT. Note that the myTag.Value
is typed as an int
and not an object
.
//Instantiate the tag with the proper mapper and datatype
var myTag = new Tag<DintPlcMapper, int>()
{
Name = "PROGRAM:SomeProgram.SomeDINT",
Gateway = "10.10.10.10",
Path = "1,0",
PlcType = PlcType.ControlLogix,
Protocol = Protocol.ab_eip,
Timeout = TimeSpan.FromSeconds(5)
};
//Initialize the tag to set up structures and prepare for read/write
//This is optional as an optimization before using the tag
//If omitted, the tag will initialize on the first Read() or Write()
myTag.Initialize();
//The value is held locally and only synchronized on Read() or Write()
myTag.Value = 3737;
//Transfer Value to PLC
myTag.Write();
//Transfer from PLC to Value
myTag.Read();
//Write to console
int myDint = myTag.Value;
Console.WriteLine(myDint);
Yeah, it's really that easy.
What's next?
We finished all of the work that we deemed necessary for an initial release. However, there is always more development to do. Here's some features/fixes that are upcoming:
- True async/await support from the lower libplctag library
- Background tag updates (read/writes on interval)
- Full discovery/listing of tags on a controller
All the Thank Yous
This has been my first real foray into open-source and it's been entirely in my spare time - so of course thanks to my family for being patient with me.
I was also really lucky to work with timyhac - a great C# developer that lives on nearly the exact opposite side of the globe from me. Doing code reviews with someone you've never met is quite the experience.
Finally, and most of all, I have to thank Kyle Hayes for the incredible libplctag base library and for being patient while the two C# devs asked all sorts of bothersome questions about C code and low level CIP protocol implementation.
Github Repo
libplctag / libplctag.NET
A .NET wrapper for libplctag.
libplctag.NET
libplctag is an open source C library for Linux, Windows and macOS using EtherNet/IP or Modbus TCP to read and write tags in PLCs.
libplctag.NET provides .NET wrapper packages for libplctag, and publishes them to Nuget.org.
This is the package intended for use in .NET applications It provides an API for libplctag that should feel natural to .NET developers by supporting the following features:
- Values are strongly-typed (both Atomic types and User-Defined Types).
- Errors are thrown as Exceptions
- Async/Await
- Native resource cleanup
See examples and the docs for more information.
This package provides low-level (raw) access to the libplctag core library which is written in C. The purpose of this package is to expose the API for this library to .NET applications, and handle platform and configuration issues.
Application developers typically won't need to reference this package directly; it is primarily for use in other wrapper libraries.
…
Top comments (11)
Hi, thanks for this. I am trying to create a project to communicate with a SLC 5/05 and get information from it, but I cannot find where to set the address of the PLC, like N7:0, N15:10, etc, to get it's data.
Some one know the proper syntax?
Thanks in advance!
We should really throw some more examples of different PLCs in the GitHub. I don't have any SLC around, but I've definitely seen this asked and answered on the Google group.
I work with PLCs and HMIs. I am interested in this library and I would like to ask if I can help develop the code? I am also a VB.NET developer. I am interested in developing a VB.NET, Toolset so to speak, to build HMIs using Visual Studio as the editor that can run on any OS and talk with any brand of PLC. Allen Bradley is normally the hardest to access. I would like be able to talk to Modicon (Schneider) using their "Data Dictionary". Ideally would like to be able to see all PLC tags in the PLC to use them directly without having to create a one-to-one mapping. I would want to be able to control the tag polling rate to include poll by exception, meaning if the value doesn't change then it is not updated. Would like to work on a concept of stale data meaning if the value does not change for a period of time throw an alarm. Please contact me to support this effort.
We're on Github (github.com/libplctag/libplctag.NET) and there's also a message list (groups.google.com/forum/#!forum/li...).
There are some challenges with what you're proposing (ex. cross OS UI is in infancy for .NET) but I think your desire is pretty common.
One has to start somewhere, let's get an HMI working on a Windows PC Touchscreen and eventually move to cross OS UI. The industry does not like Window OS for a few reasons. 1- IT owns the asset and wants to update Windows all of the time which can corrupt sometimes. 2- Most industrial sites communicate over satellite doing Windows update over satellite isn't the best method. 3- Security, most thinks Windows is a security risk and are more willing to run on Linux to keep IT out of the PC and the perception of security being better. A OEM would be a good candidate for a Window PC HMI because they can control the asset easier along with security.
Hello, I
m interested in this. I
m working with a PLC MicroLogix, I would know if this library could work with this kind of PLC. I noticed you mentioned this libary is able to work with Allen Bradleys PLC, but I
m not sure if your refered in CompactLogix, or something like that. Thanks for your time!This is an amazing peice of work, specially since this library works on .net Core, it has endless oppurtunities.
I had a question about read performance. I understand that the Tag.Read() function would create an underlying socket connection, read that tag and close the connection. When reading a large number of tags, would constantly opening/closing connection add in to the time/compute resources on PLC end? Is there a way that you can keep a connection open while you read a ton of tags and then close at once?
Hi, what is the difference between this library and opc ua, or what is the best? thanks, i just start with automation projects
Sorry for the late reply. You may have already found your answer. OPC-UA is an open network protocol - but it's not a PLC native protocol. Some modern PLCs actually do implement it directly on their hardware, but many do not. In that case you need to run a OPC-UA server that has drivers to connect to proprietary PLC protocols. Libplctag can be thought of as an open version of one of those drivers. OPC-UA can be handy, but if you're writing a C# app, running an OPC-UA server can be costly, more complex, and more prone to failure than communicating directly.
Not to mention there are additional layers on OPC UA that have unpredictable latency.
Excellent write up.
I've been using Libplctag for a couple of years now in C++.
The library is super stable and the developer is really active.
Some comments may only be visible to logged-in visitors. Sign in to view all comments.