Bluetooth

Every SolarAssistant device advertises a BLE GATT peripheral that a mobile app can use for local provisioning — configuring Wi-Fi, authenticating, and reading live metrics — without requiring a network connection.

Discovery

Scan for BLE devices and look for one whose advertised name starts with SolarAssistant- (or the organisation's custom app name if white-labelled). A # in the suffix marks a site ID, meaning the device is registered. Without one, the suffix is the last 6 characters of the device's machine ID and the device has not been registered yet:

SolarAssistant-#12345  ← registered
SolarAssistant-a3f8c2   ← not yet registered

Key off the # — never off whether the suffix parses as a number. The machine ID is hexadecimal, so for roughly one device in sixteen it happens to contain only digits, and SolarAssistant-483920 is an unregistered device rather than site 483920.

The name is a human-readable hint only — use site_id from the Service Data (see below) as the authoritative source. A non-zero value means the device is registered.

Once found, connect to the device and discover its GATT services. All SolarAssistant characteristics live under a single service UUID:

45a2b616-7083-41e9-851f-23f3ed252300

Advertisement data

The advertisement includes Service Data under UUID 0x5341. This lets a scanning app read basic device state without connecting. The payload is 6 bytes. Note: the status byte refreshes approximately once per minute — use the Network status characteristic for real-time connection state.

Bytes 0–2uint24 LEsite_id — numeric site ID. 0 if the device has not yet been registered.
Bytes 3–4uint16 LEorg_id — organisation ID. 0 for the default SolarAssistant organisation.
Byte 5bitmaskstatusbit 0: Wi-Fi connected, bit 1: Ethernet connected, bit 3: internet reachable, bit 4: monitoring running — the device is polling its inverter and battery. Bits are independent and combinable, and bit 2 is unused.

Characteristics

A connected client also discovers ...304, ...305 and ...306, which are reserved for authenticated API access and live metrics. These are not implemented yet — the Bluetooth stack accepts a write but nothing acts on it, so use only the characteristics documented below.

READNOTIFY45a2b616-7083-41e9-851f-23f3ed252302Network status

Returns the connection state of every network adapter on the device (Ethernet, Wi-Fi, and Internet). Adapter entries cover eth* and wlan* interfaces, sorted by name, followed by an Internet entry that reports whether the device has a working route to the internet. The value is a UTF-8 JSON string.

Subscribe to notifications to receive an update whenever the network state changes (e.g. after writing Wi-Fi credentials). Expect the status to reach Up within ~15–30 seconds if the credentials are correct.

Response
[
  { "adapter": "eth0",     "status": "Down", "ip": null },
  { "adapter": "wlan0",    "status": "Up",   "ip": "192.168.1.101" },
  { "adapter": "Internet", "status": "Up",   "ip": "1.2.3.4" }
]
adapterstringInterface name, e.g. eth0, wlan0, or Internet.
statusstringInterface status — Up, Down, Dormant, or other values as reported by the operating system.
ipstringIP address when connected. null otherwise.
READWRITE45a2b616-7083-41e9-851f-23f3ed252303Wi-Fi config

Read: returns the currently saved Wi-Fi configuration as a UTF-8 JSON string. The password is never included in the response.

Read response
{
  "ssid":         "MyNetwork",
  "country_code": "US"
}
ssidstringSaved network SSID. null if not configured.
country_codestringSaved ISO 3166-1 alpha-2 country code. null if not configured.

Write: stores new Wi-Fi credentials and initiates a connection attempt. The value is a UTF-8 JSON string.

Use write with response so the device can confirm the payload was accepted before attempting to connect. After a successful response, watch for Network status notifications (characteristic ...302) — the device pushes an update as the connection state changes.

Write payload
{
  "ssid":         "MyNetwork",
  "password":     "secret",
  "country_code": "US"
}
ssidstringNetwork SSID.
passwordstringWPA2 passphrase. Pass an empty string for open networks.
country_codestringISO 3166-1 alpha-2 country code (e.g. US, GB). Optional — defaults to the previously stored value on the device.
READ45a2b616-7083-41e9-851f-23f3ed252308Site URL

Returns the device's remote access URL as a UTF-8 string, e.g. https://solar-dev-rpi5.us.solar-assistant.io. An empty string means the device has not been registered yet.

Response
https://solar-dev-rpi5.us.solar-assistant.io
READ45a2b616-7083-41e9-851f-23f3ed252307Build date

Returns the firmware build date as a UTF-8 string in YYYY-MM-DD format. This is the same value published in the mDNS TXT record (build_date).

Response
2026-07-06
READ45a2b616-7083-41e9-851f-23f3ed252301Wi-Fi networks

Returns a list of nearby Wi-Fi networks seen by the device. The list is deduplicated by SSID — only the strongest signal for each SSID is included — and sorted by signal strength descending. The value is a UTF-8 JSON string.

Response
[
  { "ssid": "MyNetwork",    "signal": 96, "country": "US" },
  { "ssid": "OtherNetwork", "signal": 14, "country": "US" }
]
ssidstringSSID.
signalintegerSignal quality, 0–100.
countrystringISO 3166-1 alpha-2 country code reported by the access point.