@gravypower/node-red-franklinwh
Version:
Node-RED node to control FranklinWH gateway
117 lines (102 loc) • 4.21 kB
JavaScript
const apiHandler = require('../../../api-handler');
module.exports = function(RED) {
const SWITCHES = {
sw1: { id: 'sw1', name: 'Switch 1' },
sw2: { id: 'sw2', name: 'Switch 2' },
sw3: { id: 'sw3', name: 'Switch 3' }
};
function formatSwitchState(id, state) {
return `${id.toUpperCase()}:${state ? 'on' : 'off'}`;
}
function validateSwitch(sw) {
if (!sw?.id || !SWITCHES[sw.id]) {
throw new Error(`Invalid switch id: ${sw?.id}. Must be one of: ${Object.keys(SWITCHES).join(', ')}`);
}
if (typeof sw.state !== 'boolean') {
throw new Error('Switch state must be a boolean');
}
}
function FranklinWHSetSwitchesNode(config) {
RED.nodes.createNode(this, config);
const node = this;
const server = RED.nodes.getNode(config.server);
if (!server) {
node.status({fill:"red", shape:"ring", text:"missing config"});
node.error("No server configuration");
return;
}
function getConfiguredSwitches() {
return [
{ id: 'sw1', enabled: config.sw1enabled, state: config.sw1state },
{ id: 'sw2', enabled: config.sw2enabled, state: config.sw2state },
{ id: 'sw3', enabled: config.sw3enabled, state: config.sw3state }
]
.filter(sw => sw.enabled)
.map(({ id, state }) => ({ id, state: !!state }));
}
// Set initial status
const initialSwitches = config.usePayload ? null : getConfiguredSwitches();
if (initialSwitches?.length) {
node.status({
fill: "blue",
shape: "dot",
text: initialSwitches.map(sw => formatSwitchState(sw.id, sw.state)).join(', ')
});
} else {
node.status({
fill: "grey",
shape: "ring",
text: config.usePayload ? "waiting for input" : "no switches configured"
});
}
node.on("input", async function(msg, send, done) {
try {
// Get switches configuration
const switches = config.usePayload ?
(Array.isArray(msg.payload) ? msg.payload : [msg.payload]) :
getConfiguredSwitches();
if (!switches?.length) {
throw new Error('No switches provided');
}
// Validate each switch
switches.forEach(validateSwitch);
node.status({fill: "yellow", shape: "dot", text: "setting switches..."});
await apiHandler.executeWithRetry(
node,
server,
async (api) => {
await api.setSmartSwitches(switches);
return {
switches: switches.map(sw => ({
...sw,
name: SWITCHES[sw.id].name,
status: sw.state ? 'on' : 'off'
})),
summary: switches.map(sw =>
`${SWITCHES[sw.id].name}: ${sw.state ? 'on' : 'off'}`
).join(', ')
};
},
msg,
send,
done
);
node.status({
fill: "green",
shape: "dot",
text: switches.map(sw => formatSwitchState(sw.id, sw.state)).join(', ')
});
} catch (err) {
const errorMsg = err.message || 'Unknown error';
node.status({fill: "red", shape: "ring", text: errorMsg.substring(0, 25)});
node.error("FranklinWH Error: " + errorMsg, msg);
if (done) done(err);
}
});
node.on('close', function(done) {
node.status({});
done();
});
}
RED.nodes.registerType("franklinwh-set-switches", FranklinWHSetSwitchesNode);
}