node-red-contrib-superpower-smart-test
Version:
Node-RED integration with eWeLink Cube
252 lines (225 loc) • 9.83 kB
JavaScript
const _ = require('lodash');
const { v4 } = require('uuid');
const axios = require('axios').default;
const { v1CapabilityToV2Capability, v2CapabilityToV1Capability, frontEndDataToV1Capability } = require('./utils/capabilitiesTransform');
const {
API_URL_IHOST_CALLBACK,
API_URL_GET_DEVICE_LIST,
API_URL_ADD_THIRDPARTY_DEVICE,
API_URL_UPLOAD_THIRDPARTY_DEVICE_ONLINE,
EVENT_NODE_RED_ERROR,
TAG_API_SERVER_NODE_ID,
TAG_REG_DEV_NODE_ID,
TAG_THIRDPARTY_DEVICE_ID,
CAPA_MAP,
} = require('./utils/const');
const gatewayInfoMap = require('./utils/gatewayInfoMap');
/**
* Build capabilities array.
*
* @param {string} capaJsonData Capabilities data
*/
function buildCapabilities(config, apiServerNodeId) {
console.log('config---------------',config)
const capabilityVersion = config.capabilities_v2 ? 2 : 1;
const ihostVersion = gatewayInfoMap.get(apiServerNodeId)?.isV2 ? 2 : 1;
console.log('version---------------', capabilityVersion,ihostVersion)
let versionData = [];
if (capabilityVersion === 1 && ihostVersion === 1) {
versionData = frontEndDataToV1Capability(JSON.parse(config.capabilities));
}
if (capabilityVersion === 1 && ihostVersion === 2) {
versionData = frontEndDataToV1Capability(JSON.parse(config.capabilities));
versionData = v1CapabilityToV2Capability(versionData);
}
if (capabilityVersion === 2 && ihostVersion === 1) {
versionData = v2CapabilityToV1Capability(JSON.parse(config.capabilities_v2));
}
if (capabilityVersion === 2 && ihostVersion === 2) {
versionData = JSON.parse(config.capabilities_v2);
}
return versionData;
}
module.exports = function (RED) {
function RegisterDeviceNode(config) {
RED.nodes.createNode(this, config);
// console.log('register-------------config', config);
const node = this;
// If this node registered a device, then set it online.
const apiServerNodeId = config.server;
const thirdpartyDevId = config.device_id.trim();
if (apiServerNodeId && thirdpartyDevId) {
axios.post(`http://127.0.0.1:1880${API_URL_GET_DEVICE_LIST}`, { id: apiServerNodeId }).then((res) => {
if (res.data.error === 0) {
// Request success.
// Find the registered device.
const deviceList = res.data.data.device_list;
let found = null;
for (const dev of deviceList) {
const devId = _.get(dev, `tags.${TAG_THIRDPARTY_DEVICE_ID}`);
if (devId === thirdpartyDevId) {
found = dev;
}
}
// Call online API.
if (found) {
const onlineCmd = { online: true };
const reqData = {
id: apiServerNodeId,
deviceId: found.serial_number,
thirdPartyDeviceId: thirdpartyDevId,
params: JSON.stringify(onlineCmd),
};
axios.post(`http://127.0.0.1:1880${API_URL_UPLOAD_THIRDPARTY_DEVICE_ONLINE}`, reqData);
}
}
});
}
node.on('input', () => {
const server = config.server.trim();
const deviceId = config.device_id.trim();
const deviceName = config.device_name.trim();
const category = config.category.trim();
const capabilities = config.capabilities.trim();
const manufacturer = config.manufacturer.trim();
const model = config.model.trim();
const firmwareVersion = config.firmware_version.trim();
const serviceAddress = config.service_address.trim();
let tags = config.tags.trim();
let state = config.state.trim();
if (!server) {
RED.comms.publish(EVENT_NODE_RED_ERROR, { msg: 'register-device: no server' });
return;
}
if (!deviceId) {
RED.comms.publish(EVENT_NODE_RED_ERROR, { msg: 'register-device: no device ID' });
return;
}
if (!deviceName) {
RED.comms.publish(EVENT_NODE_RED_ERROR, { msg: 'register-device: no device name' });
return;
}
if (!manufacturer) {
RED.comms.publish(EVENT_NODE_RED_ERROR, { msg: 'register-device: no manufacturer' });
return;
}
if (!model) {
RED.comms.publish(EVENT_NODE_RED_ERROR, { msg: 'register-device: no model' });
return;
}
if (!firmwareVersion) {
RED.comms.publish(EVENT_NODE_RED_ERROR, { msg: 'register-device: no firmware version' });
return;
}
if (!serviceAddress) {
RED.comms.publish(EVENT_NODE_RED_ERROR, { msg: 'register-device: no service address' });
return;
}
if (!tags) {
RED.comms.publish(EVENT_NODE_RED_ERROR, { msg: 'register-device: no tags' });
return;
}
if (!state) {
RED.comms.publish(EVENT_NODE_RED_ERROR, { msg: 'register-device: no state' });
return;
}
try {
tags = JSON.parse(tags);
} catch (err) {
console.error(err);
RED.comms.publish(EVENT_NODE_RED_ERROR, { msg: 'register-device: tags should be JSON' });
return;
}
try {
state = JSON.parse(state);
} catch (err) {
console.error(err);
RED.comms.publish(EVENT_NODE_RED_ERROR, { msg: 'register-device: state should be JSON' });
return;
}
// Store API server node ID in tags
_.set(tags, TAG_API_SERVER_NODE_ID, server);
_.set(tags, TAG_REG_DEV_NODE_ID, node.id);
_.set(tags, TAG_THIRDPARTY_DEVICE_ID, deviceId);
console.log('buildCapabilities--------------', buildCapabilities(config, apiServerNodeId));
const capabilitiesData = buildCapabilities(config, apiServerNodeId).map(item => {
const newItem = { ...item };
if (newItem.settings) newItem.settings = JSON.parse(newItem.settings);
return newItem;
});
const params = [
{
name: deviceName,
third_serial_number: deviceId,
manufacturer,
model,
firmware_version: firmwareVersion,
display_category: category,
capabilities: capabilitiesData,
state,
tags,
service_address: `http://${serviceAddress}:1880${API_URL_IHOST_CALLBACK}`,
},
];
const data = {
id: config.server,
params: JSON.stringify(params),
};
axios
.post(`http://127.0.0.1:1880${API_URL_ADD_THIRDPARTY_DEVICE}`, data)
.then((res) => {
const errNum = _.get(res, 'data.error');
if (typeof errNum === 'number' && errNum !== 0) {
node.status({ fill: 'red', shape: 'ring', text: RED._('register-device.message.connect_fail') });
} else {
node.status({ text: '' });
}
node.send({ payload: res.data });
})
.catch((err) => {
node.status({ fill: 'red', shape: 'ring', text: RED._('register-device.message.connect_fail') });
node.error(err);
});
});
}
// Handle iHost callback.
RED.httpAdmin.post(API_URL_IHOST_CALLBACK, (req, res) => {
const apiServerNodeId = _.get(req, `body.directive.endpoint.tags.${TAG_API_SERVER_NODE_ID}`);
const apiServerNode = RED.nodes.getNode(apiServerNodeId);
const regDevNodeId = _.get(req, `body.directive.endpoint.tags.${TAG_REG_DEV_NODE_ID}`);
const regDevNode = RED.nodes.getNode(regDevNodeId);
const failedResponse = {
event: {
header: {
name: 'ErrorResponse',
message_id: v4(),
version: '1',
},
payload: {
type: 'ENDPOINT_UNREACHABLE',
},
},
};
const successResponse = {
event: {
header: {
name: 'UpdateDeviceStatesResponse',
message_id: v4(),
version: '1',
},
payload: {},
},
};
let response = null;
if (apiServerNodeId && apiServerNode && regDevNodeId && regDevNode) {
response = successResponse;
} else {
response = failedResponse;
}
if (regDevNode) {
regDevNode.send({ payload: req.body.directive });
}
res.send(JSON.stringify(response));
});
RED.nodes.registerType('register-device', RegisterDeviceNode);
};