Shelly Blu Button 1 “Stand Alone” Løsning (Danish)
- Home
- Shelly Blu Button 1 “Stand Alone” Løsning (Danish)
Shelly Blu Button 1 “stand-alone” løsning
Med dette script får du muligheden for at styre relæet i en Shelly Plus eller Pro enhed direkte ved hjælp af Shelly BLU Button 1, uden at skulle anvende internet, Wi-Fi eller en gateway. Det betyder, at du ikke er afhængig af, at dine enheder skal være tilsluttet et netværk. I denne vejledning tages der udgangspunkt i en Shelly Plus 1PM. Fremover vil Shelly BLU Button 1 blive omtalt som Blu Button.
Trin 1: BLU Button 1 forberedelse
Hent Shelly BLE Debug appen
Noter mac adressen for Shelly BLU Button
Dan par med mobil/tablet
Opdater firmware
Slå lyd fra
Trin 2: Forbind din Shelly Plus/Pro til WiFI uden brug af appen og cloud
Log ind på Shelly's egen webserver og opdater firmware
Shelly-enheder laversit eget access point når de tilsluttes spænding første gang. Det access point kan man forbinde til og derved komme ind og ændre indstillinger.
Log på dette WiFi fra din mobil, tablet eller PC og tilgå webserveren ved at skrive 192.168.33.1 i din browser.
Forbind til WiFi
For at kunne opdatere til seneste firmware, skal enheden kobles op på et WiFi netværk med internet forbindelse.
Alt efter, hvor gammel firmwaren er på din enhed , så kan de have to forskellige brugerflader
Start med at gå ind og forbind enheden med det eksisterende WiFi.
Opdater firmware
Trin 3: Klargør din Shelly enhed
Sæt input mode til button
Sørg for at Bluetooth er aktiveret
Trin 4: Indsæt og klargør script
Slå websocket debug til
Indsæt script
Nu kopieres hele det nedenstående script.
(Tryk på Copy oppe i højre hjørne af scriptet)
/**
* This script uses the BLE scan functionality in scripting
* Selects Shelly BLU Buttons from the aired advertisements, decodes
* the service data payload and toggles a relay on the device on
* button push
*/
// Shelly BLU devices:
// SBBT - Shelly BLU Button
// SBDW - Shelly BLU DoorWindow
// BTHome data format: https://bthome.io/format/
// sample Shelly DW service_data payload
// 0x40 0x00 0x4E 0x01 0x64 0x05 0x00 0x00 0x00 0x2D 0x01 0x3F 0x00 0x00
// First byte: BTHome device info, 0x40 - no encryption, BTHome v.2
// bit 0: “Encryption flag”
// bit 1-4: “Reserved for future use”
// bit 5-7: “BTHome Version”
// AD 0: PID, 0x00
// Value: 0x4E
// AD 1: Battery, 0x01
// Value, 100%
// AD 2: Illuminance, 0x05
// Value: 0
// AD 3: Window, 0x2D
// Value: true, open
// AD 4: Rotation, 0x3F
// Value: 0
// Device name can be obtained if an active scan is performed
// You can rely only on the address filtering and forego device name matching
// CHANGE ID OUTPUT HERE. The Id of the output nuber is as follow: Output:1 = id:0, Output:2 = id:1, Output:3 = id:2. Output:4 = id:3
function singlePush() {
print("Button pushed");
Shelly.call("Switch.toggle", { id: 0});
}
function doublePush() {
print("Button double pushed");
Shelly.call("Switch.toggle", { id: 0});
}
function triplePush() {
print("button triple pushed");
Shelly.call("Switch.toggle", { id: 0});
}
function longPush() {
print("Button long pushed");
Shelly.call("Switch.toggle", { id: 0});
}
function onButtonPress(BTHparsed) {
print("Button pressed, emitting event");
Shelly.emitEvent("BLU_BUTTON", {
addr: BTHparsed.addr,
rssi: BTHparsed.rssi,
Button: BTHparsed.Button,
Battery: BTHparsed.Battery,
});
}
// remove name prefix to not filter by device name
// remove address to not filter by address
// filtering early by address or device name allows for faster execution
// actions is an array objects containing condition and action property
// conditions would be checked for equality against the parsed advertisement packet
// e.g. if there is an addr property in condition and it matches the value of addr property
// in BTH parsed object then the condition is true
// Button number define type of push. 1 = Single push, 2 = Double push, 3 = Triple push, 4 = Long push
let CONFIG = {
//shelly_blu_name_prefix: "SBBT",
//shelly_blu_address: "bc:02:6e:c3:c8:b9",
actions: [
{
cond: {
Button: 1,
addr: "3c:2e:f5:6f:77:9b",
},
action: singlePush,
},
// If You want to add a second Blu Button. Type in it's mac adress below and remove "/*", "*/"
// You can add as many Buttons as You want. Just copy/paste in more sections and and change the mac adress.
// Add Ektra Singlepush Button
/* {
cond: {
Button: 1,
addr: "3c:2e:f5:6f:77:9b",
},
action: singlePush,
},
*/
// Doublepush
{
cond: {
Button: 2,
addr: "3c:2e:f5:6f:77:9b",
},
action: doublePush,
},
// If You want to add a second Blu Button. Type in it's mac adress below and remove "/*", "*/"
// You can add as many Buttons as You want. Just copy/paste in more sections and and change the mac adress.
// Add Ektra Doublepush Button
/* {
cond: {
Button: 2,
addr: "3c:2e:f5:6f:77:9b",
},
action: doublePush,
},
*/
// Triplepush
{
cond: {
Button: 3,
addr: "3c:2e:f5:6f:77:9b",
},
action: triplePush,
},
// If You want to add a second Blu Button. Type in it's mac adress below and remove "/*", "*/"
// You can add as many Buttons as You want. Just copy/paste in more sections and and change the mac adress.
// Add Ektra Trilepush Button
/* {
cond: {
Button: 3,
addr: "3c:2e:f5:6f:77:9b",
},
action: triplePush,
},
*/
// Longpush
{
cond: {
Button: 4,
addr: "3c:2e:f5:6f:77:9b",
},
action: longPush,
},
// If You want to add a second Blu Button. Type in it's mac adress below and remove "/*", "*/"
// You can add as many Buttons as You want. Just copy/paste in more sections and and change the mac adress.
// Add Ektra Longpush Button
/* {
cond: {
Button: 4,
addr: "3c:2e:f5:6f:77:9b",
},
action: longPush,
},
*/
],
};
// END OF CHANGE
let ALLTERCO_MFD_ID_STR = "0ba9";
let BTHOME_SVC_ID_STR = "fcd2";
let SCAN_DURATION = BLE.Scanner.INFINITE_SCAN;
let ACTIVE_SCAN =
typeof CONFIG.shelly_blu_name_prefix !== "undefined" &&
CONFIG.shelly_blu_name_prefix !== null;
let uint8 = 0;
let int8 = 1;
let uint16 = 2;
let int16 = 3;
let uint24 = 4;
let int24 = 5;
function getByteSize(type) {
if (type === uint8 || type === int8) return 1;
if (type === uint16 || type === int16) return 2;
if (type === uint24 || type === int24) return 3;
//impossible as advertisements are much smaller;
return 255;
}
let BTH = [];
BTH[0x00] = { n: "pid", t: uint8 };
BTH[0x01] = { n: "Battery", t: uint8, u: "%" };
BTH[0x05] = { n: "Illuminance", t: uint24, f: 0.01 };
BTH[0x1a] = { n: "Door", t: uint8 };
BTH[0x20] = { n: "Moisture", t: uint8 };
BTH[0x2d] = { n: "Window", t: uint8 };
BTH[0x3a] = { n: "Button", t: uint8 };
BTH[0x3f] = { n: "Rotation", t: int16, f: 0.1 };
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);
},
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);
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["BTHome_version"] !== 2) return null;
//Can not handle encrypted data
if (result["encryption"]) return result;
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;
},
};
let last_packet_id = 0x100;
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 are looking for name match but don't have active scan as we don't have name
if (
typeof CONFIG.shelly_blu_name_prefix !== "undefined" &&
(typeof res.local_name === "undefined" ||
res.local_name.indexOf(CONFIG.shelly_blu_name_prefix) !== 0)
)
return;
// skip if we don't have address match
if (
typeof CONFIG.shelly_blu_address !== "undefined" &&
CONFIG.shelly_blu_address !== res.addr
)
return;
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 (last_packet_id === BTHparsed.pid) return;
last_packet_id = BTHparsed.pid;
console.log("Shelly BTH packet: ", JSON.stringify(BTHparsed));
// execute actions from CONFIG
let aIdx = null;
for (aIdx in CONFIG.actions) {
// skip if no condition defined
if (typeof CONFIG.actions[aIdx]["cond"] === "undefined") continue;
let cond = CONFIG.actions[aIdx]["cond"];
let cIdx = null;
let run = true;
for (cIdx in cond) {
if (typeof BTHparsed[cIdx] === "undefined") run = false;
if (BTHparsed[cIdx] !== cond[cIdx]) run = false;
}
// if all conditions evaluated to true then execute
if (run) CONFIG.actions[aIdx]["action"](BTHparsed);
}
}
// 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: ACTIVE_SCAN }, scanCB);
if( bleScanSuccess === false ) {
Timer.set(1000, false, startBLEScan);
} else {
console.log('Success: BLU button scanner running');
}
}
//Check for BLE config and print a message if BLE is not enabled on the device
let BLEConfig = Shelly.getComponentConfig('ble');
if(BLEConfig.enable === false) {
console.log('Error: BLE not enabled');
} else {
Timer.set(1000, false, startBLEScan);
}
Konfigurer script
Når Scriptet er kopieret ind, findes linje 82 med BLU Buttons mac adresse.
På linjen:
addr: “3c:2e:f5:6f:77:9b”, (linje 82)
indsætter du den mac adressen på din BLUButton, som blev noteret i starten.
OBS!
Det er meget vigtigt der kun bruges små bogstaver.
let CONFIG = {
//shelly_blu_name_prefix: "SBBT",
//shelly_blu_address: "bc:02:6e:c3:c8:b9",
actions: [
{
cond: {
Button: 1,
addr: "90:ab:96:9f:a9:fe",
},
action: singlePush,
},
Trin 5: Afslutning
Gem script
Deaktiver WiFi
Aktiver access point med password
Trin 6: Ekstra script funktioner
Brug kort, dobbelt, trippel og langt tryk
Find linjen
// Doublepush (Linie 97)
Og erstat mac adressen med mac adressen på din BLU Button.
Det samme kan man henholdsvis gøre ved:
// Triplepush/> (linje 116)
// Longpush (linje 135)
Før
// Doublepush
{
cond: {
Button: 2,
addr: "3c:2e:f5:6f:77:9b",
},
action: doublePush,
},
Efter
// Doublepush
{
cond: {
Button: 2,
addr: "90:ab:96:9f:a9:fe",
},
action: doublePush,
},
Tilføje flere BLU Button tryk
Der kan nemt tilføjes flere tryk. Find linien
// Add Ekstra Singlpush Button (linje 88)
Slet /* og */
Og erstat mac adressen med mac adressen på din BLU Button.
Det samme kan man henholdsvis gøre ved:
// Add Ekstra Doublpush Button (linje 107)
// Add Ekstra Triplepush Button (linje 126)
// Add Ekstra Longpush Button (linje 145)
Før
// Add Ektra Singlepush Button
/* {
cond: {
Button: 1,
addr: "90:ab:96:9f:a9:fe",
},
action: singlePush,
},
*/
Efter
// Add Ektra Singlepush Button
{
cond: {
Button: 1,
addr: "5t:7ue:k95:0qf:33:1c",
},
action: singlePush,
},
Ændre hvilket output der skal tændes
Som standard tænder dette script altid for output 1 (Som I Shelly verdenen er id:0). Hvis du fx. har en Shelly Plus 2 og du vil have den til at tænde for udgang 2, så skal du finde
// CHANGE ID OUTPUT HERE (linje 40)
Og ændre id: 0 til id 1 ud for de forskellige tryk typer.
Output 1 =id: 0
Output 2 =id: 1
Output 3 =id: 2 <
Output 4 =id: 3 <
Før
function singlePush() {
print("Button pushed");
Shelly.call("Switch.toggle", { id: 0});
}
Efter
function singlePush() {
print("Button pushed");
Shelly.call("Switch.toggle", { id: 1});
}