Overview Shelly BLU - basics and gateway script

Shelly BLU devices are battery-powered sensors and push-buttons using Bluetooth. Unlike the other Shelly devices they have no WLAN and therefore cannot send MQTT messages themselves. They broadcast their readings as Bluetooth advertisements in the BTHome v2 format. For the controller to receive these readings a gateway is required: a mains-powered Shelly device with WLAN that receives the Bluetooth broadcast and forwards it to the controller as an MQTT message. The BTHome telegrams are decoded by the controller itself - the script on the gateway only forwards the raw data. New device types are therefore added with a software update of the controller, without any change to the script.

This page describes how the gateway is set up, how the messages are structured and which script runs on the gateway. The description of the individual function blocks can be found on the pages of the respective devices.

Setting up the gateway

  1. Install a Shelly device of the second or a newer generation (Plus, Pro, Gen 3, Gen 4) within reception range of the BLU devices. The device must be permanently powered.
  2. In the web interface of the device, switch on the Bluetooth gateway function under Bluetooth.
  3. Enter the connection to the controller under MQTT. The procedure is described on the page MQTT devices - general.
  4. Create a new script under Scripts, insert the example script below, save it and start it.
  5. Enable autostart for the script so that it runs again on its own after a power failure.
  6. Check in the MQTT diagnostics of the controller whether messages are arriving. The topic shown there is entered into the MQTT topic parameter of the respective function block.
One gateway can forward several BLU devices at the same time. In larger buildings several gateways can be used as well; the same device may then be reported by two gateways, which does not cause any problem for the evaluation.
Update note: The script below requires controller version 2.3131 or later. When migrating, keep this order: update the controller first, then replace the script - otherwise no values will arrive. The previous large script with built-in decoding keeps working unchanged, replacing it is not mandatory. If several gateways are used, all of them should run the same script version.
Exception valve control: The Shelly BLU TRV does not require a script. It is paired with the Shelly BLU gateway and is controlled and read through the gateway's own messages. For the TRV the topic of the gateway and the Bluetooth ID of the valve are therefore entered in the function block.

Structure of the messages

The script publishes one message for every BLU device received. The topic consists of the prefix configured in the script and the Bluetooth address of the device:

shelly-blu-aa:bb:cc:dd:ee:ff

The content is a small JSON object containing the unmodified Bluetooth payload in hexadecimal notation:

{"sv":1,"addr":"aa:bb:cc:dd:ee:ff","rssi":-62,"sd":"40004201642e2f45d600"}

Here sv is the version of the message format, addr the Bluetooth address, rssi the signal strength and sd the BTHome telegram. The controller decodes the actual values from it, for example:

{"encryption":false,"BTHome_version":2,"pid":66,"Battery":100,"humidity":47,"temperature":21.4,"addr":"aa:bb:cc:dd:ee:ff","rssi":-62}

In the MQTT diagnostics both messages appear one below the other: first the raw message of the gateway, directly followed by the decoded version with the field names. Messages of the previous large script arrive already decoded and are evaluated unchanged.

Important: The topic must not contain a slash. The controller only evaluates BLU messages if the topic consists of a single section. The default prefix shelly-blu- meets this condition. If it is changed, hyphens must still be used instead of slashes.

The topic is entered completely in the function block, that is including prefix and address. The easiest way is to copy it from the MQTT diagnostics.

Which value ends up on which output

Values in the JSON

Object ID Field in the JSON Usage
0x01 Battery Battery in percent. All BLU blocks output the value at the "battery %" output and additionally set "battery alarm" as soon as the value is 10 % or less.
0x3a Button Button press. See section "Special feature push-buttons".
0x2d Window Window contact, output at the "window" output of the Door/Window block.
0x3f Rotation Tilt of the Door/Window sensor in degrees.
0x21 motion Motion, output at the "motion" output of the Motion block. Written in lower case.
0x05 Illuminance Brightness in lux. Output directly by Door/Window and Motion. For the weather station, brightness in kLux, twilight and solar radiation are additionally calculated from it.
0x45 temperature Temperature in °C for H&T and weather station. Written in lower case.
0x2e humidity Relative humidity in percent for H&T and weather station. Written in lower case.
0x04 Pressure Air pressure in hPa, weather station.
0x08 Dewpoint Dew point in °C, weather station.
0x44 Wind / Gust Wind speed in m/s. The weather station sends wind and gust under the same object ID. During decoding the two values are separated: the first one becomes "Wind", the second one "Gust".
0x5e WindDir Wind direction in degrees, weather station.
0x46 UV UV index, weather station.
0x20 Raining Rain yes/no. This binary value reacts faster than the millimetre counter. Older script versions report it under the name "Moisture"; both spellings are read.
0x5f Rain Rain counter in mm. From the continuous counter reading the controller calculates rain rate, event, hour, day, week, month, year and total amount.
0x0c
0x4a
Voltage Voltage. For the weather station the voltage of the supercapacitor.
Upper and lower case: The field names are generated by the controller during decoding, so their spelling is fixed. Only with the previous large script, which decodes the values itself, the field names must match character by character: "Battery" is written with a capital letter, whereas "temperature", "humidity" and "motion" are written in lower case - otherwise the outputs keep their previous value.

Special feature push-buttons

On the Shelly BLU Button 1 the field "Button" contains a single number. It indicates how often or how long the button was pressed:
  • 1 = once, short
  • 2 = twice
  • 3 = three times
  • 4 = long
On the Shelly BLU RC Button 4 the field "Button" instead contains a list of four values, one for each button. The value 254 means that this button was pressed:

"Button":[0,0,254,0]

This list is created because object IDs that occur several times are collected during decoding instead of being overwritten.

Structure of the script

CONFIG Settings. The topic prefix is stored in topic_prefix (no slash allowed). With address the script can be restricted to a single device; as delivered, all received devices are forwarded.
toHex Converts the Bluetooth payload to hexadecimal notation for the MQTT transmission.
last_pid Suppresses repetitions. The packet number is stored per device address so that several BLU devices do not hide each other. Devices without a packet number, such as the weather station, and encrypted telegrams are not suppressed.
scanCB Is called for every Bluetooth broadcast received, filters out BTHome telegrams (service ID fcd2) and publishes the raw data via MQTT.

Example script

The script forwards the raw data of all BTHome devices within reception range. Which device types are evaluated is determined by the controller - currently: Button 1, RC Button 4, Door/Window, Motion, H&T and the Ecowitt WS90 weather station. New device types are added with a software update of the controller, the script remains unchanged.

// Shelly BLU Gateway - Minimalversion
// Leitet die BTHome-Rohdaten der Shelly BLU Geraete per MQTT an die Steuerung
// weiter. Die Dekodierung der Telegramme uebernimmt die Steuerung (ab Version
// 2.3131) - neue Geraetetypen erfordern daher kein Script-Update mehr.

let CONFIG = {
  topic_prefix: "shelly-blu-",      // kein "/" verwenden!
  // address: "aa:bb:cc:dd:ee:ff", // optional: nur dieses Geraet weiterleiten
};

let HEX = "0123456789abcdef";
function toHex(s) {
  let out = "";
  for (let i = 0; i < s.length; i++) {
    let hi = (s.at(i) >> 4) & 0x0f;
    let lo = s.at(i) & 0x0f;
    out = out + HEX.slice(hi, hi + 1) + HEX.slice(lo, lo + 1);
  }
  return out;
}

let last_pid = {};
function scanCB(ev, res) {
  if (ev !== BLE.Scanner.SCAN_RESULT) return;
  // nur BTHome-Telegramme (Service-Kennung fcd2) weiterleiten
  if (typeof res.service_data === "undefined" || typeof res.service_data["fcd2"] === "undefined")
    return;
  if (typeof CONFIG.address !== "undefined" && CONFIG.address !== res.addr)
    return;
  let sd = res.service_data["fcd2"];
  if (sd.length < 1) return;
  // Wiederholungen unterdruecken: die Paketnummer (Kennung 0x00) steht laut
  // BTHome-Spezifikation immer als erstes Objekt nach dem Info-Byte.
  // Verschluesselte Telegramme und Geraete ohne Paketnummer (z.B. die
  // Wetterstation WS90) werden nicht unterdrueckt.
  if ((sd.at(0) & 1) === 0 && sd.length >= 3 && sd.at(1) === 0) {
    if (last_pid[res.addr] === sd.at(2)) return;
    last_pid[res.addr] = sd.at(2);
  }
  let msg = '{"sv":1,"addr":"' + res.addr + '","rssi":' + JSON.stringify(res.rssi) + ',"sd":"' + toHex(sd) + '"}';
  if (MQTT.isConnected() === false) {
    console.log("MQTT not connected");
    return;
  }
  if (MQTT.publish(CONFIG.topic_prefix + res.addr, msg, 0, false) === false)
    console.log("MQTT error publish");
}
console.log("BLE.Scanner.Start");
BLE.Scanner.Start({ duration_ms: BLE.Scanner.INFINITE_SCAN, active: false }, scanCB);

See also MQTT devices - general.
See also general parameters of all function blocks.