//////////////////////////////////////////////////////////////////////
// Copyright (C) SUGIMURA Lab. 2022.08.30
// ECHONET Lite関係
//////////////////////////////////////////////////////////////////////
'use strict'
////////////////////////////////////////////////////////////////////////////////
// HTMLロードしたら準備
/**
* @namespace subEL
*/
window.addEventListener('DOMContentLoaded', function () {
console.log('## DOMContentLoaded subEL.js');
let facilitiesEL; // デバイスリスト EL
// config tab
let inELUse = document.getElementById('inELUse'); // check box; use or not
let inELUseOldSearch = document.getElementById('inELUseOldSearch'); // check box; use old search or not
let btnELConfigSet = document.getElementById('btnELConfigSet'); // 設定ボタン
let ELSettingsContents = document.getElementById('ELSettingsContents'); // dialog
// control tab
let H2ControlEL = document.getElementById('H2ControlEL');
let divControlEL = document.getElementById('divControlEL');
let divDetails = document.getElementById('divDetails_content'); // details
let divELSuggest = document.getElementById('divELSuggest'); // 使用していない時のサジェスト
let toIP = document.getElementById('toIP');
let eltestSEOJ = document.getElementById('eltestSEOJ');
let eltestDEOJ = document.getElementById('eltestDEOJ');
let eltestESV = document.getElementById('eltestESV');
let eltestEPC = document.getElementById('eltestEPC');
let eltestDETAILs = document.getElementById('eltestDETAILs');
let elsend = document.getElementById('elsend');
let multicastSearch = document.getElementById('multicastSearch');
let txtELLog = document.getElementById('txtELLog');
// サブメータのグラフ関連
let facilitiesSubESM; // サブメータのデータだけ
let divSubESMH3 = document.getElementById('divSubESMH3'); // サブメータのH3タイトル
divSubESMH3.style.display = 'none'; // 初期値非表示
let divSubESM = document.getElementById('divSubESM'); // サブメータのセンサデータ
divSubESM.style.display = 'none'; // 初期値非表示
let canSubEnergyChart = document.getElementById('canSubEnergyChart'); // エネルギーチャート
canSubEnergyChart.style.display = 'none'; // 初期値非表示
let inUserAmpere = document.getElementById('inUserAmpere'); // 契約アンペア
//----------------------------------------------------------------------------------------------
/**
* @func
* @memberof window
* @desc EL デバイス情報のrenew、mainからの情報で,EL関係のhtmlを変更する
* @param {void}
* @return {void}
*/
window.renewFacilitiesEL = function (arg) { // facilitiesEL = json = arg; // 機器情報確保
txtELLog.value = JSON.stringify(arg, null, ' ');
facilitiesEL = arg; // 機器情報確保
if (!inELUse.checked) { // 機能無効
// console.log('-- inELUse.checked', inELUse.checked);
return;
}
// 機能有効
if (!facilitiesEL || isObjEmpty(facilitiesEL)) { // 機器情報なし
// console.log('-- facilitiesEL', facilitiesEL);
doc = '<div class="p"><img src="./img/loadingRed.gif">接続中</div>';
divControlEL.innerHTML = doc;
return; // 機器情報なければやらない、存在も消す
}
let IPs = facilitiesEL.IPs;
// -------------------------------------------------
// controlタブ
let doc = ''; // Controlのタブ内に書かれる文字
IPs.forEach((ip) => {
// console.log('-- IP', ip);
let EOJs = facilitiesEL[ip].EOJs;
EOJs.forEach((eoj) => {
// console.log('-- IP', ip, 'EOJ', eoj);
try {
let obj = eoj.split(/\(|\)/); // マルかっこで分割
if (obj[1] === '0ef001') { return; } // Node Profileはコントローラとしては無視, eachではcontinueではなくreturn
doc += "<div class='LinearLayoutChild'> <section>"
+ `<span id='ELSettingsButton' class='fa-solid fa-gear el-settings-btn' onclick='window.ELSettings("${ip}", "${eoj}");'> </span>`
+ window.createControlELButton(facilitiesEL, ip, eoj)
+ "</section> </div>"; // ボタン設置
} catch (error) {
console.error('Error: subEL.window.renewFacilitiesEL() control tab, error:', error);
console.error('ip:', ip, 'eoj:', eoj);
detailDoc += '</dl></td></tr>';
}
});
});
divControlEL.innerHTML = doc;
// -------------------------------------------------
// detailsタブ
let detailDoc = ""; // Detailsのタブ内に書かれる文字
IPs.forEach((ip) => {
detailDoc += "<h2>" + ip + "</h2>";
detailDoc += "<table border=0 class='el-details'>";
let EOJs = facilitiesEL[ip].EOJs;
EOJs.forEach((eoj) => {
try {
let obj = eoj.split(/\(|\)/); // (と)で分割
// icon
detailDoc += "<tr><td class='opc'><img src=\"./img/" + obj[1].substring(0, 2) + ".png\" width=50 /><br />" + obj[0] + "</td>";
detailDoc += '<td class="edt">\n<dl>';
// EDT
let EPCs = facilitiesEL[ip][eoj].EPCs;
EPCs.forEach((epc) => {
detailDoc += "<dt>" + epc + "</dt><dd>" + facilitiesEL[ip][eoj][epc] + "</dd>\n";
});
detailDoc += '</dl></td></tr>';
} catch (error) {
console.error('Error: subEL.window.renewFacilitiesEL() details tab error:', error);
console.error('ip:', ip, 'eoj:', eoj);
detailDoc += '</dl></td></tr>';
}
});
detailDoc += "</table>";
});
divDetails.innerHTML = detailDoc;
// もしサブメータがあれば
for (let ip of IPs) {
for (let eoj of facilitiesEL[ip].EOJs) {
if (eoj == 'スマート電力量サブメータ01(028d01)') {
window.renewSubESM(facilitiesEL[ip]);
}
}
}
}
//----------------------------------------------------------------------------------------------
/**
* @func window.btnELConfigSet_Click
* @desc ECHONET Lite Config
* @param {void}
* @return {void}
*/
window.btnELConfigSet_Click = function () {
console.log('window.btnELConfigSet_Click() inELUse:', inELUse.checked);
btnELConfigSet.disabled = false;
btnELConfigSet.textContent = '設定';
// EL use or not
if (inELUse.checked == false) {
window.ipc.ELStop(); // ELをstopする
facilitiesEL = {};
divControlEL.innerHTML = '';
} else {
window.ipc.ELUse();
}
// old search or not
if (inELUseOldSearch.checked == false) {
window.ipc.ELStopOldSearch(); // ELをstopする
} else {
window.ipc.ELUseOldSearch();
}
};
/**
* @func window.ELConfigSaved
* @desc 設定完了通知
* @param {void}
* @return {void}
*/
window.ELConfigSaved = function () {
btnELConfigSet.disabled = false;
btnELConfigSet.textContent = '設定';
window.addToast('Info', 'EL 設定を保存しました。');
};
/**
* @func window.renewELConfigView
* @desc mainプロセスから設定値をもらったので画面を更新
* @param {void}
* @return {void}
*/
window.renewELConfigView = function (arg) {
inELUse.checked = arg.enabled;
inELUseOldSearch.checked = arg.oldSearch;
btnELConfigSet.disabled = false;
btnELConfigSet.textContent = '設定';
if (arg.enabled) { // 利用する場合
H2ControlEL.style.display = 'block';
divControlEL.style.display = '-webkit-flex';
divELSuggest.style.display = 'none';
} else { // 利用しない場合
H2ControlEL.style.display = 'none';
divControlEL.style.display = 'none';
divELSuggest.style.display = 'block';
}
};
//----------------------------------------------------------------------------------------------
/**
* @type {HTMLElement}
* @listens multicastSearch#click
* @event multicastSearch#click
* @desc ECHONET Lite Conntrol, マルチキャストボタン
*/
multicastSearch.addEventListener('click', function () {
window.ipc.ELsearch();
});
//----------------------------------------------------------------------------------------------
// サブメータ関連
/**
* @func convRT
* @desc R相、T相を数値に
* @memberof subEL
* @param {void}
* @return {void}
*/
let convRT = function (str) {
let n = str.split('[')[0];
return parseFloat(n).toFixed(2);
};
/**
* @fires window.renewSubESM
* @desc window.renewSubESM
* @param {void}
* @return {void}
*/
window.renewSubESM = function (arg) {
console.log('window.renewSubESM() arg:', arg);
facilitiesSubESM = arg;
if (Object.keys(facilitiesSubESM).length === 0) { // 利用していない場合はSuggestを表示
divSubESM.innerHTML = '';
return;
}
// 利用している場合はタイトルと概要を表示
divSubESMH3.style.display = 'block';
divSubESM.style.display = 'block';
let esmDoc = "<div class='LinearLayoutParent'>";
for (let eoj of arg.EOJs) {
if (eoj == 'スマート電力量サブメータ01(028d01)') {
let obj = arg[eoj];
esmDoc += `<section> <div class='tooltip'><img src='./img/electric.png' class='esm-icon'/><div class='description'>設置場所: ${obj['設置場所(81)']} 
 
 Version: ${obj['規格Version情報(82)']}</div></div><br>`;
esmDoc += `<div class='LinearLayoutChild_Env'> <section class='watt_color' id='subesmDocWattSec'><i class="fa-solid fa-bolt"></i> <small>瞬時電力</small><br>${arg.Means['瞬時電力計測値[W]']} W</section></div>`;
if (obj['瞬時電流計測値(E8)']) {
let amp = JSON.parse(obj['瞬時電流計測値(E8)'].split('(')[0]);
esmDoc += `<div class='LinearLayoutChild_Env'> <section class='ampereR_color' id='subesmDocAmpereRSec'><i class="fa-solid fa-bolt"></i> <small>瞬時電流R相</small><br>${convRT(amp.RPhase)} A</section></div>`;
esmDoc += `<div class='LinearLayoutChild_Env'> <section class='ampereT_color' id='subesmDocAmpereTSec'><i class="fa-solid fa-bolt"></i> <small>瞬時電流T相</small><br>${convRT(amp.TPhase)} A</section></div>`;
} else {
esmDoc += `<div class='LinearLayoutChild_Env'> <section class='ampereR_color' id='subesmDocAmpereRSec'><i class="fa-solid fa-bolt"></i> <small>瞬時電流R相</small><br>取得中 A</section></div>`;
esmDoc += `<div class='LinearLayoutChild_Env'> <section class='ampereT_color' id='subesmDocAmpereTSec'><i class="fa-solid fa-bolt"></i> <small>瞬時電流T相</small><br>取得中 A</section></div>`;
}
esmDoc += `<div class='LinearLayoutChild_Env'> <section class='comWattNorm_color' id='subesmDocComWattNormSec'><i class="fa-solid fa-bolt"></i> <small>積算電力量(正)</small><br>`
+ `${parseFloat(arg.Means['積算電力量計測値(正方向計測値)[kWh]']).toFixed(2)} kWh</section></div>`;
esmDoc += `<div class='LinearLayoutChild_Env'> <section class='comWattRev_color' id='subesmDocComWattRevSec'> <i class="fa-solid fa-bolt"></i> <small>積算電力量(逆)</small><br>`
+ `${parseFloat(arg.Means['積算電力量計測値(逆方向計測値)[kWh]']).toFixed(2)} kWh</section></div>`;
esmDoc += `</div>`;
}
}
esmDoc += "</section>";
esmDoc += "</div>"; // LinearLayoutParent
divSubESM.innerHTML = esmDoc;
};
//----------------------------------------------------------------------------------------------
// ESM chart
// 内部変数、定時積算電力はグラフに表示しない
let ocommulativeAmountNormal = [];
let ocommulativeAmountReverse = [];
let oinstantaneousCurrentsR = [];
let oinstantaneousCurrentsT = [];
let oinstantaneousPower = [];
// let ocommulativeAmountsFixedTimeNormalPower = []; // 定時必要無し
// let ocommulativeAmountsFixedTimeRiversePower = [];
/*
const LABEL_X = [
'00:00', '00:15', '00:30', '00:45', '01:00', '01:15', '01:30', '01:45', '02:00', '02:15', '02:30', '02:45',
'03:00', '03:15', '03:30', '03:45', '04:00', '04:15', '04:30', '04:45', '05:00', '05:15', '05:30', '05:45',
'06:00', '06:15', '06:30', '06:45', '07:00', '07:15', '07:30', '07:45', '08:00', '08:15', '08:30', '08:45',
'09:00', '09:15', '09:30', '09:45', '10:00', '10:15', '10:30', '10:45', '11:00', '11:15', '11:30', '11:45',
'12:00', '12:15', '12:30', '12:45', '13:00', '13:15', '13:30', '13:45', '14:00', '14:15', '14:30', '14:45',
'15:00', '15:15', '15:30', '15:45', '16:00', '16:15', '16:30', '16:45', '17:00', '17:15', '17:30', '17:45',
'18:00', '18:15', '18:30', '18:45', '19:00', '19:15', '19:30', '19:45', '20:00', '20:15', '20:30', '20:45',
'21:00', '21:15', '21:30', '21:45', '22:00', '22:15', '22:30', '22:45', '23:00', '23:15', '23:30', '23:45', '24:00'];
*/
// HTML内部とリンク
const ctxSubESM = canSubEnergyChart.getContext('2d');
let myChartSubESM = null;
// 複数軸用の、軸オプション
let complexChartOption = {
responsive: true,
plugins: {
legend: {
display: true,
position: 'top'
},
autocolors: false,
annotation: {
annotations: {
line1: {
type: 'line',
yScaleID: 'y-axis-right',
yMin: 20,
yMax: 20,
borderColor: 'rgb(255, 99, 132)',
borderWidth: 2,
borderDash: [2, 3],
label: {
display: true,
content: 'Breaker',
position: 'end'
}
}
}
}
},
scales: {
"y-axis-left-kwh": {
type: "linear", // linear固定
position: "left", // どちら側に表示される軸か?
// suggestedMax: 110,
min: 0,
title: { display: true, text: 'Commulative amounts energy [kWh]' }
},
"y-axis-left-w": {
type: "linear", // linear固定
position: "left", // どちら側に表示される軸か?
suggestedMax: 3000,
min: 0,
title: { display: true, text: 'Instantaneous electric power [W]' }
},
"y-axis-right": {
type: "linear",
position: "right",
suggestedMax: 30,
min: 0,
title: { display: true, text: 'Ampere [A]' }
},
"x": {
type: 'time',
time: {
unit: 'minutes',
parser: 'HH:mm',
displayFormats: {
minute: 'HH:mm',
hour: 'HH:mm'
}
},
min: '00:00',
max: '24:00',
ticks: {
autoSkip: false,
maxTicksLimit: 49, // 24h * 2 + 1
maxRotation: 90,
callback: function (value, index, ticks) {
return moment.tz(value, 'Asia/Tokyo').format('HH:mm');
}
}
}
}
};
// 表示データ(動的)
let datasetsSubESM = [];
/**
* @func renewCanvasSubESM
* @memberof subEL
* @desc 内部関数
* @param {void}
* @returns {number} The sum of the two numbers. (JSDoc test)
*/
let renewCanvasSubESM = function () {
// タイトルとチャート表示
divSubESMH3.style.display = 'block';
divSubESM.style.display = 'block';
canSubEnergyChart.style.display = 'block';
let esmDoc = "<div class='LinearLayoutParent'>";
if (myChartSubESM) { myChartSubESM.destroy(); } // chartがすでにctxを使っていると、リエントラントで"Canvas is already in use."のエラーが出る
myChartSubESM = new Chart(ctxSubESM, {
type: 'line',
data: {
// labels: LABEL_X,
datasets: datasetsSubESM
},
options: complexChartOption
});
};
//////////////////////////////////////////////////////////////////
/**
* @func window.renewEnergySubmeter
* @desc データをもらって画面更新
* @param {void}
* @return {void}
*/
window.renewEnergySubmeter = function (_envDataArray) {
// console.log('window.renewEnergySubmeter(); _envDataArray', _envDataArray);
let envDataArray = JSON.parse(_envDataArray);
if (inUserAmpere.value != '') { // 契約アンペアの指定があればアノテーションする
complexChartOption.plugins.annotation.annotations.line1.yMin = parseInt(inUserAmpere.value);
complexChartOption.plugins.annotation.annotations.line1.yMax = parseInt(inUserAmpere.value);
complexChartOption.scales["y-axis-right"].suggestedMax = parseInt(inUserAmpere.value) + 10;
}
datasetsSubESM = [];
if (envDataArray) {
ocommulativeAmountNormal = [];
ocommulativeAmountReverse = [];
oinstantaneousCurrentsR = [];
oinstantaneousCurrentsT = [];
oinstantaneousPower = [];
// ocommulativeAmountsFixedTimeNormalPower = []; // 定時必要無し
// ocommulativeAmountsFixedTimeRiversePower = [];
for (const d of envDataArray) {
ocommulativeAmountNormal.push({ x: moment(d.time), y: d.commulativeAmountNormal });
ocommulativeAmountReverse.push({ x: moment(d.time), y: d.commulativeAmountReverse });
oinstantaneousCurrentsR.push({ x: moment(d.time), y: d.instantaneousCurrentsR });
oinstantaneousCurrentsT.push({ x: moment(d.time), y: d.instantaneousCurrentsT });
oinstantaneousPower.push({ x: moment(d.time), y: d.instantaneousPower });
// 定時必要無し
// ocommulativeAmountsFixedTimeNormalPower.push( d.commulativeAmountsFixedTimeNormalPower );
// ocommulativeAmountsFixedTimeRiversePower.push( d.commulativeAmountsFixedTimeRiversePower );
}
datasetsSubESM.push(
{
label: '瞬時電力 [W]', type: 'line', data: oinstantaneousPower, borderColor: "rgba(178,255,178,1.0)", backgroundColor: "rgba(178,255,178,1.0)",
radius: 1.5, borderWidth: 1, yAxisID: 'y-axis-left-w', borderDash: [2, 1]
},
{
label: '瞬時電流R相 [A]', type: 'line', data: oinstantaneousCurrentsR, borderColor: "rgba(178,178,255,1.0)", backgroundColor: "rgba(178,178,255,1.0)",
radius: 1.5, borderWidth: 1, yAxisID: 'y-axis-right', borderDash: [2, 1]
},
{
label: '瞬時電流T相 [A]', type: 'line', data: oinstantaneousCurrentsT, borderColor: "rgba(255,196,137,1.0)", backgroundColor: "rgba(178,178,255,1.0)",
radius: 1.5, borderWidth: 1, yAxisID: 'y-axis-right', borderDash: [2, 1]
},
{
label: '積算電力量(正) [kWh]', type: 'line', fill: true, data: ocommulativeAmountNormal, borderColor: "rgba(255,178,178,1.0)", backgroundColor: "rgba(255,178,178,.2)",
radius: 1.5, borderWidth: 1, yAxisID: 'y-axis-left-kwh', borderDash: [2, 1]
},
{
label: '積算電力量(逆) [kWh]', type: 'line', fill: true, data: ocommulativeAmountReverse, borderColor: "rgba(255,178,255,1.0)", backgroundColor: "rgba(255,178,255,0.5)",
radius: 1.5, borderWidth: 1, yAxisID: 'y-axis-left-kwh', borderDash: [2, 1]
}
// 定時無し
// { label: '定時積算電力量(正) [kWh]', type: 'line', data: ocommulativeAmountsFixedTimeNormalPower, borderColor: "rgba(178,255,178,1.0)", backgroundColor: "rgba(178,255,178,1.0)",
// radius:1.5, borderWidth:1, yAxisID: 'y-axis-left', borderDash: [2,1] },
// { label: '定時積算電力量(逆) [kWh]', type: 'line', data: ocommulativeAmountsFixedTimeRiversePower, borderColor: "rgba(178,255,178,1.0)", backgroundColor: "rgba(178,255,178,1.0)",
// radius:1.5, borderWidth:1, yAxisID: 'y-axis-left', borderDash: [2,1] }
);
renewCanvasSubESM();
}
};
});