node-ethernet-ip

by cmseaton42

cmseaton42 /node-ethernet-ip

A Lightweight Ethernet/IP API written to interface with Rockwell ControlLogix/CompactLogix Controlle...

147 Stars 64 Forks Last release: Not found MIT License 184 Commits 13 Releases

Available items

No Items, yet!

The developer of this repository has not created any items for sale yet. Need a bug fixed? Help with integration? A different license? Create a request here:

Vue logo

npm Gitter license Travis Coveralls github Known Vulnerabilities GitHub stars

Node Ethernet/IP

A simple and lightweight node based API for interfacing with Rockwell Control/CompactLogix PLCs.

Prerequisites

latest version of NodeJS

Getting Started

Install with npm

npm install ethernet-ip --save

The API

How the heck does this thing work anyway? Great question!

The Basics

Getting Connected

const { Controller } = require("ethernet-ip");

const PLC = new Controller();

// Controller.connect(IP_ADDR[, SLOT]) // NOTE: SLOT = 0 (default) - 0 if CompactLogix PLC.connect("192.168.1.1", 0).then(() => { console.log(PLC.properties); });

Controller.properties Object

javascript
 {
    name: String, // eg "1756-L83E/B"
    serial_number: Number, 
    slot: Number,
    time: Date, // last read controller WallClock datetime
    path: Buffer,
    version: String, // eg "30.11"
    status: Number,
    faulted: Boolean,  // will be true if any of the below are true
    minorRecoverableFault: Boolean,
    minorUnrecoverableFault: Boolean,
    majorRecoverableFault: Boolean,
    majorUnrecoverableFault: Boolean,
    io_faulted: Boolean
}

Set the Clock of the Controller

NOTE

Controller.prototype.readWallClock
and
Controller.prototype.writeWallClock
are experimental features and may not be available on all controllers. 1756-L8 ControlLogix Controllers are currently the only PLCs supporting these features.

Sync Controller WallClock to PC Datetime

const { Controller } = require("ethernet-ip");

const PLC = new Controller();

PLC.connect("192.168.1.1", 0).then(async () => { // Accepts a JS Date Type // Controller.writeWallClock([Date]) await PLC.writeWallClock(); // Defaults to 'new Date()' });

Set Controller WallClock to a Specific Date

const { Controller } = require("ethernet-ip");

const PLC = new Controller();

PLC.connect("192.168.1.1", 0).then(async () => { const partyLikeIts1999 = new Date('December 17, 1999 03:24:00'); await PLC.writeWallClock(partyLikeIts1999); // Pass a custom Datetime });

Reading Tags

NOTE: Currently, the

Tag
Class only supports Atomic datatypes (SINT, INT, DINT, REAL, BOOL). Not to worry, support for STRING, ARRAY, and UDTs are in the plans and coming soon! =]

Reading Tags

Individually
... ```javascript const { Controller, Tag } = require("ethernet-ip");

const PLC = new Controller();

// Create Tag Instances const fooTag = new Tag("contTag"); // Controller Scope Tag const barTag = new Tag("progTag", "prog"); // Program Scope Tag in PLC Program "prog"

PLC.connect("192.168.1.1", 0).then(async () => { await PLC.readTag(fooTag); await PLC.readTag(barTag);

console.log(fooTag.value);
console.log(barTag.value);

}); ```

Additional Tag Name Examples ...

javascript
const fooTag = new Tag("Program:prog.progTag"); // Alternative Syntax for Program Scope Tag in PLC Program "prog"
const barTag = new Tag("arrayTag[0]"); // Array Element
const bazTag = new Tag("arrayTag[0,1,2]"); // Multi Dim Array Element
const quxTag = new Tag("integerTag.0"); // SINT, INT, or DINT Bit
const quuxTag = new Tag("udtTag.Member1"); // UDT Tag Atomic Member
const quuzTag = new Tag("boolArray[0]", null, BIT_STRING); // bool array tag MUST have the data type "BIT_STRING" passed in

Reading Tags as a

Group
... ```javascript const { Controller, Tag, TagGroup } = require("ethernet-ip");

const PLC = new Controller(); const group = new TagGroup();

// Add some tags to group group.add(new Tag("contTag")); // Controller Scope Tag group.add(new Tag("progTag", "prog")); // Program Scope Tag in PLC Program "prog"

PLC.connect("192.168.1.1", 0).then(async () => { await PLC.readTagGroup(group);

// log the values to the console
group.forEach(tag => {
    console.log(tag.value);
});

}); ```

Writing Tags

NOTE: You MUST read the tags first or manually provide a valid CIP datatype. The following examples are taking the latter approach.

Writing Tags

Individually
... ```javascript const { Controller, Tag, EthernetIP } = require("ethernet-ip"); const { DINT, BOOL } = EthernetIP.CIP.DataTypes.Types;

const PLC = new Controller();

// Create Tag Instances const fooTag = new Tag("contTag", null, DINT); // Controller Scope Tag const barTag = new Tag("progTag", "prog", BOOL); // Program Scope Tag in PLC Program "prog"

PLC.connect("192.168.1.1", 0).then(async () => {

// First way to write a new value
fooTag.value = 75;
await PLC.writeTag(fooTag);

// Second way to write a new value await PLC.writeTag(barTag, true);

console.log(fooTag.value); console.log(barTag.value);

}); ```

Writing Tags as a

Group
... ```javascript const { Controller, Tag, TagGroup, EthernetIP } = require("ethernet-ip"); const { DINT, BOOL } = EthernetIP.CIP.DataTypes.Types;

const PLC = new Controller(); const group = new TagGroup();

// Create Tag Instances const fooTag = new Tag("contTag", null, DINT); // Controller Scope Tag const barTag = new Tag("progTag", "prog", BOOL); // Program Scope Tag in PLC Program "prog"

group.add(fooTag); // Controller Scope Tag group.add(barTag); // Program Scope Tag in PLC Program "prog"

PLC.connect("192.168.1.1", 0).then(async () => { // Set new values fooTag.value = 75; barTag.value = true;

// Will only write tags whose Tag.controller_tag !== Tag.value
await PLC.writeTagGroup(group);

group.forEach(tag => { console.log(tag.value); });

}); ```

Lets Get Fancy

Subscribing to Controller Tags

const { Controller, Tag } = require("ethernet-ip");

const PLC = new Controller();

// Add some tags to group PLC.subscribe(new Tag("contTag")); // Controller Scope Tag PLC.subscribe(new Tag("progTag", "prog")); // Program Scope Tag in PLC Program "prog"

PLC.connect("192.168.1.1", 0).then(() => { // Set Scan Rate of Subscription Group to 50 ms (defaults to 200 ms) PLC.scan_rate = 50;

// Begin Scanning
PLC.scan();

});

// Catch the Tag "Changed" and "Initialized" Events PLC.forEach(tag => { // Called on the First Successful Read from the Controller tag.on("Initialized", tag => { console.log("Initialized", tag.value); });

// Called if Tag.controller_value changes
tag.on("Changed", (tag, oldValue) => {
    console.log("Changed:", tag.value);
});

});

Demos

  • Monitor Tags for Changes Demo

Simple Demo

const { Controller, Tag } = require("ethernet-ip");

// Intantiate Controller const PLC = new Controller();

// Subscribe to Tags PLC.subscribe(new Tag("TEST_TAG");); PLC.subscribe(new Tag("TEST", "Prog");); PLC.subscribe(new Tag("TEST_REAL", "Prog");); PLC.subscribe(new Tag("TEST_BOOL", "Prog"););

// Connect to PLC at IP, SLOT PLC.connect("10.1.60.205", 5).then(() => { const { name } = PLC.properties;

// Log Connected to Console
console.log(`\n\nConnected to PLC ${name}...\n`);

// Begin Scanning Subscription Group
PLC.scan();

});

// Initialize Event Handlers PLC.forEach(tag => { tag.on("Changed", (tag, lastValue) => { console.log(${tag.name} changed from ${lastValue} -> ${tag.value}); }); })

Built With

Contributers

Related Projects

Wanna become a contributor? Here's how!

License

This project is licensed under the MIT License - see the LICENCE file for details

We use cookies. If you continue to browse the site, you agree to the use of cookies. For more information on our use of cookies please see our Privacy Policy.