:robot: node-snap7js
A pure JavaScript implementation of Snap7 client for communicating with Siemens S7 PLCs. This node is a port of Sharp7, a Siemens S7 protocol driver, originally based on Snap7.
:bookmark_tabs: Table of Contents
:package: Installation
npm install node-snap7js
:rocket: Features
- Connect to Siemens S7 PLCs (300/400/1200/1500)
- Read/write PLC memory areas (DB, M, I, Q, etc.)
- Support for various data types (Bit, Byte, Word, DWord, Real, etc.)
- Pure JavaScript implementation (no native dependencies)
:hammer_and_wrench: Basic Usage
⚠️ Important PLC Configuration
To communicate successfully with your Siemens S7 PLC, make sure the following settings are configured:
Failure to apply these settings will result in connection errors or failed read/write operations.
Connection Examples
Basic Connection to S7-1200/1500
const { S7Client, S7Consts } = require('node-snap7js');
async function connectToPLC() {
const client = new S7Client();
try {
await client.ConnectTo('192.168.0.1', 0, 1);
console.log('Successfully connected to PLC!');
console.log(`Connection time: ${client.Time_ms}ms`);
console.log(`Negotiated PDU size: ${client._PDULength} bytes`);
} catch (error) {
console.error('Connection failed:');
console.error(S7Client.ErrorText(client._LastError));
} finally {
client.Disconnect();
}
}
connectToPLC();
Connection to S7-300 (with different rack/slot)
await client.ConnectTo('192.168.0.2', 0, 2);
Connection with Custom TSAPs (Advanced)
const client = new S7Client();
client.SetConnectionParams('192.168.0.1', 0x0100, 0x0102);
await client.Connect();
Connection with Timeout Configuration
const client = new S7Client();
client._ConnTimeout = 5000;
client._RecvTimeout = 3000;
client._SendTimeout = 3000;
await client.ConnectTo('192.168.0.1', 0, 1);
Checking Connection Status
if (client.Connected()) {
console.log('PLC is connected');
} else {
console.log('PLC is not connected');
}
console.log('Last error:', client._LastError);
console.log('Error text:', S7Client.ErrorText(client._LastError));
Reconnection Pattern
async function ensureConnected() {
if (!client.Connected()) {
console.log('Attempting to reconnect...');
await client.ConnectTo('192.168.0.1', 0, 1);
const testBuffer = Buffer.alloc(1);
await client.ReadArea(S7Consts.S7AreaPE, 0, 0, 1, S7Consts.S7WLByte, testBuffer);
}
}
await ensureConnected();
Error Handling Best Practices
try {
await client.ConnectTo('192.168.0.1', 0, 1);
} catch (error) {
switch (client._LastError) {
case S7Consts.errTCPConnectionFailed:
console.error('Network issue - check cables and IP address');
break;
case S7Consts.errTCPConnectionTimeout:
console.error('PLC not responding - check power and network');
break;
case S7Consts.errIsoConnect:
console.error('ISO connection failed - check TSAP parameters');
break;
case S7Consts.errCliNegotiatingPDU:
console.error('PDU negotiation failed - try smaller PDU size');
client._PduSizeRequested = 480;
await client.ConnectTo('192.168.0.1', 0, 1);
break;
default:
console.error('Unknown error:', S7Client.ErrorText(client._LastError));
}
}
Common Connection Parameters
| S7-1200 | 0 | 1 | |
| S7-1500 | 0 | 1 | |
| S7-300 (CPU) | 0 | 2 | Central rack |
| S7-300 (IM) | 1+ | 3+ | Expansion racks |
| S7-400 (CPU) | 0 | Varies | Depends on configuration |
| S7-400 (IM) | 1+ | Varies | Expansion racks |
Note: For S7-300/400 systems, the slot number depends on the physical position of the CPU in the rack.
Read Examples
Reading a single bit (boolean)
const bitBuffer = Buffer.alloc(1);
const result = await client.ReadArea(
S7Consts.S7AreaMK,
0,
0,
1,
S7Consts.S7WLBit,
bitBuffer
);
const bitValue = bitBuffer[0] > 0;
Reading multiple bytes from a Data Block
const buffer = Buffer.alloc(10);
const result = await client.ReadArea(
S7Consts.S7AreaDB,
1,
0,
10,
S7Consts.S7WLByte,
buffer
);
Reading different data types
const floatBuffer = Buffer.alloc(4);
await client.ReadArea(
S7Consts.S7AreaDB, 1, 20, 1, S7Consts.S7WLReal, floatBuffer
);
const floatValue = floatBuffer.readFloatBE(0);
const wordBuffer = Buffer.alloc(2);
await client.ReadArea(
S7Consts.S7AreaDB, 1, 30, 1, S7Consts.S7WLWord, wordBuffer
);
const wordValue = wordBuffer.readUInt16BE(0);
const timerBuffer = Buffer.alloc(2);
await client.ReadArea(
S7Consts.S7AreaTM, 0, 5, 1, S7Consts.S7WLTimer, timerBuffer
);
const timerValue = timerBuffer.readUInt16BE(0);
Reading from different memory areas
const inputBuffer = Buffer.alloc(2);
await client.ReadArea(
S7Consts.S7AreaPE, 0, 0, 2, S7Consts.S7WLByte, inputBuffer
);
const outputBuffer = Buffer.alloc(2);
await client.ReadArea(
S7Consts.S7AreaPA, 0, 0, 2, S7Consts.S7WLByte, outputBuffer
);
const counterBuffer = Buffer.alloc(2);
await client.ReadArea(
S7Consts.S7AreaCT, 0, 0, 1, S7Consts.S7WLCounter, counterBuffer
);
Write Examples
Writing a single bit (boolean)
const bitValue = Buffer.alloc(1);
bitValue[0] = 1;
const result = await client.WriteArea(
S7Consts.S7AreaMK,
0,
0,
1,
S7Consts.S7WLBit,
bitValue
);
Writing multiple bytes to a Data Block
const data = Buffer.from([0x11, 0x22, 0x33, 0x44]);
const result = await client.WriteArea(
S7Consts.S7AreaDB,
1,
10,
4,
S7Consts.S7WLByte,
data
);
Writing a floating point value
const floatValue = Buffer.alloc(4);
floatValue.writeFloatBE(123.456, 0);
const result = await client.WriteArea(
S7Consts.S7AreaDB,
1,
20,
1,
S7Consts.S7WLReal,
floatValue
);
:books: API Documentation
S7Client
Main class for PLC communication.
Methods
ConnectTo(ip, rack, slot): Connect to PLC
ReadArea(area, dbNumber, start, amount, wordLen, buffer): Read PLC data
WriteArea(area, dbNumber, start, amount, wordLen, buffer): Write PLC data
Disconnect(): Close connection
S7Consts
Contains all constants for areas, word lengths, etc.
Memory Areas:
S7AreaPE - Inputs (I)
S7AreaPA - Outputs (Q)
S7AreaMK - Memory (M)
S7AreaDB - Data Blocks
S7AreaCT - Counters
S7AreaTM - Timers
Data Types:
S7WLBit - Bit (1 bit)
S7WLByte - Byte (8 bits)
S7WLWord - Word (16 bits)
S7WLDWord - Double Word (32 bits)
S7WLReal - Float (32 bits)
S7WLCounter - Counter value
S7WLTimer - Timer value
S7
The S7 class provides several static utility functions for working with PLC data:
Buffer Operations:
GetWordAt(buffer, pos) - Read 16-bit unsigned integer (WORD) from buffer
SetWordAt(buffer, pos, value) - Write 16-bit unsigned integer (WORD) to buffer
GetUIntAt(buffer, pos) - Alias for GetWordAt
SetUIntAt(buffer, pos, value) - Alias for SetWordAt
Data Size Calculation:
DataSizeByte(wordLen) - Returns byte size for given data type (use S7Consts.S7WLxxx values)
:pray: Credits
This project is based on the following amazing open-source work:
:receipt: License
This project is licensed under the MIT License.
:mailbox: Contact
Maintainer: sesenlik
GitHub: @sesenlik
:warning: Disclaimer
This software is not affiliated with or endorsed by Siemens AG.
S7, SIMATIC, and STEP7 are trademarks of Siemens AG.
The authors of this software assume no responsibility for any issues arising from its use in industrial control systems or other critical applications.