@andrei-tatar/node-red-contrib-nibetcp
Version:
Node-red integration for Nibe S series heatpumps using modbus over TCP
82 lines (81 loc) • 4.25 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const rxjs_1 = require("rxjs");
const operators_1 = require("rxjs/operators");
const __1 = require("..");
const log_1 = require("../log");
module.exports = function (RED) {
RED.nodes.registerType('nibe-register', function (config) {
RED.nodes.createNode(this, config);
const nibeConfig = RED.nodes.getNode(config.nibe);
if (!(nibeConfig === null || nibeConfig === void 0 ? void 0 : nibeConfig.nibe$)) {
return;
}
const log = log_1.logger === null || log_1.logger === void 0 ? void 0 : log_1.logger.scope(`reg-${config.id}`);
const forceWrite = !!config.force;
let timeoutMsec = (+config.timeout || 3) * 1000;
const intervalMsec = (+config.interval || 10) * 1000;
const forceRead$ = new rxjs_1.Subject();
const close$ = new rxjs_1.Subject();
const write$ = new rxjs_1.ReplaySubject(1);
let consecutiveErrors = 0;
const resetConnectionOnConsecutiveErrors = () => {
if (++consecutiveErrors >= 3) {
log === null || log === void 0 ? void 0 : log.trace('3 consecutive errors, reseting config');
nibeConfig.reset();
}
;
};
(0, rxjs_1.concat)((0, rxjs_1.defer)(() => {
consecutiveErrors = 0;
log === null || log === void 0 ? void 0 : log.trace('starting subscription');
this.status({ fill: 'yellow', text: 'standby' });
return rxjs_1.EMPTY;
}), (0, rxjs_1.combineLatest)([
nibeConfig.nibe$,
(0, rxjs_1.merge)((0, rxjs_1.interval)(intervalMsec).pipe((0, operators_1.startWith)(0)), forceRead$),
])).pipe((0, operators_1.concatMap)(([n]) => {
log === null || log === void 0 ? void 0 : log.trace('reading register');
return n.readRegister(config.register, timeoutMsec).pipe((0, operators_1.catchError)(err => {
log === null || log === void 0 ? void 0 : log.trace('error reading');
this.warn(`Error reading ${config.register}: ${err}`);
this.status({ fill: 'red', text: `${err}` });
resetConnectionOnConsecutiveErrors();
return rxjs_1.EMPTY;
}));
}), (0, operators_1.tap)(v => {
log === null || log === void 0 ? void 0 : log.trace('got response', { value: v.formatted });
this.status({ fill: 'blue', text: v.formatted });
consecutiveErrors = 0;
}), (0, operators_1.finalize)(() => {
log === null || log === void 0 ? void 0 : log.trace('disconnected');
this.status({ fill: 'red', text: 'disconnected' });
}), (0, operators_1.retry)({ delay: 20000 }), (0, operators_1.takeUntil)(close$)).subscribe({
next: (value) => this.send({ payload: value, topic: config.topic }),
complete: () => log === null || log === void 0 ? void 0 : log.trace('complete!'),
});
write$.pipe((0, operators_1.filter)(__1.isDefined), (0, operators_1.withLatestFrom)(nibeConfig.nibe$), (0, operators_1.concatMap)(([value, nibeConnection]) => nibeConnection
.writeRegister(config.register, value, forceWrite, timeoutMsec)
.pipe((0, operators_1.tap)({
error: (err) => {
this.warn(`Error writing ${value} to ${config.register}: ${err}`);
this.status({ fill: 'red', text: `${err}` });
resetConnectionOnConsecutiveErrors();
},
complete: () => {
write$.next(null);
forceRead$.next();
consecutiveErrors = 0;
},
}), (0, operators_1.takeUntil)(close$))), (0, operators_1.retry)({ delay: 10000 })).subscribe();
this.on('input', (msg, _, done) => {
if (config.filter && config.topic && msg.topic !== config.topic) {
done === null || done === void 0 ? void 0 : done();
return;
}
write$.next(+msg.payload);
done === null || done === void 0 ? void 0 : done();
});
this.on('close', () => close$.next());
});
};