node-red-contrib-ax25 1.0.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/.eslintignore +5 -0
- package/.prettierignore +7 -0
- package/ARCHITECTURE.md +174 -0
- package/CONTEXT.md +90 -0
- package/MESSAGES.md +314 -0
- package/README.md +317 -0
- package/examples/beacons.json +130 -0
- package/examples/beacons.png +0 -0
- package/examples/bye_subflow.json +107 -0
- package/examples/bye_subflow.png +0 -0
- package/examples/delete_all_my_messages.json +491 -0
- package/examples/delete_all_my_messages.png +0 -0
- package/examples/get_message_list_subflow.json +129 -0
- package/examples/get_message_list_subflow.png +0 -0
- package/examples/send_message_subflow.json +367 -0
- package/examples/send_message_subflow.png +0 -0
- package/examples/send_test_message.json +643 -0
- package/examples/send_test_message.png +0 -0
- package/jsconfig.json +37 -0
- package/lib/agwpe-client-transport.js +99 -0
- package/lib/agwpe-frame-builder.js +176 -0
- package/lib/agwpe-frame-pretty.js +107 -0
- package/lib/ax25-codec.js +382 -0
- package/lib/frame-router.js +95 -0
- package/lib/frame-segmentation.js +53 -0
- package/lib/message-utils.js +59 -0
- package/lib/runtime-store.js +94 -0
- package/lib/session-registry.js +142 -0
- package/local/buffer_compare.json +135 -0
- package/local/debug-d-frame.js +84 -0
- package/local/raw-out-test.json +128 -0
- package/nodes/agwpe-client.html +70 -0
- package/nodes/agwpe-client.js +771 -0
- package/nodes/agwpe-client.js.bak +871 -0
- package/nodes/connect.html +128 -0
- package/nodes/connect.js +450 -0
- package/nodes/decode.html +83 -0
- package/nodes/decode.js +56 -0
- package/nodes/disconnect.html +55 -0
- package/nodes/disconnect.js +47 -0
- package/nodes/encode.html +117 -0
- package/nodes/encode.js +164 -0
- package/nodes/monitor-in.html +48 -0
- package/nodes/monitor-in.js +42 -0
- package/nodes/raw-in.html +50 -0
- package/nodes/raw-in.js +72 -0
- package/nodes/raw-out.html +76 -0
- package/nodes/raw-out.js +144 -0
- package/nodes/send.html +91 -0
- package/nodes/send.js +373 -0
- package/nodes/ui-in.html +64 -0
- package/nodes/ui-in.js +68 -0
- package/nodes/ui-out.html +80 -0
- package/nodes/ui-out.js +133 -0
- package/package.json +47 -0
package/README.md
ADDED
|
@@ -0,0 +1,317 @@
|
|
|
1
|
+
# node-red-contrib-ax25
|
|
2
|
+
|
|
3
|
+
Node-RED nodes for AX.25 packet radio connectivity via an AGWPE (AGW Packet Engine) server. Configure a connection to a local or remote AGWPE instance and use the provided nodes to establish connected sessions, exchange unconnected UI frames, monitor traffic, and encode/decode raw AX.25 frames — all from Node-RED flows without writing socket code.
|
|
4
|
+
|
|
5
|
+
## Use cases
|
|
6
|
+
|
|
7
|
+
### Connected mode — BBS and remote stations
|
|
8
|
+
|
|
9
|
+
Use the `connect` and `send` nodes to establish an AX.25 connected session to a remote station such as a bulletin board system (BBS). The `connect` node sends the AX.25 connection request and emits lifecycle events and received data as the session progresses. Chain `send` nodes after it to exchange data: each `send` takes over the data output for the session so it receives the response to its own transmission. Use `waitFor` patterns to synchronize with BBS prompts without writing polling loops.
|
|
10
|
+
|
|
11
|
+
```
|
|
12
|
+
[inject connect] → [connect] → output 1: lifecycle events (connected / disconnected / timeout)
|
|
13
|
+
→ output 2: received data
|
|
14
|
+
↓
|
|
15
|
+
[inject "send payload"] → [send] → output 2: response to this sent payload
|
|
16
|
+
↓
|
|
17
|
+
[inject] → [disconnect] → output 1: disconnecting event
|
|
18
|
+
(disconnected fires on [connect] output 1 when TNC confirms)
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
### APRS — UI frame monitoring and transmission
|
|
22
|
+
|
|
23
|
+
APRS uses AX.25 UI (unconnected) frames. Enable raw mode on the `agwpe-client` config node and use `ui-in` to receive decoded APRS packets (source, destination, via path, payload) and `ui-out` to transmit UI frames.
|
|
24
|
+
|
|
25
|
+
Use `ui-in` and `ui-out` to quickly prototype/develop APRS services or gateways.
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npm install node-red-contrib-ax25
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
Restart Node-RED. The nodes appear in the **agwpe** category in the palette.
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Nodes
|
|
40
|
+
|
|
41
|
+
### agwpe-client (config node)
|
|
42
|
+
|
|
43
|
+
Configure the AGWPE server connection in the Node-RED editor. The connection is established automatically when the flow deploys.
|
|
44
|
+
|
|
45
|
+
Any software that exposes the AGWPE TCP interface works as a backend, including:
|
|
46
|
+
|
|
47
|
+
- **[Direwolf](https://github.com/wb2osz/direwolf)** — software TNC for sound cards; widely used for APRS and packet radio on Linux, macOS, and Windows.
|
|
48
|
+
- **[Soundmodem](https://uz7.ho.ua/packetradio.htm)** — UZ7HO's sound card TNC with AGWPE server support.
|
|
49
|
+
- **[esp-tnc](https://github.com/n7get/esp-tnc)** — AX.25 router and BBS for ESP microcontrollers with AGWPE TCP server support.
|
|
50
|
+
- **[go-ax25](https://github.com/n7get/go-ax25)** — Go library for AX.25.
|
|
51
|
+
|
|
52
|
+
**Editor fields:**
|
|
53
|
+
|
|
54
|
+
| Field | Default | Description |
|
|
55
|
+
|-------|---------|-------------|
|
|
56
|
+
| Host | `127.0.0.1` | AGWPE server hostname or IP |
|
|
57
|
+
| Port | `8000` | AGWPE server TCP port |
|
|
58
|
+
| Callsigns | — | Comma-separated callsigns to register with AGWPE on connect |
|
|
59
|
+
| Username / Password | — | Optional AGWPE credentials |
|
|
60
|
+
| Monitor Mode | off | Enable monitor frame delivery to `monitor-in` nodes |
|
|
61
|
+
| Raw Mode | off | Enable raw frame delivery to `raw-in` nodes and `ui-in` / `ui-out` |
|
|
62
|
+
| Auto-Reconnect | on | Automatically reconnect after a dropped connection |
|
|
63
|
+
| Reconnect Delay | `5000` ms | Delay before each reconnect attempt |
|
|
64
|
+
|
|
65
|
+
The `connect`, `ui-out`, `ui-in`, `monitor-in`, `raw-out`, and `raw-in` nodes each select which `agwpe-client` to bind to using a **Client** dropdown in their editor. The `send` node does not need a client selection — it gets the `agwpe-client` from the `sessionId`.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
### connect
|
|
70
|
+
|
|
71
|
+
Establishes an AX.25 connected session to a remote station.
|
|
72
|
+
|
|
73
|
+
**Input:** any message with `msg.destination` set (or configured in the node editor).
|
|
74
|
+
|
|
75
|
+
```json
|
|
76
|
+
{ "destination": "N0CALL-1" }
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
`source` defaults to the first callsign registered on the `agwpe-client`. `destination` can also be set in the node editor and overridden per-message. `via` accepts a comma-separated string, array of strings, or array of `{ callsign, hasBeenRepeated }` objects.
|
|
80
|
+
|
|
81
|
+
```json
|
|
82
|
+
{ "source": "N0CALL", "destination": "N0CALL-1", "via": "RELAY" }
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
**Output 1 — lifecycle events** (`msg.event`):
|
|
86
|
+
|
|
87
|
+
| Event | Meaning |
|
|
88
|
+
|-------|---------|
|
|
89
|
+
| `connecting` | Connect request sent |
|
|
90
|
+
| `connected` | Remote station accepted |
|
|
91
|
+
| `disconnecting` | Disconnect in progress |
|
|
92
|
+
| `disconnected` | Session closed |
|
|
93
|
+
| `timeout` | No activity (sent or received) within timeout period |
|
|
94
|
+
| `failed` | Transport or session error |
|
|
95
|
+
|
|
96
|
+
**Output 2 — received data:**
|
|
97
|
+
|
|
98
|
+
Controlled by the **Mode** editor field (default: `line`):
|
|
99
|
+
|
|
100
|
+
- **line mode** — incoming bytes are buffered and split on CR or CR+LF. Each complete line is emitted as `msg.payload` (string). If `waitFor` is set (a regex string), lines accumulate until one matches; `msg.payload` is then an array of the preceding lines and `msg.match` is the matching line. On timeout, `msg.event: "timeout"` is emitted on output 1 with the current buffer contents.
|
|
101
|
+
- **binary mode** — each received frame is emitted immediately with `msg.payload` as a Buffer.
|
|
102
|
+
|
|
103
|
+
`mode`, `waitFor`, `timeout`, `source`, `destination`, and `via` can all be set in the node editor and overridden per-message with the corresponding `msg` properties.
|
|
104
|
+
|
|
105
|
+
The `sessionId` assigned to the session is included on every output message and must be passed to subsequent `send` commands.
|
|
106
|
+
|
|
107
|
+
---
|
|
108
|
+
|
|
109
|
+
### send
|
|
110
|
+
|
|
111
|
+
Sends data on an established session. When a `send` node processes an input message, it takes over the data output (output 2) for that session so it receives the response to its own transmission.
|
|
112
|
+
|
|
113
|
+
The `send` node gets the correct `agwpe-client` at runtime from the `sessionId`, so it works with any session from any client automatically.
|
|
114
|
+
|
|
115
|
+
**Input:**
|
|
116
|
+
|
|
117
|
+
```json
|
|
118
|
+
{ "sessionId": "sess-abc", "payload": "HELLO\r" }
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
`payload` may be a string or a Buffer. Arrays of strings/Buffers are also accepted; each item is sent as a separate frame. Payloads longer than 255 bytes are segmented automatically.
|
|
122
|
+
|
|
123
|
+
**Output 1** — lifecycle events (same structure as `connect` output 1).
|
|
124
|
+
**Output 2** — received data (same line/binary behaviour as `connect`; `waitFor` and `timeout` can be set in the node editor or per-message).
|
|
125
|
+
|
|
126
|
+
---
|
|
127
|
+
|
|
128
|
+
### disconnect
|
|
129
|
+
|
|
130
|
+
Initiates a graceful disconnect for an established session.
|
|
131
|
+
|
|
132
|
+
**Input:** any message with `msg.sessionId` set.
|
|
133
|
+
|
|
134
|
+
```json
|
|
135
|
+
{ "sessionId": "sess-abc" }
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
**Output 1** — emits `disconnecting` immediately on success, or `SESSION_NOT_FOUND` on error. The `disconnected` event fires on the originating `connect` node's output 1 once the TNC confirms with a `d` frame.
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
### ui-out
|
|
143
|
+
|
|
144
|
+
Encodes and transmits an AX.25 UI frame via the AGWPE raw (K-frame) transport. **Raw mode must be enabled** on the `agwpe-client`.
|
|
145
|
+
|
|
146
|
+
Set `source`, `destination`, `via`, and `payload` in the node editor. Any triggering message causes the frame to be sent; individual fields can be overridden per-message:
|
|
147
|
+
|
|
148
|
+
```json
|
|
149
|
+
{ "payload": "status text" }
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
`via` accepts the same formats as `connect`. `msg.agwpePort` overrides the AGWPE port byte (default `0`).
|
|
153
|
+
|
|
154
|
+
Output: a single message with `event: "ui-sent"` on success, or an error envelope on failure.
|
|
155
|
+
|
|
156
|
+
---
|
|
157
|
+
|
|
158
|
+
### ui-in
|
|
159
|
+
|
|
160
|
+
Receives AGWPE raw (K-frame) traffic, decodes the embedded AX.25 UI frames, and emits one message per frame. **Raw mode must be enabled** on the `agwpe-client`.
|
|
161
|
+
|
|
162
|
+
Output message fields: `source`, `destination`, `via` (array of callsigns), `payload`.
|
|
163
|
+
|
|
164
|
+
The **Payload Output** editor option selects `string` (UTF-8, default) or `buffer` (raw bytes).
|
|
165
|
+
|
|
166
|
+
Non-UI frames are silently discarded.
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
### monitor-in
|
|
171
|
+
|
|
172
|
+
Receives all frames seen by the AGWPE server in monitor mode. **Monitor mode must be enabled** on the `agwpe-client`.
|
|
173
|
+
|
|
174
|
+
Output: one message per frame with `source`, `destination`, `payload`, and AGWPE frame metadata.
|
|
175
|
+
|
|
176
|
+
---
|
|
177
|
+
|
|
178
|
+
### raw-out
|
|
179
|
+
|
|
180
|
+
Transmits a raw AX.25 frame inside an AGWPE K-frame. **Raw mode must be enabled.**
|
|
181
|
+
|
|
182
|
+
`msg.payload` accepts:
|
|
183
|
+
|
|
184
|
+
- `Buffer`
|
|
185
|
+
- `Uint8Array`
|
|
186
|
+
- byte array (numbers 0–255)
|
|
187
|
+
- hex string (`"82 a0 a8"` or `"82a0a8"`)
|
|
188
|
+
|
|
189
|
+
`msg.agwpePort` (or the editor **AGWPE Port** field, default `0`) sets the leading port byte of the K-frame.
|
|
190
|
+
|
|
191
|
+
---
|
|
192
|
+
|
|
193
|
+
### raw-in
|
|
194
|
+
|
|
195
|
+
Receives raw AGWPE K-frames. **Raw mode must be enabled.**
|
|
196
|
+
|
|
197
|
+
Output: `msg.payload` is a Buffer of the raw AX.25 wire bytes (leading AGWPE port byte stripped and exposed separately as `msg.agwpePort`).
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
### decode
|
|
202
|
+
|
|
203
|
+
Decodes a raw AX.25 frame Buffer into its constituent fields.
|
|
204
|
+
|
|
205
|
+
**Input:** `msg.payload` must be a Buffer containing AX.25 wire bytes (e.g. from `raw-in`).
|
|
206
|
+
|
|
207
|
+
**Output:**
|
|
208
|
+
|
|
209
|
+
```json
|
|
210
|
+
{
|
|
211
|
+
"source": "N0CALL",
|
|
212
|
+
"destination": "CQ",
|
|
213
|
+
"via": [{ "callsign": "WIDE1-1", "hasBeenRepeated": false }],
|
|
214
|
+
"control": 3,
|
|
215
|
+
"pid": 240,
|
|
216
|
+
"payload": "decoded payload here"
|
|
217
|
+
}
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
The **Payload Output** editor option selects `string` (UTF-8, default) or `buffer`.
|
|
221
|
+
|
|
222
|
+
---
|
|
223
|
+
|
|
224
|
+
### encode
|
|
225
|
+
|
|
226
|
+
Encodes structured fields into a raw AX.25 frame Buffer. Editor defaults are pre-set for a UI frame (control `0x03`, PID `0xF0`). All fields can be overridden per-message.
|
|
227
|
+
|
|
228
|
+
**Input fields** (message overrides editor defaults):
|
|
229
|
+
|
|
230
|
+
| Field | Example | Notes |
|
|
231
|
+
|-------|---------|-------|
|
|
232
|
+
| `source` | `"N0CALL"` | |
|
|
233
|
+
| `destination` | `"CQ"` | |
|
|
234
|
+
| `via` | `"WIDE1-1,WIDE2-1"` | string, array of strings, or array of `{callsign, hasBeenRepeated}` |
|
|
235
|
+
| `control` | `3` | byte value, or use `frameType` (`"U"`, `"I"`, `"S"`) |
|
|
236
|
+
| `pid` | `240` | byte value |
|
|
237
|
+
| `payload` | `"text"` | string or Buffer |
|
|
238
|
+
|
|
239
|
+
**Output:** `msg.payload` is the encoded AX.25 frame as a Buffer, ready to pass to `raw-out`.
|
|
240
|
+
|
|
241
|
+
---
|
|
242
|
+
|
|
243
|
+
## Examples
|
|
244
|
+
|
|
245
|
+
Ready-to-import flows are provided in the [`examples/`](examples/) directory. Import any `.json` file via **Menu → Import** in the Node-RED editor.
|
|
246
|
+
|
|
247
|
+
---
|
|
248
|
+
|
|
249
|
+
### Beacons
|
|
250
|
+
|
|
251
|
+
**File:** [`examples/beacons.json`](examples/beacons.json)
|
|
252
|
+
|
|
253
|
+

|
|
254
|
+
|
|
255
|
+
Receives and transmits AX.25 UI frames using the `ui-in` and `ui-out` nodes. Demonstrates APRS-style beacon monitoring and periodic transmission.
|
|
256
|
+
|
|
257
|
+
---
|
|
258
|
+
|
|
259
|
+
### Send message test
|
|
260
|
+
|
|
261
|
+
**File:** [`examples/send_test_message.json`](examples/send_test_message.json)
|
|
262
|
+
|
|
263
|
+

|
|
264
|
+
|
|
265
|
+
A complete flow that connects to a packet BBS, composes and sends a test message using the **Send message** subflow, and disconnects via the **Bye** subflow. Demonstrates end-to-end message delivery from connection through graceful teardown.
|
|
266
|
+
|
|
267
|
+
---
|
|
268
|
+
|
|
269
|
+
### Send message subflow
|
|
270
|
+
|
|
271
|
+
**File:** [`examples/send_message_subflow.json`](examples/send_message_subflow.json)
|
|
272
|
+
|
|
273
|
+

|
|
274
|
+
|
|
275
|
+
A reusable subflow that composes and sends a message to a packet BBS: sets the addressee, subject, and body via a sequence of `send` nodes, each waiting for the BBS prompt before advancing.
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
### Get message list subflow
|
|
280
|
+
|
|
281
|
+
**File:** [`examples/get_message_list_subflow.json`](examples/get_message_list_subflow.json)
|
|
282
|
+
|
|
283
|
+

|
|
284
|
+
|
|
285
|
+
A reusable subflow that retrieves the message list from a packet BBS using the `send` / `waitFor` pattern and returns a parsed list.
|
|
286
|
+
|
|
287
|
+
---
|
|
288
|
+
|
|
289
|
+
### Delete all my messages
|
|
290
|
+
|
|
291
|
+
**File:** [`examples/delete_all_my_messages.json`](examples/delete_all_my_messages.json)
|
|
292
|
+
|
|
293
|
+

|
|
294
|
+
|
|
295
|
+
A full flow that connects to a packet BBS, retrieves the message list using the **Get message list** subflow, deletes every message addressed to the registered callsign, and disconnects cleanly. Demonstrates composing subflows into a complete automated task.
|
|
296
|
+
|
|
297
|
+
---
|
|
298
|
+
|
|
299
|
+
### Bye subflow
|
|
300
|
+
|
|
301
|
+
**File:** [`examples/bye_subflow.json`](examples/bye_subflow.json)
|
|
302
|
+
|
|
303
|
+

|
|
304
|
+
|
|
305
|
+
A reusable subflow that sends a `BYE` command and waits for the BBS to close the session gracefully. Intended to be composed into larger BBS flows.
|
|
306
|
+
|
|
307
|
+
---
|
|
308
|
+
|
|
309
|
+
## Testing
|
|
310
|
+
|
|
311
|
+
```bash
|
|
312
|
+
npm test
|
|
313
|
+
```
|
|
314
|
+
## TODO
|
|
315
|
+
|
|
316
|
+
Implement `listen` and `accept` nodes for creating AX.25 servers.
|
|
317
|
+
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"id": "65a0d887c03a3e96",
|
|
4
|
+
"type": "tab",
|
|
5
|
+
"label": "Beacons",
|
|
6
|
+
"disabled": false,
|
|
7
|
+
"info": "",
|
|
8
|
+
"env": []
|
|
9
|
+
},
|
|
10
|
+
{
|
|
11
|
+
"id": "a4494b4c19e5a930",
|
|
12
|
+
"type": "ui-in",
|
|
13
|
+
"z": "65a0d887c03a3e96",
|
|
14
|
+
"client": "9563d0689b7ce1af",
|
|
15
|
+
"name": "",
|
|
16
|
+
"payloadOutput": "string",
|
|
17
|
+
"x": 164,
|
|
18
|
+
"y": 100,
|
|
19
|
+
"wires": [
|
|
20
|
+
[
|
|
21
|
+
"799c276c66fa1dce"
|
|
22
|
+
]
|
|
23
|
+
]
|
|
24
|
+
},
|
|
25
|
+
{
|
|
26
|
+
"id": "24e57122cb89257d",
|
|
27
|
+
"type": "debug",
|
|
28
|
+
"z": "65a0d887c03a3e96",
|
|
29
|
+
"name": "debug 1",
|
|
30
|
+
"active": true,
|
|
31
|
+
"tosidebar": true,
|
|
32
|
+
"console": true,
|
|
33
|
+
"tostatus": false,
|
|
34
|
+
"complete": "true",
|
|
35
|
+
"targetType": "full",
|
|
36
|
+
"statusVal": "",
|
|
37
|
+
"statusType": "auto",
|
|
38
|
+
"x": 564,
|
|
39
|
+
"y": 100,
|
|
40
|
+
"wires": []
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"id": "799c276c66fa1dce",
|
|
44
|
+
"type": "function",
|
|
45
|
+
"z": "65a0d887c03a3e96",
|
|
46
|
+
"name": "function 2",
|
|
47
|
+
"func": "\nconst vias = msg.via.map( v => v.callsign + (v.hasBeenRepeated ? '*' : '') ).join(' ');\n\nreturn {\n source: msg.source,\n destination: msg.destination,\n vias,\n payload: msg.payload,\n};",
|
|
48
|
+
"outputs": 1,
|
|
49
|
+
"timeout": 0,
|
|
50
|
+
"noerr": 0,
|
|
51
|
+
"initialize": "",
|
|
52
|
+
"finalize": "",
|
|
53
|
+
"libs": [],
|
|
54
|
+
"x": 354,
|
|
55
|
+
"y": 100,
|
|
56
|
+
"wires": [
|
|
57
|
+
[
|
|
58
|
+
"24e57122cb89257d"
|
|
59
|
+
]
|
|
60
|
+
]
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
"id": "69164145ed38640a",
|
|
64
|
+
"type": "inject",
|
|
65
|
+
"z": "65a0d887c03a3e96",
|
|
66
|
+
"name": "",
|
|
67
|
+
"props": [],
|
|
68
|
+
"repeat": "",
|
|
69
|
+
"crontab": "",
|
|
70
|
+
"once": false,
|
|
71
|
+
"onceDelay": 0.1,
|
|
72
|
+
"topic": "",
|
|
73
|
+
"x": 190,
|
|
74
|
+
"y": 180,
|
|
75
|
+
"wires": [
|
|
76
|
+
[
|
|
77
|
+
"3207efd50fdb02f8"
|
|
78
|
+
]
|
|
79
|
+
]
|
|
80
|
+
},
|
|
81
|
+
{
|
|
82
|
+
"id": "3207efd50fdb02f8",
|
|
83
|
+
"type": "ui-out",
|
|
84
|
+
"z": "65a0d887c03a3e96",
|
|
85
|
+
"client": "9563d0689b7ce1af",
|
|
86
|
+
"name": "",
|
|
87
|
+
"source": "N0CALL-7",
|
|
88
|
+
"destination": "APX100",
|
|
89
|
+
"via": "WIDE1-1,WIDE2-1",
|
|
90
|
+
"payload": "!3612.97N/11517.07W-node-red-contrib-ax25 test",
|
|
91
|
+
"x": 350,
|
|
92
|
+
"y": 180,
|
|
93
|
+
"wires": [
|
|
94
|
+
[
|
|
95
|
+
"de2571a8cf9037f8"
|
|
96
|
+
]
|
|
97
|
+
]
|
|
98
|
+
},
|
|
99
|
+
{
|
|
100
|
+
"id": "de2571a8cf9037f8",
|
|
101
|
+
"type": "debug",
|
|
102
|
+
"z": "65a0d887c03a3e96",
|
|
103
|
+
"name": "debug 7",
|
|
104
|
+
"active": true,
|
|
105
|
+
"tosidebar": true,
|
|
106
|
+
"console": true,
|
|
107
|
+
"tostatus": false,
|
|
108
|
+
"complete": "true",
|
|
109
|
+
"targetType": "full",
|
|
110
|
+
"statusVal": "",
|
|
111
|
+
"statusType": "auto",
|
|
112
|
+
"x": 550,
|
|
113
|
+
"y": 180,
|
|
114
|
+
"wires": []
|
|
115
|
+
},
|
|
116
|
+
{
|
|
117
|
+
"id": "9563d0689b7ce1af",
|
|
118
|
+
"type": "agwpe-client",
|
|
119
|
+
"name": "",
|
|
120
|
+
"host": "192.168.68.20",
|
|
121
|
+
"port": 8000,
|
|
122
|
+
"callsigns": "N0CALL",
|
|
123
|
+
"username": "",
|
|
124
|
+
"password": "",
|
|
125
|
+
"monitor": false,
|
|
126
|
+
"raw": true,
|
|
127
|
+
"reconnect": true,
|
|
128
|
+
"reconnectDelay": 5000
|
|
129
|
+
}
|
|
130
|
+
]
|
|
Binary file
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
[
|
|
2
|
+
{
|
|
3
|
+
"id": "f1e3c30bea1bbe94",
|
|
4
|
+
"type": "subflow",
|
|
5
|
+
"name": "Bye",
|
|
6
|
+
"info": "",
|
|
7
|
+
"category": "",
|
|
8
|
+
"in": [
|
|
9
|
+
{
|
|
10
|
+
"x": 80,
|
|
11
|
+
"y": 120,
|
|
12
|
+
"wires": [
|
|
13
|
+
{
|
|
14
|
+
"id": "0813fedcec47e075"
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
],
|
|
19
|
+
"out": [],
|
|
20
|
+
"env": [],
|
|
21
|
+
"meta": {},
|
|
22
|
+
"color": "#DDAA99"
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
"id": "0813fedcec47e075",
|
|
26
|
+
"type": "function",
|
|
27
|
+
"z": "f1e3c30bea1bbe94",
|
|
28
|
+
"name": "B",
|
|
29
|
+
"func": "\"use strict\";\n\nif (!msg.sessionId) {\n const errorCode = 'NO_SESSION_ID';\n const errorText = \"sessionID not found\";\n\n node.error(`[${errorCode}] ${errorText}`);\n\n return [{\n status: 'error',\n errorCode,\n errorText,\n msg,\n }, null];\n}\n\nreturn [null, {\n sessionId: msg.sessionId,\n command: 'send',\n payload: 'B',\n timeout: 30000,\n}];\n",
|
|
30
|
+
"outputs": 2,
|
|
31
|
+
"timeout": 0,
|
|
32
|
+
"noerr": 0,
|
|
33
|
+
"initialize": "",
|
|
34
|
+
"finalize": "",
|
|
35
|
+
"libs": [],
|
|
36
|
+
"x": 210,
|
|
37
|
+
"y": 120,
|
|
38
|
+
"wires": [
|
|
39
|
+
[
|
|
40
|
+
"637170b1c7227488"
|
|
41
|
+
],
|
|
42
|
+
[
|
|
43
|
+
"1e49e3218b1dd308"
|
|
44
|
+
]
|
|
45
|
+
]
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
"id": "1e49e3218b1dd308",
|
|
49
|
+
"type": "send",
|
|
50
|
+
"z": "f1e3c30bea1bbe94",
|
|
51
|
+
"name": "",
|
|
52
|
+
"timeout": "",
|
|
53
|
+
"waitFor": "",
|
|
54
|
+
"x": 390,
|
|
55
|
+
"y": 160,
|
|
56
|
+
"wires": [
|
|
57
|
+
[
|
|
58
|
+
"e3ab85e4461b92a5"
|
|
59
|
+
],
|
|
60
|
+
[
|
|
61
|
+
"fed58202ceb48e13"
|
|
62
|
+
]
|
|
63
|
+
]
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
"id": "e3ab85e4461b92a5",
|
|
67
|
+
"type": "function",
|
|
68
|
+
"z": "f1e3c30bea1bbe94",
|
|
69
|
+
"name": "check error",
|
|
70
|
+
"func": "\"use strict\";\n\nif (msg.status === 'error') {\n node.error(`[${msg.errorCode}] ${msg.errorText}`, msg);\n return msg;\n}\nreturn null;",
|
|
71
|
+
"outputs": 1,
|
|
72
|
+
"timeout": 0,
|
|
73
|
+
"noerr": 0,
|
|
74
|
+
"initialize": "",
|
|
75
|
+
"finalize": "",
|
|
76
|
+
"libs": [],
|
|
77
|
+
"x": 610,
|
|
78
|
+
"y": 140,
|
|
79
|
+
"wires": [
|
|
80
|
+
[
|
|
81
|
+
"fed58202ceb48e13"
|
|
82
|
+
]
|
|
83
|
+
]
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
"id": "fed58202ceb48e13",
|
|
87
|
+
"type": "disconnect",
|
|
88
|
+
"z": "f1e3c30bea1bbe94",
|
|
89
|
+
"name": "",
|
|
90
|
+
"x": 810,
|
|
91
|
+
"y": 180,
|
|
92
|
+
"wires": [
|
|
93
|
+
[]
|
|
94
|
+
]
|
|
95
|
+
},
|
|
96
|
+
{
|
|
97
|
+
"id": "637170b1c7227488",
|
|
98
|
+
"type": "disconnect",
|
|
99
|
+
"z": "f1e3c30bea1bbe94",
|
|
100
|
+
"name": "",
|
|
101
|
+
"x": 410,
|
|
102
|
+
"y": 80,
|
|
103
|
+
"wires": [
|
|
104
|
+
[]
|
|
105
|
+
]
|
|
106
|
+
}
|
|
107
|
+
]
|
|
Binary file
|