npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2025 – Pkg Stats / Ryan Hefner

node-snap7js

v0.2.0

Published

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.

Readme

: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

  1. Installation
  2. Features
  3. PLC Configuration
  4. Basic Usage
  5. API Documentation
  6. Credits
  7. License
  8. Contact
  9. Disclaimer

: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:

  • Enable "PUT/GET" communication on your PLC.
    In TIA Portal:

    • Open your PLC device.
    • Navigate to "Protection & Security".
    • Enable "Permit access with PUT/GET communication from remote partner". PUT/GET enabled
  • Disable optimized block access for any Data Blocks you plan to access.
    In TIA Portal:

    • Open the Data Block properties.
    • Uncheck "Optimized block access" under the "Attributes" section. Optimized Block Access disabled

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 {
    // Connect to PLC (IP, Rack, Slot)
    // For S7-1200/1500: Rack = 0, Slot = 1
    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`);

    // Perform operations here...

  } catch (error) {
    console.error('Connection failed:');
    console.error(S7Client.ErrorText(client._LastError));
  } finally {
    client.Disconnect();
  }
}

connectToPLC();

Connection to S7-300 (with different rack/slot)

// For S7-300 typically:
// - Rack = 0 (unless using multi-rack configuration)
// - Slot = 2 (for CPU in central rack)
await client.ConnectTo('192.168.0.2', 0, 2);

Connection with Custom TSAPs (Advanced)

const client = new S7Client();

// Set connection parameters (IP, Local TSAP, Remote TSAP)
// Local TSAP: Typically 0x0100 (256) for client
// Remote TSAP: Depends on PLC configuration (often 0x0102 for PG/OP communication)
client.SetConnectionParams('192.168.0.1', 0x0100, 0x0102);

// Then connect
await client.Connect();

Connection with Timeout Configuration

const client = new S7Client();

// Configure timeouts (in ms) before connecting
client._ConnTimeout = 5000;  // 5 second connection timeout
client._RecvTimeout = 3000;  // 3 second receive timeout
client._SendTimeout = 3000;  // 3 second send timeout

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');
}

// Get last error code
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);
    
    // Optional: Verify connection with a small read
    const testBuffer = Buffer.alloc(1);
    await client.ReadArea(S7Consts.S7AreaPE, 0, 0, 1, S7Consts.S7WLByte, testBuffer);
  }
}

// Use before any operation
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; // Try smaller PDU
      await client.ConnectTo('192.168.0.1', 0, 1);
      break;
    default:
      console.error('Unknown error:', S7Client.ErrorText(client._LastError));
  }
}

Common Connection Parameters

| PLC Type | Typical Rack | Typical Slot | Notes | |----------------|-------------|-------------|-------| | 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,  // Merker memory area
  0,                  // DB number (0 for Merker)
  0,                  // Start at bit 0 of byte 0
  1,                  // Read 1 bit
  S7Consts.S7WLBit,   // Bit data type
  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,  // Data Block area
  1,                  // DB number
  0,                  // Start at byte 0
  10,                 // Read 10 bytes
  S7Consts.S7WLByte,  // Byte data type
  buffer
);

Reading different data types

// Reading a REAL (float) value
const floatBuffer = Buffer.alloc(4);
await client.ReadArea(
  S7Consts.S7AreaDB, 1, 20, 1, S7Consts.S7WLReal, floatBuffer
);
const floatValue = floatBuffer.readFloatBE(0);

// Reading a WORD (16-bit unsigned)
const wordBuffer = Buffer.alloc(2);
await client.ReadArea(
  S7Consts.S7AreaDB, 1, 30, 1, S7Consts.S7WLWord, wordBuffer
);
const wordValue = wordBuffer.readUInt16BE(0);

// Reading a timer value
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

// Inputs (I area)
const inputBuffer = Buffer.alloc(2);
await client.ReadArea(
  S7Consts.S7AreaPE, 0, 0, 2, S7Consts.S7WLByte, inputBuffer
);

// Outputs (Q area)
const outputBuffer = Buffer.alloc(2);
await client.ReadArea(
  S7Consts.S7AreaPA, 0, 0, 2, S7Consts.S7WLByte, outputBuffer
);

// Counters (C area)
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; // Set to true (0 for false)

const result = await client.WriteArea(
  S7Consts.S7AreaMK,  // Merker memory area
  0,                  // DB number (0 for Merker)
  0,                  // Start at bit 0 of byte 0
  1,                  // Write 1 bit
  S7Consts.S7WLBit,   // Bit data type
  bitValue
);

Writing multiple bytes to a Data Block

const data = Buffer.from([0x11, 0x22, 0x33, 0x44]);

const result = await client.WriteArea(
  S7Consts.S7AreaDB,  // Data Block area
  1,                  // DB number
  10,                 // Start at byte 10
  4,                  // Write 4 bytes
  S7Consts.S7WLByte,  // Byte data type
  data
);

Writing a floating point value

const floatValue = Buffer.alloc(4);
floatValue.writeFloatBE(123.456, 0); // Write float to buffer

const result = await client.WriteArea(
  S7Consts.S7AreaDB,  // Data Block area
  1,                  // DB number
  20,                 // Start at byte 20
  1,                  // Write 1 REAL value (4 bytes)
  S7Consts.S7WLReal,  // Real data type
  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.

  • Snap7 Siemens S7 communication library by Davide Nardella License: LGPL-3.0

  • Sharp7 .NET/C# port of Snap7 by Federico Barresi License: MIT


: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.