javi-forge 1.2.0 → 1.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ci-local/ci-local.sh +20 -8
- package/package.json +1 -1
- package/ai-config/.skillignore +0 -15
- package/ai-config/AUTO_INVOKE.md +0 -300
- package/ai-config/agents/_TEMPLATE.md +0 -93
- package/ai-config/agents/business/api-designer.md +0 -1657
- package/ai-config/agents/business/business-analyst.md +0 -1331
- package/ai-config/agents/business/product-strategist.md +0 -206
- package/ai-config/agents/business/project-manager.md +0 -178
- package/ai-config/agents/business/requirements-analyst.md +0 -1277
- package/ai-config/agents/business/technical-writer.md +0 -1679
- package/ai-config/agents/creative/ux-designer.md +0 -205
- package/ai-config/agents/data-ai/ai-engineer.md +0 -487
- package/ai-config/agents/data-ai/analytics-engineer.md +0 -953
- package/ai-config/agents/data-ai/data-engineer.md +0 -173
- package/ai-config/agents/data-ai/data-scientist.md +0 -672
- package/ai-config/agents/data-ai/mlops-engineer.md +0 -814
- package/ai-config/agents/data-ai/prompt-engineer.md +0 -772
- package/ai-config/agents/development/angular-expert.md +0 -620
- package/ai-config/agents/development/backend-architect.md +0 -795
- package/ai-config/agents/development/database-specialist.md +0 -212
- package/ai-config/agents/development/frontend-specialist.md +0 -686
- package/ai-config/agents/development/fullstack-engineer.md +0 -668
- package/ai-config/agents/development/golang-pro.md +0 -338
- package/ai-config/agents/development/java-enterprise.md +0 -400
- package/ai-config/agents/development/javascript-pro.md +0 -422
- package/ai-config/agents/development/nextjs-pro.md +0 -474
- package/ai-config/agents/development/python-pro.md +0 -570
- package/ai-config/agents/development/react-pro.md +0 -487
- package/ai-config/agents/development/rust-pro.md +0 -246
- package/ai-config/agents/development/spring-boot-4-expert.md +0 -326
- package/ai-config/agents/development/typescript-pro.md +0 -336
- package/ai-config/agents/development/vue-specialist.md +0 -605
- package/ai-config/agents/infrastructure/cloud-architect.md +0 -472
- package/ai-config/agents/infrastructure/deployment-manager.md +0 -358
- package/ai-config/agents/infrastructure/devops-engineer.md +0 -455
- package/ai-config/agents/infrastructure/incident-responder.md +0 -519
- package/ai-config/agents/infrastructure/kubernetes-expert.md +0 -705
- package/ai-config/agents/infrastructure/monitoring-specialist.md +0 -674
- package/ai-config/agents/infrastructure/performance-engineer.md +0 -658
- package/ai-config/agents/orchestrator.md +0 -241
- package/ai-config/agents/quality/accessibility-auditor.md +0 -1204
- package/ai-config/agents/quality/code-reviewer-compact.md +0 -123
- package/ai-config/agents/quality/code-reviewer.md +0 -363
- package/ai-config/agents/quality/dependency-manager.md +0 -743
- package/ai-config/agents/quality/e2e-test-specialist.md +0 -1005
- package/ai-config/agents/quality/performance-tester.md +0 -1086
- package/ai-config/agents/quality/security-auditor.md +0 -133
- package/ai-config/agents/quality/test-engineer.md +0 -453
- package/ai-config/agents/specialists/api-designer.md +0 -87
- package/ai-config/agents/specialists/backend-architect.md +0 -73
- package/ai-config/agents/specialists/code-reviewer.md +0 -77
- package/ai-config/agents/specialists/db-optimizer.md +0 -75
- package/ai-config/agents/specialists/devops-engineer.md +0 -83
- package/ai-config/agents/specialists/documentation-writer.md +0 -78
- package/ai-config/agents/specialists/frontend-developer.md +0 -75
- package/ai-config/agents/specialists/performance-analyst.md +0 -82
- package/ai-config/agents/specialists/refactor-specialist.md +0 -74
- package/ai-config/agents/specialists/security-auditor.md +0 -74
- package/ai-config/agents/specialists/test-engineer.md +0 -81
- package/ai-config/agents/specialists/ux-consultant.md +0 -76
- package/ai-config/agents/specialized/agent-generator.md +0 -1190
- package/ai-config/agents/specialized/blockchain-developer.md +0 -149
- package/ai-config/agents/specialized/code-migrator.md +0 -892
- package/ai-config/agents/specialized/context-manager.md +0 -978
- package/ai-config/agents/specialized/documentation-writer.md +0 -1078
- package/ai-config/agents/specialized/ecommerce-expert.md +0 -1756
- package/ai-config/agents/specialized/embedded-engineer.md +0 -1714
- package/ai-config/agents/specialized/error-detective.md +0 -1034
- package/ai-config/agents/specialized/fintech-specialist.md +0 -1659
- package/ai-config/agents/specialized/freelance-project-planner-v2.md +0 -1988
- package/ai-config/agents/specialized/freelance-project-planner-v3.md +0 -2136
- package/ai-config/agents/specialized/freelance-project-planner-v4.md +0 -4503
- package/ai-config/agents/specialized/freelance-project-planner.md +0 -722
- package/ai-config/agents/specialized/game-developer.md +0 -1963
- package/ai-config/agents/specialized/healthcare-dev.md +0 -1620
- package/ai-config/agents/specialized/mobile-developer.md +0 -188
- package/ai-config/agents/specialized/parallel-plan-executor.md +0 -506
- package/ai-config/agents/specialized/plan-executor.md +0 -485
- package/ai-config/agents/specialized/solo-dev-planner-modular/00-INDEX.md +0 -485
- package/ai-config/agents/specialized/solo-dev-planner-modular/01-CORE.md +0 -3493
- package/ai-config/agents/specialized/solo-dev-planner-modular/02-SELF-CORRECTION.md +0 -778
- package/ai-config/agents/specialized/solo-dev-planner-modular/03-PROGRESSIVE-SETUP.md +0 -918
- package/ai-config/agents/specialized/solo-dev-planner-modular/04-DEPLOYMENT.md +0 -1537
- package/ai-config/agents/specialized/solo-dev-planner-modular/05-TESTING.md +0 -2633
- package/ai-config/agents/specialized/solo-dev-planner-modular/06-OPERATIONS.md +0 -5610
- package/ai-config/agents/specialized/solo-dev-planner-modular/INSTALL.md +0 -335
- package/ai-config/agents/specialized/solo-dev-planner-modular/QUICK-REFERENCE.txt +0 -215
- package/ai-config/agents/specialized/solo-dev-planner-modular/README.md +0 -260
- package/ai-config/agents/specialized/solo-dev-planner-modular/START-HERE.md +0 -379
- package/ai-config/agents/specialized/solo-dev-planner-modular/WORKFLOW-DIAGRAM.md +0 -355
- package/ai-config/agents/specialized/solo-dev-planner-modular/solo-dev-planner.md +0 -279
- package/ai-config/agents/specialized/template-writer.md +0 -347
- package/ai-config/agents/specialized/test-runner.md +0 -99
- package/ai-config/agents/specialized/vibekanban-smart-worker.md +0 -244
- package/ai-config/agents/specialized/wave-executor.md +0 -138
- package/ai-config/agents/specialized/workflow-optimizer.md +0 -1114
- package/ai-config/commands/git/changelog.md +0 -32
- package/ai-config/commands/git/ci-local.md +0 -70
- package/ai-config/commands/git/commit.md +0 -35
- package/ai-config/commands/git/fix-issue.md +0 -23
- package/ai-config/commands/git/pr-create.md +0 -42
- package/ai-config/commands/git/pr-review.md +0 -50
- package/ai-config/commands/git/worktree.md +0 -39
- package/ai-config/commands/refactoring/cleanup.md +0 -24
- package/ai-config/commands/refactoring/dead-code.md +0 -40
- package/ai-config/commands/refactoring/extract.md +0 -31
- package/ai-config/commands/testing/e2e.md +0 -30
- package/ai-config/commands/testing/tdd.md +0 -36
- package/ai-config/commands/testing/test-coverage.md +0 -30
- package/ai-config/commands/testing/test-fix.md +0 -24
- package/ai-config/commands/workflow/generate-agents-md.md +0 -85
- package/ai-config/commands/workflow/planning.md +0 -47
- package/ai-config/commands/workflows/compound.md +0 -89
- package/ai-config/commands/workflows/diagnose.md +0 -70
- package/ai-config/commands/workflows/discover.md +0 -86
- package/ai-config/commands/workflows/plan.md +0 -77
- package/ai-config/commands/workflows/review.md +0 -78
- package/ai-config/commands/workflows/work.md +0 -75
- package/ai-config/config.yaml +0 -18
- package/ai-config/hooks/_TEMPLATE.md +0 -96
- package/ai-config/hooks/block-dangerous-commands.md +0 -75
- package/ai-config/hooks/commit-guard.md +0 -90
- package/ai-config/hooks/context-loader.md +0 -73
- package/ai-config/hooks/improve-prompt.md +0 -91
- package/ai-config/hooks/learning-log.md +0 -72
- package/ai-config/hooks/model-router.md +0 -86
- package/ai-config/hooks/secret-scanner.md +0 -64
- package/ai-config/hooks/skill-validator.md +0 -102
- package/ai-config/hooks/task-artifact.md +0 -114
- package/ai-config/hooks/validate-workflow.md +0 -100
- package/ai-config/prompts/base.md +0 -71
- package/ai-config/prompts/modes/debug.md +0 -34
- package/ai-config/prompts/modes/deploy.md +0 -40
- package/ai-config/prompts/modes/research.md +0 -32
- package/ai-config/prompts/modes/review.md +0 -33
- package/ai-config/prompts/review-policy.md +0 -79
- package/ai-config/skills/_TEMPLATE.md +0 -157
- package/ai-config/skills/backend/api-gateway/SKILL.md +0 -254
- package/ai-config/skills/backend/bff-concepts/SKILL.md +0 -239
- package/ai-config/skills/backend/bff-spring/SKILL.md +0 -364
- package/ai-config/skills/backend/chi-router/SKILL.md +0 -396
- package/ai-config/skills/backend/error-handling/SKILL.md +0 -255
- package/ai-config/skills/backend/exceptions-spring/SKILL.md +0 -323
- package/ai-config/skills/backend/fastapi/SKILL.md +0 -302
- package/ai-config/skills/backend/gateway-spring/SKILL.md +0 -390
- package/ai-config/skills/backend/go-backend/SKILL.md +0 -457
- package/ai-config/skills/backend/gradle-multimodule/SKILL.md +0 -274
- package/ai-config/skills/backend/graphql-concepts/SKILL.md +0 -352
- package/ai-config/skills/backend/graphql-spring/SKILL.md +0 -398
- package/ai-config/skills/backend/grpc-concepts/SKILL.md +0 -283
- package/ai-config/skills/backend/grpc-spring/SKILL.md +0 -445
- package/ai-config/skills/backend/jwt-auth/SKILL.md +0 -412
- package/ai-config/skills/backend/notifications-concepts/SKILL.md +0 -259
- package/ai-config/skills/backend/recommendations-concepts/SKILL.md +0 -261
- package/ai-config/skills/backend/search-concepts/SKILL.md +0 -263
- package/ai-config/skills/backend/search-spring/SKILL.md +0 -375
- package/ai-config/skills/backend/spring-boot-4/SKILL.md +0 -172
- package/ai-config/skills/backend/websockets/SKILL.md +0 -532
- package/ai-config/skills/data-ai/ai-ml/SKILL.md +0 -423
- package/ai-config/skills/data-ai/analytics-concepts/SKILL.md +0 -195
- package/ai-config/skills/data-ai/analytics-spring/SKILL.md +0 -340
- package/ai-config/skills/data-ai/duckdb-analytics/SKILL.md +0 -440
- package/ai-config/skills/data-ai/langchain/SKILL.md +0 -238
- package/ai-config/skills/data-ai/mlflow/SKILL.md +0 -302
- package/ai-config/skills/data-ai/onnx-inference/SKILL.md +0 -290
- package/ai-config/skills/data-ai/powerbi/SKILL.md +0 -352
- package/ai-config/skills/data-ai/pytorch/SKILL.md +0 -274
- package/ai-config/skills/data-ai/scikit-learn/SKILL.md +0 -321
- package/ai-config/skills/data-ai/vector-db/SKILL.md +0 -301
- package/ai-config/skills/database/graph-databases/SKILL.md +0 -218
- package/ai-config/skills/database/graph-spring/SKILL.md +0 -361
- package/ai-config/skills/database/pgx-postgres/SKILL.md +0 -512
- package/ai-config/skills/database/redis-cache/SKILL.md +0 -343
- package/ai-config/skills/database/sqlite-embedded/SKILL.md +0 -388
- package/ai-config/skills/database/timescaledb/SKILL.md +0 -320
- package/ai-config/skills/docs/api-documentation/SKILL.md +0 -293
- package/ai-config/skills/docs/docs-spring/SKILL.md +0 -377
- package/ai-config/skills/docs/mustache-templates/SKILL.md +0 -190
- package/ai-config/skills/docs/technical-docs/SKILL.md +0 -447
- package/ai-config/skills/frontend/astro-ssr/SKILL.md +0 -441
- package/ai-config/skills/frontend/frontend-design/SKILL.md +0 -54
- package/ai-config/skills/frontend/frontend-web/SKILL.md +0 -368
- package/ai-config/skills/frontend/mantine-ui/SKILL.md +0 -396
- package/ai-config/skills/frontend/tanstack-query/SKILL.md +0 -439
- package/ai-config/skills/frontend/zod-validation/SKILL.md +0 -417
- package/ai-config/skills/frontend/zustand-state/SKILL.md +0 -350
- package/ai-config/skills/infrastructure/chaos-engineering/SKILL.md +0 -244
- package/ai-config/skills/infrastructure/chaos-spring/SKILL.md +0 -378
- package/ai-config/skills/infrastructure/devops-infra/SKILL.md +0 -435
- package/ai-config/skills/infrastructure/docker-containers/SKILL.md +0 -420
- package/ai-config/skills/infrastructure/kubernetes/SKILL.md +0 -456
- package/ai-config/skills/infrastructure/opentelemetry/SKILL.md +0 -546
- package/ai-config/skills/infrastructure/traefik-proxy/SKILL.md +0 -474
- package/ai-config/skills/infrastructure/woodpecker-ci/SKILL.md +0 -315
- package/ai-config/skills/mobile/ionic-capacitor/SKILL.md +0 -504
- package/ai-config/skills/mobile/mobile-ionic/SKILL.md +0 -448
- package/ai-config/skills/prompt-improver/SKILL.md +0 -125
- package/ai-config/skills/quality/ghagga-review/SKILL.md +0 -216
- package/ai-config/skills/references/hooks-patterns/SKILL.md +0 -238
- package/ai-config/skills/references/mcp-servers/SKILL.md +0 -275
- package/ai-config/skills/references/plugins-reference/SKILL.md +0 -110
- package/ai-config/skills/references/skills-reference/SKILL.md +0 -420
- package/ai-config/skills/references/subagent-templates/SKILL.md +0 -193
- package/ai-config/skills/systems-iot/modbus-protocol/SKILL.md +0 -410
- package/ai-config/skills/systems-iot/mqtt-rumqttc/SKILL.md +0 -408
- package/ai-config/skills/systems-iot/rust-systems/SKILL.md +0 -386
- package/ai-config/skills/systems-iot/tokio-async/SKILL.md +0 -324
- package/ai-config/skills/testing/playwright-e2e/SKILL.md +0 -289
- package/ai-config/skills/testing/testcontainers/SKILL.md +0 -299
- package/ai-config/skills/testing/vitest-testing/SKILL.md +0 -381
- package/ai-config/skills/workflow/ci-local-guide/SKILL.md +0 -118
- package/ai-config/skills/workflow/claude-automation-recommender/SKILL.md +0 -299
- package/ai-config/skills/workflow/claude-md-improver/SKILL.md +0 -158
- package/ai-config/skills/workflow/finishing-a-development-branch/SKILL.md +0 -117
- package/ai-config/skills/workflow/git-github/SKILL.md +0 -334
- package/ai-config/skills/workflow/git-github/references/examples.md +0 -160
- package/ai-config/skills/workflow/git-workflow/SKILL.md +0 -214
- package/ai-config/skills/workflow/ide-plugins/SKILL.md +0 -277
- package/ai-config/skills/workflow/ide-plugins-intellij/SKILL.md +0 -401
- package/ai-config/skills/workflow/obsidian-brain-workflow/SKILL.md +0 -199
- package/ai-config/skills/workflow/using-git-worktrees/SKILL.md +0 -100
- package/ai-config/skills/workflow/verification-before-completion/SKILL.md +0 -73
- package/ai-config/skills/workflow/wave-workflow/SKILL.md +0 -178
- package/schemas/agent.schema.json +0 -34
- package/schemas/ai-config.schema.json +0 -28
- package/schemas/plugin.schema.json +0 -62
- package/schemas/skill.schema.json +0 -44
|
@@ -1,410 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: modbus-protocol
|
|
3
|
-
description: >
|
|
4
|
-
Modbus industrial protocol implementation in Rust, Go, and Python.
|
|
5
|
-
Trigger: modbus, plc, scada, industrial protocol, registers, coils
|
|
6
|
-
tools:
|
|
7
|
-
- Read
|
|
8
|
-
- Write
|
|
9
|
-
- Bash
|
|
10
|
-
- Grep
|
|
11
|
-
metadata:
|
|
12
|
-
author: plataforma-industrial
|
|
13
|
-
version: "2.0"
|
|
14
|
-
tags: [industrial, modbus, plc, sensors, protocol]
|
|
15
|
-
language: rust
|
|
16
|
-
updated: "2026-02"
|
|
17
|
-
---
|
|
18
|
-
|
|
19
|
-
# Modbus Protocol
|
|
20
|
-
|
|
21
|
-
> Industrial Modbus TCP/RTU implementation for sensor communication
|
|
22
|
-
|
|
23
|
-
## When to Use
|
|
24
|
-
|
|
25
|
-
- [ ] Reading data from PLCs (Siemens, Allen-Bradley, Schneider)
|
|
26
|
-
- [ ] Communicating with industrial sensors
|
|
27
|
-
- [ ] Building SCADA/gateway systems
|
|
28
|
-
- [ ] Implementing OT (Operational Technology) integrations
|
|
29
|
-
|
|
30
|
-
## Stack
|
|
31
|
-
|
|
32
|
-
```yaml
|
|
33
|
-
# Rust
|
|
34
|
-
tokio-modbus: "0.13+"
|
|
35
|
-
|
|
36
|
-
# Go
|
|
37
|
-
github.com/simonvetter/modbus: latest
|
|
38
|
-
|
|
39
|
-
# Python
|
|
40
|
-
pymodbus: "3.6+"
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
## Modbus Fundamentals
|
|
44
|
-
|
|
45
|
-
### Register Types
|
|
46
|
-
|
|
47
|
-
| Type | Address Range | Access | Use Case |
|
|
48
|
-
|------|---------------|--------|----------|
|
|
49
|
-
| Coils | 00001-09999 | R/W | Digital outputs (on/off) |
|
|
50
|
-
| Discrete Inputs | 10001-19999 | R | Digital inputs (read-only) |
|
|
51
|
-
| Input Registers | 30001-39999 | R | Analog inputs (16-bit) |
|
|
52
|
-
| Holding Registers | 40001-49999 | R/W | Configuration & data |
|
|
53
|
-
|
|
54
|
-
### Function Codes
|
|
55
|
-
|
|
56
|
-
| Code | Function | Description |
|
|
57
|
-
|------|----------|-------------|
|
|
58
|
-
| 01 | Read Coils | Read multiple digital outputs |
|
|
59
|
-
| 02 | Read Discrete Inputs | Read digital inputs |
|
|
60
|
-
| 03 | Read Holding Registers | Read configuration registers |
|
|
61
|
-
| 04 | Read Input Registers | Read analog inputs |
|
|
62
|
-
| 05 | Write Single Coil | Set single output |
|
|
63
|
-
| 06 | Write Single Register | Write one register |
|
|
64
|
-
| 16 | Write Multiple Registers | Write block of registers |
|
|
65
|
-
|
|
66
|
-
## Rust Implementation
|
|
67
|
-
|
|
68
|
-
### Client Setup
|
|
69
|
-
|
|
70
|
-
```rust
|
|
71
|
-
use tokio_modbus::prelude::*;
|
|
72
|
-
use tokio_modbus::client::tcp;
|
|
73
|
-
use std::net::SocketAddr;
|
|
74
|
-
use tokio::time::{timeout, Duration};
|
|
75
|
-
|
|
76
|
-
pub struct ModbusClient {
|
|
77
|
-
ctx: client::Context,
|
|
78
|
-
timeout_duration: Duration,
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
impl ModbusClient {
|
|
82
|
-
pub async fn connect(addr: SocketAddr, slave_id: u8) -> Result<Self, ModbusError> {
|
|
83
|
-
let ctx = tcp::connect_slave(addr, Slave(slave_id)).await?;
|
|
84
|
-
Ok(Self { ctx, timeout_duration: Duration::from_secs(5) })
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
pub async fn read_holding_registers(&mut self, address: u16, count: u16) -> Result<Vec<u16>> {
|
|
88
|
-
timeout(self.timeout_duration, self.ctx.read_holding_registers(address, count))
|
|
89
|
-
.await
|
|
90
|
-
.map_err(|_| ModbusError::Timeout)?
|
|
91
|
-
.map_err(ModbusError::from)
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
pub async fn write_single_register(&mut self, address: u16, value: u16) -> Result<()> {
|
|
95
|
-
timeout(self.timeout_duration, self.ctx.write_single_register(address, value))
|
|
96
|
-
.await
|
|
97
|
-
.map_err(|_| ModbusError::Timeout)?
|
|
98
|
-
.map_err(ModbusError::from)
|
|
99
|
-
}
|
|
100
|
-
}
|
|
101
|
-
```
|
|
102
|
-
|
|
103
|
-
### Data Type Conversions
|
|
104
|
-
|
|
105
|
-
```rust
|
|
106
|
-
/// Two 16-bit registers to f32 (big-endian)
|
|
107
|
-
pub fn registers_to_f32(regs: &[u16]) -> f32 {
|
|
108
|
-
let bytes = [
|
|
109
|
-
(regs[0] >> 8) as u8, regs[0] as u8,
|
|
110
|
-
(regs[1] >> 8) as u8, regs[1] as u8,
|
|
111
|
-
];
|
|
112
|
-
f32::from_be_bytes(bytes)
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
/// Two 16-bit registers to f32 (little-endian, swapped)
|
|
116
|
-
pub fn registers_to_f32_le(regs: &[u16]) -> f32 {
|
|
117
|
-
let bytes = [
|
|
118
|
-
regs[1] as u8, (regs[1] >> 8) as u8,
|
|
119
|
-
regs[0] as u8, (regs[0] >> 8) as u8,
|
|
120
|
-
];
|
|
121
|
-
f32::from_le_bytes(bytes)
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
/// f32 to two 16-bit registers
|
|
125
|
-
pub fn f32_to_registers(value: f32) -> [u16; 2] {
|
|
126
|
-
let bytes = value.to_be_bytes();
|
|
127
|
-
[
|
|
128
|
-
((bytes[0] as u16) << 8) | (bytes[1] as u16),
|
|
129
|
-
((bytes[2] as u16) << 8) | (bytes[3] as u16),
|
|
130
|
-
]
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
/// Scale raw value to engineering units
|
|
134
|
-
pub fn scale_value(raw: u16, min_raw: u16, max_raw: u16, min_eng: f32, max_eng: f32) -> f32 {
|
|
135
|
-
let range_raw = (max_raw - min_raw) as f32;
|
|
136
|
-
let range_eng = max_eng - min_eng;
|
|
137
|
-
let normalized = (raw - min_raw) as f32 / range_raw;
|
|
138
|
-
min_eng + (normalized * range_eng)
|
|
139
|
-
}
|
|
140
|
-
```
|
|
141
|
-
|
|
142
|
-
### Sensor Reader
|
|
143
|
-
|
|
144
|
-
```rust
|
|
145
|
-
#[derive(Debug, Clone)]
|
|
146
|
-
pub struct SensorConfig {
|
|
147
|
-
pub id: String,
|
|
148
|
-
pub name: String,
|
|
149
|
-
pub address: u16,
|
|
150
|
-
pub data_type: DataType,
|
|
151
|
-
pub unit: String,
|
|
152
|
-
pub scale: Option<Scale>,
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
#[derive(Debug, Clone)]
|
|
156
|
-
pub enum DataType {
|
|
157
|
-
UInt16,
|
|
158
|
-
Int16,
|
|
159
|
-
Float32,
|
|
160
|
-
Float32LE,
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
#[derive(Debug, Clone)]
|
|
164
|
-
pub struct SensorReading {
|
|
165
|
-
pub sensor_id: String,
|
|
166
|
-
pub value: f64,
|
|
167
|
-
pub quality: u8, // 192=Good, 128=Uncertain, 0=Bad
|
|
168
|
-
pub timestamp: i64,
|
|
169
|
-
}
|
|
170
|
-
|
|
171
|
-
pub struct SensorReader {
|
|
172
|
-
client: ModbusClient,
|
|
173
|
-
sensors: Vec<SensorConfig>,
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
impl SensorReader {
|
|
177
|
-
pub async fn read_sensor(&mut self, sensor: &SensorConfig) -> Result<SensorReading> {
|
|
178
|
-
let count = match sensor.data_type {
|
|
179
|
-
DataType::UInt16 | DataType::Int16 => 1,
|
|
180
|
-
DataType::Float32 | DataType::Float32LE => 2,
|
|
181
|
-
};
|
|
182
|
-
|
|
183
|
-
let registers = self.client.read_holding_registers(sensor.address, count).await?;
|
|
184
|
-
|
|
185
|
-
let raw_value: f64 = match sensor.data_type {
|
|
186
|
-
DataType::UInt16 => registers[0] as f64,
|
|
187
|
-
DataType::Int16 => (registers[0] as i16) as f64,
|
|
188
|
-
DataType::Float32 => registers_to_f32(®isters) as f64,
|
|
189
|
-
DataType::Float32LE => registers_to_f32_le(®isters) as f64,
|
|
190
|
-
};
|
|
191
|
-
|
|
192
|
-
let value = if let Some(scale) = &sensor.scale {
|
|
193
|
-
scale_value(raw_value as u16, scale.min_raw, scale.max_raw, scale.min_eng, scale.max_eng) as f64
|
|
194
|
-
} else {
|
|
195
|
-
raw_value
|
|
196
|
-
};
|
|
197
|
-
|
|
198
|
-
Ok(SensorReading {
|
|
199
|
-
sensor_id: sensor.id.clone(),
|
|
200
|
-
value,
|
|
201
|
-
quality: 192, // Good
|
|
202
|
-
timestamp: chrono::Utc::now().timestamp_millis(),
|
|
203
|
-
})
|
|
204
|
-
}
|
|
205
|
-
}
|
|
206
|
-
```
|
|
207
|
-
|
|
208
|
-
## Go Implementation
|
|
209
|
-
|
|
210
|
-
```go
|
|
211
|
-
package modbus
|
|
212
|
-
|
|
213
|
-
import (
|
|
214
|
-
"encoding/binary"
|
|
215
|
-
"math"
|
|
216
|
-
"sync"
|
|
217
|
-
"time"
|
|
218
|
-
|
|
219
|
-
"github.com/simonvetter/modbus"
|
|
220
|
-
)
|
|
221
|
-
|
|
222
|
-
type Client struct {
|
|
223
|
-
client *modbus.ModbusClient
|
|
224
|
-
mu sync.Mutex
|
|
225
|
-
}
|
|
226
|
-
|
|
227
|
-
func NewClient(address string, slaveID uint8) (*Client, error) {
|
|
228
|
-
client, err := modbus.NewClient(&modbus.ClientConfiguration{
|
|
229
|
-
URL: fmt.Sprintf("tcp://%s", address),
|
|
230
|
-
Speed: 19200,
|
|
231
|
-
Timeout: 5 * time.Second,
|
|
232
|
-
})
|
|
233
|
-
if err != nil { return nil, err }
|
|
234
|
-
|
|
235
|
-
if err := client.Open(); err != nil { return nil, err }
|
|
236
|
-
client.SetUnitId(slaveID)
|
|
237
|
-
|
|
238
|
-
return &Client{client: client}, nil
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
func (c *Client) ReadHoldingRegisters(address, count uint16) ([]uint16, error) {
|
|
242
|
-
c.mu.Lock()
|
|
243
|
-
defer c.mu.Unlock()
|
|
244
|
-
return c.client.ReadRegisters(address, count, modbus.HOLDING_REGISTER)
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
func RegistersToFloat32(regs []uint16) float32 {
|
|
248
|
-
bytes := make([]byte, 4)
|
|
249
|
-
binary.BigEndian.PutUint16(bytes[0:2], regs[0])
|
|
250
|
-
binary.BigEndian.PutUint16(bytes[2:4], regs[1])
|
|
251
|
-
return math.Float32frombits(binary.BigEndian.Uint32(bytes))
|
|
252
|
-
}
|
|
253
|
-
```
|
|
254
|
-
|
|
255
|
-
## Python Implementation
|
|
256
|
-
|
|
257
|
-
```python
|
|
258
|
-
from pymodbus.client import AsyncModbusTcpClient
|
|
259
|
-
from dataclasses import dataclass
|
|
260
|
-
import struct
|
|
261
|
-
|
|
262
|
-
@dataclass
|
|
263
|
-
class SensorConfig:
|
|
264
|
-
id: str
|
|
265
|
-
address: int
|
|
266
|
-
data_type: str # 'uint16', 'int16', 'float32'
|
|
267
|
-
unit: str
|
|
268
|
-
|
|
269
|
-
class ModbusReader:
|
|
270
|
-
def __init__(self, host: str, port: int = 502, slave_id: int = 1):
|
|
271
|
-
self.host = host
|
|
272
|
-
self.port = port
|
|
273
|
-
self.slave_id = slave_id
|
|
274
|
-
|
|
275
|
-
async def connect(self):
|
|
276
|
-
self.client = AsyncModbusTcpClient(self.host, port=self.port)
|
|
277
|
-
await self.client.connect()
|
|
278
|
-
|
|
279
|
-
async def read_holding_registers(self, address: int, count: int):
|
|
280
|
-
result = await self.client.read_holding_registers(address, count, slave=self.slave_id)
|
|
281
|
-
return result.registers
|
|
282
|
-
|
|
283
|
-
async def read_sensor(self, config: SensorConfig) -> float:
|
|
284
|
-
count = 2 if 'float32' in config.data_type else 1
|
|
285
|
-
regs = await self.read_holding_registers(config.address, count)
|
|
286
|
-
|
|
287
|
-
if config.data_type == 'uint16':
|
|
288
|
-
return regs[0]
|
|
289
|
-
elif config.data_type == 'int16':
|
|
290
|
-
return struct.unpack('>h', struct.pack('>H', regs[0]))[0]
|
|
291
|
-
elif config.data_type == 'float32':
|
|
292
|
-
bytes_data = struct.pack('>HH', regs[0], regs[1])
|
|
293
|
-
return struct.unpack('>f', bytes_data)[0]
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
## PLC Address Maps
|
|
297
|
-
|
|
298
|
-
### Siemens S7-1200/1500
|
|
299
|
-
|
|
300
|
-
```yaml
|
|
301
|
-
holding_registers:
|
|
302
|
-
40001: DB1.DBD0 # Float, first double word in DB1
|
|
303
|
-
40003: DB1.DBD4 # Float, second double word
|
|
304
|
-
40005: MW100 # Word memory
|
|
305
|
-
|
|
306
|
-
coils:
|
|
307
|
-
00001: Q0.0 # Output bit 0.0
|
|
308
|
-
00002: Q0.1 # Output bit 0.1
|
|
309
|
-
```
|
|
310
|
-
|
|
311
|
-
### Allen-Bradley ControlLogix
|
|
312
|
-
|
|
313
|
-
```yaml
|
|
314
|
-
holding_registers:
|
|
315
|
-
40001: N7:0 # Integer file
|
|
316
|
-
40002: F8:0 # Float (uses 2 registers)
|
|
317
|
-
```
|
|
318
|
-
|
|
319
|
-
### Schneider Modicon
|
|
320
|
-
|
|
321
|
-
```yaml
|
|
322
|
-
holding_registers:
|
|
323
|
-
40001: %MW0 # Memory word 0
|
|
324
|
-
40003: %MF0 # Float (2 registers)
|
|
325
|
-
```
|
|
326
|
-
|
|
327
|
-
## Error Handling
|
|
328
|
-
|
|
329
|
-
```rust
|
|
330
|
-
pub fn modbus_error_description(code: u8) -> &'static str {
|
|
331
|
-
match code {
|
|
332
|
-
0x01 => "Illegal Function",
|
|
333
|
-
0x02 => "Illegal Data Address",
|
|
334
|
-
0x03 => "Illegal Data Value",
|
|
335
|
-
0x04 => "Slave Device Failure",
|
|
336
|
-
0x05 => "Acknowledge",
|
|
337
|
-
0x06 => "Slave Device Busy",
|
|
338
|
-
_ => "Unknown Error",
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
```
|
|
342
|
-
|
|
343
|
-
## Best Practices
|
|
344
|
-
|
|
345
|
-
### Batch Reads
|
|
346
|
-
|
|
347
|
-
```rust
|
|
348
|
-
// ✅ Single read for contiguous registers
|
|
349
|
-
client.read_holding_registers(40001, 10).await?;
|
|
350
|
-
|
|
351
|
-
// ❌ Multiple individual reads - slow!
|
|
352
|
-
for addr in 40001..40011 {
|
|
353
|
-
client.read_holding_registers(addr, 1).await?;
|
|
354
|
-
}
|
|
355
|
-
```
|
|
356
|
-
|
|
357
|
-
### Connection Reuse
|
|
358
|
-
|
|
359
|
-
```rust
|
|
360
|
-
// ✅ Reuse connection
|
|
361
|
-
let client = ModbusClient::connect(addr, slave_id).await?;
|
|
362
|
-
for _ in 0..100 {
|
|
363
|
-
client.read_holding_registers(addr, count).await?;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
// ❌ New connection per read
|
|
367
|
-
for _ in 0..100 {
|
|
368
|
-
let client = ModbusClient::connect(addr, slave_id).await?;
|
|
369
|
-
client.read_holding_registers(addr, count).await?;
|
|
370
|
-
}
|
|
371
|
-
```
|
|
372
|
-
|
|
373
|
-
### Polling Intervals
|
|
374
|
-
|
|
375
|
-
| Sensor Type | Recommended Interval |
|
|
376
|
-
|-------------|---------------------|
|
|
377
|
-
| Vibration | 10-50ms |
|
|
378
|
-
| Temperature/Pressure | 500ms-1s |
|
|
379
|
-
| Level/Flow totals | 5-10s |
|
|
380
|
-
|
|
381
|
-
## Quick Reference
|
|
382
|
-
|
|
383
|
-
| Task | Rust |
|
|
384
|
-
|------|------|
|
|
385
|
-
| Read holding | `ctx.read_holding_registers(addr, count).await` |
|
|
386
|
-
| Read input | `ctx.read_input_registers(addr, count).await` |
|
|
387
|
-
| Write single | `ctx.write_single_register(addr, value).await` |
|
|
388
|
-
| Write multiple | `ctx.write_multiple_registers(addr, &values).await` |
|
|
389
|
-
| Read coils | `ctx.read_coils(addr, count).await` |
|
|
390
|
-
|
|
391
|
-
## Quality Codes (OPC UA)
|
|
392
|
-
|
|
393
|
-
| Code | Meaning |
|
|
394
|
-
|------|---------|
|
|
395
|
-
| 192 (0xC0) | Good |
|
|
396
|
-
| 128 (0x80) | Uncertain |
|
|
397
|
-
| 0 (0x00) | Bad |
|
|
398
|
-
|
|
399
|
-
## Resources
|
|
400
|
-
|
|
401
|
-
- [Modbus Specification](https://modbus.org/specs.php)
|
|
402
|
-
- [tokio-modbus Docs](https://docs.rs/tokio-modbus)
|
|
403
|
-
- [pymodbus Documentation](https://pymodbus.readthedocs.io/)
|
|
404
|
-
|
|
405
|
-
## Related Skills
|
|
406
|
-
|
|
407
|
-
- `mqtt-rumqttc`: Data forwarding to MQTT
|
|
408
|
-
- `tokio-async`: Async polling patterns
|
|
409
|
-
- `timescaledb`: Industrial data storage
|
|
410
|
-
- `rust-systems`: Full Rust integration
|