mirror of
https://github.com/Koenkk/zigbee2mqtt.git
synced 2026-09-01 16:48:31 +00:00
Improved Livolo extension (#1016)
* Improved Livolo extension (pause polling after 3 unsuccessful attempts) * Added: queuing of all Zigbee messages * Fixed problem with .startsWith
This commit is contained in:
@@ -18,6 +18,31 @@ class PollLivoloSwitch {
|
||||
this.startTimer();
|
||||
}
|
||||
|
||||
_resetDeviceState(ieeeAddr) {
|
||||
this.configured[ieeeAddr] = {
|
||||
stage: 0,
|
||||
retry: 0,
|
||||
waitresp: false,
|
||||
};
|
||||
}
|
||||
|
||||
onZigbeeMessage(message, device, mappedDevice) {
|
||||
if (!device) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ((message.type == 'devInterview') ||
|
||||
(message.type == 'devIncoming') ||
|
||||
(message.type == 'endDeviceAnnce') ||
|
||||
(message.type == 'devStatus')) {
|
||||
if (this.configured.hasOwnProperty(device.ieeeAddr)) {
|
||||
logger.info(`LIVOLO ${device.ieeeAddr}. (Re)joins in the network (after power off?)`);
|
||||
this._resetDeviceState(device.ieeeAddr);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
startTimer() {
|
||||
this.clearTimer();
|
||||
this.timer = setInterval(() => this.handleInterval(), interval);
|
||||
@@ -35,21 +60,32 @@ class PollLivoloSwitch {
|
||||
}
|
||||
|
||||
_handleCommandRespSimple(err, rsp) {
|
||||
this.ext.configured[this.ieeeAddr].waitresp = false;
|
||||
|
||||
if (err) {
|
||||
logger.error(this.cid + '.' + this.ctype, 'response error:', err);
|
||||
if (this.cid === 'toggle') {
|
||||
this.ext.configured[this.ieeeAddr] = 0;
|
||||
if (this.ctype === 'toggle') {
|
||||
logger.debug(`LIVOLO ${this.ieeeAddr}. Toggle command error:`, err.message);
|
||||
}
|
||||
} else {
|
||||
this.ext.configured[this.ieeeAddr] = 2; // sucessfully send command
|
||||
logger.debug(`LIVOLO ${this.ieeeAddr}. Sucessfully configured`, rsp);
|
||||
this.ext.configured[this.ieeeAddr].stage = 1; // sucessfully send command
|
||||
this.ext.configured[this.ieeeAddr].retry = 0;
|
||||
this.device.status = 'online';
|
||||
}
|
||||
}
|
||||
|
||||
_handleCommandRespWithData(err, rsp) {
|
||||
this.ext.configured[this.ieeeAddr].waitresp = false;
|
||||
|
||||
if (err) {
|
||||
logger.info(this.cid + '.' + this.ctype, 'response error:', err);
|
||||
logger.info(`LIVOLO ${this.ieeeAddr}. ${this.cid}.${this.ctype} response error:`, err.message);
|
||||
if (this.ext.configured[this.ieeeAddr].retry >= 3) {
|
||||
// errors in three sequental reads, stop polling, wait for a device message
|
||||
this.device.status = 'offline';
|
||||
logger.info(`LIVOLO ${this.ieeeAddr}. Stopped polling after 3 unsuccessful attempts`);
|
||||
}
|
||||
} else {
|
||||
this.ext.configured[this.ieeeAddr].retry = 0;
|
||||
this.device.status = 'online';
|
||||
if (this.ext.zigbee) {
|
||||
this.ext.zigbee.shepherd.emit('ind:reported', this.ep, this.cid, rsp, this.ep.last_af_msg);
|
||||
@@ -64,6 +100,40 @@ class PollLivoloSwitch {
|
||||
ep.last_af_msg = msg;
|
||||
}
|
||||
|
||||
_sendToggle(zdev, ieeeAddr, ep, retry) {
|
||||
this.zigbee.queue.push((queueCallback) => {
|
||||
const cfg = {};
|
||||
logger.debug(`LIVOLO ${ieeeAddr}. Sending the 'toggle' command. Retry: ${retry}`);
|
||||
ep.functional('genOnOff', 'toggle', [cfg], foundationCfg,
|
||||
this._handleCommandRespSimple.bind({
|
||||
device: zdev,
|
||||
ieeeAddr: ieeeAddr,
|
||||
cid: 'genOnOff',
|
||||
ctype: 'toggle',
|
||||
ext: this,
|
||||
}));
|
||||
|
||||
queueCallback();
|
||||
});
|
||||
}
|
||||
|
||||
_sendPoll(zdev, ieeeAddr, ep, retry) {
|
||||
this.zigbee.queue.push((queueCallback) => {
|
||||
ep.foundation('genOnOff', 'read', [{
|
||||
attrId: 0, // onOff
|
||||
}], this._handleCommandRespWithData.bind({
|
||||
device: zdev,
|
||||
ieeeAddr: ieeeAddr,
|
||||
ep: ep,
|
||||
cid: 'genOnOff',
|
||||
ctype: 'read',
|
||||
ext: this,
|
||||
}));
|
||||
|
||||
queueCallback();
|
||||
});
|
||||
}
|
||||
|
||||
handleInterval() {
|
||||
this.zigbee.getAllClients()
|
||||
.filter((d) => d.manufName && d.manufName.startsWith('LIVOLO')) // LIVOLO
|
||||
@@ -84,31 +154,24 @@ class PollLivoloSwitch {
|
||||
ep.onAfIncomingMsg = this._handleAfMessage;
|
||||
|
||||
if (!this.configured.hasOwnProperty(d.ieeeAddr)) {
|
||||
this.configured[d.ieeeAddr] = 0;
|
||||
this._resetDeviceState(d.ieeeAddr);
|
||||
}
|
||||
|
||||
if (!this.configured[d.ieeeAddr]) {
|
||||
const cfg = {};
|
||||
// logger.info('=====>Send toggle');
|
||||
this.configured[d.ieeeAddr] = 1; // command sent, wait a result
|
||||
ep.functional('genOnOff', 'toggle', [cfg], foundationCfg,
|
||||
this._handleCommandRespSimple.bind({
|
||||
device: zdev,
|
||||
ieeeAddr: d.ieeeAddr,
|
||||
cid: 'genOnOff',
|
||||
ctype: 'toggle',
|
||||
ext: this,
|
||||
}));
|
||||
} else if (this.configured[d.ieeeAddr] === 2) {
|
||||
ep.foundation('genOnOff', 'read', [{
|
||||
attrId: 0, // onOff
|
||||
}], this._handleCommandRespWithData.bind({
|
||||
device: zdev,
|
||||
ep: ep,
|
||||
cid: 'genOnOff',
|
||||
ctype: 'read',
|
||||
ext: this,
|
||||
}));
|
||||
const state = this.configured[d.ieeeAddr];
|
||||
if (state.waitresp) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (state.retry < 3) {
|
||||
if (state.stage === 0) {
|
||||
state.retry += 1;
|
||||
state.waitresp = true;
|
||||
this._sendToggle(zdev, d.ieeeAddr, ep, state.retry);
|
||||
} else if (state.stage === 1) {
|
||||
state.retry += 1;
|
||||
state.waitresp = true;
|
||||
this._sendPoll(zdev, d.ieeeAddr, ep, state.retry);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user