Ich habe mal ein Skript gebaut, welches eine funktionierende Anwesenheitserkennung auf einem beliebigen Gen 2 Shelly realisiert.
Die Erkennung basiert darauf, dass die Geräte (z.B. Handys) sich im Wlan ein/ausloggen, in dem sich der Shelly mit dem Skript befindet.
Das Skript ist getestet und macht genau, was es soll. Sollte es Probleme geben, basiert das auf Fehlern in eurem Netz, oder falschen Eintragungen in der Config.
Z.B. brachte bei mir in einem AVM-Netz mit vielen Mesh-Repeatern das Update auf FRITZOS 7.57 eine entscheidende Verbesserung des Netzwerkes.
Voraussetzung ist ein Gen2 Shelly mit guter Wlan/Lan Versorgung und (WICHTIG) der FW 1.0.3.
Ich erkläre mal die Funktions- und Vorgehensweise:
Als erstes sollte man dafür sorgen, dass die Handys eine feste IP im Netz haben und das Wlan fehlerfrei funktioniert.
Alle Ips der Handys werden in der Config unter ips in den eckigen Klammern und in Anführungszeichen durch Kommata getrennt eingetragen. Als nächstes werden exakt gleich viele Namen, nach dem selben Schema in names eingetragen.
(Die Anzahl muss unbedingt gleich der Anzahl der IP-Adressen sein.)
Die Reihenfolge bestimmt die Zuordnung Ip zu Name. (Je mehr Ips, desto träger funktioniert die Erkennung)
Das Skript gibt in der Konsole die An/Abwesenheiten der Handys im Netz mit den Namen aus.
Außerdem reagiert das Skript auf zwei verschiedene Arten:
1.) Jemand oder keiner zu Hause.
Wenn das letzte im Wlan eingebuchte Handy das Netz verlässt, wird die unter last_user_out_action angegebene URL (einmalig) aufgerufen.
Umgekehrt wird, wenn sich das erste Handy wieder in das Wlan einbucht, die URL unter first_user_in_action (einmalig) aufgerufen.
Für einen ersten Test, können dort erst einmal leere Anführungszeichen angegeben werden.
2.) Individueller User kommt / geht.
Jedem Handy kann eine individuell URL zugeordnet werden, die ausgelöst wird, wenn das Handy sich ein-, bzw. ausbucht. Die Anzahl MUSS genau
so groß sein, wie die Anzahl der in ips angegebenen Ips. Die Reihenfolge bestimmt die Zuordnung.
Für den ersten Test kann man auch hier leere Anführungszeichen verwenden.
Hier ein Beispiel der Config für einen ersten Test mit 3 Usern:
//############################## Config ############################
let Config = {
ips: ["172.16.0.193", "172.16.0.199", "172.16.0.132"],
names: ["Peter", "Paul", "Marie"],
first_user_in_action : "",
last_user_out_action : "",
user_action_online : ["",
"",
""],
user_action_offline : ["",
"",
""],
timeout : 1,
verbose : false,
buffer : 30
}
Display More
So startet man dann einen ersten Test und schaut, ob An/Abwesenheiten richtig erkannt werden.
timeout gibt an, wie lange auf eine Antwort vom Handy gewatet wird, verbose bestimmt, wie gesprächig das Skript in der Konsole ist.
buffer sagt aus, wie lange ein Handy nicht mehr "gesehen" werden muss, damit es als offline erkannt wird.
Das dient dazu, das zum Beispiel ein schneller Wechsel des Handys von einem Repeater zum nächsten nicht gleich als Abwesenheit erkannt wird.
Wenn alles läuft, dann könnt ihr die Action-URLs füllen und testen.
Ideen für den Einsatz des Skriptes (Heizung, Licht, Alarm...) überlasse ich euch.
Noch ein Tipp (Dank an @De kat ) Das Handy wird schneller erkannt, wenn man unter Entwickleroptionen
die Option Drosselung der Wlan Suche ausschaltet (Android). Apple fasse ich nicht an
Hier das Skript:
//GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007
//More information: https://www.gnu.org/licenses/gpl-3.0.txt
//ABSOLUTELY NO WARRANTY!!!
//Made by Ostfriese
//############################## Config ############################
let Config = {
ips: ["172.16.0.193", "172.16.0.199", "172.16.0.132", "172.16.0.153","172.16.0.185"],
names: ["Peter", "Paul", "Marie", "Otto", "Willy"],
first_user_in_action : "http://172.16.0.102/relay/0?turn=on",
last_user_out_action : "http://172.16.0.52/relay/0?turn=off",
user_action_online : ["http://172.16.0.48/relay/0?turn=on&timer=25",
"http://172.16.0.59/relay/0?turn=on&timer=5",
"",
"",
""],
user_action_offline : ["",//"http://172.16.0.100/relay/0?turn=off",
"",//"http://172.16.0.10/relay/0?turn=off",
"",
"",
""],
timeout : 1,
verbose : false,
buffer : 30
}
//############################## Config end ############################
let busy = false;
let users_online_array = [];
let offline_buffer_array = [];
let empty_house = true;
let i = 0;
function log(to_log) {
if(Config.verbose) {
print(to_log);
}
}
function count_absent() {
// count absent users
false_count = 0;
for(let k = 0; k < Config.ips.length; k++) {
if(users_online_array[k] === false) {
false_count += 1;
}
}
// if all users are absent
if(false_count === Config.ips.length) {
log("Config.last_user_out_action :", Config.last_user_out_action);
// call last_user_out_action
Shelly.call("http.get", {url: Config.last_user_out_action, timeout: Config.timeout});
// set house to empty
empty_house = true;
return;
}
// if house was empty
if (empty_house) {
log("Config.first_user_in_action :", Config.first_user_in_action);
// call first_user_in_action
Shelly.call("http.get", {url: Config.first_user_in_action, timeout: Config.timeout});
// set house to 'someone in'
empty_house = false;
}
}
// find next index
function iterate_index() {
if(i < Config.ips.length - 1) {
i += 1;
return;
}
i = 0;
}
function ping() {
try {
// return if already busy
if (busy === true) {
return;
}
busy = true;
ip = Config.ips[i];
// do a ping
Shelly.call("http.get", {url: ip, timeout: Config.timeout},
function(result, error_code, error_message) {
if(error_message === "-1: Connection error: -14") {;
// check if status changed from absent to present
if(users_online_array[i] === false || users_online_array[i] === '') {
print(Config.names[i], "online");
log("Config.user_action_online[" + i + "] :", Config.user_action_online[i]);
// call specific user action for present
Shelly.call("http.get", {url: Config.user_action_online[i], timeout: Config.timeout});
// set user to present in users_online_array
users_online_array[i] = true;
// check how much users present
count_absent();
}
users_online_array[i] = true;
offline_buffer_array[i] = Shelly.getComponentStatus("sys").unixtime;
// get index of next user
iterate_index();
busy = false;
return;
}
// check if user offline for longer than buffer seconds
t = Shelly.getComponentStatus("sys").unixtime - offline_buffer_array[i];
if((users_online_array[i] === true && t > 60) || users_online_array[i] === '') {
print(Config.names[i], "offline");
log("Config.user_action_offline[" + i + "] :", Config.user_action_offline[i]);
// call specific user action for absent
Shelly.call("http.get", {url: Config.user_action_offline[i], timeout: Config.timeout});
// set user to absent in users_online_array
users_online_array[i] = false;
// check how much users absent
count_absent();
}
// get index of next user
iterate_index();
busy = false;
return;
})
// catch errors
} catch(err) {
busy = false;
}
}
// set ping timer
function start() {
Timer.set(10,true,ping);
}
// set all users to absent
for(let j = 0; j < Config.ips.length; j++) {
users_online_array.push('');
offline_buffer_array.push(Shelly.getComponentStatus("sys").unixtime);
//print(Config.names[j], "offline");
}
// wait 1 second before start to avoid error after reboot
Timer.set(1000,false,start);
Display More