Automate for dynamic pricing

I’ve done some reading the last week but think I need help. Maybe someone knows a Thread this was allready tackled. All I’ve found automates for solar production.

I want to find the optimal time to start for example the dishwasher, wich uses most power at the beginning and end of its programm.
Was thinking about an array with typical energy consumption in 10 min intervalls. I then could approximate the cost for starting at 10:00, 10:10, 10:20 and so on and use the cheapest time to start.

But I really do not know how I would programm this in Home Assistant.

Best case someone allready did this :smiley:

But if not, can someone push me in the right direction, how I would tackle such automation?

Don’t really want to only search for the cheapest hour.

Update:
I’ve started the endeavour using node red and the function node with javaScript.

Really had to chew on handling times in javaScript…
BUT I have a working flow to save the energy prices as JSON in a .txt and a flow to calculate the cheapest start time.

If I’m able to finish this I will try and document it, but for now I will leave my progress here for people finding this googling.

And the two functions:
Function 2

//Daten aus Flow lesen
var profil = msg.payload.energieprofil;
var preise = msg.payload.strompreise;

// Die nächsten vollen zehn Minuten finden
var startZeit = new Date()
var minuten = startZeit.getMinutes();
minuten = Math.ceil(minuten / 10) * 10;
startZeit.setMinutes(minuten);
startZeit.setSeconds(0);
startZeit.setMilliseconds(0);

//Dauer des Programms ermitteln
var dauerProgrammMinuten = profil.length * 10;

//Spätesten Startpunkt finden
var letzteUhrzeit = preise[(preise.length - 1)].start_time;
var letzterStartUnix = Date.parse(letzteUhrzeit);
var letzterStart = new Date(letzterStartUnix);
letzterStart.setMinutes(60 - dauerProgrammMinuten);

//Kosten für jede Startzeit ermitteln
var index = 0;
var output = [];
while((startZeit.getTime())<=(letzterStart.getTime())){
    
    //Kosten für einen Durchlauf ermitteln
    var zeitPunkt = new Date(startZeit);
    var positionInPreisliste = 0;
    var kosten = 0;
    

    //Aktuelle position in Preisliste bestimmen
    var zeit_puffer = preise[0].start_time
    zeit_puffer = new Date(zeit_puffer)
    while((zeitPunkt.getTime()) > (zeit_puffer.getTime())){
        positionInPreisliste++;
        zeit_puffer = preise[positionInPreisliste].start_time
        zeit_puffer = new Date(zeit_puffer)
    }
    if((zeitPunkt.getMinutes()) != 0){
        positionInPreisliste = positionInPreisliste -1;
        zeit_puffer = preise[positionInPreisliste].start_time
        zeit_puffer = new Date(zeit_puffer)
    }

    //Energieprofil durchgehen und Einzelpreise addieren
    for(var i = 0; i < profil.length; i++){
        //Position in Preisliste wechseln falls nötig
        if((zeitPunkt.getTime()) >= (zeit_puffer.getTime()+3600000)){
            positionInPreisliste++;
            zeit_puffer = preise[positionInPreisliste].start_time
            zeit_puffer = new Date(zeit_puffer)
        }
        zeitPunkt.setMinutes(zeitPunkt.getMinutes()+10);
        kosten = kosten + (profil[i].wh * preise[positionInPreisliste].price / 1000);
        kosten = Math.round(kosten * 10000)/10000;
    }

    //Endzeit berechnen
    var endZeit = new Date(startZeit);
    endZeit.setMinutes(endZeit.getMinutes() + dauerProgrammMinuten)

    var obj = new Object();
    obj.start_time =new Date(startZeit);
    obj.end_time = new Date(endZeit);
    obj.price = kosten;

    output[index] = obj;
    index++;

    startZeit.setMinutes(startZeit.getMinutes()+10);
}
msg.payload = output;
return msg;

And Function 3

var test = msg.payload;
var teuer = test[0].price;
var billig = test[0].price;
var puffer = 0;
var indexbilligster = 0;
for( let i=1; i < test.length; i++){
    puffer = test[i].price;
    if(puffer > teuer){
        teuer = puffer;
    }
    if(puffer < billig){
        billig = puffer;
        indexbilligster = i;
    }
}

msg.payload = teuer;
node.send(msg);
msg.payload = billig;
node.send(msg);

msg.payload = test[indexbilligster];
return msg;