Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Variables used by Scriptable.
- // These must be at the very top of the file. Do not edit.
- // icon-color: deep-blue; icon-glyph: calculator;
- /*
- Electricity consumption widget for Slovenian users.
- */
- // parameter in format MEASURING_POINT|API_TOKEN
- let param = args.widgetParameter ? args.widgetParameter.split('|') : null;
- if (param === null || param.length !== 2) {
- param = [
- '2-11111',
- '604APITOKENfa'
- ]
- }
- const measuringPoint = param[0];
- const apiToken = param[1];
- const minPowerConsumption = 3.8
- const blocks = {
- T00_06: {
- duration: '22h - 6h',
- weekdays: { ht: 3, lt: 4 },
- weekends: { ht: 4, lt: 5 }
- },
- T06_07: {
- duration: '6h - 7h',
- weekdays: { ht: 2, lt: 3 },
- weekends: { ht: 3, lt: 4 }
- },
- T07_14: {
- duration: '7h - 14h',
- weekdays: { ht: 1, lt: 2 },
- weekends: { ht: 2, lt: 3 }
- },
- T14_16: {
- duration: '14h - 16h',
- weekdays: { ht: 2, lt: 3 },
- weekends: { ht: 3, lt: 4 }
- },
- T16_20: {
- duration: '16h - 20h',
- weekdays: { ht: 1, lt: 2 },
- weekends: { ht: 2, lt: 3 }
- },
- T20_22: {
- duration: '20h - 22h',
- weekdays: { ht: 2, lt: 3 },
- weekends: { ht: 3, lt: 4 }
- },
- T22_24: {
- duration: '22h - 6h',
- weekdays: { ht: 3, lt: 4 },
- weekends: { ht: 4, lt: 5 }
- }
- }
- const slovenian_holidays = [
- '-01-01', // Novo leto
- '-01-02', // Novo leto
- '-02-08', // Prešernov dan
- '-04-27', // Dan upora proti okupatorju
- '-05-01', // Praznik dela
- '-05-02', // Praznik dela
- '-06-25', // Dan državnosti
- '-08-15', // Marijino vnebovzetje
- '-10-31', // Dan reformacije
- '-11-01', // Dan spomina na mrtve
- '-12-25', // Božič
- '-12-26' // Dan samostojnosti in enotnosti
- ]
- let easter_monday = function(year) {
- let a = year % 19;
- let b = Math.floor(year / 100);
- let c = year % 100;
- let d = Math.floor(b / 4);
- let e = b % 4;
- let f = Math.floor((b + 8) / 25);
- let g = Math.floor((b - f + 1) / 3);
- let h = (19 * a + b - d - g + 15) % 30;
- let i = Math.floor(c / 4);
- let k = c % 4;
- let l = (32 + 2 * e + 2 * i - h - k) % 7;
- let m = Math.floor((a + 11 * h + 22 * l) / 451);
- let month = Math.floor((h + l - 7 * m + 114) / 31);
- let day = ((h + l - 7 * m + 114) % 31) + 1;
- return new Date(year, month - 1, day + 1);
- }
- low_tariff_months_start = 3
- low_tariff_months_end = 10
- let holidays = slovenian_holidays.map(holiday => {
- return new Date(new Date().getFullYear() + holiday)
- })
- holidays.push(easter_monday(new Date().getFullYear()))
- if (config.runsInWidget) {
- const size = config.widgetFamily;
- const widget = await createWidget(size);
- Script.setWidget(widget);
- Script.complete();
- } else {
- // For debugging
- const size = 'small';
- //const size = 'medium'
- //const size = 'large'
- const widget = await createWidget(size);
- if (size == 'small') {
- widget.presentSmall();
- } else if (size == 'medium') {
- widget.presentMedium();
- } else {
- widget.presentLarge();
- }
- Script.complete();
- }
- async function createWidget(size) {
- let prev_dates = {
- fromDate: new Date(new Date(new Date().getFullYear(), new Date().getMonth() - 1, 1).setHours(12,0,0,0)).toISOString().split("T")[0],
- toDate: new Date(new Date(new Date().getFullYear(), new Date().getMonth(), 0).setHours(12,0,0,0)).toISOString().split("T")[0]
- }
- let curr_dates = {
- fromDate: new Date(new Date(new Date().getFullYear(), new Date().getMonth(), 1).setHours(12,0,0,0)).toISOString().split("T")[0],
- toDate: new Date(new Date(new Date().getFullYear(), new Date().getMonth() + 1, 0).setHours(12,0,0,0)).toISOString().split("T")[0]
- }
- const pData = await fetchData(measuringPoint, apiToken, prev_dates.fromDate, prev_dates.toDate);
- const cData = await fetchData(measuringPoint, apiToken, curr_dates.fromDate, curr_dates.toDate);
- const prev_data = formatData(pData);
- const curr_data = formatData(cData);
- if (curr_data === undefined) {
- const widget = new ListWidget();
- widget.addText('404 - data not found');
- return widget;
- }
- if (size != 'small') {
- const widget = new ListWidget();
- widget.addText('size currently not supported');
- return widget;
- }
- const widget = new ListWidget();
- let nextRefresh = Date.now() + 1000 * 60 * 60 * 1; // 1hour
- widget.refreshAfterDate = new Date(nextRefresh);
- widget.setPadding(10, 15, 15, 15); // top, leading, bot, trailing
- const gradient = new LinearGradient()
- gradient.locations = [0, 1]
- gradient.colors = [
- new Color('#034078'),
- new Color('#022A50')
- ]
- widget.backgroundGradient = gradient
- const contentStack = widget.addStack();
- contentStack.layoutVertically();
- // Main info section with large total price
- const primaryInfo = contentStack.addStack();
- primaryInfo.layoutHorizontally();
- let boltImage = primaryInfo.addImage(SFSymbol.named("bolt.fill").image);
- boltImage.tintColor = new Color('#FFD700');
- boltImage.imageSize = new Size(35, 35);
- primaryInfo.addSpacer();
- prev_total = calculateTotal(prev_data)
- curr_total = calculateTotal(curr_data)
- const priceInfoBox = primaryInfo.addStack();
- priceInfoBox.layoutVertically();
- priceInfoBox.centerAlignContent();
- const p_priceBox = priceInfoBox.addText(`${prev_total.toFixed(2)} €`);
- p_priceBox.font = Font.regularRoundedSystemFont(12);
- p_priceBox.minimumScaleFactor = 0.75;
- p_priceBox.textColor = Color.white();
- p_priceBox.shadowColor = new Color("#000000", 0.3);
- p_priceBox.shadowRadius = 2;
- p_priceBox.shadowOffset = new Point(2, 2);
- p_priceBox.rightAlignText();
- // priceInfoBox.addSpacer();
- const priceBox = priceInfoBox.addText(`${curr_total.toFixed(2)} €`);
- priceBox.font = Font.boldRoundedSystemFont(20);
- priceBox.minimumScaleFactor = 0.75;
- priceBox.textColor = Color.white();
- priceBox.shadowColor = new Color("#000000", 0.3);
- priceBox.shadowRadius = 2;
- priceBox.shadowOffset = new Point(2, 2);
- priceBox.rightAlignText();
- contentStack.addSpacer();
- // block data
- for (let block_number of ['1', '2', '3', '4', '5']) {
- const pBlock = prev_data[block_number];
- const block = curr_data[block_number];
- const blockStack = contentStack.addStack();
- blockStack.layoutHorizontally();
- blockStack.centerAlignContent();
- const blockName = blockStack.addText(block.name);
- blockName.font = Font.regularRoundedSystemFont(12);
- blockName.textColor = Color.white();
- blockName.shadowColor = new Color("#000000", 0.3);
- blockName.shadowRadius = 2;
- blockName.shadowOffset = new Point(2, 2);
- blockName.leftAlignText();
- blockStack.addSpacer();
- const p_blockPrice = blockStack.addText(pBlock.priceValue ? pBlock.priceValue.toFixed(1) + ' kW' : '');
- p_blockPrice.font = Font.regularRoundedSystemFont(12);
- p_blockPrice.textColor = Color.white();
- p_blockPrice.shadowColor = new Color("#000000", 0.3);
- p_blockPrice.shadowRadius = 2;
- p_blockPrice.shadowOffset = new Point(2, 2);
- p_blockPrice.rightAlignText();
- blockStack.addSpacer();
- const blockPrice = blockStack.addText(block.priceValue ? block.priceValue.toFixed(1) + ' kW' : '');
- blockPrice.font = Font.boldRoundedSystemFont(14);
- blockPrice.textColor = Color.white();
- blockPrice.shadowColor = new Color("#000000", 0.3);
- blockPrice.shadowRadius = 2;
- blockPrice.shadowOffset = new Point(2, 2);
- blockPrice.rightAlignText();
- }
- // // Refresh date
- // const dateStack = contentStack.addStack();
- // const date = dateStack.addText(`🔄 ${resort.date}`);
- // date.font = Font.systemFont(10);
- // date.textColor = Color.white();
- return widget;
- }
- // Helper functions
- async function fetchData(measuringPoint, apiToken, fromDate, toDate) {
- // dates in format YYYY-MM-DD
- let url = "https://api.informatika.si/mojelektro/v1/meter-readings?"
- + "option=ReadingType%3D32.0.2.4.1.2.37.0.0.0.0.0.0.0.0.3.38.0"
- + `&usagePoint=${measuringPoint}`
- + `&startTime=${fromDate}&endTime=${toDate}`
- let req = new Request(url)
- req.headers = {
- "X-API-TOKEN": apiToken,
- "Content-Type": "application/json"
- }
- let jsonData = await req.loadJSON()
- return jsonData.intervalBlocks[0].intervalReadings
- }
- function calculateTotal(data) {
- // calculate total price
- let total = 0
- for (let block of Object.values(data)) {
- total += block.priceValue * block.price
- }
- total += 0.99
- total = total * 1.22
- return total
- }
- function formatData(readings) {
- // summarize readings into block data
- let blocks = {
- "1": { name: "B1", color: "#ED1D1D", price: 3.42250, priceValue: minPowerConsumption, maxValue: 0 },
- "2": { name: "B2", color: "#F05000", price: 0.91224, priceValue: minPowerConsumption, maxValue: 0 },
- "3": { name: "B3", color: "#FFB03A", price: 0.16297, priceValue: minPowerConsumption, maxValue: 0 },
- "4": { name: "B4", color: "#2D808B", price: 0.00407, priceValue: minPowerConsumption, maxValue: 0 },
- "5": { name: "B5", color: "#2C232B", price: 0.00000, priceValue: minPowerConsumption, maxValue: 0 }
- }
- for (let reading of readings) {
- let blockNumber = getBlockNumberForReading(reading)
- blocks[blockNumber].maxValue = Math.max(blocks[blockNumber].maxValue, parseFloat(reading.value))
- blocks[blockNumber].priceValue = Math.max(blocks[blockNumber].priceValue, parseFloat(reading.value))
- }
- // if previous block has higher max value than current block,
- // set current block max value to previous block max value
- let previousBlock = null
- for (let block of Object.values(blocks)) {
- if (previousBlock) {
- block.priceValue = Math.max(block.priceValue, previousBlock.priceValue)
- }
- previousBlock = block
- }
- let month = new Date().getMonth()
- let isLowTariff = month >= low_tariff_months_start && month <= low_tariff_months_end;
- // if low tariff is active remove block 1
- if (isLowTariff) {
- // delete blocks["1"]
- blocks["1"].maxValue = 0
- blocks["1"].priceValue = 0
- } else {
- // delete blocks["5"]
- blocks["5"].maxValue = 0
- blocks["5"].priceValue = 0
- }
- return blocks
- }
- function getBlockNumberForReading(reading) {
- let reading_time = new Date(reading.timestamp)
- let hour = reading_time.getHours()
- let date = reading_time.getDate()
- let month = reading_time.getMonth()
- let day = reading_time.getDay()
- let isWeekend = day == 0 || day == 6
- let isHoliday = holidays.some(holiday => holiday.getMonth() == month && holiday.getDate() == date)
- let tariff = month >= low_tariff_months_start && month <= low_tariff_months_end ? 'lt' : 'ht'
- let block_name = Object.keys(blocks).find(block => {
- let start = parseInt(block.split('_')[0].split('T')[1]);
- let end = parseInt(block.split('_')[1]);
- return hour >= start && hour < end;
- })
- return isWeekend || isHoliday ? blocks[block_name].weekends[tariff] : blocks[block_name].weekdays[tariff];
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement