Moin,
da ich mir viele Inspirationen und Hilfe hier im Forum durchs Lesen von Userbeiträgen geholt habe wollte ich nun auch mal mein bisher längstes/größtes Skript hier veröffentlichen.
Es ist eine Bewässerungssteuerung, die die zu erwartende Tageshöchsttemperatur bei Accuweather abfragt und je nach Ergebnis in 3 Staffelungen die Bewässerungsdauer abends schaltet. Das Skript läuft auf einem der derzeit 2 eingesetzten Shelly Pro 2, der zweite Shelly auf der anderen Hausseite wird übers Netzwerk mit angesteuert (ohne eigenes Skript). So kann man bis zu 4 Ventile (Pro Ausgang 1) theoretisch ansteuern. Zur Funktion: Morgens Temperaturabfrage, zur Abendzeit gibts ne Meldung per SIGNAL aufs Handy, dass man (wenn bewässert werden soll) gefälligst den Garten aufräumen soll, um 21Uhr beginnt dann die Bewässerung mit unterschiedlichen Schaltzeiten nach Tageshöchsttemperatur. An dem Shelly ist noch ein Taster angeschlossen (Einstellung im Setup natürlich als unabhängiger Eingang, ohne direkte Verknüpfung zum Ausgang), mit dem man manuell ein- und ausschalten kann. Tastendruck < 2 Sek. einfaches ein- und ausschalten ohne Zeitsteuerung, drückt man länger als 3 Sek. wird für eine pauschale Zeitlänge eingeschaltet und geht dann wieder automatisch aus (spart für Faule wie mich den zweiten Gang zum Taster ein bzw. die Kids wissen, wenn Wasser aus, dann Wasserspiele vorbei
). Wenn manuell bewässert wurde, wird nicht nochmal extra automatisch bewässert. Das Ein-/Aus Verhalten wird über die Abfrage des ersten Schaltausgangs realisiert, so dass man die automatische Bewässerung auch abbrechen kann, ohne dass man Laufzeitmerker o.ä. mitschleppen muss.
Das Skript ist sicherlich nicht perfekt, da JavaSkript nicht meine primäre Programmiersprache ist, da gibt es noch Verbesserungspotential, auch die Fehlerabsicherung ist alles andere als ausgereift. Auch die gestaffelte Bewässerungsdauer könnte man optimieren, derzeit ist nur ein Start zur ganzen Stunde +58min Laufzeit möglich. Kann man ändern, indem man dann bei Minuten > 60 die Std erhöht und die Minuten entsprechend ausrechnet - war ich aber zu faul für, das es für mich ausreicht und die Bewässerung nicht dynamisch 8 Minuten nach Sonnenuntergang angehen muss ![]()
Viel Spaß damit, wer (Teile) davon als Inspiration verwenden mag
// Bewaesserungs-Script fuer 2(+) Shelly (Master-Slave Verbund)
// Manuell Ein/Aus (Tastendruck kurz), Automatik-Ein fuer Zeit X nach 3.Sek-Tastendruck, Voll-Automatik nach Temperaturstaffelung fuer Zeit X+n
// Benachrichtigungssystem über SIGNAL ueber geplante Bewaesserung
// Max S. - Nov. 2025
// IP Master: 192.168.178.150 (Garten Westseite)
// IP SLAVE 1: 192.168.178.151 (Garten Ostseite)
// IP SLAVE 2: 192.168.178.152 (Erweiterung extern)
// http://dataservice.accuweather.com/forecasts/v1/daily/1day/ <location> ?apikey= <api_key> &details=true&metric=true
// 02:01 Uhr: RESET vars etc.
// 10:01 Uhr: Abfrage zu erwartende Tageshoechsttemperatur ueber *Accuweather*
// 18:01 Uhr: Meldung *Garten aufraeumen, Bewaesserung startet um XY fuer N Minuten*
// 21:01 Uhr: Bewaesserung EIN, wenn nicht vorher manuell bewaessert wurde (egal wie lange, EIN reicht)
let CONFIG = {
accuWeatherAPIKEY: "api_key",
weatherForecastEndpoint: "http://dataservice.accuweather.com/forecasts/v1/daily/1day/ <location> ",
// Max
phone_number: "<phone_number> ",
sigAPIkey: " <sig_api_key> ",
RESET_HOUR: 2, // 2
RESET_MINUTE: 1, // 1
REQUEST_HOUR: 10, // 10
REQUEST_MINUTE: 1, // 1
INFO_HOUR: 18, // 18
INFO_MINUTE: 30, // 30
START_WATERING_HOUR: 21, // 21
START_WATERING_MINUTE: 1, // 1 - muss 1 sein fuer Bewaesserungszeit <=58min
END_WATERING_MINUTE: 1, // 1 - gleich wie Start zum rechnen
START_TEMP_1: 25, // 25
WATER_DURATION_1: 15, // 15
START_TEMP_2: 30, // 31
WATER_DURATION_2: 30, // 30
START_TEMP_3: 34, // 34
WATER_DURATION_3: 45, // 45
WATER_MANU_DURATION: 30, // 30 - 3Sek. Druck
WATER_WAS_ON: 0, // 0
FINAL_WATER_DURATION: 0, // 0
WATER_PLANNED_ON: 0, // 0
MaxTempExpectValue: 0, // 0
TEXT_BEWAESSERUNG_A: "Garten+aufraeumen:+Bewaesserung+startet+um+21Uhr+fuer+",
TEXT_BEWAESSERUNG_B: "min+nach+",
TEXT_BEWAESSERUNG_C: "Grad+Tageshoechsttemperatur",
//alle 60 Sekunden Check der Tageszeit
checkInterval: 1000 * 60,
pressStart: 0,
};
function getWeatherURLForLocation() {
return (
CONFIG.weatherForecastEndpoint + "?apikey=" + CONFIG.accuWeatherAPIKEY + "&details=true&metric=true"
);
}
function activateSwitch(activate) {
Shelly.call("Switch.Set", { id: 0, on: activate });
Shelly.call("Switch.Set", { id: 1, on: activate });
Shelly.call("http.get", {url: "http://192.168.178.151/rpc/Switch.Set?id=0&on=" + activate }, function (response, error_code, error_message) {});
Shelly.call("http.get", {url: "http://192.168.178.151/rpc/Switch.Set?id=1&on=" + activate }, function (response, error_code, error_message) {});
//Shelly.call("http.get", {url: "http://192.168.178.152/rpc/Switch.Set?id=0&on=" + activate }, function (response, error_code, error_message) {});
}
function MaxTempExpected() {
//console.log("Starte Wetterdatenabfrage");
Shelly.call("http.get", { url: getWeatherURLForLocation() }, function (response, error_code, error_message) {
let weatherData = JSON.parse(response.body);
CONFIG.MaxTempExpectValue = weatherData.DailyForecasts[0].Temperature.Maximum.Value;
//console.log("Erwartete Tageshoechsttemperatur: ", CONFIG.MaxTempExpectValue, " Grad");
if (CONFIG.MaxTempExpectValue >= CONFIG.START_TEMP_1) {
CONFIG.FINAL_WATER_DURATION = CONFIG.WATER_DURATION_1;
CONFIG.WATER_PLANNED_ON = 1;
CONFIG.END_WATERING_MINUTE = CONFIG.START_WATERING_MINUTE + CONFIG.FINAL_WATER_DURATION;
};
if (CONFIG.MaxTempExpectValue >= CONFIG.START_TEMP_2) {
CONFIG.FINAL_WATER_DURATION = CONFIG.WATER_DURATION_2;
CONFIG.WATER_PLANNED_ON = 1;
CONFIG.END_WATERING_MINUTE = CONFIG.START_WATERING_MINUTE + CONFIG.FINAL_WATER_DURATION;
};
if (CONFIG.MaxTempExpectValue >= CONFIG.START_TEMP_3) {
CONFIG.FINAL_WATER_DURATION = CONFIG.WATER_DURATION_3;
CONFIG.WATER_PLANNED_ON = 1;
CONFIG.END_WATERING_MINUTE = CONFIG.START_WATERING_MINUTE + CONFIG.FINAL_WATER_DURATION;
};
//console.log("Bewaesserung: ", CONFIG.WATER_PLANNED_ON, ", Dauer: ", CONFIG.FINAL_WATER_DURATION, " bei ", CONFIG.MaxTempExpectValue, " Grad");
}
);
}
Timer.set(CONFIG.checkInterval, true, function () {
let dnow = new Date();
let std = dnow.getHours();
let min = dnow.getMinutes();
// Werte Zuruecksetzen
if (std == CONFIG.RESET_HOUR) {
if (min == CONFIG.RESET_MINUTE) {
//console.log("Setze Werte zurueck");
CONFIG.WATER_PLANNED_ON = 0;
CONFIG.WATER_WAS_ON = 0;
CONFIG.MaxTempExpectValue = 0;
CONFIG.FINAL_WATER_DURATION = 0;
};
};
// Temperaturabfrage
if (std == CONFIG.REQUEST_HOUR) {
if (min == CONFIG.REQUEST_MINUTE) {
//console.log("Pruefe das Wetter");
MaxTempExpected();
};
};
// Nachricht vorab senden wenn bewaessert werden soll
if (std == CONFIG.INFO_HOUR) {
if (min == CONFIG.INFO_MINUTE) {
if (CONFIG.WATER_PLANNED_ON == 1) {
//console.log("Sende Info-Nachricht");
let message = CONFIG.TEXT_BEWAESSERUNG_A + CONFIG.FINAL_WATER_DURATION + CONFIG.TEXT_BEWAESSERUNG_B + CONFIG.MaxTempExpectValue + CONFIG.TEXT_BEWAESSERUNG_C
//console.log("Nachricht: " + sig_url_1 + message);
let sig_url_1 = "https://signal.callmebot.com/signal/send.php?phone=" + CONFIG.phone_number + "&apikey=" + CONFIG.sigAPIkey + "&text=";
//let sig_url_2 = "https://signal.callmebot.com/signal/send.php?phone=" + CONFIG.phone_number2 + "&apikey=" + CONFIG.sigAPIkey + "&text=";
//let sig_url_3 = "https://signal.callmebot.com/signal/send.php?phone=" + CONFIG.phone_number3 + "&apikey=" + CONFIG.sigAPIkey + "&text=";
Shelly.call("http.get", {url:sig_url_1 + message,timeout:30});
//Shelly.call("http.get", {url:sig_url_2 + message,timeout:30});
//Shelly.call("http.get", {url:sig_url_3 + message,timeout:30});
};
};
};
// Wasser Marsch wenn vorher nicht manuell bewaessert wurde
if (CONFIG.WATER_WAS_ON == 0 && CONFIG.WATER_PLANNED_ON == 1) {
if (std == CONFIG.START_WATERING_HOUR) {
if (min == CONFIG.START_WATERING_MINUTE) {
//console.log("Starte Auto-Bewaesserung nach Zeit und Dauer");
activateSwitch(true);
};
};
};
if (std == CONFIG.START_WATERING_HOUR) {
if (min == CONFIG.END_WATERING_MINUTE) {
//console.log("Beende Auto-Bewaesserung nach Zeit und Dauer");
activateSwitch(false);
};
};
});
Shelly.addEventHandler(function (event) {
if (event.component === "input:0") {
//console.log("Event erkannt:", JSON.stringify(event));
// Taster wird gedrueckt
if (event.info.state == true) {
CONFIG.pressStart = Shelly.getComponentStatus("sys").uptime || 0;
//console.log("Taste gedrückt (Startzeit:", CONFIG.pressStart, ")");
}
// Taster wird los gelassen
if (event.info.state == false) {
let pressEnd = Shelly.getComponentStatus("sys").uptime || 0;
let pressDuration = pressEnd - CONFIG.pressStart;
//console.log("Taste losgelassen (Dauer:", pressDuration, "Sekunden)");
if (pressDuration >= 3) {
// Wasser geplant fuer bestimmte Zeit WATER_MANU_DURATION ein. Kein weiterer geplanter Start nach Uhrzeit mehr
CONFIG.WATER_WAS_ON = 1;
CONFIG.WATER_PLANNED_ON = 0;
activateSwitch(true);
//console.log("Bewaesserung nach 3Sek.Druck AUTO-EIN fuer ", CONFIG.WATER_MANU_DURATION, " min");
timer = Timer.set(CONFIG.WATER_MANU_DURATION * 60 * 1000, false, function () {
activateSwitch(false);
timer = null;
//console.log("Bewaesserung nach 3Sek.Druck AUTO-AUS nach ", CONFIG.WATER_MANU_DURATION, " min");
});
} else {
if (pressDuration <= 2) {
// Abfrage, ob Ausgang aktuell EIN oder AUS ist, Variablen setzen
Shelly.call("http.get", { url: "http://127.0.0.1/rpc/Shelly.GetStatus", timeout: 2}, function(result) {
if (result.code === 200) {
let status = JSON.parse(result.body);
if (status["switch:0"].output == false) {
//console.log("Geraet war AUS -> EIN");
//Einschalten
CONFIG.WATER_WAS_ON = 1;
CONFIG.WATER_PLANNED_ON = 0;
activateSwitch(true);
} else {
//console.log("Geraet war EIN -> AUS");
activateSwitch(false);
}
} else {
console.log("Fehler beim Abrufen des Geraetestatus EIN/AUS");
}
});
}
};
};
};
});
Alles anzeigen