Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions .clang-format
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
BasedOnStyle: Microsoft
IndentWidth: 4
UseTab: Never
ColumnLimit: 100
BreakBeforeBraces: Attach
PointerAlignment: Left
NamespaceIndentation: None
AllowShortFunctionsOnASingleLine: Empty
AllowShortIfStatementsOnASingleLine: true
BinPackArguments: false
BinPackParameters: false
AlignAfterOpenBracket: Align
AllowAllArgumentsOnNextLine: false
89 changes: 89 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
name: Release
on:
push:
tags: ['*']
jobs:
build:
permissions:
contents: read
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-latest
arch: x64
build-group: linux-x64
- os: ubuntu-latest
arch: x64
build-group: linux-arm
- os: ubuntu-latest
arch: x64
build-group: android-arm
- os: macos-latest
arch: x64
build-group: darwin-x64+arm64
- os: windows-latest
arch: x86
build-group: win32-x86
- os: windows-latest
arch: x64
build-group: win32-x64
- os: windows-latest
arch: x64
build-group: win32-arm64
runs-on: ${{ matrix.os }}
name: Build ${{ matrix.build-group }}
env:
BUILD_GROUP: ${{ matrix.build-group }}
steps:
- name: Checkout
uses: actions/checkout@v5
with:
submodules: recursive
fetch-depth: 2

- name: Set up node
uses: actions/setup-node@v5
with:
node-version: 18
architecture: ${{ matrix.arch }}

- name: Install
run: npm install --ignore-scripts

- name: Prebuild
run: npm run prebuild-$BUILD_GROUP
shell: bash

- name: Prepare artifact
run: tar -zcvf $BUILD_GROUP.tar.gz -C prebuilds .
shell: bash

- name: Upload artifact
uses: actions/upload-artifact@v4
with:
name: ${{ env.BUILD_GROUP }}
path: ${{ env.BUILD_GROUP }}.tar.gz
retention-days: 1

release:
needs: build
permissions:
contents: write
runs-on: ubuntu-latest
name: Release
steps:
- name: Checkout
uses: actions/checkout@v5

- name: Download artifacts
uses: actions/download-artifact@v4
with:
path: artifacts

- name: Create GitHub release
uses: docker://antonyurchenko/git-release:v4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
args: artifacts/*/*.tar.gz
Original file line number Diff line number Diff line change
@@ -1,41 +1,46 @@
name: Test and Release
on: [push, pull_request, workflow_dispatch]
name: Test
on: [push, pull_request]
permissions:
contents: read
jobs:
build:
test:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
node: [16, 18, 20, 22, 24]
node: [18, 20, 22]
arch: [x86, x64]
exclude:
- { os: ubuntu-latest, arch: x86 }
- { os: macos-latest, arch: x86 }
- { os: windows-latest, arch: x86, node: 24 }
runs-on: ${{ matrix.os }}
name: ${{ matrix.os }} / Node ${{ matrix.node }} ${{ matrix.arch }}
steps:
- name: Checkout
uses: actions/checkout@v4
uses: actions/checkout@v5
with:
submodules: recursive
fetch-depth: 2
# Force Python to 3.10 until prebuild updates to node-gyp 10
- name: Use Python 3.10
if: ${{ matrix.os != 'windows-latest' }}
uses: actions/setup-python@v4
with:
python-version: '3.10'

- name: Use node ${{ matrix.node }} ${{ matrix.arch }}
uses: actions/setup-node@v4
uses: actions/setup-node@v5
with:
node-version: ${{ matrix.node }}
architecture: ${{ matrix.arch }}

- name: Install
run: npm install

- name: Test
env:
PREBUILD_TOKEN: ${{ secrets.PREBUILD_TOKEN }}
run: npm test

# https://github.com/electron/electron/issues/42510#issuecomment-2171583086
- name: Disable AppArmor restriction
if: matrix.os == 'ubuntu-latest'
run: sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0

- name: Test Electron
if: matrix.os == 'ubuntu-latest' && matrix.node == '18'
uses: GabrielBB/xvfb-action@v1
with:
run: npm run test-electron
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
.vscode/
build/
prebuilds/
node_modules/
test/
9 changes: 6 additions & 3 deletions .npmignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
.github/
.vscode/
test/
.travis.yml
appveyor.yml
.npmignore
scripts/
build/
.clang-format
.gitignore
.npmignore
2 changes: 1 addition & 1 deletion LICENSE
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
(The MIT License)

Copyright (c) 2019 Mathias Küsel
Copyright (c) 2025 Mathias Küsel

Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
Expand Down
109 changes: 77 additions & 32 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,78 +1,96 @@
# node-snap7
# node-snap7

[![npm](https://img.shields.io/npm/v/node-snap7.svg?label=&logo=npm)](https://www.npmjs.com/package/node-snap7)
[![Node version](https://img.shields.io/node/v/node-snap7.svg)](https://www.npmjs.com/package/node-snap7)
[![Test and Release](https://github.com/mathiask88/node-snap7/actions/workflows/test-and-release.yml/badge.svg)](https://github.com/mathiask88/node-snap7/actions/workflows/test-and-release.yml)
[![npm](https://img.shields.io/npm/dm/node-snap7.svg?label=dl)](https://www.npmjs.com/package/node-snap7)

**Current node-snap7 version:** 1.0.9\
**Current snap7 version:** 1.4.2
**Current node-snap7 version:** 2.0.0-beta\
**Current snap7 version:** 1.4.3

**In my spare time I am working on a [node-addon-api](https://github.com/nodejs/node-addon-api) rewrite and want to switch from [prebuild-install](https://github.com/prebuild/prebuild-install) to [prebuildify](https://github.com/prebuild/prebuildify).\
The current S7Server implementation has some bugs, please use with caution.**
node-snap7 now uses [node-addon-api](https://github.com/nodejs/node-addon-api) (N-API) instead of NAN, ships N-API prebuilds generated with [prebuildify](https://github.com/prebuild/prebuildify), and the S7Server implementation is considered stable. Promise, callback, and synchronous call styles are available across the API.

## About
This is a node.js wrapper for snap7. Snap7 is an open source, 32/64 bit, multi-platform Ethernet communication suite for interfacing natively with Siemens S7 PLCs (See [compatibility](http://snap7.sourceforge.net/snap7_client.html#target_compatibility)).
This is a node.js wrapper for [snap7](https://github.com/davenardella/snap7). [snap7](https://github.com/davenardella/snap7) is an open source, 32/64 bit, multi-platform Ethernet communication suite for interfacing natively with Siemens S7 PLCs (see [compatibility](http://snap7.sourceforge.net/snap7_client.html#target_compatibility)).

## Installation
Install with:

npm install node-snap7
```
npm install node-snap7
```

node-snap7 uses `prebuild` and `prebuild-install` for handling prebuilt binaries. See [this list](https://github.com/mathiask88/node-snap7/releases) of supported prebuilt platform binaries. When installing node-snap7 `prebuild-install` will install prebuilt binaries from GitHub if they exist and fallback to a compile step if they don't.
node-snap7 ships N-API prebuilt binaries generated with `prebuildify` and loaded locally through `node-gyp-build` during install. If a prebuild for your platform is not included, installation will fall back to compiling from source.

If you don't want to use the `prebuild` for the platform you are installing on, specify the `--build-from-source` flag when you install.

For building from source you need the following requirements:

- Windows:
- [Visual Studio 2013 Express or higher](https://www.visualstudio.com/de/vs/visual-studio-express/)
- [Python 2.7](https://www.python.org/downloads/release/python-2714/)
- Visual Studio Build Tools with Desktop C++ workload (2019 or newer recommended)
- [Python 3](https://www.python.org/downloads/)
- Linux:
- C++11 toolchain
- [Python 2.7](https://www.python.org/downloads/release/python-2714/)
- [Python 3](https://www.python.org/downloads/)
- `make` and other common build essentials

## Special thanks to
- Davide Nardella for creating snap7
- Davide Nardella for creating [snap7](https://github.com/davenardella/snap7)

## How to use
### API
- [Client](doc/client.md)
- [Server](doc/server.md)

### Call styles
Each exported method is available as a Promise-returning async function, a callback-style function (when a callback is passed as the last argument), and a synchronous variant (with the `Sync` suffix).

### Client Example
```javascript
var snap7 = require('node-snap7');
const snap7 = require('node-snap7');

var s7client = new snap7.S7Client();
s7client.ConnectTo('192.168.1.12', 0, 1, function(err) {
if(err)
return console.log(' >> Connection failed. Code #' + err + ' - ' + s7client.ErrorText(err));
const s7client = new snap7.S7Client();

// Read the first byte from PLC process outputs...
s7client.ABRead(0, 1, function(err, res) {
if(err)
return console.log(' >> ABRead failed. Code #' + err + ' - ' + s7client.ErrorText(err));
async function main() {
try {
await s7client.ConnectTo('192.168.1.12', 0, 1);

// Read the first byte from PLC process outputs and print it
const res = await s7client.ABRead(0, 1);
console.log(res);
} catch (err) {
console.error(' >> Operation failed. Code #', err, '-', s7client.ErrorText(err));
}
}

main();
```

// ... and write it to stdout
console.log(res)
});
Callback style remains available:
```javascript
s7client.ABRead(0, 1, (err, res) => {
if (err) console.error(s7client.ErrorText(err));
else console.log(res);
});
```

### Server Example
Synchronous variants can be used with the `Sync` suffix:
```javascript
var snap7 = require('node-snap7');
const res = s7client.ABReadSync(0, 1);
console.log(res);
```

var s7server = new snap7.S7Server();
### Server Example
```javascript
const snap7 = require('node-snap7');
const s7server = new snap7.S7Server();

// Set up event listener
s7server.on("event", function(event) {
console.log(s7server.EventText(event));
});

// Create a new Buffer and register it to the server as DB1
var db1 = new Buffer(100).fill('ÿ');
const db1 = Buffer.alloc(100, 0);
s7server.RegisterArea(s7server.srvAreaDB, 1, db1);

// Start the server
Expand All @@ -85,11 +103,38 @@ setTimeout(function() {
}, 20000);
```

Have a look at the resourceless server example [here](doc/server.md#event-read-write).
### Resourceless server example
```javascript
const snap7 = require('node-snap7');
const s7server = new snap7.S7Server();

// Enable resourceless mode to handle requests manually
s7server.SetResourceless(true);

s7server.on('readWrite', (sender, operation, tag, buffer, done) => {
console.log(`${operation === s7server.operationRead ? 'Read' : 'Write'} from ${sender}`);
console.log(tag);

if (operation === s7server.operationRead) {
buffer.fill(0x42); // respond with dummy data
return done(buffer);
}

console.log('Payload:', buffer);
done(); // always call to release the worker thread
});

s7server.StartTo('127.0.0.1');
```

## Testing
- Run Node.js tests (Node runtime): `npm test`
- Run the same suite inside Electron's Node runtime: `npm run test-electron`
On headless CI, wrap with `xvfb-run npm run test-electron`.

## License & copyright
Copyright (c) 2019, Mathias Küsel
Copyright (c) 2025, Mathias Küsel

node-snap7 is licensed under the MIT license. All rights not explicitly granted in the MIT license are reserved. See the included LICENSE file for more details.

node-snap7 builds on the excellent work of the snap7 framework from Davide Nardella. Snap7 is issued under the GPL/LGPLv3 (see `./deps/snap7/gpl.txt ./deps/snap7/lgpl-3.0.txt`).
node-snap7 builds on the excellent work of the [snap7](https://github.com/davenardella/snap7) framework from Davide Nardella. [snap7](https://github.com/davenardella/snap7) is issued under the GPL/LGPLv3 (see [`./deps/snap7/gpl.txt`](./deps/snap7/gpl.txt) and [`./deps/snap7/lgpl-3.0.txt`](./deps/snap7/lgpl-3.0.txt)).
Loading