Independant scripts for Shelly Pro 2PM

  • Hi,

    I am installing Shelly Pro 2PM smart switch in order to control the Water heater (on channel 1) and floor heating (on channel 2) operations separately.

    The idea is that the script fetches the next day electricity spot prices in Finland which are published everyday at about 15:00.

    After this, for example in the water heater case, it looks for the cheapest 3h period between 23:00 and 07:00 and turns the water heater ON during that time.

    The same thing is repeated for floor heating but the heating period is 4h.

    Can the two scripts be added to Shelly Pro 2PM so that their operations do not interfere with each other and each script acts independently without effecting the other one?

    Below is the script if it is any help (written by Lari Lohikoski, https://elspotcontrol.netlify.app/):

    // https://elspotcontrol.netlify.app/

    // This version: 18.1.2023


    // Find the time from time period starting here and lasting this many hours

    let period_start = 23;

    let period_length = 8;


    // If period_start refers to this hour today, this should be 0. If the it is tomorrow, it must be 1.

    let period_day = 0;


    // Request cheapest hours for this length. Set this to typical length needed for f. ex. water heater.

    let needed_length = 3;


    // Turn off after this many hours. May be good to keep this longer than needed_length, as

    // f. ex. heating water may sometimes take longer

    let turn_off_hours = 5;


    // If fetching prices fails, use these schedules. Crontab format

    let defaultstart = "0 1 2 * * SUN,MON,TUE,WED,THU,FRI,SAT";

    let defaultend = "0 1 7 * * SUN,MON,TUE,WED,THU,FRI,SAT";


    // Maximum average hourly price. If hourly price is higher than this, do not turn switch on!

    // This setting still sets the schedule, but sets switch off both on start and stop.

    // If you want, you can manually then turn the scheduled time on.

    // By default, and if you do not want to uset this, set this very high.

    // The price is EUR per megawatthour, not including taxes! So eg. for a price of 50c/kWH, use 500

    let max_avg_price = 999999;


    // Crontab for running this script. Good to keep this way

    // This means that this script is run at random moment during the first 15 minutes after 18.00

    // Random timing is used so that all clients wouldn't be polling the server exactly at same time

    let minrand = JSON.stringify(Math.floor(Math.random() * 15));

    let secrand = JSON.stringify(Math.floor(Math.random() * 60));

    let script_schedule = secrand+" "+minrand+" "+"18 * * SUN,MON,TUE,WED,THU,FRI,SAT";

    print(script_schedule);


    // Number for this script. If this doesn't work (as in earlier versions), get it from this url (use your own ip) http://192.168.68.128/rpc/Script.List

    let script_number = Shelly.getCurrentScriptId();


    // You can check the schedules here (use your own ip) http://192.168.68.128/rpc/Schedule.List


    function maybe_over_midnight(hour) {

    if (hour>24) {

    return hour-24;

    }

    else {

    return hour;

    }

    }


    function find_cheapest(result) {

    print("HTTP response is", result);

    if (result === null) {

    updateSchedules(defaultstart, defaultend, true);

    }

    else {

    print("Finding cheapest hours");


    let prices = JSON.parse(result.body);


    let hourly_prices = prices["hourly_prices"];

    let num = 0;


    let cheapest_period = {};

    cheapest_period["period_price"] = 999999999999;


    for (let i = period_start; i < period_start + period_length; i++) {


    let hour = i;


    if (i >= 24) {

    hour = hour - 24;

    period_day = 1;

    }


    let hr = JSON.stringify(period_day)+"."+JSON.stringify(hour);


    hourly_prices[hr]["period_price"] = 0;


    for (let a = 0; a < needed_length; a++) {

    let ah = hour + a;

    let ahday=period_day;

    if (ah >= 24) { ah = ah - 24; ahday=1; }

    let ahh = JSON.stringify(ahday)+"."+JSON.stringify(ah);

    hourly_prices[hr]["period_price"] = hourly_prices[hr]["period_price"] + hourly_prices[ahh]["price"];

    }


    if (hourly_prices[hr]["period_price"] < cheapest_period["period_price"]) {

    cheapest_period = hourly_prices[hr];

    cheapest_period["hour"] = hour;

    print("cheapest");

    }


    print(hour, hourly_prices[hr]["time"], hourly_prices[hr]["price"], hourly_prices[hr]["period_price"]);


    }

    print("Cheapest hour", cheapest_period["time"], cheapest_period["period_price"], "average",

    cheapest_period["period_price"] / needed_length)


    // Set the timers

    let timespec = "0 0 " + JSON.stringify(cheapest_period["hour"]) + " * * SUN,MON,TUE,WED,THU,FRI,SAT";

    let offspec = "0 0 " + JSON.stringify(maybe_over_midnight(cheapest_period["hour"] + turn_off_hours)) + " * * SUN,MON,TUE,WED,THU,FRI,SAT";


    // Check the avg price if the switch should or should not be turned on.

    let turn_on=true;


    if (cheapest_period["period_price"] / needed_length > max_avg_price) {

    print("Turning off!");

    turn_on=false;

    }


    updateSchedules(timespec, offspec, turn_on);

    }

    }


    function updateSchedules(timespec, offspec, turn_on) {


    print(Shelly.call("Schedule.DeleteAll"));


    print(Shelly.call("Schedule.Create", {

    "id": 0, "enable": true, "timespec": timespec,

    "calls": [{

    "method": "Switch.Set",

    "params": {

    id: 0,

    "on": turn_on

    }

    }]

    }

    ));


    print(Shelly.call("Schedule.Create", {

    "id": 0, "enable": true, "timespec": offspec,

    "calls": [{

    "method": "Switch.Set",

    "params": {

    id: 0,

    "on": false

    }

    }]

    }

    ));


    // Schedule for the script itself

    print(Shelly.call("Schedule.create", {

    "id": 3, "enable": true, "timespec": script_schedule,

    "calls": [{

    "method": "Script.start",

    "params": {

    "id": script_number

    }

    }]

    }));


    //Stop this script in one minute from now

    Timer.set(60 * 1000, false, function () {

    print("Stopping the script");

    Shelly.call("Script.stop", { "id": script_number })

    });


    }


    function updateTimer() {

    print("Starting, fetching hourly prices");

    Shelly.call("HTTP.GET", { url: "https://elspotcontrol.netlify.app/spotprices-v01-FI.json", timeout:60, ssl_ca:"*"}, find_cheapest);

    }


    updateTimer();

  • First of all, please use the Code Formats feature of the forum, with this your code would look much clearer.

    Then to your problem, you have 2 scripts that both work with schedule's jobs and want to know if they get in each other's way?

    Up to 3 scripts can run in parallel on a Shelly, as long as they are not switching the same devices, I see no problem.