Nachdem ich die letzten Tage einige Tests mache konnte, bin ich mit der ersten Versions meines Scripts recht zufrieden. Ausgangslage war das Script von hardy. Da ich aber kein Fan von Blockly bin und mir die Möglichkeit fehlte, das Auto auch mal ohne Sonne vollzuladen, habe ich es in Javascript angepasst. Das Script nutzt den Telegram Adapter, um Nachrichten über den Status zu versenden und um zwischen Überschuss und voller Leistung zu wählen. Würde mich freuen, wenn ihr es ausprobiert und bei Bedarf mit mir zusammen optimiert.
var stateTimer, timerDreiphasig, timerStop, overageList, pvOverage, overageSum, pvOverageKWh, timeout, socLevelLast, maxSocLevel, currentP1, currentP2, currentP3, overageCurrent, chargerOPmode, smartCharge;
// ### Wallbox Garage ###
timerDreiphasig = 0; // Timer für Start für dreiphasiges Laden
timerStop = 0; // Timer für Ladestop, wenn zu wenig Leistung von der PV-Anlage
const reservePower = 200; // Leistung die für den Haushalt reserviert bleibt
overageList = []; // Array für den gleitenden Mittelwert
const scheduleInterval = 12; // Aktualisierungsintervall in Sekunden
// ----------------------------------------------------------------------------------------------
// Funktion zum Anlegen und Beschreiben eines Datenpunkts
// ----------------------------------------------------------------------------------------------
function ForceSetState(objectname, value, options)
{
if (!existsState(objectname)) createState(objectname, value, options);
else setState(objectname, value);
}
// ----------------------------------------------------------------------------------------------
// Funktion: Message über Telegram
// ----------------------------------------------------------------------------------------------
function Telegram (sText, sValue, blPing, blQuestion)
{
if (blQuestion)
{
sendTo('telegram.0',
{
text: sText + sValue,
disable_notification: blPing,
reply_markup:
{
keyboard:
[
['Volle Power', 'Überschuss'],
],
resize_keyboard: true,
one_time_keyboard: true
}
});
const Sleep = setInterval(()=>
{
// Warten auf eine Auswahl des Lademodus
on({id: "javascript.0.Wallbox.Garage.Überschussladen", change: "any"}, async function (obj)
{
clearInterval(Sleep);
});
},300000);
}
else
{
sendTo('telegram.0',
{
text: sText + sValue,
disable_notification: blPing,
});
}
};
// ----------------------------------------------------------------------------------------------
// Easee und VW Adapter neustarten falls offline
// ----------------------------------------------------------------------------------------------
on({id: "easee.0.info.connection", change: "lt"}, async function (obj)
{
var value = obj.state.val;
(function () {if (timeout) {clearTimeout(timeout); timeout = null;}})();
timeout = setTimeout(function ()
{
if (!value)
{
setState("system.adapter.easee.0.alive", false);
setStateDelayed("system.adapter.easee.0.alive", true, 5000, false);
}
}, 20000);
});
on({id: "system.adapter.easee.0.connected", change: "lt"}, async function (obj)
{
var value = obj.state.val;
(function () {if (timeout) {clearTimeout(timeout); timeout = null;}})();
timeout = setTimeout(function ()
{
if (!value)
{
setState("system.adapter.easee.0.alive", false);
setStateDelayed("system.adapter.easee.0.alive", true, 5000, false);
}
}, 20000);
});
on({id: "vw-connect.0.info.connection", change: "ne"}, async function (obj)
{
var value = obj.state.val;
(function () {if (timeout) {clearTimeout(timeout); timeout = null;}})();
timeout = setTimeout(function ()
{
if (!value)
{
setState("system.adapter.vw-connect.0.alive", false);
setStateDelayed("system.adapter.vw-connect.0.alive", true, 5000, false);
}
}, 20000);
});
on({id: "system.adapter.vw-connect.0.connected", change: "ne"}, async function (obj)
{
var value = obj.state.val;
(function () {if (timeout) {clearTimeout(timeout); timeout = null;}})();
timeout = setTimeout(function ()
{
if (!value)
{
setState("system.adapter.vw-connect.0.alive", false);
setStateDelayed("system.adapter.vw-connect.0.alive", true, 5000, false);
}
}, 20000);
});
// ----------------------------------------------------------------------------------------------
// Führt die Abfrage in regelmäßigen Zeitabständen durch
// ----------------------------------------------------------------------------------------------
schedule(`*/${scheduleInterval} * * * * *`, async function ()
{
stateTimer++;
// Variablen einlesen
socLevelLast = getState("Datenpunkt.AktuellerBatteriestand").val;
maxSocLevel = getState("Datenpunkt.ZielBatteriestand").val;
currentP1 = getState("easee.0.XXXXXXXX.config.dynamicCircuitCurrentP1").val;
currentP2 = getState("easee.0.XXXXXXXX.config.dynamicCircuitCurrentP2").val;
currentP3 = getState("easee.0.XXXXXXXX.config.dynamicCircuitCurrentP3").val;
chargerOPmode = getState("easee.0.XXXXXXXX.status.chargerOpMode").val;
smartCharge = getState("javascript.0.Wallbox.Garage.Überschussladen").val;
// ----------------------------------------------------------------------------------------------
// PV Überschuss ermitteln = Import/Export - Offset + aktuelle Leistung Wallbox
// ----------------------------------------------------------------------------------------------
pvOverage = Math.round((parseFloat(getState("Datenpunkt.AktuellerÜberschuss").val) - reservePower) + parseFloat(getState("easee.0.XXXXXXXX.status.totalPower").val) * 1000);
console.log('PV Überschuss = ' + pvOverage);
// Gleitender Mittelwert innerhalb 3 Minuten berechnen, gerundet auf 100er
overageList.unshift(pvOverage);
if (overageList.length > 180/scheduleInterval)
{
overageSum = overageList.reduce(function(x, y) {return x + y;});
pvOverageKWh = Math.round(parseFloat(overageSum) / overageList.length);
overageCurrent = Math.round(pvOverageKWh / getState("easee.0.XXXXXXXX.status.voltage").val);
overageList.pop();
// Logging
ForceSetState("javascript.0.Wallbox.Garage.pvOverageKWh", pvOverageKWh, {name: "", unit: "kWh"});
console.log(('Überschuss Leistung gemittelt = ' + String(pvOverageKWh)));
console.log(('Überschuss Strom gemittelt = ' + String(overageCurrent)));
}
// ----------------------------------------------------------------------------------------------
// Timer 3-phasig laden: Erhöhe den Timer sekundengenau, wenn PV-Überschuss >18 Ampere
// ----------------------------------------------------------------------------------------------
if (socLevelLast < maxSocLevel && overageCurrent >= 18)
{
timerDreiphasig = (typeof timerDreiphasig == 'number' ? timerDreiphasig : 0) + scheduleInterval;
console.log((['Timer 3-phasig = ',timerDreiphasig,'Sekunden'].join('')));
}
// Andernfalls Timer zurücksetzen
else timerDreiphasig = 0;
// ----------------------------------------------------------------------------------------------
// Timer Ladeabbruch: Erhöhe den Timer sekundengenau, wenn PV-Überschuss <6 Ampere
// ----------------------------------------------------------------------------------------------
if (overageCurrent < 6)
{
timerStop = (typeof timerStop == 'number' ? timerStop : 0) + scheduleInterval;
console.log((['Timer Ladeabbruch = ',timerStop,'Sekunden'].join('')));
}
// Andernfalls Timer zurücksetzen
else timerStop = 0;
// ----------------------------------------------------------------------------------------------
// Wenn Überschussladen aktiviert ist
// ----------------------------------------------------------------------------------------------
if (smartCharge == true)
{
console.debug(('Überschussladen ist aktiv' + ''));
// 1-phasig laden: Wenn PV Überschuss größer als minimale Ladeleistung für eine Phase und kleiner als minimale Ladeleistung für drei Phases
if (socLevelLast < maxSocLevel && overageCurrent >= 6 && (overageCurrent < 18 || timerDreiphasig < 300))
{
console.log((['Einphasiges Laden mit ',overageCurrent,' Ampere'].join('')));
setState("easee.0.XXXXXXXX.config.dynamicChargerCurrent", 16);
setState("easee.0.XXXXXXXX.config.dynamicCircuitCurrentP1", overageCurrent);
setState("easee.0.XXXXXXXX.config.dynamicCircuitCurrentP2", 0);
setState("easee.0.XXXXXXXX.config.dynamicCircuitCurrentP3", 0);
}
// 3-phasig laden: Wenn PV Überschuss 5 Minuten konstant größer als 18 Ampere war
if (timerDreiphasig >= 300)
{
console.log((['Dreiphasiges Laden mit ',Math.round(overageCurrent / 3),' Ampere'].join('')));
setState("easee.0.XXXXXXXX.config.dynamicChargerCurrent", 16);
setState("easee.0.XXXXXXXX.config.dynamicCircuitCurrentP1", Math.round(overageCurrent / 3));
setState("easee.0.XXXXXXXX.config.dynamicCircuitCurrentP2", Math.round(overageCurrent / 3));
setState("easee.0.XXXXXXXX.config.dynamicCircuitCurrentP3", Math.round(overageCurrent / 3));
}
// Stoppe Laden, wenn nach 5 Minuten nicht genug PV-Überschuss vorhanden ist. Stoppe Timeout wenn während 5 Minuten doch wieder genug PV-Überschuss vorhanden ist
if (timerStop >= 60 && currentP1 > 0)
{
console.warn(('Pausiere Laden, weil kein PV-Überschuss' + ''));
setState("easee.0.XXXXXXXX.config.dynamicChargerCurrent", 16);
setState("easee.0.XXXXXXXX.config.dynamicCircuitCurrentP1", 0);
setState("easee.0.XXXXXXXX.config.dynamicCircuitCurrentP2", 0);
setState("easee.0.XXXXXXXX.config.dynamicCircuitCurrentP3", 0);
//setState("easee.0.XXXXXXXX.control.pause", true);
//setState("easee.0.XXXXXXXX.control.stop", true);
}
}
// ----------------------------------------------------------------------------------------------
// Wenn Laden mit voller Leistung aktiv ist
// ----------------------------------------------------------------------------------------------
else
{
console.debug('Dreiphasiges Laden mit voller Leistung');
setState("easee.0.XXXXXXXX.config.dynamicChargerCurrent", 16);
setState("easee.0.XXXXXXXX.config.dynamicCircuitCurrentP1", 16);
setState("easee.0.XXXXXXXX.config.dynamicCircuitCurrentP2", 16);
setState("easee.0.XXXXXXXX.config.dynamicCircuitCurrentP3", 16);
}
});
// ----------------------------------------------------------------------------------------------
// Trigger beim Einstecken des Ladekabels
// ----------------------------------------------------------------------------------------------
on({id: "easee.0.XXXXXXXX.status.chargerOpMode", change: "ne"}, async function (obj)
{
var value = obj.state.val;
var oldValue = obj.oldState.val;
stateTimer = 0;
// Ladekabel wurde angeschlossen
if (oldValue == 1)
{
console.warn(('Ladekabel wurde an das Fahrzeug angeschlossen' + ''));
Telegram("Der Akkustand beträgt: ", socLevelLast, false, true);
}
// Ladekabel wurde entfernt
if (value == 1)
{
console.warn(('Ladekabel wurde vom Fahrzeug getrennt' + ''));
Telegram("Ladekabel wurde vom Fahrzeug getrennt. Der Akkustand beträgt: ", socLevelLast, false, false);
}
// Auto angeschlossen, aber lädt nicht
if (value == 2)
{
console.log(('Ladevorgang gestoppt. Wallbox bereits zum Laden' + ''));
Telegram("Ladevorgang gestoppt. Wallbox bereit zum Laden. Der Akkustand beträgt: ", socLevelLast, false, false);
if (currentP1 > 0 && maxSocLevel > socLevelLast)
{
if (smartCharge == true) console.warn(('PV Überschussladen gestartet' + ''));
else console.warn(('Laden mit voller Leistung gestartet' + ''));
//setState("easee.0.XXXXXXXX.control.resume", true);
setState("easee.0.XXXXXXXX.control.start", true);
Telegram("Ladevorgang gestartet.", "", false, false);
}
else if (maxSocLevel <= socLevelLast)
{
console.log(('Ladevorgang gestoppt. Ladeziel erreicht' + ''));
Telegram("Ladevorgang gestoppt. Ladeziel erreicht. Der Akkustand beträgt: ", socLevelLast, false, false);
}
}
if (value == 4)
{
console.log(('Ladevorgang gestoppt. Batterie vollgeladen' + ''));
Telegram("Ladevorgang gestoppt. Batterie vollgeladen.", "", false, false);
}
if (value == 5)
{
console.log(('Ladevorgang gestoppt. Es ist ein Fehler aufgetreten' + ''));
Telegram("Ladevorgang gestoppt. Es ist ein Fehler aufgetreten. Der Akkustand beträgt: ", socLevelLast, false, false);
}
});
// ----------------------------------------------------------------------------------------------
// Wenn Auto bis Sonnenuntergang nicht geladen, fragen ob über Netz vollgeladen werden soll
// ----------------------------------------------------------------------------------------------
schedule({astro: "sunset", shift: 0}, async function ()
{
if (maxSocLevel > socLevelLast && chargerOPmode != 1)
{
Telegram("Der Akkustand beträgt: ", socLevelLast, true, false);
}
});