Shelly Binding

Just in case I missed it:
Shelly Plus UNI counter channel issue was not addressed so far in any of the DEV builds, was it?
Last time I asked if my feedback was of help was back in February

I can confirm that your ShellyBinding (5.0.0.202506020151) now works fine with a ShellyPlus2PM (roller-mode) with both firmware 1.6.2 and 1.7.0-beta1 . It fixed the “websocket”-error that happened at the start of every minute. Thanks for fixing this!

good news, thanks. Did you tried to discover a 2PM while in roller mode?

What‘s about Gen4 devices? Did somebody tried 1/1PM Gen4 or Mini 1/1PM/EM Gen4

I also fixed the Plug US. Could somebody test?

Support dor Pro Dimmer 1PM/2PM is almost done. Could somebody help testing?

Discovery worked fine with the 2PM in roller mode. I only have this device to test at the moment.

1 Like

Do you still have a 2PM Roller with 1.5.x?
I need to separate the changes into 3 PRs to simplify review/merging process so would be good to test each PR separately.

Unfortunately, I only have this single 2PM roller. In about three weeks I would have access to 2PMs with older 1.4.4 firmware, but even with those - I’d need someone to send me the 1.5.x firmware file, because Shelly only offers access to 1.6.2 firmware at the moment.

fyi: I created a new PR: #18782

  • Adds support for Gen4 Devices: 1, 1PM and Mini 1, 1PM, EM
  • Firmware 1.6.1, which as a serious bug reporting status.id == null rather than component id. The PR adds a work around to explicitly set the id value if it’s null
  • Some Gen4 devices are providing the measure frequency (new channel)
  • Add decoding for new profile types
  • Plus Plug US needs special handling, because serviceName doesn’t indicate a Plus device (“shellyplugus” rather than “shellyplusplugus”)
  • README updated/fixed

This does NOT include the Plus2PM fix, this will be the next PW

1 Like

1.4.4 would also be ok for the test
I prepared a separated PR for this, but it doesn’t include the 1.6.1+ work around

In this case you could try this build: https://github.com/markus7017/myfiles/blob/master/shelly/org.openhab.binding.shelly-5.0.0-SNAPSHOT-plus2pm.jar?raw=true

Hello all,

it looks like @markus7017 has also fixed today with a new version of the 4.3.6 binding this errors:

  • No (or less) Shelly where listed when trying to install a new one
  • The websocket error that brings the shellys offline in the overview.

Tested with OH 3.4.5 on three different installation.
Shelly Plus 1, Plus 1PM, have different FW 1.4.4. 1.5.1, and also 1.7.0 Beta1
→ All works now, at least for me.

Thanks @markus7017 !!!

thanks for confirming that the 4.3.6 build also works. It‘s based on the 5.0.0 code with some modifications that OH4 does not support


5.0.0-DEV | 4.3.6-DEV | README | READMEbeta
Avdanced Users | Shelly Manager | Bugs/Features | API Doc
Note:

  • The DEV build is always newer than the version in the official Distro or Milestone builds.
  • 5.0.0 build might be newer than 4.3.x

EDIT: Tried again and now it works. Maybe I swapped the versions


@markus7017 :slight_smile:

I tried the new 4.3.6 version too:
All channels of my installed things were now shown correctly.

But when I tried to create a new thing the Shelly binding was not shown at all. Did anybody else experience this?

EDIT: Problem solved

1 Like

Have you checked that is listet?

the upper is the offical, the unoffical is listet down.

Are you sure it is running?

Have you manual added the command in the OH console:

“feature:install openhab-transport-coap” ?

It should work fine now.

Meanwhilie I also flashed my shelly plus 1 with th 1.7.0-beta1 and it has been working over the night.

1 Like

I tried again and now it works. Probably I swapped versions during copying. Thank you.

Instead I keep the tradfri-binding installed because that installs coap too.

Thanks for the fixes! Unfortunately i still got the exception at the status call:

[ly.internal.handler.ShellyBaseHandler] - shelly2pmg3-b08184e9dce8: Unable to refresh status: Status konnte nicht aktualisiert werden
java.lang.NullPointerException: Cannot invoke "java.lang.Double.doubleValue()" because "cs.temperature.tC" is null
        at org.openhab.binding.shelly.internal.api2.Shelly2ApiClient.updateRollerStatus(Shelly2ApiClient.java:633) ~[?:?]
        at org.openhab.binding.shelly.internal.api2.Shelly2ApiClient.fillDeviceStatus(Shelly2ApiClient.java:235) ~[?:?]
        at org.openhab.binding.shelly.internal.api2.Shelly2ApiRpc.getStatus(Shelly2ApiRpc.java:844) ~[?:?]
        at org.openhab.binding.shelly.internal.api2.Shelly2ApiRpc.getDeviceProfile(Shelly2ApiRpc.java:327) ~[?:?]
        at org.openhab.binding.shelly.internal.handler.ShellyBaseHandler.initializeThing(ShellyBaseHandler.java:336) ~[?:?]
        at org.openhab.binding.shelly.internal.handler.ShellyBaseHandler.refreshStatus(ShellyBaseHandler.java:561) ~[?:?]
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:572) ~[?:?]
        at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:358) ~[?:?]
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305) ~[?:?]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) ~[?:?]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) ~[?:?]
        at java.lang.Thread.run(Thread.java:1583) [?:?]

I tested with 5.0.0.202506020151 (https://github.com/markus7017/myfiles/blob/master/shelly/org.openhab.binding.shelly-5.0.0-SNAPSHOT.jar) as well as with the dedicated plus2pm-jar that i found here:
shelly/org.openhab.binding.shelly-5.0.0-SNAPSHOT-plus2pm.jar

Am i doing something wrong here?

obviously another firmware bug. If coverStatus.temperature is != null, coverStatus.temperature.tmpC has to have a value. I added an additional check, in your case inner device temp will not be available/updated.
try updated jar (5.0 build only)

1 Like

Thanks a lot Markus! Now it seems to work just fine :slight_smile:

@markus7017, I just installed your latest 4.3.6 dev build, and I noticed my BLU devices didn’t get discovered, even after three scans. (I added them manually, and they seem to work on first glance.)

Second thing: I’ve got two devices for Christmas decoration, so I disable them during non-Christmas. I got them up and running for the deletion and re-creation process, but when I disabled them again, I saw this in the log:

log:display | grep -i fcb467269c34
17:46:59.043 [INFO ] [ig.discovery.internal.PersistentInbox] - Added new thing 'shelly:shellyplusplug:fcb467269c34' to inbox.
17:46:59.043 [INFO ] [openhab.event.InboxAddedEvent        ] - Discovery Result with UID 'shelly:shellyplusplug:fcb467269c34' has been added.
17:51:00.948 [INFO ] [openhab.event.InboxRemovedEvent      ] - Discovery Result with UID 'shelly:shellyplusplug:fcb467269c34' has been removed.
17:51:00.963 [INFO ] [hab.event.ThingStatusInfoChangedEvent] - Thing 'shelly:shellyplusplug:fcb467269c34' changed from UNINITIALIZED to INITIALIZING
17:51:02.968 [INFO ] [hab.event.ThingStatusInfoChangedEvent] - Thing 'shelly:shellyplusplug:fcb467269c34' changed from INITIALIZING to ONLINE (CONFIGURATION_PENDING): Device is initializing or in sleep mode.
17:51:03.107 [INFO ] [hab.event.ThingStatusInfoChangedEvent] - Thing 'shelly:shellyplusplug:fcb467269c34' changed from ONLINE (CONFIGURATION_PENDING): Device is initializing or in sleep mode. to ONLINE
18:05:45.410 [INFO ] [hab.event.ThingStatusInfoChangedEvent] - Thing 'shelly:shellyplusplug:fcb467269c34' changed from ONLINE to UNINITIALIZED
18:05:45.424 [INFO ] [hab.event.ThingStatusInfoChangedEvent] - Thing 'shelly:shellyplusplug:fcb467269c34' changed from UNINITIALIZED to OFFLINE (COMMUNICATION_ERROR): Unexpected error: WebSocket connection closed abnormally
18:05:45.428 [INFO ] [hab.event.ThingStatusInfoChangedEvent] - Thing 'shelly:shellyplusplug:fcb467269c34' changed from OFFLINE (COMMUNICATION_ERROR): Unexpected error: WebSocket connection closed abnormally to UNINITIALIZED (DISABLED)

“Unexpected error” seems like it’s not as it should be?

This was before I physically unplugged them from the electricity outlet.

I have a Shelly BW Gateway and two door window v1 with 1.6.2 fw and Ive installed the latest 4.3.6 and everything works flawlessly. Same with my Shelly Plugs (old ones).

1 Like

you need to update to latest DEV build
and enable BLU support in the thing config for those devices you like to use as hub - see doc

Hi @markus7017,

I did that with a Plus2PM and firmware 1.6.2 and ran into a ‘flapping error’, where the shelly thing was online, went to offline (websocket error), came back online and so forth.

OH is 4.3.5 with the default Shelly binding.

Enabling the debug log showed repeating messages like this:

2025-06-09 18:19:46.261 [DEBUG] [g.shelly.internal.api2.Shelly2ApiRpc] - shellyplus2pm-roller-e465b8f349cc: Install or restart script oh-blu-scanner.js on Shelly Device
2025-06-09 18:19:46.262 [DEBUG] [g.shelly.internal.api2.Shelly2ApiRpc] - shellyplus2pm-roller-e465b8f349cc: Script oh-blu-scanner.js is already installed, id=1
2025-06-09 18:19:46.357 [DEBUG] [g.shelly.internal.api2.Shelly2ApiRpc] - shellyplus2pm-roller-e465b8f349cc: Same script version was found, restart

Since I don’t intend to use this very device as a Bluetooth gateway, I disabled enableBluGateway in the Things configuration and the flapping problem disappeared.

So maybe, in roller-mode there’s some issue with the provisioning of that script or with the reception / processing of the data that the script sends to OH?

In order to troubleshoot this a bit further, I left the enableBluGateway to false but manually started the already provisioned JS script on my shelly device. Immediately thereafter, the Thing status on OH turned to offline: COMMUNICATION_ERROR Unexpected error: websocket error.

The script that ran on my Shelly was:

/*
 * This script uses the BLE scan functionality in scripting to pass scan results to openHAB
 * Supported BLU Devices: BLU Button 1, BLU Door/Window, BLU Motion, BLU H&T
 * Version 0.4
 */

let ALLTERCO_DEVICE_NAME_PREFIX = ["SBBT", "SBDW", "SBMO", "SBHT"];
let ALLTERCO_MFD_ID_STR = "0ba9";
let BTHOME_SVC_ID_STR = "fcd2";

let ALLTERCO_MFD_ID = JSON.parse("0x" + ALLTERCO_MFD_ID_STR);
let BTHOME_SVC_ID = JSON.parse("0x" + BTHOME_SVC_ID_STR);
let SCAN_DURATION = BLE.Scanner.INFINITE_SCAN;

let SHELLY_BLU_CACHE = {};
let LAST_PID = {};

let uint8 = 0;
let int8 = 1;
let uint16 = 2;
let int16 = 3;
let uint24 = 4;
let int24 = 5;
let uint32 = 6;
let int32 = 7;

let BTH = [];
BTH[0x00] = { n: "pid", t: uint8 };
BTH[0x01] = { n: "Battery", t: uint8, u: "%" };
BTH[0x02] = { n: "Temperature", t: int16, f: 0.01 };
BTH[0x03] = { n: "Humidity", t: uint16, f: 0.01 };
BTH[0x05] = { n: "Illuminance", t: uint24, f: 0.01 };
BTH[0x08] = { n: "Dewpoint", t: int16, f: 0.01 };
BTH[0x12] = { n: "Co2", t: uint16 };
BTH[0x14] = { n: "Moisture16", t: uint16, f: 0.01 };
BTH[0x1a] = { n: "Door", t: uint8 };
BTH[0x20] = { n: "Moisture", t: uint8 };
BTH[0x21] = { n: "Motion", t: uint8 };
BTH[0x2d] = { n: "Window", t: uint8 };
BTH[0x2e] = { n: "Humidity", t: uint8 };
BTH[0x2f] = { n: "Moisture8", t: uint8 };
BTH[0x3a] = { n: "Button", t: uint8 };
BTH[0x3f] = { n: "Rotation", t: int16, f: 0.1 };
BTH[0x43] = { n: "Current", t: uint16, f: 0.1 };
BTH[0x45] = { n: "Temperature", t: int16, f: 0.1 };
BTH[0x46] = { n: "UVIndex", t: uint8 };
BTH[0x51] = { n: "Acceleration", t: uint16, f: 0.1 };

function getByteSize(type) {
  if (type === uint8 || type === int8) return 1;
  if (type === uint16 || type === int16) return 2;
  if (type === uint24 || type === int24) return 3;
  if (type === uint32 || type === int32) return 4;
  //impossible as advertisements are much smaller;
  return 255;
}

let BTHomeDecoder = {
  utoi: function (num, bitsz) {
    let mask = 1 << (bitsz - 1);
    return num & mask ? num - (1 << bitsz) : num;
  },
  getUInt8: function (buffer) {
    return buffer.at(0);
  },
  getInt8: function (buffer) {
    return this.utoi(this.getUInt8(buffer), 8);
  },
  getUInt16LE: function (buffer) {
    return 0xffff & ((buffer.at(1) << 8) | buffer.at(0));
  },
  getInt16LE: function (buffer) {
    return this.utoi(this.getUInt16LE(buffer), 16);
  },
  getUInt24LE: function (buffer) {
    return (
      0x00ffffff & ((buffer.at(2) << 16) | (buffer.at(1) << 8) | buffer.at(0))
    );
  },
  getInt24LE: function (buffer) {
    return this.utoi(this.getUInt24LE(buffer), 24);
  },
  getUInt32LE: function (buffer) {
    return (
      (buffer.at(2) << 24) | (buffer.at(2) << 16) | (buffer.at(1) << 8) | buffer.at(0)
    );
  },
  getInt32LE: function (buffer) {
    return this.utoi(this.getUInt32LE(buffer), 32);
  },
  getBufValue: function (type, buffer) {
    if (buffer.length < getByteSize(type)) return null;
    let res = null;
    if (type === uint8) res = this.getUInt8(buffer);
    if (type === int8) res = this.getInt8(buffer);
    if (type === uint16) res = this.getUInt16LE(buffer);
    if (type === int16) res = this.getInt16LE(buffer);
    if (type === uint24) res = this.getUInt24LE(buffer);
    if (type === int24) res = this.getInt24LE(buffer);
    if (type === uint32) res = this.getUInt24LE(buffer);
    if (type === int32) res = this.getInt24LE(buffer);
    return res;
  },
  unpack: function (buffer) {
    // beacons might not provide BTH service data
    if (typeof buffer !== "string" || buffer.length === 0) return null;
    let result = {};
    let _dib = buffer.at(0);
    result["encryption"] = _dib & 0x1 ? true : false;
    result["BTHome_version"] = _dib >> 5;
    if (result["encryption"]) return result; // Can not handle encrypted data
    if (result["BTHome_version"] !== 2) return null; // Can not handle BT version != 2    
    buffer = buffer.slice(1);

    let _bth;
    let _value;
    while (buffer.length > 0) {
      _bth = BTH[buffer.at(0)];
      if (typeof _bth === "undefined") {
        console.log("BTH: unknown type");
        break;
      }
      buffer = buffer.slice(1);
      _value = this.getBufValue(_bth.t, buffer);
      if (_value === null) break;
      if (typeof _bth.f !== "undefined") _value = _value * _bth.f;
      result[_bth.n] = _value;
      buffer = buffer.slice(getByteSize(_bth.t));
    }
    return result;
  },
};

let ShellyBLUParser = {
  getData: function (res) {
    let result = BTHomeDecoder.unpack(res.service_data[BTHOME_SVC_ID_STR]);
    result.addr = res.addr;
    result.rssi = res.rssi;
    return result;
  },
};

function scanCB(ev, res) {
  if (ev !== BLE.Scanner.SCAN_RESULT) return;
  // skip if there is no service_data member
  if (typeof res.service_data === 'undefined' || typeof res.service_data[BTHOME_SVC_ID_STR] === 'undefined') return;
  // skip if we have already found this device
 
  if (typeof SHELLY_BLU_CACHE[res.addr] === 'undefined') {
    if (typeof res.local_name === "undefined") console.log("res.local_name undefined")
    if (typeof res.local_name !== 'string') return;
  
    let shellyBluNameIdx = 0; 
    for (shellyBluNameIdx in ALLTERCO_DEVICE_NAME_PREFIX) {
      if (res.local_name.indexOf(ALLTERCO_DEVICE_NAME_PREFIX[shellyBluNameIdx]) === 0) {
        console.log('New device found: address=', res.addr, ', name=', res.local_name);
        Shelly.emitEvent("oh-blu.scan_result", {"addr":res.addr, "name":res.local_name, "rssi":res.rssi, "tx_power":res.tx_power_level});
        SHELLY_BLU_CACHE[res.addr] = res.local_name;
      }
    }
  }
  
  let BTHparsed = ShellyBLUParser.getData(res); // skip if parsing failed
  if (BTHparsed === null) {
    console.log("Failed to parse BTH data");
    return;
  }
  
  // skip, we are deduping results
  if (typeof LAST_PID[res.addr] === 'undefined' ||
      BTHparsed.pid !== LAST_PID[res.addr]) {
    Shelly.emitEvent("oh-blu.data", BTHparsed);
    LAST_PID[res.addr] = BTHparsed.pid;
  }
}

// retry several times to start the scanner if script was started before
// BLE infrastructure was up in the Shelly
function startBLEScan() {
    let bleScanSuccess = BLE.Scanner.Start({ duration_ms: SCAN_DURATION, active: true }, scanCB);
    if( bleScanSuccess === null ) {
        console.log('Unable to start OH-BLU Scanner, make sure Shelly Gateway Support is disabled in device config.');
        Timer.set(3000, false, startBLEScan);
    } else {
        console.log('Success: OH-BLU Event Gateway running');
    }
 }
 
let BLEConfig = Shelly.getComponentConfig('ble');
if(BLEConfig.enable === false) {
    console.log('Error: BLE not enabled, unable to start OH-BLU Scanner');
} else {
    Timer.set(1000, false, startBLEScan);
}

I guess, that’s the default script as shipped with the Binding.

Best regards
Marco