L5Sharp 4.2.0

There is a newer version of this package available.
See the version list below for details.
dotnet add package L5Sharp --version 4.2.0                
NuGet\Install-Package L5Sharp -Version 4.2.0                
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="L5Sharp" Version="4.2.0" />                
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add L5Sharp --version 4.2.0                
#r "nuget: L5Sharp, 4.2.0"                
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install L5Sharp as a Cake Addin
#addin nuget:?package=L5Sharp&version=4.2.0

// Install L5Sharp as a Cake Tool
#tool nuget:?package=L5Sharp&version=4.2.0                

L5Sharp

A library for intuitively interacting with Rockwell's L5X import/export files.

Purpose

The purpose of this library is to offer a reusable, strongly typed, intuitive API over Rockwell's L5X schema, allowing developers to quickly modify or generate L5X content. In doing so, this library can aid in creation of tools or scripts that automate the PLC development, maintenance, or testing processes for automation engineers.

Goals

The following are some high level goals this project aimed to accomplish.

  1. Provide a simple and intuitive API, making the learning curve as low as possible.
  2. Ensure performance as much as possible without sacrificing simplicity.
  3. Make it easy and seamless to extend the API to support custom queries or functions.
  4. Support strongly typed mutable tag data, so we can reference complex structures statically at compile time.

Packages

You can consume the library via NuGet.

Install-Package L5Sharp

Previously I had two separate libraries but have since consolidated to a single package to avoid confusion and since I think most people would want all functionality anyway. L5Sharp.Extensions is no longer maintained.

Quick Start

  1. Install package from Nuget.

    Install-Package L5Sharp
    
  2. Load an L5X file using the L5X class static factory methods.

    var content = L5X.Load("C:\PathToMyFile\FileName.L5X");
    
  3. Get started by querying elements across the L5X using the Query() methods and LINQ extensions. The following query gets all tags and their nested tag members of type TIMER and returns the TagName, Description, and Preset value in a flat list ordered by TagName.

    var results = content.Query<Tag>()
                .SelectMany(t => t.Members())
                .Where(t => t.DataType == "TIMER")
                .Select(t => new {t.TagName, t.Description, Preset = t["PRE"].Value})
                .OrderBy(v => v.TagName)
                .ToList();
    

    Query<T>() returns an IEnumerable<T>, allowing for complex queries using LINQ and the strongly typed objects in the library. Since Query<T>() queries the entire L5X for the specified type, the above query will return all Tag components found, including controller and program tags.

Usage

The following is some basic examples of how you can use this library to query and modify the L5X content.

Querying

Using Container Collections

Once the L5X is created, you can use the component properties to access the LogixContainer for the specified type. This gets you simple collection APIs that allow you to query for component objects.

This library supports all primary components including the following:

  • Controller
  • DataType
  • AddOnInstruction
  • Module
  • Tag
  • Program
  • Routine
  • Task
  • Trend
  • WatchList

For example, the following shows some simple querying via the Tags component container.

//Get all controller tags. 
var tags = content.Tags.ToList();

//Get a tag by name.
var tag = content.Tags.Find("MyTag");

//Use LINQ to query further.
var results = content.Tags.Where(t => t.DataType == "TIMER");
Using Query Methods

The previous code will only return controller scoped tags since the Tags container on the root L5X represents controller scoped tag elements. To get program tags we would have to access the Tags container on a specific program.

//Get the first program in the L5X and find a tag called 'MyProgramTag'
var programTags = content.Programs.First().Tags.Find("MyProgramTag");

This is a little cumbersome. It would be nice to have a single way to query for all tags across the file and filter those results as well. And there is using the Query methods. These generic methods will return all instances of the type found in the file and allow you to further filter them using LINQ.

//Gets all tags (controller, program, module/IO)
var allTags = content.Query<Tag>().ToList();

var programTags = allTags.Where(t => t.Scope == Scope.Program);
var ioTags = allTags.Where(t => t.Name.Contains(':'));
var readWriteTags = allTags.Where(t => t.ExternalAccess == ExternalAccess.ReadWrite);
var timerTags = allTags.Where(t => t.DataType == "TIMER");
Using Index Methods

Some L5X projects can contain a lot of Tag components especially when you consider all the nested tag members as an individual tag that can be referenced in the project. If you have to perform continuous lookup of tag objects for some operation or task, that could be costly or time intensive. We need a fast way to retrieve components, and this library offers that as well.

The following methods use an internal index or set of dictionaries to quickly find a component with by name and type.

//Find a data type component by name
var tag = content.Find<DataType>("MyUserDefined");

//Get a data type component by name 
//(the different here is Get throws an exception if not found)
var tag = content.Get<DataType>("MyUserDefined");

//Get a nested tag member 
//(we don't need to specify <Tag> since it is implied with the Tagname overload)
var tag = content.Find("MyTag.Member[1].SubMember.1");

//Gets all tags with name 
//(this could be controller and/or program tags)
var tags = content.All("ScopedTag").ToList();

The above calls all operate in constant time since the components are indexed using dictionaries. The L5X is only indexed when the first call to an index method such as Find, Get or All is made. The index is cached so everytime after we don't need to recreate it. It will also be maintained internally as components are added or removed.

Modifying

Modifying components is simple as well. The same component collection interface offers methods for adding, removing, and updating components.

//Add a new component.
var tag = new Tag { Name = "MyTag", Value = 100 };
content.Tags.Add(tag);

//Remove an existing component.
var result = content.Tags.Remove("MyTag");

//Repalce an existing component.
var result = content.Tags.Find("MyTag").Replace(tag);

//Configure individual properties.
var tag = content.Tags.Get("MyTag");
tag.Value = 100;
tag.Description = "This is an update";
tag.ExternalAccess = ExternalAccess.ReadOnly;
tag.Constant = true;

//Apply update funtion to all components that satisfy a condition.
content.Tags.Update(t => t.DataType == "TIMER", t => t.Description = "Updated TIMER description");

//Save changes when done.
content.Save("C:\PathToMyOutputFile\FileName.L5X");

Documentation

I started working on a GitHub Page here for more in depth articles and API documentation, but it's a work in progress so bear with me. In fact it is currently out of date, so reference this readme for the most up to date information. If you think something is unclear or can be improved upon, feel free to let me know in the issues tab of the project repository.

Feedback

If you like or use this project, leave a star! If you have questions or issues, please post in the issues tab of the project repository. Any feedback or contributions are welcome!

Product Compatible and additional computed target framework versions.
.NET net5.0 was computed.  net5.0-windows was computed.  net6.0 was computed.  net6.0-android was computed.  net6.0-ios was computed.  net6.0-maccatalyst was computed.  net6.0-macos was computed.  net6.0-tvos was computed.  net6.0-windows was computed.  net7.0 was computed.  net7.0-android was computed.  net7.0-ios was computed.  net7.0-maccatalyst was computed.  net7.0-macos was computed.  net7.0-tvos was computed.  net7.0-windows was computed.  net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed. 
.NET Core netcoreapp2.0 was computed.  netcoreapp2.1 was computed.  netcoreapp2.2 was computed.  netcoreapp3.0 was computed.  netcoreapp3.1 was computed. 
.NET Standard netstandard2.0 is compatible.  netstandard2.1 was computed. 
.NET Framework net461 was computed.  net462 was computed.  net463 was computed.  net47 was computed.  net471 was computed.  net472 was computed.  net48 was computed.  net481 was computed. 
MonoAndroid monoandroid was computed. 
MonoMac monomac was computed. 
MonoTouch monotouch was computed. 
Tizen tizen40 was computed.  tizen60 was computed. 
Xamarin.iOS xamarinios was computed. 
Xamarin.Mac xamarinmac was computed. 
Xamarin.TVOS xamarintvos was computed. 
Xamarin.WatchOS xamarinwatchos was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
  • .NETStandard 2.0

    • No dependencies.
  • net8.0

    • No dependencies.

NuGet packages (1)

Showing the top 1 NuGet packages that depend on L5Sharp:

Package Downloads
L5Sharp.Extensions

A library for intuitively interacting with Rockwell's L5X import/export files.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last updated
4.7.2 44 11/28/2024
4.7.1 80 11/15/2024
4.7.0 71 11/15/2024
4.6.0 86 11/14/2024
4.5.0 87 11/11/2024
4.4.0 89 10/31/2024
4.3.0 83 10/30/2024
4.2.0 130 10/8/2024
4.1.0 89 10/7/2024
4.0.0 91 10/5/2024
3.3.1 107 9/24/2024
3.3.0 132 7/29/2024
3.2.0 123 7/7/2024
3.1.0 96 7/5/2024
3.0.0 116 6/3/2024
2.3.2 92 5/9/2024
2.3.1 346 5/6/2024
2.3.0 125 5/4/2024
2.2.1 113 4/29/2024
2.2.0 119 4/23/2024
2.1.0 112 4/18/2024
2.0.0 176 4/4/2024
0.19.7 137 3/27/2024
0.19.6 234 3/22/2024
0.19.5 130 3/9/2024
0.19.4 125 2/5/2024
0.19.3 106 2/3/2024
0.19.1 118 1/16/2024
0.19.0 97 1/16/2024
0.18.3 129 1/8/2024
0.18.2 115 1/4/2024
0.18.1 113 12/29/2023
0.18.0 161 12/9/2023
0.17.0 147 12/8/2023
0.16.1 130 11/28/2023
0.16.0 126 11/28/2023
0.15.2 188 8/18/2023
0.15.1 153 8/17/2023
0.15.0 198 8/16/2023
0.14.0 197 8/9/2023
0.13.0 203 8/6/2023
0.12.0 182 8/1/2023
0.11.0 173 7/12/2023
0.10.1 237 3/31/2023
0.10.0 204 3/31/2023
0.9.2 210 3/24/2023
0.9.1 224 3/15/2023
0.9.0 228 3/15/2023
0.8.0 229 3/15/2023
0.7.0 213 3/14/2023
0.6.0 219 3/14/2023
0.5.3 223 3/13/2023
0.5.2 220 3/13/2023
0.5.0 224 3/13/2023
0.4.0 232 3/12/2023
0.3.0 235 3/5/2023
0.2.0 285 3/1/2023

Removed StringData virtual members.