LoRa Add-on
Shelly
Description
Download Signed DDF
min. OS version: 10384-07
Mit diesem DDF können Shelly-Geräte mit LoRa-Addon eingebunden werden, wobei jeweils ein Ein- und Ausgang genutzt werden kann. Hinweis: Beachten Sie die regional geltenden Vorschriften zur LoRa-Nutzung. Ein Shelly mit LoRa-Addon wird im selben IP-Netzwerk wie der myGEKKO-Controller betrieben. Er dient als LoRa-Master-Gateway und kommuniziert mit weiteren Shelly-Geräten (Slaves) über LoRa.
Verbinden Sie sich über 192.168.33.1 mit dem WLAN-Access-Point des Shelly, verbinden Sie ihn anschließend mit dem WLAN und führen Sie bei Bedarf ein Firmware-Update durch. Getestet mit 2.0.0-beta1.
Shelly Master (Gateway im WLAN)
- Script
lora_master.jserstellen und aktivieren - Run on startup aktivieren
- LoRa Add-on aktivieren
- LoRa transport layer Device Address:
0001(HEX) - User LoRa calls aktivieren
Skript-Code: lora_master.js
let lastByAddr = {};
function nowIso() {
return new Date().toISOString();
}
function nowUnix() {
return Math.floor(Date.now() / 1000);
}
// Shelly-safe Query Parser (KEIN decodeURIComponent!)
function parseQuery(qs) {
let out = {};
if (!qs) return out;
let parts = qs.split("&");
for (let i = 0; i < parts.length; i++) {
let kv = parts[i].split("=");
let key = kv[0];
let val = kv.length > 1 ? kv[1] : "";
if (key) out[key] = val;
}
return out;
}
Shelly.addEventHandler(function (ev) {
if (!ev || !ev.info) return;
let addr = ev.info.lr_addr || ev.info.addr || ev.info.sender;
let data = ev.info.data;
if (addr === undefined || data === undefined) return;
addr = String(addr);
try {
data = JSON.parse(atob(String(data)));
} catch (e) {
try {
data = atob(String(data));
} catch (e2) {
data = String(data);
}
}
lastByAddr[addr] = {
addr: addr,
data: data,
rssi: ev.info.rssi,
snr: ev.info.snr,
received: nowIso(),
received_unix: nowUnix()
};
print("LoRa empfangen: " + addr);
});
HTTPServer.registerEndpoint("lora", function (req, res) {
let query = parseQuery(req.query);
let addr = query.addr;
if (!addr) {
res.code = 400;
res.headers = [["Content-Type", "application/json"]];
res.body = JSON.stringify({ error: "addr fehlt" });
res.send();
return;
}
let result = lastByAddr[String(addr)];
if (!result) {
res.code = 404;
res.headers = [["Content-Type", "application/json"]];
res.body = JSON.stringify({ error: "nicht gefunden", addr: addr });
res.send();
return;
}
res.code = 200;
res.headers = [["Content-Type", "application/json"]];
res.body = JSON.stringify(result);
res.send();
});
print("Endpunkt aktiv: /script//lora?addr=");
Shelly Slave (LoRa Endgeräte)
- Script
lora_slave.jserstellen und aktivieren - Run on startup aktivieren
- LoRa transport layer Device Address:
0002(HEX) – erstes Gerät0003bis000F(HEX) – weitere Slaves
- User LoRa calls aktivieren
Skript-Code: lora_slave.js
let LORA_ID = 100;
let LORA_ADDR = "00000001";
let OUTPUT_ID = 0;
let di = 0;
let doo = 0;
let last = "";
function send(force) {
// Status als Array senden
let msg = JSON.stringify([di, doo]);
if (!force && msg === last) return;
last = msg;
console.log("SENDE:", msg);
Shelly.call("LoRa.Send", {
id: LORA_ID,
lr_addr: LORA_ADDR,
data: btoa(msg)
}, function (res, err, msg) {
if (err !== 0) {
console.log("LoRa Fehler:", err, msg);
}
});
}
function startPeriodicSend() {
// alle 15 Minuten ein Status-Heartbeat
Timer.set(15 * 60 * 1000, true, function () {
send(true);
});
}
function handleCommand(rawPayload) {
let payload = rawPayload;
// Falls data base64-kodiert ankommt, dekodieren
try {
payload = atob(rawPayload);
} catch (e) {
// wenn nicht base64, dann rawPayload direkt verwenden
}
console.log("LoRa RX raw:", rawPayload, "decoded:", payload);
if (payload === "1" || payload === "ON" || payload === "true") {
Shelly.call("Switch.Set", { id: OUTPUT_ID, on: true }, function (res, err, msg) {
console.log("Switch.Set ON -> err:", err, "msg:", msg);
});
} else if (payload === "0" || payload === "OFF" || payload === "false") {
Shelly.call("Switch.Set", { id: OUTPUT_ID, on: false }, function (res, err, msg) {
console.log("Switch.Set OFF -> err:", err, "msg:", msg);
});
} else {
console.log("Unbekannter Payload:", payload);
}
}
Shelly.addEventHandler(function (ev) {
if (ev.name !== "lora") return;
if (!ev.info) return;
if (ev.info.component !== "lora:100") return;
if (ev.info.event !== "user_rx") return;
handleCommand(ev.info.data);
});
Shelly.addStatusHandler(function (e) {
if (!e || !e.component || !e.delta) return;
if (e.component === "input:0" && e.delta.state !== undefined) {
di = e.delta.state ? 1 : 0;
send(false);
}
if (e.component === "switch:0" && e.delta.output !== undefined) {
doo = e.delta.output ? 1 : 0;
send(false);
}
});
// einmaliger zufälliger Startversatz
var startDelay = Math.floor(Math.random() * 15 * 60 * 1000);
console.log("Start in", startDelay, "ms");
Timer.set(startDelay, false, function () {
send(true);
startPeriodicSend();
});
console.log("LoRa Kombi-Skript gestartet");
DeviceStation
- Domain:
http://<IP_Shelly_Master> - Slave-Adressen:
1,2, ... ,15
System „Gerät“
- Je Shelly einen Baustein anlegen und Dashboard wählen
- Als Widgets auf Startseite oder Räume/Bereiche verknüpfen
System „Licht“ oder „Steckdose“
- Schaltausgang:
SET Output - Rückmeldung:
State Output
General Info
| Manufacturer | Type | Protocol | Model | Version | ID |
|---|---|---|---|---|---|
| Shelly | Gateway | REST-API (DDF) | 2 | 1 | 0x0D00002D00020100 |
Documents
No documents.