//////////////////////////////////////////////////////////////////////
/**
* @file mainSwitchBot.js
* @author SUGIMURA Hiroshi
* @copyright © 2020.10.30 Sugimura Laboratory, KAIT
* @license MIT
*/
//////////////////////////////////////////////////////////////////////
/**
* @module mainSwitchBot
*/
'use strict'
//////////////////////////////////////////////////////////////////////
// 基本ライブラリ
const Store = require('electron-store');
const { SwitchBot } = require('switchbot-handler');
const cron = require('node-cron');
require('date-utils'); // for log
const { Sequelize, Op, switchBotRawModel, switchBotDataModel } = require('./models/localDBModels'); // DBデータと連携
const { objectSort, isObjEmpty, mergeDeeply } = require('./mainSubmodule');
const store = new Store();
/** mainSwitchBotのconfig */
let config = {
enabled: false,
token: '',
secret: '',
debug: false
};
/** mainSwitchBotのpersist */
let persist = {};
/** mainSwitchBotからIPCMessageを呼ぶためのcallback */
let sendIPCMessage = null;
//////////////////////////////////////////////////////////////////////
/** mainSwitchBot
* @desc SwitchBotとの通信を管理
*/
let mainSwitchBot = {
/** @member client
* @desc SwitchBotとの接続を保持
* @default null
*/
client: null,
/** @member observationJob
* @desc 定期的にSwitchBotの状態を取得するタイマー
* @default null
*/
observationJob: null,
/** @member callback
* @desc SwitchBotの状態を取得したら呼ばれる関数を保持
* @default null
*/
callback: null,
/** @member isRun
* @desc 初期化して起動済みのフラグ
* @default null
*/
isRun: false,
//////////////////////////////////////////////////////////////////////
// interfaces
/**
* @async
* @function start
* @param {sendIPCMessage} [_sendIPCMessage]
* @return {void}
*/
start: function (_sendIPCMessage) {
sendIPCMessage = _sendIPCMessage;
if (mainSwitchBot.isRun) {
if (!isObjEmpty(persist)) {
sendIPCMessage("renewSwitchBotConfigView", config);
sendIPCMessage("fclSwitchBot", persist);
mainSwitchBot.sendTodayRoomEnv(); // 現在のデータを送っておく
}
return;
}
config.enabled = store.get('config.SwitchBot.enabled', false);
config.debug = store.get('config.SwitchBot.debug', false);
config.token = store.get('config.SwitchBot.token', '');
config.secret = store.get('config.SwitchBot.secret', '');
persist = store.get('persist.SwitchBot', {});
sendIPCMessage("renewSwitchBotConfigView", config);
if (!config.enabled) {
config.debug ? console.log(new Date().toFormat("YYYY-MM-DDTHH24:MI:SS"), '| mainSwitchBot is disabled.') : 0;
mainSwitchBot.isRun = false;
return;
}
mainSwitchBot.isRun = true;
config.debug ? console.log(new Date().toFormat("YYYY-MM-DDTHH24:MI:SS"), '| mainSwitchBot.start()') : 0;
if (config.token == '') {
config.debug ? console.log(new Date().toFormat("YYYY-MM-DDTHH24:MI:SS"), '| mainSwitchBot.start() token is empty.') : 0;
mainSwitchBot.isRun = false;
return;
}
if (config.secret == '') {
config.debug ? console.log(new Date().toFormat("YYYY-MM-DDTHH24:MI:SS"), '| mainSwitchBot.start() secret is empty.') : 0;
mainSwitchBot.isRun = false;
return;
}
try {
mainSwitchBot.startCore((facilities) => {
persist = facilities;
sendIPCMessage("fclSwitchBot", persist);
switchBotRawModel.create({ detail: JSON.stringify(persist) }); // store raw data
mainSwitchBot.storeData(facilities); // store meaningfull data
mainSwitchBot.sendTodayRoomEnv(); // 現在のデータを送っておく
});
} catch (error) {
console.error(new Date().toFormat("YYYY-MM-DDTHH24:MI:SS"), '| mainSwitchBot.start() error:\x1b[32m', error, '\x1b[0m');
}
},
/**
* @async
* @function stop
* @param {void} [void]
* @return {void}
*/
stop: async function () {
mainSwitchBot.isRun = false;
config.debug ? console.log(new Date().toFormat("YYYY-MM-DDTHH24:MI:SS"), '| mainSwitchBot.stop()') : 0;
await mainSwitchBot.stopObservation();
await store.set('config.SwitchBot', config);
await store.set('persist.SwitchBot', persist);
},
/**
* @async
* @function stopWithoutSave
* @param {void} [void]
* @return {void}
*/
stopWithoutSave: async function () {
mainSwitchBot.isRun = false;
config.debug ? console.log(new Date().toFormat("YYYY-MM-DDTHH24:MI:SS"), '| mainSwitchBot.stopWithoutSave()') : 0;
await mainSwitchBot.stopObservation();
},
/**
* @async
* @function setConfig
* @param {_config} [_config]
* @return {void}
*/
setConfig: async function (_config) {
if (_config) {
config = mergeDeeply(config, _config);
}
await store.set('config.SwitchBot', config);
sendIPCMessage("configSaved", 'SwitchBot'); // 保存したので画面に通知
sendIPCMessage("renewSwitchBotConfigView", config); // 保存したので画面に通知
},
/**
* @async
* @function getConfig
* @param {void}
* @return {config}
*/
getConfig: function () {
return config;
},
/**
* @async
* @function getPersist
* @param {void}
* @return {persist}
*/
getPersist: function () {
return persist;
},
// デバイスタイプごとに制御
/**
* @function control
* @param {id} [id]
* @param {command} [command]
* @return {void}
*/
control: function (id, command) {
// mainSwitchBot.client
console.log(new Date().toFormat("YYYY-MM-DDTHH24:MI:SS"), '| mainSwitchBot.control() id:', id, 'command:', command);
mainSwitchBot.client.setDeviceStatus(id, command, '', (ret) => {
console.log('mainSwitchBot.client.sendControlCommand ret:', r);
});
},
//////////////////////////////////////////////////////////////////////
// inner functions
/**
* @function renewFacilities
* @param {Object} [_client]
* @param {function} [callback(devStatusList)]
*/
renewFacilities: function (_client, callback) {
let ret = {};
try {
_client.getDevices(async (devlist) => {
if (!devlist || !devlist.deviceList) {
console.log(new Date().toFormat("YYYY-MM-DDTHH24:MI:SS"), '| mainSwitchBot.renewFacilities() devlist is undefined or null.');
return;
}
ret.deviceList = devlist.deviceList;
ret.infraredRemoteList = devlist.infraredRemoteList;
for (let d of ret.deviceList) {
ret[d.deviceId] = await _client.getDeviceStatusSync(d.deviceId);
}
callback(objectSort(ret));
});
// mainSwitchBot.debug?console.log( new Date().toFormat("YYYY-MM-DDTHH24:MI:SS"), '| mainSwitchBot.renewFacilities() devlist:\x1b[32m', devlist, '\x1b[0m' ):0;
} catch (error) {
switch (error) {
case 'Error: Http 401 Error. User permission is denied due to invalid token.':
console.log(JSON.stringify(_client));
sendIPCMessage('Error', { datetime: new Date().toFormat("YYYY-MM-DDTHH24:MI:SS"), moduleName: 'mainSwitchBot.renewFacilities()', stackLog: `Http 401 Error. User permission is denied due to invalid token.\n${error}` });
break;
}
console.error(new Date().toFormat("YYYY-MM-DDTHH24:MI:SS"), '| mainSwitchBot.renewFacilities() error:\x1b[32m', error, '\x1b[0m');
console.log(ret.deviceList);
throw error;
}
},
//////////////////////////////////////////////////////////////////////
// 定時処理のインタフェース
// 監視開始
/**
* @function startCore
* @callback {_callback} [_callback]
* @return {void}
*/
startCore: function (_callback) {
if (config.token == '' || config.secret == '') {
throw new Error('mainSwitchBot.startCore() config.token or config.secret is empty.');
}
mainSwitchBot.callback = _callback;
config.debug ? console.log(new Date().toFormat("YYYY-MM-DDTHH24:MI:SS"), '| mainSwitchBot.startCore() config:\x1b[32m', config, '\x1b[0m') : 0;
try {
mainSwitchBot.client = new SwitchBot(config.token, config.secret);
mainSwitchBot.renewFacilities(mainSwitchBot.client, (devStatusList) => {
mainSwitchBot.facilities = devStatusList;
mainSwitchBot.callback(mainSwitchBot.facilities); // mainに通知
}); // 一回実行
// 監視はcronで実施、処理が相当重いので3分毎、DBへのクエリ方法をもっと高速になるように考えたほうが良い
// 1分に1回実施
mainSwitchBot.observationJob = cron.schedule('*/1 * * * *', async () => {
config.debug ? console.log(new Date().toFormat("YYYY-MM-DDTHH24:MI:SS"), '| mainSwitchBot.cron.schedule()') : 0;
mainSwitchBot.renewFacilities(mainSwitchBot.client, (devStatusList) => { // 現在のデータ取得
mainSwitchBot.facilities = devStatusList;
mainSwitchBot.callback(mainSwitchBot.facilities); // mainに通知
}); // 一回実行
});
mainSwitchBot.observationJob.start();
} catch (error) {
console.error(new Date().toFormat("YYYY-MM-DDTHH24:MI:SS"), '| mainSwitchBot.startCore() error:\x1b[32m', error, '\x1b[0m');
}
},
// 監視をやめる
/**
* @async
* @function stopObservation
* @param {void} [void]
*/
stopObservation: function () {
config.debug ? console.log(new Date().toFormat("YYYY-MM-DDTHH24:MI:SS"), '| mainSwitchBot.stopObserve().') : 0;
if (mainSwitchBot.observationJob) {
mainSwitchBot.observationJob.stop();
mainSwitchBot.observationJob = null;
config.debug ? console.log(new Date().toFormat("YYYY-MM-DDTHH24:MI:SS"), '| mainSwitchBot.stopObserve() is stopped.') : 0;
} else {
config.debug ? console.log(new Date().toFormat("YYYY-MM-DDTHH24:MI:SS"), '| mainSwitchBot.stopObserve() has already stopped.') : 0;
}
// mainSwitchBot.client.close(); // axiosのソケットcloseの方法不明
},
// デバイスタイプごとにステータスの読見方を変えてDBにためる
/**
* @async
* @function storeData
* @param {facilities} [facilities]
*/
storeData: async function (facilities) {
for (let d of facilities.deviceList) {
let det = facilities[d.deviceId];
// console.log('SwitchBot:dev:', d, ' detail:', det);
try {
switch (d.deviceType) {
case 'Plug':
switchBotDataModel.create({
deviceId: d.deviceId,
deviceType: d.deviceType,
deviceName: d.deviceName,
property: 'power',
value: det.power
});
break;
case 'Plug Mini (JP)':
switchBotDataModel.create({
deviceId: d.deviceId,
deviceType: d.deviceType,
deviceName: d.deviceName,
property: 'power',
value: det.power
});
switchBotDataModel.create({
deviceId: d.deviceId,
deviceType: d.deviceType,
deviceName: d.deviceName,
property: 'voltage',
value: det.voltage
});
switchBotDataModel.create({
deviceId: d.deviceId,
deviceType: d.deviceType,
deviceName: d.deviceName,
property: 'weight',
value: det.weight
});
switchBotDataModel.create({
deviceId: d.deviceId,
deviceType: d.deviceType,
deviceName: d.deviceName,
property: 'electricityOfDay',
value: det.electricityOfDay
});
switchBotDataModel.create({
deviceId: d.deviceId,
deviceType: d.deviceType,
deviceName: d.deviceName,
property: 'electricCurrent',
value: det.electricCurrent
});
break;
case 'Meter':
case 'MeterPlus':
switchBotDataModel.create({
deviceId: d.deviceId,
deviceType: d.deviceType,
deviceName: d.deviceName,
property: 'temperature',
value: det.temperature
});
switchBotDataModel.create({
deviceId: d.deviceId,
deviceType: d.deviceType,
deviceName: d.deviceName,
property: 'humidity',
value: det.humidity
});
break;
case 'Curtain': // カーテン
switchBotDataModel.create({
deviceId: d.deviceId,
deviceType: d.deviceType,
deviceName: d.deviceName,
property: 'slidePosition',
value: det.slidePosition
});
switchBotDataModel.create({
deviceId: d.deviceId,
deviceType: d.deviceType,
deviceName: d.deviceName,
property: 'openDirection',
value: d.openDirection
});
break;
case 'Humidifier': // 加湿器
switchBotDataModel.create({
deviceId: d.deviceId,
deviceType: d.deviceType,
deviceName: d.deviceName,
property: 'power',
value: det.power
});
switchBotDataModel.create({
deviceId: d.deviceId,
deviceType: d.deviceType,
deviceName: d.deviceName,
property: 'humidity',
value: det.humidity
});
switchBotDataModel.create({
deviceId: d.deviceId,
deviceType: d.deviceType,
deviceName: d.deviceName,
property: 'temperature',
value: det.temperature
});
switchBotDataModel.create({
deviceId: d.deviceId,
deviceType: d.deviceType,
deviceName: d.deviceName,
property: 'lackWater',
value: det.lackWater
});
break;
case 'Motion Sensor': // 人感センサ=動きセンサ
switchBotDataModel.create({
deviceId: d.deviceId,
deviceType: d.deviceType,
deviceName: d.deviceName,
property: 'moveDetected',
value: det.moveDetected
});
switchBotDataModel.create({
deviceId: d.deviceId,
deviceType: d.deviceType,
deviceName: d.deviceName,
property: 'brightness',
value: det.brightness
});
break;
case 'Contact Sensor': // 開閉センサ=接触センサ
switchBotDataModel.create({
deviceId: d.deviceId,
deviceType: d.deviceType,
deviceName: d.deviceName,
property: 'moveDetected',
value: det.moveDetected
});
switchBotDataModel.create({
deviceId: d.deviceId,
deviceType: d.deviceType,
deviceName: d.deviceName,
property: 'brightness',
value: det.brightness
});
switchBotDataModel.create({
deviceId: d.deviceId,
deviceType: d.deviceType,
deviceName: d.deviceName,
property: 'openState',
value: det.openState
});
break;
case 'Color Bulb': // ライト
switchBotDataModel.create({
deviceId: d.deviceId,
deviceType: d.deviceType,
deviceName: d.deviceName,
property: 'power',
value: det.power
});
switchBotDataModel.create({
deviceId: d.deviceId,
deviceType: d.deviceType,
deviceName: d.deviceName,
property: 'brightness',
value: det.brightness
});
switchBotDataModel.create({
deviceId: d.deviceId,
deviceType: d.deviceType,
deviceName: d.deviceName,
property: 'color',
value: det.color
});
switchBotDataModel.create({
deviceId: d.deviceId,
deviceType: d.deviceType,
deviceName: d.deviceName,
property: 'colorTemperature',
value: det.colorTemperature
});
break;
case 'Bot': // ボット
switchBotDataModel.create({
deviceId: d.deviceId,
deviceType: d.deviceType,
deviceName: d.deviceName,
property: 'power',
value: det.power
});
break;
// 以下はDB格納無し
case 'Hub Mini': break;
case 'Indoor Cam': break;
case 'Remote': break;
default:
// console.log( 'unknown device in SwitchBot:dev:', d, ' detail:', det );
// 屋外カメラはなぜかdeviceType持ってない
break;
}
} catch (error) {
sendIPCMessage('Error', { datetime: new Date().toFormat("YYYY-MM-DDTHH24:MI:SS"), moduleName: 'mainSwitchBot', stackLog: `${error.message}, d:${d}, det:${det}` });
console.error(new Date().toFormat("YYYY-MM-DDTHH24:MI:SS"), '| mainSwitchBot.storeData() error:\x1b[32m', error, 'SwitchBot:dev:', d, ' detail:', det, '\x1b[0m');
throw error;
}
}
},
//////////////////////////////////////////////////////////////////////
// 定時処理
/*
getCases
input
date: Date="2023-01-06"
output
when createdAt >= "2023-01-05 23:57" and createdAt < "2023-01-06 00:00" then "00:00"
when createdAt >= "2023-01-06 00:00" and createdAt < "2023-01-06 00:03" then "00:03"
when createdAt >= "2023-01-06 00:03" and createdAt < "2023-01-06 00:06" then "00:06"
...
when createdAt >= "2023-01-06 23:54" and createdAt < "2023-01-06 23:57" then "23:57"
else "24:00"
*/
/**
* @async
* @function getCases
* @param {date} [date]
* @return {ret}
*/
getCases: function (date) {
let T1 = new Date(date);
let T2 = new Date(date);
let T3 = new Date(date);
let T4 = new Date(date);
// UTCだがStringにて表現しているので、なんか複雑
T1.setHours(T1.getHours() - T1.getHours() - 10, 57, 0, 0); // 前日の14時57分xx秒 14:57:00 .. 15:00:00 --> 00:00
T2.setHours(T1.getHours() - T1.getHours() - 10, 58, 0, 0); // T1 + 1min
T3.setHours(T1.getHours() - T1.getHours() - 10, 59, 0, 0); // T1 + 2min
T4.setHours(T1.getHours() - T1.getHours(), 0, 0, 0); // 集約先
let ret = "";
for (let t = 0; t < 480; t += 1) { // 24h * 20 times (= 60min / 3min)
// console.log( T1.toISOString(), ':', T1.toFormat('YYYY-MM-DD HH24:MI'), ', ', T4.toFormat('HH24:MI') );
ret += `WHEN "createdAt" LIKE "${T1.toFormat('YYYY-MM-DD HH24:MI')}%" OR "createdAt" LIKE "${T2.toFormat('YYYY-MM-DD HH24:MI')}%" OR "createdAt" LIKE "${T3.toFormat('YYYY-MM-DD HH24:MI')}%" THEN "${T4.toFormat('HH24:MI')}" \n`;
T1.setMinutes(T1.getMinutes() + 3); // + 3 min
T2.setMinutes(T2.getMinutes() + 3); // + 3 min
T3.setMinutes(T3.getMinutes() + 3); // + 3 min
T4.setMinutes(T4.getMinutes() + 3); // + 3 min
}
return ret + 'ELSE "24:00"';
},
// meterListを取得
/**
* @async
* @function getMeterList
* @param {theDayBegin} [theDayBegin]
* @param {theDayEnd} [theDayEnd]
* @return {rows}
*/
getMeterList: async function (theDayBegin, theDayEnd) {
let meterList = [];
try {
// 1日分で記録があるデバイスリスト(温湿度計)
let rows = [];
rows = await switchBotDataModel.findAll({
attributes: ['deviceName'],
group: ['deviceName'],
where: {
deviceType: { [Op.or]: ['Meter', 'MeterPlus'] },
createdAt: { [Op.between]: [theDayBegin.toISOString(), theDayEnd.toISOString()] }
}
});
for (const row of rows) {
meterList.push(row.dataValues.deviceName);
}
return meterList;
} catch (error) {
console.error(new Date().toFormat("YYYY-MM-DDTHH24:MI:SS"), '| mainSwitchBot.getMeterList()', error);
}
},
// plugMiniListを取得
/**
* @async
* @function plugMiniList
* @param {theDayBegin} [theDayBegin]
* @param {theDayEnd} [theDayEnd]
* @return {rows}
*/
getPlugMiniList: async function (theDayBegin, theDayEnd) {
let list = [];
try {
// 1日分で記録があるデバイスリスト(プラグミニ)
let rows = [];
rows = await switchBotDataModel.findAll({
attributes: ['deviceName'],
group: ['deviceName'],
where: {
deviceType: { [Op.or]: ['Plug Mini (JP)', 'Plug Mini (US)'] },
createdAt: { [Op.between]: [theDayBegin.toISOString(), theDayEnd.toISOString()] }
}
});
for (const row of rows) {
list.push(row.dataValues.deviceName);
}
return list;
} catch (error) {
console.error(new Date().toFormat("YYYY-MM-DDTHH24:MI:SS"), '| mainSwitchBot.getPlugMiniList()', error);
}
},
// 3分毎のtemperature
/**
* @async
* @function getTempratureRows
* @param {theDayBegin} [theDayBegin]
* @param {theDayEnd} [theDayEnd]
* @param {meter} [meter]
* @param {subQuery} [subQuery]
* @return {rows}
*/
getTempratureRows: async function (theDayBegin, theDayEnd, meter, subQuery) {
try {
// 3分毎データ tempreture
let rows = await switchBotDataModel.findAll({
attributes: [
[Sequelize.fn('AVG', Sequelize.col('value')), 'avgTemperature'],
'createdAt',
[Sequelize.literal(subQuery), 'timeunit']
],
where: {
deviceType: { [Op.or]: ['Meter', 'MeterPlus'] },
deviceName: meter,
property: 'temperature',
createdAt: { [Op.between]: [theDayBegin.toISOString(), theDayEnd.toISOString()] }
},
group: ['timeunit']
});
return rows;
} catch (error) {
console.error(new Date().toFormat("YYYY-MM-DDTHH24:MI:SS"), '| mainSwitchBot.getTempratureRows()', error);
}
},
// 3分毎のhumidity
/**
* @async
* @function getHumidityRows
* @param {sendIPCMessage} [_sendIPCMessage]
* @return {rows}
*/
getHumidityRows: async function (theDayBegin, theDayEnd, meter, subQuery) {
let ret = [];
try {
// 3分毎データ humidity
let rows = await switchBotDataModel.findAll({
attributes: [
[Sequelize.fn('AVG', Sequelize.col('value')), 'avgHumidity'],
'createdAt',
[Sequelize.literal(subQuery), 'timeunit']
],
where: {
deviceType: { [Op.or]: ['Meter', 'MeterPlus'] },
deviceName: meter,
property: 'humidity',
createdAt: { [Op.between]: [theDayBegin.toISOString(), theDayEnd.toISOString()] }
},
group: ['timeunit']
});
return rows;
} catch (error) {
console.error(new Date().toFormat("YYYY-MM-DDTHH24:MI:SS"), '| mainSwitchBot.getHumidityRows()', error);
}
},
// 3分毎のvoltage
/**
* @async
* @function getVoltageRows
* @param {theDayBegin} [theDayBegin]
* @param {theDayEnd} [theDayEnd]
* @param {plug} [plug]
* @param {subQuery} [subQuery]
* @return {rows}
*/
getVoltageRows: async function (theDayBegin, theDayEnd, plug, subQuery) {
try {
// 3分毎データ tempreture
let rows = await switchBotDataModel.findAll({
attributes: [
[Sequelize.fn('AVG', Sequelize.col('value')), 'avgVoltage'],
'createdAt',
[Sequelize.literal(subQuery), 'timeunit']
],
where: {
deviceType: { [Op.or]: ['Plug Mini (JP)', 'Plug Mini (US)'] },
deviceName: plug,
property: 'voltage',
createdAt: { [Op.between]: [theDayBegin.toISOString(), theDayEnd.toISOString()] }
},
group: ['timeunit']
});
return rows;
} catch (error) {
console.error(new Date().toFormat("YYYY-MM-DDTHH24:MI:SS"), '| mainSwitchBot.getVoltageRows()', error);
}
},
// 3分毎のwatt
/**
* @async
* @function getWeightRows
* @param {theDayBegin} [theDayBegin]
* @param {theDayEnd} [theDayEnd]
* @param {plug} [plug]
* @param {subQuery} [subQuery]
* @return {rows}
*/
getWeightRows: async function (theDayBegin, theDayEnd, plug, subQuery) {
let ret = [];
try {
// 3分毎データ humidity
let rows = await switchBotDataModel.findAll({
attributes: [
[Sequelize.fn('AVG', Sequelize.col('value')), 'avgWatt'],
'createdAt',
[Sequelize.literal(subQuery), 'timeunit']
],
where: {
deviceType: { [Op.or]: ['Plug Mini (JP)', 'Plug Mini (US)'] },
deviceName: plug,
property: 'weight',
createdAt: { [Op.between]: [theDayBegin.toISOString(), theDayEnd.toISOString()] }
},
group: ['timeunit']
});
return rows;
} catch (error) {
console.error(new Date().toFormat("YYYY-MM-DDTHH24:MI:SS"), '| mainSwitchBot.getWeightRows()', error);
}
},
// 3分毎のAmpere
/**
* @async
* @function getCurrentRows
* @param {theDayBegin} [theDayBegin]
* @param {theDayEnd} [theDayEnd]
* @param {plug} [plug]
* @param {subQuery} [subQuery]
* @return {rows}
*/
getCurrentRows: async function (theDayBegin, theDayEnd, plug, subQuery) {
let ret = [];
try {
// 3分毎データ humidity
let rows = await switchBotDataModel.findAll({
attributes: [
[Sequelize.fn('AVG', Sequelize.col('value')), 'avgAmpere'],
'createdAt',
[Sequelize.literal(subQuery), 'timeunit']
],
where: {
deviceType: { [Op.or]: ['Plug Mini (JP)', 'Plug Mini (US)'] },
deviceName: plug,
property: 'electricCurrent',
createdAt: { [Op.between]: [theDayBegin.toISOString(), theDayEnd.toISOString()] }
},
group: ['timeunit']
});
return rows;
} catch (error) {
console.error(new Date().toFormat("YYYY-MM-DDTHH24:MI:SS"), '| mainSwitchBot.getCurrentRows()', error);
}
},
// DBからテーブル取得
/**
* @async
* @function getTodayRoomEnvSwitchBot
* @param {void}
* @return {object}
*/
getTodayRoomEnvSwitchBot: async function () {
// 画面に今日のデータを送信するためのデータ作る
let ret = { srcType: 'switchBot', meterList: [], plugList: [] }; // 戻り値 // { meterList:[], meter1:[], meter2[], .... }
try {
let now = new Date(); // 現在
let begin = new Date(now); // 現在時刻UTCで取得
begin.setHours(begin.getHours() - begin.getHours() - 1, 57, 0, 0); // 前日の23時57分0秒にする
let end = new Date(begin); // 現在時刻UTCで取得
end.setHours(begin.getHours() + 25, 0, 0, 0); // 次の日の00:00:00にする
ret.meterList = await mainSwitchBot.getMeterList(begin, end); // 温湿度計のリストを取得
ret.plugMiniList = await mainSwitchBot.getPlugMiniList(begin, end); // Plug Miniのリストを取得
//------------------------------------------------------------
// 温湿度計毎にデータ作る
const cases = mainSwitchBot.getCases(now);
const subQuery = `CASE ${cases} END`;
for (const meter of ret.meterList) {
let rowsT = await mainSwitchBot.getTempratureRows(begin, end, meter, subQuery); // 3分毎データ tempreture
let rowsH = await mainSwitchBot.getHumidityRows(begin, end, meter, subQuery); // 3分毎データ humidity
// console.log( rowsT );
// console.log( rowsH );
let T1 = new Date();
T1.setHours(0, 0, 0);
let array = [];
for (let t = 0; t < 480; t += 1) {
let pushRow = {
id: t,
time: T1.toISOString()
}
// temperature
if (rowsT) {
let row = rowsT.find((row) => row.dataValues.timeunit == T1.toFormat('HH24:MI'));
if (row) {
pushRow.temperature = row.dataValues.avgTemperature;
} else {
pushRow.temperature = null;
}
}
// humidity
if (rowsH) {
let row = rowsH.find((row) => row.dataValues.timeunit == T1.toFormat('HH24:MI'));
if (row) {
pushRow.humidity = row.dataValues.avgHumidity;
} else {
pushRow.humidity = null;
}
}
array.push(pushRow);
T1.setMinutes(T1.getMinutes() + 3); // + 3 min
}
ret[meter] = array;
}
//------------------------------------------------------------
// プラグ毎にデータ作る
for (const plug of ret.plugMiniList) {
let rowsV = await mainSwitchBot.getVoltageRows(begin, end, plug, subQuery); // 3分毎データ volt
let rowsW = await mainSwitchBot.getWeightRows(begin, end, plug, subQuery); // 3分毎データ watt
let rowsC = await mainSwitchBot.getCurrentRows(begin, end, plug, subQuery); // 3分毎データ ampere
// console.log( rowsV );
// console.log( rowsW );
// console.log( rowsC );
let T1 = new Date();
T1.setHours(0, 0, 0);
let array = [];
for (let t = 0; t < 480; t += 1) {
let pushRow = {
id: t,
time: T1.toISOString()
}
// volt
if (rowsV) {
let row = rowsV.find((row) => row.dataValues.timeunit == T1.toFormat('HH24:MI'));
if (row) {
pushRow.voltage = row.dataValues.avgVoltage;
} else {
pushRow.voltage = null;
}
}
// watt
if (rowsW) {
let row = rowsW.find((row) => row.dataValues.timeunit == T1.toFormat('HH24:MI'));
if (row) {
pushRow.watt = row.dataValues.avgWatt;
} else {
pushRow.watt = null;
}
}
// ampere
if (rowsC) {
let row = rowsC.find((row) => row.dataValues.timeunit == T1.toFormat('HH24:MI'));
if (row) {
pushRow.ampere = row.dataValues.avgAmpere;
} else {
pushRow.ampere = null;
}
}
array.push(pushRow);
T1.setMinutes(T1.getMinutes() + 3); // + 3 min
}
ret[plug] = array;
}
return ret;
} catch (error) {
console.error(new Date().toFormat("YYYY-MM-DDTHH24:MI:SS"), '| mainSwitchBot.getTodayRoomEnvSwitchBot()', error);
}
},
/**
* @async
* @function sendTodayRoomEnv
* @param {void}
* @return {void}
*/
sendTodayRoomEnv: async function () {
let arg = {};
if (config.enabled) {
arg = await mainSwitchBot.getTodayRoomEnvSwitchBot();
sendIPCMessage('renewRoomEnvSwitchBot', JSON.stringify(arg));
} else {
console.error(new Date().toFormat("YYYY-MM-DDTHH24:MI:SS"), '| mainSwitchBot.sendTodayRoomEnv() config.enabled:', config.enabled);
}
}
};
module.exports = mainSwitchBot;
//////////////////////////////////////////////////////////////////////
// EOF
//////////////////////////////////////////////////////////////////////