Script Shelly scripts
Track your peak demand on a demand tariff, with a daily report
Measures your home's demand in each half-hour of your tariff's peak window and sends you the day's highest through ntfy, with the highest of the last 30 days.
- Gen3
- Gen4
- Pro
// Peak demand tracker: measures your home's demand in each half-hour of your// tariff's demand window and tells your phone through ntfy each day's peak. Needs a Shelly energy meter. let CONFIG = { fromTime: "15:00", toTime: "21:00", weekdaysOnly: true, blockMin: 30, ntfyTopic: "", meterId: 0,}; // Check the clock every 20 seconds, so each block starts within the minute.let CHECK_EVERY_SEC = 20;// Days of daily peaks to keep, for the highest-in-a-month figure.let HISTORY_DAYS = 30;let KVS_KEY = "peak-demand"; let lastBoundary = "";let blockStartWh = null;let blockStartTime = "";let blockCounts = false;let dayPeak = null;let history = []; function localNow() { let s = Shelly.getComponentStatus("sys"); if (s === null || typeof s.unixtime !== "number" || s.time === null) return null; return { date: Math.floor((s.unixtime + (s.utc_offset || 0)) / 86400), time: s.time };} function minutesOf(t) { return Number(t.slice(0, 2)) * 60 + Number(t.slice(3, 5));} // 1 January 1970 was a Thursday, so day 0 is a Thursday.function isWeekend(date) { let dow = (date + 4) % 7; return dow === 0 || dow === 6;} function counts(now) { if (CONFIG.weekdaysOnly && isWeekend(now.date)) return false; return now.time >= CONFIG.fromTime && now.time < CONFIG.toTime;} function readWh() { let d = Shelly.getComponentStatus("em1data", CONFIG.meterId); if (d === null || typeof d.total_act_energy !== "number") return null; return d.total_act_energy;} function onSent(res, err) { if (err !== 0 || res.code !== 200) print("Couldn't send the report to ntfy.");} function send(msg) { print(msg); if (CONFIG.ntfyTopic === "") return; Shelly.call("HTTP.Request", { method: "POST", url: "https://ntfy.sh/" + CONFIG.ntfyTopic, body: msg, headers: { "Content-Type": "text/plain" }, timeout: 15, }, onSent);} function report(date) { history.push({ d: date, kw: dayPeak.kw }); let kept = []; let top = 0; for (let i = 0; i < history.length; i++) { if (history[i].d > date - HISTORY_DAYS) { kept.push(history[i]); if (history[i].kw > top) top = history[i].kw; } } history = kept; Shelly.call("KVS.Set", { key: KVS_KEY, value: JSON.stringify(history) }); send("Today's peak demand was " + dayPeak.kw.toFixed(2) + " kW, from " + dayPeak.from + " to " + dayPeak.to + ". Highest in the last " + HISTORY_DAYS + " days: " + top.toFixed(2) + " kW."); dayPeak = null;} function check() { let now = localNow(); // Without the clock it can't tell where the window is, so it does nothing. if (now === null) return; if (minutesOf(now.time) % CONFIG.blockMin !== 0 || now.time === lastBoundary) return; lastBoundary = now.time; let wh = readWh(); // The block that just ended: average power over it is its demand. if (blockCounts && blockStartWh !== null && wh !== null) { let kw = (wh - blockStartWh) / 1000 * 60 / CONFIG.blockMin; print("Demand " + blockStartTime + " to " + now.time + ": " + kw.toFixed(2) + " kW."); if (dayPeak === null || kw > dayPeak.kw) dayPeak = { kw: kw, from: blockStartTime, to: now.time }; } let next = counts(now); // The window has just closed: send the day's peak. if (!next && dayPeak !== null) report(now.date); blockStartWh = wh; blockStartTime = now.time; blockCounts = next;} function onLoaded(res, err) { if (err === 0 && res && typeof res.value === "string") { try { history = JSON.parse(res.value); } catch (e) { print("Couldn't read the saved peaks. Starting a new list."); } } Timer.set(CHECK_EVERY_SEC * 1000, true, check); print("Peak demand tracker started. Window " + CONFIG.fromTime + " to " + CONFIG.toTime + (CONFIG.weekdaysOnly ? " on weekdays." : " every day."));} Shelly.call("KVS.Get", { key: KVS_KEY }, onLoaded); What it does
A demand tariff charges for the highest demand you reach in a set window of the day, measured in blocks of time. Your tariff sets the window and the block length. The script reads the meter's energy counter at the start and end of each block in your window and works out the average power over it, in kilowatts. When the window closes, your phone gets the day's highest block, when it was, and the highest of the last 30 days. Seeing that the oven and the dryer landed in the same half-hour is how you learn to spread them out.
The first block after the script starts isn't counted, because it only saw part of it. Weekends are skipped if you've set weekdaysOnly, but public holidays aren't known to the script. The meter's counter moves once a minute, so a block can be off by up to a minute's use. The last 30 days are saved on the Shelly, so a restart keeps them. Until the Shelly's clock has synced, it doesn't read anything.
Install it on your Shelly
Before you install
- Check the meter and its clock
Once the meter is installed, check it shows power in the Shelly app and that the device's time zone is your own. The blocks start on the hour and the half-hour on the Shelly's clock.
- Find your demand window
Your bill or your retailer's tariff page shows the hours your demand charge applies, and whether it's weekdays only.
- Subscribe in ntfy
Install the ntfy app and subscribe to a topic name nobody would guess, such as smith-demand-4821.
Install the script
Install it on the meter.
Shelly Smart Control
- Open the device and tap Scripts
In Shelly Smart Control, open the room, then the device. Tap Scripts, the { } icon in the menu down the left.
- Tap Create new script
If the device has no scripts yet, the screen says No scripts created.
- Name it, paste the code, then tap Save
Name it peak-demand-tracker. Tap in the code area, paste the script you copied above, then tap Save (the disk icon at the top right).
- Tap the play button
The play button lights up once the script is saved. Tap it and a message says the script has been started.
- Close the editor and turn on Run on startup
Back on the Scripts screen, turn on Run on startup next to your script, so it starts again after a power cut or a firmware update.
Direct access via IP
- Open the device's web page and click Scripts
Find the IP address in the Shelly app under Device settings, then Device information, and type it into a browser on the same Wi-Fi. Click Scripts in the menu on the left.
- Click Create script
If the device has no scripts yet, the list says so.
- Name it, paste the code, then click Save
Name it peak-demand-tracker. Click in the code area, paste the script you copied above, then click Save (the disk icon above the code).
- Click Run and check the console
Run appears once the script is saved. The console under the code then prints what the script is doing.
- Turn on Run on startup
Click Scripts again and turn on Run on startup next to your script, so it starts again after a power cut or a firmware update.
After you install
- Check the console
During the window, the console prints each block's demand in kW as it ends. At the end of the window your phone gets the day's peak.
Changelog
v1.0 First release. Still need a hand?
We answer most messages within one business day. If your question is about an existing order, have your order number ready. It speeds things up.
Contact us