Skip to content
Merged
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
45 changes: 44 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,47 @@
node_modules
coverage
.tool-versions
build
build

# Node.js
node_modules/
npm-debug.log
yarn-debug.log
yarn-error.log
.npm
.yarn

# Build output
build/
dist/
*.dll
*.dylib

# Go
*.exe
*.exe~
*.dll
*.dylib
*.test
*.out
go.work

# IDE
.idea/
.vscode/
*.swp
*.swo
.DS_Store

# Debug logs
debug/
*.log

# Environment variables
.env
.env.local
.env.*.local

# Ignore all .so files except libmodbus.so
*.so
!libmodbus.so
122 changes: 122 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# Project name
PROJECT_NAME=modbus

# Paths
GO_PATH=/usr/local/go/bin/go
GO=$(shell which go || echo $(GO_PATH))
GOBUILD=$(GO) build
GOTEST=$(GO) test
GOGET=$(GO) get
GOCLEAN=$(GO) clean

# Go version
GO_VERSION=1.21.0
GO_ARCH=arm64
GO_OS=linux

# Node.js paths
NODE_ROOT=$(shell dirname $$(dirname $$(which node)))
NODE_INCLUDE=$(NODE_ROOT)/include/node
NODE_ADDON_API=$(shell npm root -g)/node-addon-api
NODE_LIB=$(NODE_ROOT)/lib

# Build flags
LDFLAGS=-ldflags "-s -w"
CGO_FLAGS=CGO_ENABLED=1 CGO_CFLAGS="-I$(NODE_INCLUDE) -I$(NODE_ADDON_API)" CGO_LDFLAGS="-L$(NODE_LIB) -lnode"

# Check if Go is installed
check-go:
@if [ ! -f "$(GO)" ]; then \
echo "Error: Go is not installed. Please run 'sudo make install-go' first"; \
exit 1; \
fi

# Check if running on Raspberry Pi
check-raspberry:
@if ! uname -m | grep -q "aarch64\|armv7l"; then \
echo "Error: This Makefile is designed for Raspberry Pi (ARM architecture)"; \
exit 1; \
fi

# Check if running with sudo
check-sudo:
@if [ "$(shell id -u)" != "0" ]; then \
echo "Error: This command requires sudo privileges"; \
exit 1; \
fi

# Default target
all: check-raspberry check-go deps binary

# Build target
build: check-raspberry check-go deps binary

# Install Go
install-go: check-raspberry check-sudo
@echo "Installing Go $(GO_VERSION)..."
@if [ ! -f "go$(GO_VERSION).$(GO_OS)-$(GO_ARCH).tar.gz" ]; then \
wget https://golang.org/dl/go$(GO_VERSION).$(GO_OS)-$(GO_ARCH).tar.gz; \
fi
sudo tar -C /usr/local -xzf go$(GO_VERSION).$(GO_OS)-$(GO_ARCH).tar.gz
@if ! grep -q "export PATH=\$PATH:/usr/local/go/bin" ~/.bashrc; then \
echo 'export PATH=$$PATH:/usr/local/go/bin' >> ~/.bashrc; \
echo "Added Go to PATH in ~/.bashrc"; \
fi
@echo "Go installation completed. Please run 'source ~/.bashrc' to update PATH"

# Install system dependencies
install-deps: check-raspberry check-sudo
@echo "Installing system dependencies..."
sudo apt-get update
sudo apt-get install -y gcc g++ make git libnode-dev npm
sudo npm install -g node-addon-api

# Install dependencies
deps: check-raspberry check-go
@echo "Installing Go dependencies..."
cd go && $(GO) mod download
cd go && $(GO) mod tidy

# Build as shared library
so: check-raspberry check-go deps
@echo "Building as shared library..."
cd go && $(CGO_FLAGS) $(GOBUILD) -buildmode=c-shared -o ../lib$(PROJECT_NAME).so $(LDFLAGS)

# Build as binary executable
binary: check-raspberry check-go deps
@echo "Building as binary executable..."
cd go && $(CGO_FLAGS) $(GOBUILD) -o ../$(PROJECT_NAME) $(LDFLAGS)

# Build for Raspberry Pi
raspberry: check-raspberry check-go deps
@echo "Building for Raspberry Pi..."
cd go && GOOS=linux GOARCH=arm64 $(GOBUILD) -o ../$(PROJECT_NAME)_raspberry $(LDFLAGS)

# Clean build files
clean:
@echo "Cleaning..."
cd go && $(GOCLEAN)
rm -f $(PROJECT_NAME) $(PROJECT_NAME)_raspberry lib$(PROJECT_NAME).so
rm -f go$(GO_VERSION).$(GO_OS)-$(GO_ARCH).tar.gz

# Run tests
test: check-raspberry check-go
@echo "Running tests..."
cd go && $(GOTEST) -v ./...

# Show help
help:
@echo "Available commands:"
@echo " make install-deps - Install system dependencies (requires sudo)"
@echo " make install-go - Install Go and configure PATH (requires sudo)"
@echo " make all - Install dependencies and build as binary"
@echo " make build - Build the project"
@echo " make deps - Install Go dependencies"
@echo " make so - Build as shared library"
@echo " make binary - Build as binary executable"
@echo " make raspberry - Build for Raspberry Pi"
@echo " make clean - Clean build files"
@echo " make test - Run tests"
@echo " make help - Show this help"

.PHONY: all build deps so binary raspberry clean test help install-go install-deps check-raspberry check-sudo check-go
121 changes: 98 additions & 23 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,40 +1,115 @@
# max485-raspberry-nodejs
# ModbusRTU

A simple and reliable Modbus RTU library for Node.js using **SerialPort** and **Raspberry Pi GPIO** with **MAX485 RS485 transceivers**.
Node.js library for Modbus RTU communication over serial port, optimized for Raspberry Pi.

## Installation

```sh
npm install max485-raspberry-nodejs
```bash
npm install modbus-rtu
```

## Usage
## Requirements

```js
const ModbusRTU = require("max485-raspberry-nodejs");
- Node.js >= 14.0.0
- Linux (tested on Raspberry Pi)
- RS-485 Serial Port

const client = new ModbusRTU({ path: "/dev/ttyAMA0", baudRate: 9600, re_pin: 27, de_pin: 17 });
## Usage Example

(async () => {
await new Promise(resolve => setTimeout(resolve, 2000));
```javascript
const ModbusRTU = require('modbus-rtu');

await client.write(1, 1, 1);
// Create Modbus device instance
// Parameters:
// - port: serial port path (e.g., '/dev/serial0' or '/dev/ttyUSB0')
// - baudRate: communication speed (e.g., 9600)
// - dePin: GPIO pin number for DE (Driver Enable)
// - rePin: GPIO pin number for RE (Receiver Enable)
const device = new ModbusRTU('/dev/serial0', 9600, 17, 27);

const value = await client.read(1, 1);
console.log(`Register value: ${value}`);
})();
async function example() {
try {
// Read coils (function 0x01)
const coils = await device.readCoils(1, 0, 4);
console.log('Coils state:', coils);

// Write single coil (function 0x05)
await device.writeCoil(1, 0, true);

// Write multiple coils (function 0x0F)
await device.writeMultipleCoils(1, 0, [true, false, true, false]);

// Read holding registers (function 0x03)
const registers = await device.readHoldingRegisters(1, 0, 4);
console.log('Registers state:', registers);

// Write single register (function 0x06)
await device.writeRegister(1, 0, 123);

// Write multiple registers (function 0x10)
await device.writeMultipleRegisters(1, 0, [50, 100, 150, 200]);

} catch (error) {
console.error('Error:', error.message);
} finally {
// Close connection
device.close();
}
}

example();
```

## Features
## API

• Supports Modbus RTU communication over RS485
• Handles TX/RX switching for MAX485 chips
• Implements retry logic to handle timeouts and bad responses
• CRC validation for error detection
• Optimized for Raspberry Pi GPIO control
### Constructor

## License
#### `new ModbusRTU(port, baudRate, dePin, rePin)`

- `port` (string): Serial port path
- `baudRate` (number): Communication speed
- `dePin` (number): GPIO pin number for DE signal
- `rePin` (number): GPIO pin number for RE signal

### Methods

#### Reading Data

- `readCoils(slaveId, startAddr, count)`: Read coils (function 0x01)
- `readDiscreteInputs(slaveId, startAddr, count)`: Read discrete inputs (function 0x02)
- `readHoldingRegisters(slaveId, startAddr, count)`: Read holding registers (function 0x03)
- `readInputRegisters(slaveId, startAddr, count)`: Read input registers (function 0x04)

---
Parameters:
- `slaveId` (number): Modbus device address (1-247)
- `startAddr` (number): Starting address
- `count` (number): Number of elements to read

Returns: Promise with array of values (boolean for coils/inputs, number for registers)

#### Writing Data

- `writeCoil(slaveId, addr, value)`: Write single coil (function 0x05)
- `writeRegister(slaveId, addr, value)`: Write single register (function 0x06)
- `writeMultipleCoils(slaveId, startAddr, values)`: Write multiple coils (function 0x0F)
- `writeMultipleRegisters(slaveId, startAddr, values)`: Write multiple registers (function 0x10)

Parameters:
- `slaveId` (number): Modbus device address (1-247)
- `addr`/`startAddr` (number): Address to write to
- `value` (boolean/number): Value to write
- `values` (Array): Array of values to write

Returns: Promise

#### Connection Management

- `close()`: Closes the connection to the device

## Error Handling

All methods (except `close()`) return a Promise. In case of an error, the Promise is rejected with an appropriate error message.

## License

MIT
MIT
15 changes: 15 additions & 0 deletions binding.gyp
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"targets": [{
"target_name": "modbus",
"sources": [ "src/binding.cc" ],
"include_dirs": [
"<!@(node -p \"require('node-addon-api').include\")"
],
"dependencies": [
"<!(node -p \"require('node-addon-api').gyp\")"
],
"libraries": ["$(PWD)/libmodbus.so"],
"cflags!": [ "-fno-exceptions" ],
"cflags_cc!": [ "-fno-exceptions" ]
}]
}
Loading
Loading