Skip to content
Open
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
123 changes: 123 additions & 0 deletions nodes/node-red-contrib-ble-seizu/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
# node-red-contrib-ble-seizu

A Node-RED node for Bluetooth Low Energy (BLE) read, write and notify operations, based on the `node-ble` library.

## Features
- **Hybrid Configuration**: Set MAC, Handle, and Operation in the node settings or override them via `msg.payload`.
- **Auto-Retry**: Configurable retry attempts and delay for connection errors.
- **Notify Support**: Subscribe to BLE notifications, either once or continuously.
- **Integrated Write Trigger**: Optionally send a write command after notify is active (no timing issues).
- **Three Outputs**:
1. `stdout`: Success confirmation.
2. `stderr`: Error messages.
3. `return`: Raw hex data from read or notify operations.

## Operations

| Operation | Description |
|---|---|
| `read` | Read value from handle |
| `write` | Write hex data to handle |
| `subscribe_once` | Enable notify, send optional write trigger, receive first notification, auto-unsubscribe |
| `subscribe` | Enable notify, send optional write trigger, forward every notification to output 3 |
| `unsubscribe` | Disable notify and disconnect |

## Input Payload Format

### Read
```json
{
"operation": "read",
"handle": "0x002C",
"mac": "90:38:0C:58:99:42"
}
```

### Write
```json
{
"operation": "write",
"handle": "0x002A",
"mac": "90:38:0C:58:99:42",
"data": "50"
}
```

### Subscribe Once (with optional write trigger)
```json
{
"operation": "subscribe_once",
"handle": "0x002C",
"mac": "90:38:0C:58:99:42",
"write_handle": "0x002A",
"write_data": "50"
}
```

### Subscribe (with optional write trigger)
```json
{
"operation": "subscribe",
"handle": "0x002C",
"mac": "90:38:0C:58:99:42",
"write_handle": "0x002A",
"write_data": "50"
}
```

### Unsubscribe
```json
{
"operation": "unsubscribe",
"handle": "0x002C",
"mac": "90:38:0C:58:99:42"
}
```

## Node Settings

| Setting | Description | Default |
|---|---|---|
| MAC Address | BLE device MAC address | - |
| Handle | GATT handle (hex, e.g. `0x002C`) | - |
| Operation | Default operation | `read` |
| Max Retries | Connection retry attempts | `3` |
| Retry Delay | Delay between retries in ms | `2000` |

## Example: RadonEye RD200

Single Node-RED inject with `subscribe_once` — no separate write node needed:

```json
{
"operation": "subscribe_once",
"mac": "90:38:0C:58:99:42",
"handle": "0x002C",
"write_handle": "0x002A",
"write_data": "50"
}
```

Response on output 3 (hex): `500a0a000000000000000300`

Parse radon value:
- **Byte 1** = current Radon in Bq/m³
- **Byte 2** = short term average in Bq/m³

## Installation

Local installation:
```bash
cd ~/.node-red
npm install /path/to/node-red-contrib-ble-seizu
```

Then restart Node-RED:
```bash
node-red-restart
```

## Requirements
- Node-RED
- `node-ble` library
- Linux with BlueZ (e.g. Raspberry Pi)
97 changes: 97 additions & 0 deletions nodes/node-red-contrib-ble-seizu/ble.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
<script type="text/javascript">
RED.nodes.registerType('ble-seizu', {
category: 'input',
color: '#a6bbcf',
defaults: {
name: { value: "" },
mac: { value: "" },
handle: { value: "" },
operation: { value: "read", required: true },
retries: { value: 3 },
retryDelay: { value: 2000 },
subscribeTimeout: { value: 30000 }
},
inputs: 1,
outputs: 3,
outputLabels: ["stdout", "stderr", "return"],
icon: "bluetooth.png",
label: function() {
return this.name || "BLE Node";
}
});
</script>

<script type="text/html" data-template-name="ble-seizu">
<div class="form-row">
<label for="node-input-name"><i class="fa fa-tag"></i> Name</label>
<input type="text" id="node-input-name" placeholder="Node Name">
</div>

<div class="form-row">
<label for="node-input-mac"><i class="fa fa-bluetooth"></i> MAC Address</label>
<input type="text" id="node-input-mac" placeholder="D8:71:4D:00:6D:3D">
</div>

<div class="form-row">
<label for="node-input-handle"><i class="fa fa-cog"></i> Handle</label>
<input type="text" id="node-input-handle" placeholder="e.g. 0x0074">
</div>

<div class="form-row">
<label for="node-input-operation"><i class="fa fa-exchange"></i> Operation</label>
<select id="node-input-operation">
<option value="read">Read</option>
<option value="write">Write</option>
<option value="subscribe">Subscribe</option>
<option value="unsubscribe">Unsubscribe</option>
<option value="subscribe_once">Subscribe Once</option>
</select>
</div>

<div class="form-row">
<label for="node-input-retries"><i class="fa fa-repeat"></i> Max Retries</label>
<input type="number" id="node-input-retries" placeholder="3" min="1" max="10">
</div>

<div class="form-row">
<label for="node-input-retryDelay"><i class="fa fa-clock-o"></i> Retry Delay (ms)</label>
<input type="number" id="node-input-retryDelay" placeholder="2000" min="500" max="10000">
</div>

<div class="form-row">
<label for="node-input-subscribeTimeout"><i class="fa fa-hourglass"></i> Subscribe Timeout (ms)</label>
<input type="number" id="node-input-subscribeTimeout" placeholder="30000" min="1000" max="120000">
</div>
</script>

<script type="text/html" data-help-name="ble-seizu">
<p>A node for BLE (Bluetooth Low Energy) operations using <code>node-ble</code>.</p>

<h3>Inputs</h3>
<dl class="message-properties">
<dt>payload.operation <span class="property-type">string</span></dt>
<dd>"read", "write", "subscribe", "unsubscribe" or "subscribe_once". Overrides node configuration.</dd>

<dt>payload.mac <span class="property-type">string</span></dt>
<dd>The MAC address of the BLE device.</dd>

<dt>payload.handle <span class="property-type">string | hex</span></dt>
<dd>The GATT handle to interact with.</dd>

<dt>payload.data <span class="property-type">string</span></dt>
<dd>Hex string data (required for write operations).</dd>

<dt>payload.write_handle <span class="property-type">string</span></dt>
<dd>Optional write handle for subscribe/subscribe_once trigger.</dd>

<dt>payload.write_data <span class="property-type">string</span></dt>
<dd>Optional hex data for subscribe/subscribe_once trigger.</dd>
</dl>

<h3>Outputs</h3>
<ol class="node-ports">
<li><strong>stdout:</strong> Success confirmation messages.</li>
<li><strong>stderr:</strong> Error messages.</li>
<li><strong>return:</strong> Raw hex data from read or notify operations.</li>
</ol>
</script>
Loading
Loading