WellNuo/docs/BLE_PROTOCOL.md
Sergei 2b68b70584 Add sensor system documentation
BLE_PROTOCOL.md:
- ESP32 BLE provisioning protocol spec
- Characteristics UUIDs and data formats
- WiFi credential exchange flow
- Security considerations
- Error handling

SENSORS_IMPLEMENTATION_PLAN.md:
- Complete implementation roadmap
- Phase 1: BLE scanning and connection
- Phase 2: WiFi provisioning
- Phase 3: Device management
- Phase 4: Status monitoring
- API endpoints and data models
- Testing checklist

Technical reference for:
- Backend developers
- Mobile developers
- QA team
2026-01-14 19:08:19 -08:00

14 KiB

WellPlug BLE Protocol Documentation

Overview

WellPlug devices (WP_XXX) use Bluetooth Low Energy (BLE) for configuration. This document describes the communication protocol.

Device Information

Parameter Value
Service UUID 4fafc201-1fb5-459e-8fcc-c5c9c331914b
Characteristic UUID beb5483e-36e1-4688-b7f5-ea07361b26a8
Properties read, write, notify
Platform ESP32

Connection Flow

  1. Scan for devices with name starting with WP_
  2. Connect to the device
  3. Subscribe to notifications on the characteristic
  4. Unlock device with PIN command
  5. Send commands and receive responses

Commands

1. Unlock Device (Required First!)

Must be sent before any other command.

Command pin|7856
Response pin|ok
Note PIN 7856 is universal for all devices

Example:

Send: pin|7856
Recv: pin|ok

2. Get WiFi Networks List

Scans and returns available WiFi networks.

Command w
Response mac,XXXXXX|w|COUNT|SSID1,RSSI1|SSID2,RSSI2|...

Response Format:

  • mac,XXXXXX - Device MAC address
  • w - Command echo
  • COUNT - Number of networks found (-1 = scanning, -2 = no networks, 0+ = count)
  • SSID,RSSI - Network name and signal strength (dBm)

Example:

Send: w
Recv: mac,142b2f81a14c|w|19|FrontierTower,-55|MyNetwork,-67|...

3. Set WiFi Credentials

Configures the device to connect to a WiFi network.

Command W|SSID,PASSWORD
Response mac,XXXXXX|W|ok or mac,XXXXXX|W|fail

Example:

Send: W|FrontierTower,mypassword123
Recv: mac,142b2f81a14c|W|ok

For devices with long MAC (>12 chars): Use JSON format instead:

{"FUNC":"W","SSID":"NetworkName","PSW":"password123"}

4. Get WiFi Connection Status

Returns current WiFi connection status.

Command a
Response mac,XXXXXX|a|SSID,STATUS

Status Values:

  • 0 - Not connected
  • Other - Connected

Example:

Send: a
Recv: mac,142b2f81a14c|a|FrontierTower,1

5. Reboot Device

Restarts the device. BLE connection will be lost.

Command s
Response (device disconnects)

Example:

Send: s
(device reboots and disconnects)

6. Disconnect BLE

Disconnects BLE connection (device side).

Command D
Response (connection closed)

Response Format

All responses follow this format:

mac,XXXXXX|COMMAND|DATA

Where:

  • mac,XXXXXX - Device MAC address (last 12 hex chars)
  • COMMAND - Echo of the command sent
  • DATA - Response data (varies by command)

Error Response:

error

Python Example

import asyncio
from bleak import BleakClient, BleakScanner

SERVICE_UUID = "4fafc201-1fb5-459e-8fcc-c5c9c331914b"
CHAR_UUID = "beb5483e-36e1-4688-b7f5-ea07361b26a8"

async def configure_wellplug(device_name, wifi_ssid, wifi_password):
    # Find device
    device = await BleakScanner.find_device_by_name(device_name, timeout=10)
    if not device:
        print("Device not found")
        return

    def on_notify(sender, data):
        print(f"Response: {data.decode('utf-8')}")

    async with BleakClient(device) as client:
        # Subscribe to notifications
        await client.start_notify(CHAR_UUID, on_notify)

        # 1. Unlock device
        await client.write_gatt_char(CHAR_UUID, b"pin|7856", response=True)
        await asyncio.sleep(1)

        # 2. Get WiFi list
        await client.write_gatt_char(CHAR_UUID, b"w", response=True)
        await asyncio.sleep(2)

        # 3. Set WiFi credentials
        cmd = f"W|{wifi_ssid},{wifi_password}".encode()
        await client.write_gatt_char(CHAR_UUID, cmd, response=True)
        await asyncio.sleep(2)

        # 4. Check status
        await client.write_gatt_char(CHAR_UUID, b"a", response=True)
        await asyncio.sleep(1)

# Usage
asyncio.run(configure_wellplug("WP_497_81a14c", "MyWiFi", "password123"))

Important Notes

  1. Always unlock first - Device won't respond to commands without PIN
  2. Use response=True - When writing with bleak, use response=True for reliable communication
  3. Subscribe before writing - Subscribe to notifications before sending commands
  4. Wait for responses - Allow 1-2 seconds between commands for device to respond
  5. Reboot disconnects - Command s will disconnect BLE, need to reconnect after

Known Devices

Device Name MAC Address Notes
WP_497_81a14c 142b2f81a14c Test device 1
WP_523_81aad4 142b2f81aad4 Test device 2


WellNuo Legacy API Documentation

Overview

The WellNuo Legacy API (eluxnetworks.net) is used for device management, deployments, and sensor data. This is a REST-like API using POST requests with form-urlencoded parameters.

Base URL

https://eluxnetworks.net/function/well-api/api

Authentication

Login (Get Token)

Function credentials
Method POST

Parameters:

Parameter Value
function credentials
user_name username
ps password
clientId 001
nonce any value

Response:

{
  "access_token": "eyJhbGci...",
  "privileges": "-1",
  "user_id": 32,
  "max_role": -1,
  "status": "200 OK"
}

Example:

curl -X POST "https://eluxnetworks.net/function/well-api/api" \
  -d "function=credentials&user_name=USERNAME&ps=PASSWORD&clientId=001&nonce=111"

Deployments

List Deployments

Function deployments_list

Parameters:

Parameter Required Description
function Yes deployments_list
user_name Yes Username
token Yes Access token
first Yes Start index (0)
last Yes End index (50)

Response:

{
  "result_list": [
    {"deployment_id": 21, "email": "user@example.com", "first_name": "John", "last_name": "Doe"},
    ...
  ],
  "status": "200 OK"
}

Devices

List All Devices

Function device_list

Parameters:

Parameter Required Description
function Yes device_list
user_name Yes Username
token Yes Access token
first Yes Start index
last Yes End index

Response:

{
  "result_list": [
    [device_id, well_id, "MAC_ADDRESS", timestamp, "location", "description", deployment_id],
    ...
  ],
  "status": "200 OK"
}

Device Array Format:

  • [0] device_id - Internal device ID
  • [1] well_id - Device well ID (from device name WP_XXX)
  • [2] MAC address (uppercase, no colons)
  • [3] Last seen timestamp (Unix)
  • [4] Location name
  • [5] Description
  • [6] deployment_id (0 = not assigned)

List Devices by Deployment

Function device_list_by_deployment

Parameters:

Parameter Required Description
function Yes device_list_by_deployment
user_name Yes Username
token Yes Access token
deployment_id Yes Target deployment ID
first Yes Start index
last Yes End index

Assign Device to Deployment

Function device_set_well_id

Parameters:

Parameter Required Description
function Yes device_set_well_id
user_name Yes Username
token Yes Access token
device_id Yes Internal device ID
well_id Yes New well_id to assign
mac Yes Device MAC address

Example - Reassign device:

curl -X POST "https://eluxnetworks.net/function/well-api/api" \
  -d "function=device_set_well_id&user_name=USER&token=TOKEN&device_id=743&well_id=500&mac=142B2F81A14C"

Update Device Settings

Function device_form

Parameters:

Parameter Required Description
function Yes device_form
user_name Yes Username
token Yes Access token
well_id Yes Device well_id
device_mac Yes MAC address
description No Description text
location No Location code
close_to No Position description
radar_threshold No Radar sensitivity (0-100)
group No Group ID

Reboot Device

Function device_reboot

Parameters:

Parameter Required Description
function Yes device_reboot
user_name Yes Username
token Yes Access token
device_id Yes Device ID to reboot

Device Online Status Checking

Method 1: device_list API (Individual Check)

Use device_list to check last seen timestamp for specific devices.

How to determine online/offline:

  • Field [3] contains Unix timestamp of last update
  • Calculate hours since last update
  • If < 1 hour → ONLINE
  • If > 1 hour → OFFLINE

Example:

curl -X POST "https://eluxnetworks.net/function/well-api/api" \
  -d "function=device_list&user_name=USER&token=TOKEN&first=0&last=100"

Response:

{
  "result_list": [
    [743, 497, "142B2F81A14C", 1736859744, "Location", "Description", 70],
    [769, 523, "142B2F81AAD4", 1736859630, "Location", "Description", 70]
  ],
  "status": "200 OK"
}

Status calculation:

Device 743 (WP_497):
  Last seen: 1736859744 → 2026-01-14 10:02:24
  Hours ago: 0.0 → ONLINE

Device 769 (WP_523):
  Last seen: 1736859630 → 2026-01-14 10:00:30
  Hours ago: 0.03 → ONLINE

Method 2: request_devices API (Batch Check by Deployment)

IMPORTANT: This is the endpoint Robert uses to show "green" (online) devices in the app!

Quote from Robert: "there is API call to find out if set of devices are recently seen by server"

This endpoint returns only devices that are recently active (sent data to server in the last ~1 hour).

Function request_devices

Parameters:

Parameter Required Description
function Yes request_devices
user_name Yes Username
token Yes Access token
deployment_id Yes Deployment to check
group_id Yes Group filter ("All" for all groups)
location Yes Location filter ("All" for all locations)
fresh Yes true ← KEY PARAMETER! Filters only recently seen devices

Example:

curl -X POST "https://eluxnetworks.net/function/well-api/api" \
  -d "function=request_devices" \
  -d "user_name=USER" \
  -d "token=TOKEN" \
  -d "deployment_id=38" \
  -d "group_id=All" \
  -d "location=All" \
  -d "fresh=true"

How it works (Robert's app logic):

  1. Call request_devices with fresh=true
  2. Response contains ONLY online devices (recently seen by server)
  3. If device is in response → Show GREEN (online)
  4. If device is NOT in response → Show GRAY (offline)

Response example:

{
  "result_list": [
    [device_id_1, well_id_1, "MAC1", timestamp_1, ...],
    [device_id_2, well_id_2, "MAC2", timestamp_2, ...]
  ],
  "status": "200 OK"
}

Only devices that sent data recently appear in the list!

Alternative without fresh=true:

  • Returns ALL devices in deployment (regardless of status)
  • You need to manually check timestamp field [3] to determine online/offline

Note: This endpoint requires devices to be properly linked to the deployment in the Legacy API system. Use Method 1 (device_list) if deployment linkage is not set up.


Creating and Activating Deployments

Create/Update Deployment with Devices

Function: set_deployment

This endpoint is used to create a new deployment or update existing one with devices, beneficiary info, and WiFi credentials.

Key Parameters:

Parameter Description
function set_deployment
user_name Installer username
token Access token
deployment Deployment name or "NEW" for new deployment
beneficiary_name Beneficiary full name
beneficiary_email Beneficiary email
beneficiary_user_name Beneficiary login username
beneficiary_password Beneficiary password
beneficiary_address Beneficiary address
caretaker_username Caretaker username (can be same as installer)
caretaker_email Caretaker email
persons Number of persons in household
pets Number of pets
gender Gender
race Race index
born Year born
lat GPS latitude
lng GPS longitude
wifis JSON array of WiFi credentials: ["SSID1|password1", "SSID2|password2"]
devices JSON array of device well_ids: [497, 523]
beneficiary_photo Photo filename
beneficiary_photo_data Base64 encoded JPEG photo
reuse_existing_devices 1 to reuse, 0 to create new

Example WiFi credentials format:

["FrontierTower|frontiertower995", "HomeNetwork|password123"]

Example devices list:

[497, 523]

After creating deployment:

  1. Devices are linked to the deployment
  2. WiFi credentials are stored
  3. Beneficiary account is created
  4. Devices will start reporting data to server
  5. Devices become "live" and visible in request_devices with fresh=true

Known Test Devices

Device Name device_id well_id MAC Address Status
WP_497_81a14c 743 497 142B2F81A14C Configured
WP_523_81aad4 769 523 142B2F81AAD4 Configured

Both devices are assigned to:

  • Deployment ID: 70
  • Beneficiary: Sergei Terekhov (ID: 76)
  • Owner: serter2069@gmail.com (User ID: 63)
  • WiFi Network: FrontierTower

Changelog

  • 2026-01-14 - Added Legacy API documentation (deployments, devices)
  • 2026-01-13 - Initial BLE protocol documentation created