A comprehensive full-stack asynchronous Modbus data monitoring system built with Python asyncio, FastAPI, Vue 3, and Redis. Provides CLI tools, REST API services, and modern web interfaces with complete support for Modbus TCP read/write operations.
This project is a comprehensive full-stack Modbus monitoring solution featuring:
- Core Python Module: Asynchronous Modbus client library (
scripts/async_modbus_monitor.py) with advanced features - FastAPI Backend: REST API server with Redis integration for real-time data persistence and time-series storage
- Modern Vue 3 Frontend: Component-based web interface with Vite build system (
frontend-vite/) - Legacy Frontend: Simple single-page application (
frontend/) for compatibility - Redis Integration: Real-time data caching, latest values, and historical data storage
- Docker Deployment: Multi-container orchestration with custom port configuration
- Multiple Interfaces: CLI, REST API, and modern web interface options
# 1. Clone and configure
git clone <repository-url>
cd modbus_monitor
cp .env.example .env
# Edit .env with your Modbus device settings
# 2. Start all services
docker-compose up -d --build
# 3. Access applications
# - Web Interface: http://localhost:18081
# - API Documentation: http://localhost:18000/docs
# - Redis: localhost:16380# 1. Install dependencies
uv sync
# 2. Start Redis
docker run -d -p 6379:6379 redis:7-alpine
# 3. Start backend
uv run python scripts/start_backend.py
# 4. Start frontend (in new terminal)
cd frontend-vite && npm install && npm run dev
A modern Vue 3 interface with configuration panel (Host, Port, Device ID, Poll Interval) and connection control buttons (Update Config, Connect, Disconnect, Start/Stop Monitoring).
The Manual Read section allows specifying register address, count, and register type (Holding/Input/Coils/Discrete Inputs). Write operations for Holding Registers with immediate feedback.
Demonstrates complete write and monitoring workflow. Write to Holding Registers (single/multiple) with real-time Modbus data table showing register name, address, type, values, and timestamp.
Visit http://localhost:8000/docs to see the complete Swagger UI interactive API documentation, allowing developers to quickly test all endpoints (connection, read, write, monitoring, data query, etc.).
modbus_monitor/
├── scripts/
│ ├── async_modbus_monitor.py - Core asynchronous Modbus client library (377 lines)
│ └── start_backend.py - Backend service startup script
├── backend/
│ ├── main.py - FastAPI REST API application with CORS
│ ├── config.py - Pydantic-based configuration management
│ ├── modbus_service.py - Modbus service with Redis integration
│ └── Dockerfile - Backend container configuration
├── frontend/ - Legacy single-page Vue 3 application
│ ├── index.html
│ ├── app.js
│ └── css/styles.css
├── frontend-vite/ - Modern Vue 3 + Vite frontend (Recommended)
│ ├── src/
│ │ ├── App.vue - Root Vue component
│ │ ├── main.js - Application entry point
│ │ ├── components/ - Modular Vue components
│ │ ├── composables/ - Vue composables (useAlerts.js)
│ │ └── services/ - Axios API client
│ └── Dockerfile - Frontend container with Nginx
├── docs/
│ ├── CLAUDE.md - Development guidelines
│ ├── configuration.md - Detailed configuration guide
│ ├── USAGE.md - Usage instructions
│ └── UML.md - System architecture diagrams
├── docker-compose.yml - Multi-container orchestration
├── pyproject.toml - UV project configuration
├── requirements.txt - Python dependencies
└── .env.example - Environment variables template
For detailed architecture diagrams (Component, Sequence, Class, State diagrams), see docs/UML.md.
┌─────────────────────────────────────────────────────────┐
│ Presentation Layer: Vue 3 Frontend (Vite/Legacy) │
│ - Configuration Interface - Real-time Data Display │
└────────────────────┬────────────────────────────────────┘
│ HTTP/REST API (JSON)
┌────────────────────▼────────────────────────────────────┐
│ Business Logic: FastAPI Backend + Modbus Service │
│ - Pydantic Config/Validation - Async Operations │
└────────────────────┬────────────────────────────────────┘
│ TCP/IP + Redis
┌────────────────────▼────────────────────────────────────┐
│ Data/Device Layer: Redis + Modbus TCP Devices │
│ - Time-Series Storage - PLC/Sensors (Port 502) │
└─────────────────────────────────────────────────────────┘
- Async I/O: Python asyncio for concurrent connections
- Type Safety: Pydantic validation for config and API models
- Real-time Caching: Redis sorted sets for time-series data (1000-entry retention)
- Modular Design: Independent component deployment/scaling
- Modern Stack: Vue 3 + Vite + FastAPI + Docker Compose
- Flexible Deployment: Container or direct development workflows
- Event Loop: Built on Python
asynciofor high concurrency - Non-blocking I/O: All network operations use
async/awaitpattern - Concurrency: Multiple registers read simultaneously using
asyncio.gather() - Performance Advantage: Single thread handles hundreds of concurrent connections
- Automatic Reconnection: Built-in retry logic with configurable limits (max 5 consecutive errors)
1. Environment Variables (.env file) - Highest priority
2. Default values in Pydantic models
3. Fallback values in validators| Section | Class | Description |
|---|---|---|
| Modbus | ModbusConfig |
Connection parameters, polling, retry settings |
| Redis | RedisConfig |
Redis server connection details |
| API | APIConfig |
FastAPI server configuration |
| Logging | LoggingConfig |
Log level and format settings |
| Register Ranges | RegisterRangeConfig |
Flexible register monitoring configuration |
The system provides robust write operations for Modbus holding registers:
| Operation | Function | Purpose |
|---|---|---|
| Single Write | write_holding_register() |
Write single value (Function Code 06) |
| Multiple Write | write_holding_registers() |
Write multiple consecutive values (Function Code 16) |
| Write Verification | Read-back after write | Verify written values |
| Hex/Decimal Support | Value parsing | Support both hex (0x prefix) and decimal |
| Error Handling | Exception management | Graceful error handling with logging |
consecutive_errors = 0
max_consecutive_errors = 5
while self.running:
if not self.client.connected:
if not await self.connect():
consecutive_errors += 1
if consecutive_errors >= max_consecutive_errors:
break # Stop if limit exceeded- Catches
ModbusExceptionand genericException - Detailed error logging
- Returns
Noneinstead of raising exceptions for graceful degradation
| Type | Modbus Function Code | Read | Write | Data Type | Typical Use | |---|---|---|---|---| | Holding Registers | FC03, FC06, FC16 | ✅ | ✅ | 16-bit | Setpoints, parameters | | Input Registers | FC04 | ✅ | ❌ | 16-bit | Sensor readings | | Coils | FC01, FC05, FC15 | ✅ | ✅ | 1-bit | Digital output control | | Discrete Inputs | FC02 | ✅ | ❌ | 1-bit | Switch status, alarms |
Note: Write operations are fully implemented for Holding Registers (FC06, FC16). Coil write operations (FC05, FC15) are supported in backend service.
Basic Usage (scripts/async_modbus_monitor.py):
# Run CLI tool with default configuration
uv run python scripts/async_modbus_monitor.py
# Or with uvicorn for backend mode
uv run python scripts/start_backend.pyThe CLI tool demonstrates:
- Direct read_register() calls
- Continuous monitoring with monitor_continuously()
- Custom data handlers
- Write operations (single and multiple)
Start backend service:
# Method 1: Using scripts/start_backend.py
uv run python scripts/start_backend.py
# Method 2: Direct uvicorn
uv run uvicorn backend.main:app --host 0.0.0.0 --port 8000 --reloadAPI Endpoint List (backend/main.py):
| Endpoint | Method | Function | Request Body |
|---|---|---|---|
/api/config |
GET | Get configuration | - |
/api/config |
POST | Update configuration | ModbusConfigModel |
/api/connect |
POST | Connect to device | - |
/api/disconnect |
POST | Disconnect from device | - |
/api/status |
GET | Get connection status | - |
/api/read |
POST | Read registers | RegisterReadRequest |
/api/write |
POST | Write single register | RegisterWriteRequest |
/api/write_multiple |
POST | Write multiple registers | MultipleRegisterWriteRequest |
/api/start_monitoring |
POST | Start continuous monitoring | - |
/api/stop_monitoring |
POST | Stop monitoring | - |
/api/data/latest |
GET | Get latest data | - |
/api/data/history |
GET | Get historical data | limit (query param) |
API Usage Example:
# Connect to device (Docker deployment)
curl -X POST http://localhost:18000/api/connect
# Connect to device (Direct deployment)
curl -X POST http://localhost:8000/api/connect
# Read registers
curl -X POST http://localhost:18000/api/read \
-H "Content-Type: application/json" \
-d '{"address": 0, "count": 10, "register_type": "holding"}'
# Write a register
curl -X POST http://localhost:18000/api/write \
-H "Content-Type: application/json" \
-d '{"address": 10, "value": 1234}'
# Write multiple registers
curl -X POST http://localhost:18000/api/write_multiple \
-H "Content-Type: application/json" \
-d '{"address": 10, "values": [100, 200, 300]}'
# Get latest data
curl http://localhost:18000/api/data/latest
# Get historical data (last 50 entries)
curl "http://localhost:18000/api/data/history?limit=50"Modern Frontend (Vue 3 + Vite) - Primary Implementation:
# Development mode
cd frontend-vite
npm install
npm run dev
# Access at: http://localhost:5173
# Production build
npm run build
# Serves dist/ folder via Nginx in Docker
# Docker deployment
docker-compose up frontend -d
# Access at: http://localhost:18081Modern Frontend Component Architecture:
- Configuration Panel: Dynamic Modbus connection parameters with validation
- Connection Control: Real-time connection status with Connect/Disconnect/Start/Stop buttons
- Manual Read Operations: Interactive register reading with address, count, and type selection
- Write Operations: Single and multiple register writes with immediate feedback and validation
- Data Display: Real-time data table with timestamps, register names, and auto-refresh capabilities
- Alert System: Toast notifications using composables for user feedback
- Status Indicators: Visual connection, monitoring, and operation status indicators
- Responsive Design: Modern CSS with responsive layouts and glassmorphism effects
Legacy Frontend - Compatibility Option:
# Simple HTTP server for legacy frontend
# Access at: http://localhost:8081 (if served separately)
# Single-page Vue 3 application with basic styling# Modbus device network configuration
MODBUS_HOST=192.168.30.24 # Your Modbus device IP
MODBUS_PORT=502 # Standard Modbus TCP port
MODBUS_DEVICE_ID=1 # Modbus slave/unit ID
# Polling and timeout settings
MODBUS_POLL_INTERVAL=2.0 # Seconds between polling
MODBUS_TIMEOUT=3.0 # Connection timeout
MODBUS_RETRIES=3 # Retry attempts
# Register range configuration
START_ADDRESS=1 # First register to monitor
END_ADDRESS=26 # Last register to monitor
# Redis configuration
REDIS_HOST=localhost # Redis server host
REDIS_PORT=6379 # Redis server port (16380 in Docker)
REDIS_PASSWORD= # Redis password (empty for no auth)
REDIS_DB=0 # Redis database number
# API configuration
API_HOST=0.0.0.0 # FastAPI bind address
API_PORT=8000 # FastAPI port (18000 in Docker)
API_DEBUG=False # Enable debug mode
API_CORS_ORIGINS=* # CORS allowed origins
# Logging configuration
LOG_LEVEL=INFO # Logging level (DEBUG, INFO, WARN, ERROR)[modbus]
host = 192.168.30.24
port = 502
device_id = 1
[polling]
poll_interval = 2.0
timeout = 3.0
retries = 3
[registers]
start_address = 1
end_address = 26[project]
name = "modbus-monitor"
version = "0.1.0"
requires-python = ">=3.10"
dependencies = [
"fastapi>=0.104.0", # Modern web framework
"uvicorn[standard]>=0.24.0", # ASGI server
"pymodbus>=3.0.0", # Modbus protocol
"redis>=5.0.0", # Redis async client
"python-dotenv>=1.0.0", # Environment variables
"pydantic>=2.0.0" # Data validation
]{
"dependencies": {
"vue": "^3.5.24", // Vue 3 framework
"axios": "^1.13.2" // HTTP client
},
"devDependencies": {
"@vitejs/plugin-vue": "^6.0.1",
"vite": "^7.2.4"
}
}- Python: >= 3.10
- Redis: >= 7.0
- Node.js: >= 18 (for frontend-vite development)
- UV: Python package manager (recommended)
- Docker: >= 20.10 (optional)
- Python: >= 3.10
- Redis: >= 7.0
- Node.js: >= 18 (for frontend-vite development)
- Docker: >= 20.10 (optional, for containerized deployment)
# Configure environment
cp .env.example .env
nano .env # Edit MODBUS_HOST, etc.
# Start all services
docker-compose up -d --build
# Access services
# - Frontend: http://localhost:18081
# - API Docs: http://localhost:18000/docs
# - Redis: localhost:16380
# Stop services
docker-compose down# Install UV
curl -LsSf https://astral.sh/uv/install.sh | sh
# Setup project
git clone https://github.com/sprigga/modbus_monitor.git
cd modbus_monitor
cp .env.example .env
uv sync
# Start Redis
docker run -d -p 6379:6379 --name modbus-redis redis:7-alpine
# Run backend
uv run python scripts/start_backend.py
# Run frontend (in new terminal)
cd frontend-vite && npm install && npm run dev
# Access at http://localhost:5173# Setup virtual environment
python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
cp .env.example .env
# Run backend
python scripts/start_backend.py
# Serve frontend/ folder with any web server# Run with default configuration
uv run python scripts/async_modbus_monitor.py
# Start backend server
uv run python scripts/start_backend.pyfrom scripts.async_modbus_monitor import AsyncModbusMonitor, ModbusConfig
import asyncio
async def main():
config = ModbusConfig(host='192.168.1.100', port=502, device_id=1)
monitor = AsyncModbusMonitor(config)
monitor.add_register(address=0, count=10, register_type='holding', name='Temperature')
if await monitor.connect():
# Read registers
data = await monitor.read_registers(0, 10, 'holding')
print(f"Data: {data}")
# Write single register
await monitor.write_holding_register(address=10, value=1234)
# Write multiple registers
await monitor.write_holding_registers(address=20, values=[100, 200, 300])
asyncio.run(main())FastAPI auto-generates interactive documentation:
- Swagger UI:
http://localhost:18000/docs(Docker) orhttp://localhost:8000/docs(Direct) - ReDoc:
http://localhost:18000/redoc - OpenAPI JSON:
http://localhost:18000/openapi.json
For complete endpoint details with request/response schemas, see lines 313-358 or visit /docs endpoint.
- Use a firewall to restrict access to Modbus port (502)
- Isolate Modbus devices on a dedicated VLAN
- Use VPN for remote access
- Configure CORS origins appropriately
- Implement authentication (JWT, OAuth2)
- Add rate limiting
- Enable HTTPS with SSL/TLS
- Implement audit logging
- Use secret management for sensitive data
- Disable debug mode in production
# backend/main.py - Configure CORS for production
app.add_middleware(
CORSMiddleware,
allow_origins=["https://your-domain.com"], # Restrict to your domain
allow_credentials=True,
allow_methods=["GET", "POST"],
allow_headers=["Authorization", "Content-Type"],
)- Use UV for Python environment management
- Follow PEP 8 standards
- Add type hints to all functions
- Write comprehensive docstrings
- Preserve original code with comments when modifying
- Test all changes before committing
- Use
.envfile for environment-specific settings - Never commit
.envfiles to version control - Use
pydantic-settingsfor type-safe configuration - Validate all user inputs
- Provide sensible defaults
# Test connectivity
ping <modbus-ip>
nc -zv <modbus-ip> 502
# Check firewall
sudo iptables -L -n | grep 502For testing without actual hardware, you can use the IBM Maximo Modbus Simulator:
- Link: https://ibm.github.io/maximo-labs/monitor_modbus_simulator/
- Purpose: A web-based Modbus TCP simulator for testing and development
- Usage: Configure your monitor to connect to the simulator's IP and port (typically 502)
- Features: Simulates various register types, supports read/write operations
This simulator is especially useful for:
- Initial setup and testing of the monitoring system
- Development and debugging without physical Modbus devices
- Training and demonstrations
# Check Redis status (Docker deployment)
redis-cli -p 16380 ping
# Check Redis status (Direct deployment)
redis-cli ping
# Start Redis with Docker
docker run -d -p 6379:6379 redis:7-alpine
# Or use Docker Compose
docker-compose up redis -d# Clear node modules and reinstall
cd frontend-vite
rm -rf node_modules package-lock.json
npm install- Fork the project
- Create a feature branch
- Make changes following development guidelines
- Run tests
- Submit a pull request with conventional commit message
Use Conventional Commits:
feat: New featurefix: Bug fixdocs: Documentation updatestyle: Code style adjustmentsrefactor: Refactoringtest: Test-relatedchore: Build/tool-related
This project is licensed under the MIT License. See LICENSE file for details.
For questions, issues, or contributions:
- Repository: GitHub project page
- Issues: Report bugs and feature requests
- Discussions: Community discussion and support
- Documentation: See
docs/folder for detailed guides
This project is licensed under the MIT License.
- pymodbus - Modbus protocol implementation
- FastAPI - Modern Python web framework
- Vue.js - Progressive JavaScript framework
- Redis - High-performance in-memory database
- UV - Fast Python package manager
- Vite - Next-generation frontend tool
Last Updated: 2025-12-30 | Version: 0.1.0 | Python: >= 3.10