// ==UserScript==
// @name 台電網頁工具
// @namespace https://github.com/x94fujo6rpg/SomeTampermonkeyScripts
// @version 0.01
// @description 計算並顯示實際發電能力
// @author x94fujo6
// @match https://www.taipower.com.tw/tc/page.aspx?mid=206*
// ==/UserScript==
/* jshint esversion: 9 */
(async function () {
let lastest = new Date(),
hold = true;
addCss();
await addInfo(new Date(lastest));
setHold();
setInterval(() => {
let isUpdate = checkUpdate();
if (isUpdate > lastest && !hold) {
let now = new Date();
setHold();
lastest = now.getTime();
console.log(`資料更新@${getTimeString(now)}`);
addInfo(now);
}
}, 1000);
function setHold() {
hold = true;
setTimeout(() => {
hold = false;
}, 61000);
}
function getTimeString(time) {
return time.toTimeString().split(" ")[0];
}
function getHMS(time) {
return getTimeString(time).split(":");
}
function checkUpdate() {
let now = new Date(),
[h, m, s] = getHMS(now);
return ((m % 10 == 0) && (s > 10)) ? now.getTime() : false;
}
async function addInfo(time) {
let pos = document.querySelector("#main_info"),
box = document.createElement("div"),
data = await getData(),
html = [],
box_id = "usInfo",
old_box = document.getElementById(box_id);
if (old_box) old_box.remove();
box.id = box_id;
box.classList.add("usBox");
for (let [key, value] of Object.entries(data)) {
html.push(`
<div class="usLine usUnderLine">
<div class="usBold usTextL">${key.replace(/\d_/, "")}</div>
<div class="usBold usTextR">${value}</div>
</div>
`);
}
html.push(`
<div class="usLine">
<div class="usBold usTextL">單位: MW</div>
<div class="usBold usTextR">最後更新: ${getTimeString(time)}</div>
</div>
`);
box.innerHTML = html.join("");
pos.insertAdjacentElement("afterbegin", box);
}
async function getData() {
let url = "https://www.taipower.com.tw/d006/loadGraph/loadGraph/data/genary.json",
raw = await fetch(url),
parseRaw = (arr) => {
let [type, group, name, cap, gen, gen_percent, note] = arr;
type = type.match(/b>(.*)<\/b/)[1].trim();
cap = parseFloat(cap);
gen = parseFloat(gen);
note = note.trim();
if (isNaN(cap)) cap = 0;
if (isNaN(gen)) gen = 0;
return { type, name, cap, gen, note };
},
not_run = [
"歲修",
"故障",
"環保停機檢修",
"檢修",
"機組安檢",
"測試停機",
],
limit = [
"水文限制",
"燃料限制",
"環保限制",
"空污減載",
"測試運轉",
"運轉限制",
"EOH限制",
"合約限制",
"電源線限制",
"輔機檢修",
"外溫高限制",
"歲修逾排程",
"部分歲修",
"部分檢修",
"部分故障",
"友善降載減排",
],
green = [
"水力(Hydro)",
"風力(Wind)",
"太陽能(Solar)",
"抽蓄發電(Pumping Gen)",
"其它再生能源(Other Renewable Energy)",
],
offshore = [
"澎湖",
"金門",
"馬祖",
"離島",
],
data = [],
p = [],
sum_max_cap = 0,
sum_max_actual = 0,
sum_green_cap = 0,
sum_no_green_cap = 0,
sum_green_gen = 0
;
raw = await raw.json();
raw = raw.aaData;
raw.forEach(arr => {
let pp = parseRaw(arr),
{ name, cap, gen } = pp;
if (
name != "小計" &&
(cap || gen) &&
!offshore.some(t => name.includes(t))
) {
data.push(pp);
}
});
//console.log(data);
data.forEach(pp => {
p.push((async () => {
if (!not_run.some(t => t == pp.note)) {
if (limit.some(t => t == pp.note) || pp.type == "抽蓄負載(Pumping Load)") {
if (green.some(t => t == pp.type)) {
sum_green_cap += pp.gen;
sum_green_gen += pp.gen;
} else {
sum_no_green_cap += pp.gen;
}
} else {
if (green.some(t => t == pp.type)) {
sum_green_cap += pp.cap;
sum_green_gen += pp.gen;
} else {
sum_no_green_cap += pp.cap;
}
}
}
})());
});
await Promise.all(p);
sum_max_cap = sum_no_green_cap + sum_green_cap;
sum_max_actual = sum_no_green_cap + sum_green_gen;
[
sum_max_cap,
sum_green_cap,
sum_no_green_cap,
sum_green_gen,
sum_max_actual,
] = [
sum_max_cap,
sum_green_cap,
sum_no_green_cap,
sum_green_gen,
sum_max_actual,
].map(num => num = Math.floor(num));
sum_green_gen = `${sum_green_gen} (${Math.floor(sum_green_gen / sum_green_cap * 10000) / 100}%)`;
let result;
result = {
"1_總容量": sum_max_cap,
"2_總容量 (綠能僅實際發電)": sum_max_actual,
"3_容量 (非綠能)": sum_no_green_cap,
"5_容量 (綠能)": sum_green_cap,
"4_容量 (綠能-實際發電)": sum_green_gen,
};
console.log(result);
return result;
}
function addCss() {
let s = document.createElement("style");
document.head.appendChild(s);
s.textContent = `
.usBox {
display: block;
width: 50%;
margin: auto;
}
.usBold {
font-weight: bold;
font-size: large;
}
.usLine {
display: flex;
margin-bottom: 0.5rem;
}
.usUnderLine {
border-bottom: 0.1rem black solid;
border-left: 0.2rem black solid;
}
.usTextL {
position: relative;
margin: 0 auto 0 0;
padding-left: 0.25rem;
}
.usTextR {
position: relative;
margin: 0 0 0 auto;
padding-right: 0.25rem;
}
`;
}
})();