@caitken-com/node-red-contrib-daikin-api
Version:
Daikin Control API
289 lines (251 loc) • 7.4 kB
JavaScript
const DaikinConfig = require('./DaikinConfig');
const DaikinUserConfig = require('./DaikinUserConfig');
const DaikinApi = require('./DaikinApi');
/**
* @description Routes and models Daikin API requests
* @see https://github.com/fredrike/pydaikin/
* @see https://github.com/ael-code/daikin-control
* @package DaikinApiNode
* @param {Object} RED
* @author Christopher Aitken 2022
* @version 1.0
*/
module.exports = function(RED)
{
function DaikinApiNode(config)
{
RED.nodes.createNode(this, config);
const node = this;
node.server = RED.nodes.getNode(config.server);
node.user = new DaikinUserConfig({
'auto_id': node.server.auto_id,
'dehumidifier_id': node.server.dehumidifier_id,
'dry_id': node.server.dry_id,
'fan_id': node.server.fan_id,
'cool_id': node.server.cool_id,
'heat_id': node.server.heat_id,
});
node.daikin = new DaikinConfig({});
let req = getApiFullConfig();
/**
* @description Handle incoming messages
* @memberof DaikinApiNode
* @param {object} msg [msg.topic => (string), msg.payload => (json)]
* @return {void}
*/
node.on('input', function(msg)
{
let cmd = null;
let topic = null;
let promise;
if (typeof msg !== 'object') msg = {};
if (!('payload' in msg) || typeof msg.payload !== 'object') msg.payload = {};
if ('cmd' in msg.payload) cmd = msg.payload.cmd;
if ('topic' in msg) topic = msg.topic;
if (!cmd && topic) cmd = topic;
if (!cmd && !topic) return node.send(msg);
switch (cmd)
{
case 'getRaw':
promise = doRequest(msg.payload);
promise.then((data) =>
{
node.send({topic: topic, payload: data});
})
.catch(err =>{node.warn(err);});
break;
case 'getRawConfig':
promise = getApiFullConfig();
promise.then((data) =>
{
node.daikin.updateFromJSON(data);
node.send({topic: topic, payload: data});
})
.catch(err =>{node.warn(err);});
break;
case 'getConfig':
promise = getApiFullConfig();
promise.then((data) =>
{
node.daikin.updateFromJSON(data);
node.send({topic: topic, payload: DaikinApi.getConfig(node.daikin, node.user)});
})
.catch(err =>{node.warn(err);});
break;
case 'getControlInfo':
promise = doRequest({endpoint: 'get_control_info', data: null});
promise.then((data) =>
{
node.daikin.updateFromJSON(data);
node.send({topic: topic, payload: DaikinApi.getControlInfo(node.daikin, node.user)});
})
.catch(err =>{node.warn(err);});
break;
case 'setControlInfo':
promise = doRequest({endpoint: 'set_control_info', data: DaikinApi.setControlInfo(msg.payload, node.daikin, node.user)});
promise.then((data) =>
{
node.send({topic: topic, payload: data});
})
.catch(err =>{node.warn(err);});
break;
case 'getSensorInfo':
promise = doRequest({endpoint: 'get_sensor_info', data: null});
promise.then((data) =>
{
node.daikin.updateFromJSON(data);
node.send({topic: topic, payload: DaikinApi.getSensorInfo(node.daikin, node.user)});
})
.catch(err =>{node.warn(err);});
break;
case 'getZoneSetting':
promise = doRequest({endpoint: 'get_zone_setting', data: null});
promise.then((data) =>
{
node.daikin.updateFromJSON(data);
node.send({topic: topic, payload: DaikinApi.getZoneSetting(node.daikin, node.user)});
})
.catch(err =>{node.warn(err);});
break;
default:
node.send(msg);
break;
}
});
/**
* @description Request raw API data
* @param {object} payload {endpoint: string, payload: json}
* @return {object} json data
*/
function doRequest(payload)
{
let promise = new Promise((resolve, reject) =>
{
if (typeof payload !== 'object') return reject('No data given');
if (!('endpoint' in payload)) return reject('No endpoint specified');
if (!('data' in payload)) payload.data = null;
node.status({fill:'grey', shape:'ring', text:'Connecting...'});
let req = node.server.request(payload.endpoint, payload.data);
req.then((payload) =>
{
node.status({fill:'grey', shape:'ring', text:'Ready...'});
setTimeout(updateStatus, 1000);
resolve(payload);
})
.catch(err =>
{
setTimeout(updateStatus, 2000);
reject(err);
});
});
return promise;
}
/**
* @description get the full config from the Daikin device
* @memberof DaikinApiNode
* @returns {Promise<json>}
*/
function getApiFullConfig()
{
node.status({fill:'grey', shape:'ring', text:'Connecting...'});
let promise = new Promise((resolve, reject) =>
{
// get_control_info
let req = node.server.request('get_control_info', null);
let info = {};
// get_model_info
req.then((payload) =>
{
node.status({fill:'grey', shape:'ring', text:'Syncing'});
info = {...info, ...payload};
return node.server.request('get_model_info', null);
})
// basic_info
.then((payload) =>
{
node.status({fill:'grey', shape:'ring', text:'Syncing...'});
info = {...info, ...payload};
return node.server.request('basic_info', null);
})
// get_sensor_info
.then((payload) =>
{
node.status({fill:'grey', shape:'ring', text:'Syncing'});
info = {...info, ...payload};
return node.server.request('get_sensor_info', null);
})
// get_zone_setting
.then((payload) =>
{
node.status({fill:'grey', shape:'ring', text:'Syncing...'});
info = {...info, ...payload};
return node.server.request('get_zone_setting', null);
})
// done
.then((payload) =>
{
node.status({fill:'grey', shape:'ring', text:'Ready...'});
info = {...info, ...payload};
setTimeout(updateStatus, 1000);
resolve(info);
})
.catch(err =>
{
setTimeout(updateStatus, 2000);
reject(err);
});
});
return promise;
}
/**
* @description Update node status
* @return {void}
*/
function updateStatus()
{
let colours = {'Dehumidifier': 'green', 'Fan': 'grey', 'Heat': 'red', 'Cool': 'blue', 'Dry': 'yellow', 'Unknown': 'grey'};
let text;
switch (node.user.getMode(node.daikin.getMode()))
{
case 'Cool':
text = `Cooling ${node.daikin.getStemp()}°C, ${node.daikin.getFrate()}`;
break;
case 'Heat':
text = `Heating ${node.daikin.getStemp()}°C, ${node.daikin.getFrate()}`;
break;
case 'Fan':
text = `Fan: ${node.daikin.getFrate()}`;
break;
case 'Dehumidifier':
text = `Dehumidifier: ${node.daikin.getFrate()}`;
break;
case 'Dry':
text = `Drying: ${node.daikin.getFrate()}`;
break;
default:
text = 'Unknown';
break;
}
if (!node.daikin.getPower()) text = 'Off';
node.status({
fill: colours[node.user.getMode(node.daikin.getMode())],
shape: node.daikin.getPower() ? 'dot' : 'ring',
text: text
});
}
/**
* @description Initialize the node
* @memberof DaikinApiNode
* @param {Object} payload Json data
* @returns {void}
*/
req.then((payload) =>
{
node.daikin.updateFromJSON(payload);
node.send({payload: DaikinApi.getControlInfo(node.daikin, node.user)});
delete(req);
})
.catch(err =>{node.warn(err);});
}
RED.nodes.registerType('daikin-api', DaikinApiNode);
}