You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: packages/binding-modbus/README.md
+96-66Lines changed: 96 additions & 66 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -3,62 +3,98 @@
3
3
## Overview
4
4
5
5
W3C Web of Things (WoT) Protocol Binding for [Modbus](https://en.wikipedia.org/wiki/Modbus) TCP [RFC](https://tools.ietf.org/html/draft-dube-modbus-applproto-00).
6
-
This package uses [modbus-serial](https://www.npmjs.com/package/modbus-serial) as a lowlevel client for Modbus TCP.
6
+
This package uses [modbus-serial](https://www.npmjs.com/package/modbus-serial) as a low-level client for Modbus TCP.
7
7
W3C WoT Binding Template for Modbus can be found [here](https://w3c.github.io/wot-binding-templates/bindings/protocols/modbus/index.html).
8
8
9
9
Current Maintainer(s): [@relu91](https://github.com/relu91)[@fillobotto](https://github.com/fillobotto)
10
10
11
-
## Protocol specifier
11
+
## Client Example
12
+
13
+
You can use a code like the following to use the binding. This specific code is interacting with one of the Eclipse Thingweb Test Things at <https://github.com/eclipse-thingweb/test-things/tree/main/things/elevator>.
The protocol prefix handled by this binding is `modbus+tcp://`.
14
48
15
-
## New Form Fields for the Modbus Binding
49
+
###New Form Fields for the Modbus Binding
16
50
17
51
**Note**: for further details please refer to the [documentation](https://github.com/eclipse-thingweb/node-wot/blob/master/packages/binding-modbus/src/modbus.ts).
18
52
19
-
### modbus:function
53
+
#### modv:function
54
+
55
+
Specifies which Modbus function should be issued in the requested command. The list of the available functions is the following:
56
+
57
+
| Function ID | Label |
58
+
| ----------- | :---------------------------: |
59
+
| 1 | readCoil |
60
+
| 2 | readDiscreteInput |
61
+
| 3 | readHoldingRegisters |
62
+
| 4 | readInputRegisters |
63
+
| 5 | writeSingleCoil |
64
+
| 6 | writeSingleHoldingRegister |
65
+
| 15 | writeMultipleCoils |
66
+
| 16 | writeMultipleHoldingRegisters |
20
67
21
-
Specifies which modbus function should be issue in the requested command. The list of the available function is the following:
22
-
| Function ID | Label
23
-
| ------------- |:--------------------:|
24
-
| 1 | readCoil |
25
-
| 2 | readDiscreteInput |
26
-
| 3 | readHoldingRegisters |
27
-
| 4 | readInputRegisters |
28
-
| 5 | writeSingleCoil |
29
-
| 6 | writeSingleHoldingRegister |
30
-
| 15 | writeMultipleCoils |
31
-
| 16 | writeMultipleHoldingRegisters |
32
-
The list is build from [wikipedia definition](https://en.wikipedia.org/wiki/Modbus) of modbus function names, it can be different in proprietary implementations of modbus protocol.
33
-
Function IDs or labels can be either used as values of `modbus:function` property.
68
+
This list is from [the Modbus Binding Template](https://w3c.github.io/wot-binding-templates/bindings/protocols/modbus/#function).
69
+
Function IDs are used on the wire but the labels should be used in a TD as the values of `modv:function` property.
34
70
35
-
###modbus:entity
71
+
#### modv:entity
36
72
37
-
A more user-friendly property to specify `modbus:function`. It can be filled with the following keywords: `Coil`, `DiscreteInput`, `InputRegister`, `HoldingRegister`. The client will then determine the right function code to be applied in the modbus request. Futhermore, it can be used in multi-operation forms whereas modbus:function cannot. See the [example]
73
+
The Modbus resource the `modv:function` acts on. It can be filled with the following keywords: `Coil`, `DiscreteInput`, `InputRegister`, `HoldingRegister`. The client will then determine the right function code to be applied in the Modbus request. Furthermore, it can be used in multi-operation forms where `modv:function` cannot be used but the correct function is filled based on [the default assumptions](https://w3c.github.io/wot-binding-templates/bindings/protocols/modbus/#default-mappings). See the [example].
38
74
39
-
**Notice** that when used in conjunction with `modbus:function`, the value of `modbus:function` property is ignored.
75
+
**Note** that when used in conjunction with `modv:function`, the value of `modv:entity` property is ignored.
40
76
41
-
###modbus:unitID
77
+
#### modv:unitID
42
78
43
-
The physical bus address of the unit targeted by the modbus request.
79
+
The physical bus address of the unit targeted by the Modbus request.
44
80
45
-
###modbus:address
81
+
#### modv:address
46
82
47
83
This property defines the starting address of registers or coils that are meant to be written.
48
84
49
-
###modbus:quantity
85
+
#### modv:quantity
50
86
51
-
This property defines the total amount of registers or coils that should be written, beginning with the register specified with the property 'modbus:address'.
87
+
This property defines the total amount of registers or coils that should be written, beginning with the register specified with the property `modv:address`.
52
88
53
-
###modbus:pollingTime
89
+
#### modv:pollingTime
54
90
55
-
The polling time used for subscriptions. The client will issue a reading command every modbus:pollingTime milliseconds. Note that the reading request timeout can be still controlled using modbus:timeout property.
91
+
The polling time used for subscriptions. The client will issue a reading command every `modv:pollingTime` milliseconds. Note that the reading request timeout can be still controlled using `modv:timeout` property.
56
92
57
-
###modbus:timeout
93
+
#### modv:timeout
58
94
59
-
Timeout in milliseconds of the modbus request. Default to 1000 milliseconds
95
+
Timeout in milliseconds of the Modbus request. Default to 1000 milliseconds
60
96
61
-
## URL format
97
+
###URL format
62
98
63
99
The URL is used to transport all addressing information necessary to describe the MODBUS connection and register addresses. It has the following structure:
-`<host>` is the host name or IP address of the MODBUS slave
107
+
-`<host>` is the hostname or IP address of the MODBUS slave
72
108
-`<port>` is the optional TCP port number used to access the MODBUS slave. Default is 502
73
-
-`<unitid>` is the MODBUS unit id of the MODBUS slave; same as [modbus:unitID](#modbus:unitID)
74
-
-`<address>` is the starting address register number; see [modbus:address](#modbus:address)
75
-
-`<quantity>` is the optional number of registers to access. Default is 1; see [modbus:quantity](#modbus:quantity)
109
+
-`<unitid>` is the MODBUS unit id of the MODBUS slave; same as [modv:unitID](#modv:unitID)
110
+
-`<address>` is the starting address register number; see [modv:address](#modv:address)
111
+
-`<quantity>` is the optional number of registers to access. Default is 1; see [modv:quantity](#modv:quantity)
76
112
77
113
When specified URL values override the corresponding `form` parameter.
78
114
79
-
## DataSchema
115
+
###DataSchema
80
116
81
-
The MODBUS binding uses and provides plain binary data for reading and writing. Therefore in most cases it will be associated with the content type `application/octet-stream`. Please refer to the description of this codec on how to decode and encode plain register values to/from JavaScript objects (See `OctetstreamCodec`). **Note**`array` and `object` schema are not supported.
117
+
The MODBUS binding uses and provides plain binary data for reading and writing. Therefore in most cases, it will be associated with the content type `application/octet-stream`. Please refer to the description of this codec on how to decode and encode plain register values to/from JavaScript objects (See `OctetstreamCodec`). **Note**`array` and `object` schema are not supported.
82
118
83
119
Along with content type `application/octet-stream`, this protocol binding accepts also an optional `byteSeq` parameter. `byteSeq` specifies the endian-ness of the raw byte data being read/written by the MODBUS binding. It follows the notation `application/octet-stream;byteSeq=value`, where its value can be one of the following:
84
120
@@ -87,7 +123,7 @@ Along with content type `application/octet-stream`, this protocol binding accept
87
123
-`BIG_ENDIAN_BYTE_SWAP`
88
124
-`LITTLE_ENDIAN_BYTE_SWAP`
89
125
90
-
**Note**: the list may be extended in the future.
126
+
**Note**: the list above may be extended in the future.
91
127
92
128
In particular, the decimal numbers `9545` and `22880` will be encoded as follows:
93
129
@@ -96,45 +132,45 @@ In particular, the decimal numbers `9545` and `22880` will be encoded as follows
96
132
-`BIG_ENDIAN_BYTE_SWAP`: `49 25 60 59`
97
133
-`LITTLE_ENDIAN_BYTE_SWAP`: `59 60 25 49`
98
134
99
-
For register properties the payload is just the plain sequence of bytes read from or written to the registers. For coils and discrete inputs, the payload is a sequence of bytes, each corresponding to a single coil or discrete input. Each byte contains the value `0` or `1`. So the encoder / decoder should work on this series of bytes and does not have to take care about handling the individual bits. Mapping each coil or discrete input to a single property of type `boolean` works just fine!
135
+
For register resources, the payload is just the plain sequence of bytes read from or written to the registers. For coils and discrete inputs, the payload is a sequence of bytes, each corresponding to a single coil or discrete input. Each byte contains the value `0` or `1`. So the encoder and decoder should work on this series of bytes and does not have to take care about handling the individual bits. Mapping each coil or discrete input to a single property of type `boolean` works just fine.
100
136
101
137
Another parameter that can be used in conjunction with `application/octet-stream` is `length`. This parameter specifies the length of the payload in bytes. This is useful to indicate the actual length of the payload when reading or writing a sequence of registers. For example, when reading a property using `readHoldingRegisters`, the payload length can be used to specify the number of registers to be read. Notice that the payload length must always
102
-
be equal to the number of registers multiplied by the registers size in bytes.
138
+
be equal to the number of registers multiplied by the size of the register in bytes.
103
139
104
-
## Security
140
+
###Security
105
141
106
142
The protocol does not support security.
107
143
108
-
# Implementation notes
144
+
##Implementation notes
109
145
110
146
This implementation handles multiple requests to the same slave by serializing and combining them if possible. In the following, the terms **request** and **transaction** are used as follows to describe this:
111
147
112
148
- A **request** is a read or write request to a resource as issued by a user of the node-wot API.
113
-
- A **transaction** is a MODBUS operation and may cover the data of multiple **requests**.
149
+
- A **transaction** is a Modbus operation and may cover the data of multiple **requests**.
114
150
115
-
## Combination
151
+
###Combination
116
152
117
-
When two **requests** of the same type are issued and these requests cover neighboured registers, then they are combined into a single **transaction** reading or writing the combined register range. Note that this algorithm is currently rather simple: New **requests** are just checked if they can be prepended or appended to an existing **transaction**. If not, a new **transaction** is created. When a **transaction** completes, all **requests** contained in this **transaction** are completed.
153
+
When two **requests** of the same type are issued and these requests cover neighbored registers, then they are combined into a single **transaction** reading or writing the combined register range. Note that this algorithm is currently rather simple: New **requests** are just checked if they can be prepended or appended to an existing **transaction**. If not, a new **transaction** is created. When a **transaction** completes, all **requests** contained in this **transaction** are completed.
118
154
119
-
## Serialization
155
+
###Serialization
120
156
121
157
Multiple **transactions** to the same slave are serialized. This means that a new MODBUS **transaction** is only started when the previous **transaction** was finished. **Transactions** are held in a queue and executed in a first-come-first-serve manner.
122
158
123
-
## Combination using the node-wot API
159
+
###Combination using the node-wot API
124
160
125
-
To help the MODBUS binding to perform combination a user of the API should create several requests for neighboured registers and resolve them all together in a single call to `Promise.all()`, e.g. as follows:
161
+
To help the MODBUS binding to perform combination a user of the API should create several requests for neighbor registers and resolve them all together in a single call to `Promise.all()`, e.g. as follows:
126
162
127
163
```javascript
128
164
console.info("Creating promise vl1n");
129
-
let vl1n =pac3200.properties["Voltage/L1N"].read();
165
+
let vl1n =pac3200Thing.readProperty("Voltage/L1N");
130
166
console.info("Creating promise vl2n");
131
-
let vl2n =pac3200.properties["Voltage/L2N"].read();
167
+
let vl2n =pac3200Thing.readProperty("Voltage/L2N");
132
168
console.info("Creating promise vl3n");
133
-
let vl3n =pac3200.properties["Voltage/L3N"].read();
169
+
let vl3n =pac3200Thing.readProperty("Voltage/L3N");
0 commit comments