Hallo
chrs1978 hat geschrieben: Freitag 21. November 2025, 10:16
Gibts für die API eine Doku ? Kann man ggf. direkt drauf zugreifen. Für meinen Prozess wäre es praktisch, wenn man die Aktoren ohne Handy / Touch schalten könnte. Ich würde mir dann einfach eine Art HVO bauen mit einem weiteren ESP, der auf Tastendruck was an die API sendet.
Oder gibts gar eine Möglichkeit, Eingänge des Bautomat ESPs mit Ausgängen zu verknüpfen ? Also z.B. wenn IO 0.1 High ist, schaltet er den Aktor HLT Pumpe ein. Als tastenden Eingang.
Eine
API doc habe ich begonnen. 99% der Routen an und vom WebServer werden über die Schnittstellen apiGET und apiPOST verarbeitet (siehe unten). Die API ist noch eine frühe alpha Version. Die Firmware fängt zwar viel ab, aber die Eingabekontrolle habe ich auf den Client ausgelagert.
Einen Input PIN oder Interrupt zur Steuerung von Aktoren bietet der Brautomat nicht und aktuell gibt es keine Planung in der Richtung. Ich verstehe aus der Beschreibung noch nicht, was Du aufbauen möchtest (was ist HVO?). Du kannst jeden Aktor über Deinen Maischeplan schalten. Oder manuell per Click bzw. Touch. Wofür einen Taster?
Innu
Code: Alles auswählen
/**
* Universelle GET-Funktion (Promise-basiert, keine Callbacks)
* Erkennt automatisch JSON oder Text
* @param {string} url - Endpoint-URL
* @param {boolean} alarm - sendAlarm aktivieren, default false
* @param {boolean} toast - toast nachricht bei fehler, default false
* @param {boolean} log - debug ausgaben auf console im browser, default false
* @returns {Promise<any>} - Antwort vom Server (JSON-Objekt oder Text)
* Beispiele:
* Standard Aufruf: apiGET('/getMisc')
* mit alarm und toast: apiGET('/getMisc', true, true)
* mit Ausgabe console.log: apiGET('/getMisc', false, false, true)
*/
async function apiGET(url, alarm = false, toast = false, log = true) {
try {
const response = await fetch(url, {
method: "GET",
cache: "default"
// cache: "no-cache"
// cache: "no-store"
});
if (!response.ok) {
throw new Error(`Error apiGET: ${response.status}`);
}
const contentType = (response.headers.get("Content-Type") || "").toLowerCase();
let data;
if (contentType.includes("application/json")) {
try {
data = await response.json();
} catch (jsonErr) {
throw new Error(`Ungültiges JSON: ${jsonErr.message}`);
}
if (log) logVerbose(`apiGET JSON: url: ${url} response:`, data);
} else {
data = await response.text();
if (log) logVerbose(`apiGET TEXT: url: ${url} response:`, data);
}
if (toastVis > 0 && alarm) {
playSound(ALARMWARNING);
}
return data;
} catch (err) {
const msg = `Error apiGET: ${url} - ${err.message}`;
if (log) logError(msg);
if (toast && toastVis > 0) {
if (alarm) { playSound(ALARMERROR); }
showToastConfirm({
title: 'Error apiGET',
content: msg,
type: 'danger',
displayTime: 20000,
autoHide: false,
buttons: [
{
content: 'close',
type: 'danger',
default: 'true'
}
]
});
}
return null;
}
}
/**
* Universelle POST-Funktion
* @param {string} url - Endpoint-URL
* @param {Object} data - Daten, die gesendet werden (josn oder txt)
* @param {boolean} alarm - sendAlarm aktivieren, default false
* @param {boolean} toast - toast nachricht bei fehler, default false
* @param {boolean} log - debug ausgaben auf console im browser, default false
* @param {"json"|"text" | "formdata"} postType - content-type für header, default json
* @param {"json"|"text"} responseType - erwarteter Rückgabewert, Nutzt response.headers.get("content-type") -> responseType wird ignoriert
* @returns {Promise<any>} - Antwort vom Server
* Beispiele:
* Standard Aufruf: apiPOST('/setMisc', obj)
* mit alarm und toast: apiPOST('/setMisc', obj, true, true)
* mit Ausgabe console.log: apiPOST('/setMisc', obj, true, true, true, "json", "text")
* Kurzversion: apiPOST('/setMisc')
*/
async function apiPOST(url, data = null, alarm = false, toast = false, log = true, postType = "json") {
try {
const headers = {
"json": { "Content-Type": "application/json" },
"text": { "Content-Type": "text/plain" },
"formdata": {} // FormData setzt selbst boundary-Header
};
if (!headers[postType]) {
throw new Error(`postType not valid: ${postType}`);
}
const options = {
method: "POST",
headers: postType === "formdata" ? undefined : headers[postType],
body: data ? (postType === "json" ? JSON.stringify(data) : data) : undefined
};
if (log) logVerbose(`apiPOST url: ${url} postType: ${postType} data: `, data);
const response = await fetch(url, options);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
// Content-Type automatisch erkennen
const contentType = response.headers.get("content-type") || "";
let result;
if (contentType.includes("application/json")) {
result = await response.json();
if (log) logVerbose(`apiPOST JSON Response [${url}] →`, result);
} else {
result = await response.text();
if (log) logVerbose(`apiPOST TEXT Response [${url}] →`, result);
}
// Alarm optional abspielen
if (typeof toastVis !== "undefined" && toastVis > 0 && alarm) {
playSound(ALARMWARNING);
}
return result;
} catch (err) {
const msg = `Error apiPOST: ${url} err: ${err.message}`;
if (log) logError(msg);
if (toastVis > 0) {
if (alarm) playSound(ALARMERROR);
if (toast && toastVis > 0) {
showToastConfirm({
title: 'Error apiPOST',
content: msg,
type: 'danger',
displayTime: 20000,
autoHide: false,
buttons: [
{
content: 'close',
type: 'danger',
default: 'true'
}
]
});
}
}
return null;
}
}