Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 9 additions & 5 deletions lib/deviceLabel.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,10 @@ const utils = require('./utils');

/**
* Resolve a device log label from any id/IEEE/group-id form (with or without namespace prefix).
* Looks up the user-assigned name via the adapter's state controller; when the user has not
* renamed the device, the name of the device object (usually the model, cached by the state
* controller) is used, so an un-named device is labelled the same way the admin shows it. The id
* Name resolution order: user override from the local config (per-device wins over per-model,
* the per-model lookup needs the model parameter) -> name of the device object (usually the
* model, cached by the state controller), so the label matches what the admin shows -> the model
* parameter itself (covers devices without an object, e.g. while pairing) -> "unnamed". The id
* is always kept for unique identification (see utils.deviceDisplayName). Never throws — a log
* line can never fail because of this. An invalid id resolves to "unknown device" (via
* deviceDisplayName), a lookup failure to "failed to get name".
Expand All @@ -15,16 +16,19 @@ const utils = require('./utils');
*
* @param {object} adapter the ioBroker adapter instance (needs .stController.verifyDeviceName)
* @param {string|number} idOrIeee the device id / IEEE address / group id (always shown in the label)
* @param {string} [model] the device model — per-model override key and default name when un-named
* @param {string} [model] the mapped model (common.type key space, 'group' for groups) — per-model
* override key and last-resort default name; empty/non-string values are ignored
* @returns {string} the display label ("name (id)"), or "failed to get name (id)" on error
*/
function devLabel(adapter, idOrIeee, model) {
let name = 'unnamed';
try {
const bareId = adapter && adapter.namespace ? String(idOrIeee).replace(`${adapter.namespace}.`, '') : idOrIeee;
const adId = utils.zbIdorIeeetoAdId(adapter, bareId, false);
// '' must not reach verifyDeviceName: it is not nullish and would suppress the fallbacks
const mdl = typeof model === 'string' && model.length > 0 ? model : undefined;
if (adapter && adapter.stController && typeof adapter.stController.verifyDeviceName === 'function') {
name = adapter.stController.verifyDeviceName(adId, model, model);
name = adapter.stController.verifyDeviceName(adId, mdl, undefined);
}
} catch {
return `failed to get name (${idOrIeee})`;
Expand Down
14 changes: 7 additions & 7 deletions lib/groups.js
Original file line number Diff line number Diff line change
Expand Up @@ -241,7 +241,7 @@ class Groups {
if (!mappedModel) return;
const obj = await this.adapter.getObjectAsync((member.ieee.includes('x') ? member.ieee.split('x')[1] : member.ieee));
if (obj && obj.common.deactivated) {
this.debug(`omitting reading member state for deactivated device '${devLabel(this.adapter, member.ieee)}'`);
this.debug(`omitting reading member state for deactivated device '${devLabel(this.adapter, member.ieee, mappedModel.model)}'`);
return;
}
const converter = mappedModel.toZigbee.find(c => c && (c.key.includes(item.state)));
Expand All @@ -250,28 +250,28 @@ class Groups {
try {
await converter.convertGet(endpoint, item.state, {device:entity.device});
} catch (error) {
this.debug(`reading ${item.state} from '${devLabel(this.adapter, member.id)}'${member.ieee ? '/' + member.epid : ''} via convertGet failed with ${error && error.message ? error.message : 'no reason given'}`);
this.debug(`reading ${item.state} from '${devLabel(this.adapter, member.ieee, mappedModel.model)}'${member.ieee ? '/' + member.epid : ''} via convertGet failed with ${error && error.message ? error.message : 'no reason given'}`);
return {unread:member.device};
}
this.debug(`reading ${item.state} from '${devLabel(this.adapter, member.ieee)}'${member.ep ? '/' + member.epid : ''} via convertGet succeeded` );
this.debug(`reading ${item.state} from '${devLabel(this.adapter, member.ieee, mappedModel.model)}'${member.ep ? '/' + member.epid : ''} via convertGet succeeded` );
return {read:member.device};
}
if (toRead.cluster) {
if (device && endpoint) {
if (entity.endpoint.inputClusters.includes(toRead.cluster)) {
try {
const result = await endpoint.read(toRead.cluster, toRead.attributes,{disableDefaultResponse : true });
this.debug(`readGroupMemberStatus for ${item.state} from '${devLabel(this.adapter, member.ieee)}'${member.ep ? '/' + member.epid : ''} resulted in ${JSON.stringify(result)}`);
this.debug(`readGroupMemberStatus for ${item.state} from '${devLabel(this.adapter, member.ieee, mappedModel.model)}'${member.ep ? '/' + member.epid : ''} resulted in ${JSON.stringify(result)}`);
}
catch (error) {
this.debug(`reading ${item.state} from '${devLabel(this.adapter, member.ieee)}'${member.ep ? '/' + member.epid : ''} via endpoint.read with ${toRead.cluster}, ${JSON.stringify(toRead.attributes)} resulted in ${error && error.message ? error.message : 'an unspecified error'}`);
this.debug(`reading ${item.state} from '${devLabel(this.adapter, member.ieee, mappedModel.model)}'${member.ep ? '/' + member.epid : ''} via endpoint.read with ${toRead.cluster}, ${JSON.stringify(toRead.attributes)} resulted in ${error && error.message ? error.message : 'an unspecified error'}`);
}
this.debug(`reading ${item.state} from '${devLabel(this.adapter, member.ieee)}'${member.ep ? '/' + member.epid : ''} via endpoint.read with ${toRead.cluster}, ${JSON.stringify(toRead.attributes)} succeeded`);
this.debug(`reading ${item.state} from '${devLabel(this.adapter, member.ieee, mappedModel.model)}'${member.ep ? '/' + member.epid : ''} via endpoint.read with ${toRead.cluster}, ${JSON.stringify(toRead.attributes)} succeeded`);
}
else this.debug(`omitting cluster ${toRead.cluster} - not supported`);
}
else {
this.debug(`unable to read ${item.state} from '${devLabel(this.adapter, member.id)}'${member.ep ? '/' + member.epid : ''} - unable to resolve the entity`);
this.debug(`unable to read ${item.state} from '${devLabel(this.adapter, member.ieee, mappedModel.model)}'${member.ep ? '/' + member.epid : ''} - unable to resolve the entity`);
}
return;
}
Expand Down
20 changes: 10 additions & 10 deletions lib/ota.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,28 +164,28 @@ class Ota {
return result;
}
if (this.inProgress.has(devIeee)) {
this.error(`Update or check already in progress for '${devLabel(this.adapter, devIeee)}', skipping...`);
this.error(`Update or check already in progress for '${devLabel(this.adapter, devIeee, entity?.mapped?.model)}', skipping...`);
return;
}
// do not attempt update for a device which has been deactivated or is unavailable
const stateObj = await this.adapter.getObjectAsync(objID);
if (stateObj && stateObj.common && stateObj.common.deactivated) {
this.info(`Device '${devLabel(this.adapter, devIeee)}' is deactivated, skipping ota check`);
this.info(`Device '${devLabel(this.adapter, devIeee, entity?.mapped?.model)}' is deactivated, skipping ota check`);
return;
}
const availablestate = await this.adapter.getStateAsync(`${objID}.available`);
const lqi = await this.adapter.getStateAsync(`${objID}.link_quality`);
if ((availablestate && (!availablestate.val)) || (lqi && lqi.val < 1)) {
this.info(`Device '${devLabel(this.adapter, devIeee)}' is marked unavailable, skipping ota check`);
this.info(`Device '${devLabel(this.adapter, devIeee, entity?.mapped?.model)}' is marked unavailable, skipping ota check`);
return;
}
const result = { status: 'unknown', decice:entity?.name ?? 'no name'};
this.inProgress.add(entity.device.ieeeAddr);
try {
this.info('Start firmware update for ' + "'" + devLabel(this.adapter, entity.device.ieeeAddr) + "'");
this.info('Start firmware update for ' + "'" + devLabel(this.adapter, entity.device.ieeeAddr, entity.mapped?.model) + "'");

const onProgress = (progress, remaining) => {
let message = `Update of '${devLabel(this.adapter, entity.device.ieeeAddr)}' at ${progress}%`;
let message = `Update of '${devLabel(this.adapter, entity.device.ieeeAddr, entity.mapped?.model)}' at ${progress}%`;
if (remaining) {
message += `, +- ${Math.round(remaining / 60)} minutes remaining`;
}
Expand Down Expand Up @@ -225,7 +225,7 @@ class Ota {

this.info(result.msg);
} catch (error) {
const message = `Update of '${devLabel(this.adapter, entity.device.ieeeAddr)}' failed (${error.message})`;
const message = `Update of '${devLabel(this.adapter, entity.device.ieeeAddr, entity.mapped?.model)}' failed (${error.message})`;
result.status = 'fail';
result.msg = message;
this.error(message);
Expand Down Expand Up @@ -282,20 +282,20 @@ class Ota {
}
this.inProgress.add(ieeeAddr);
try {
this.debug(`Checking if firmware update is available for '${devLabel(this.adapter, ieeeAddr)}'`);
this.debug(`Checking if firmware update is available for '${devLabel(this.adapter, ieeeAddr, entity?.mapped?.model)}'`);

if (entity && entity.mapped.ota) {
const available = await entity.device.checkOta({ downgrade:false }, undefined, typeof entity.mapped.ota === 'object' ? entity.mapped.ota : {}, undefined);
result.status = available.available ? 'available' : 'not_available';
if (available.currentFileVersion !== available.otaFileVersion) {
this.debug(`current Firmware for '${devLabel(this.adapter, ieeeAddr)}' is ${available.currentFileVersion} new is ${available.otaFileVersion}`);
this.debug(`current Firmware for '${devLabel(this.adapter, ieeeAddr, entity?.mapped?.model)}' is ${available.currentFileVersion} new is ${available.otaFileVersion}`);
}
} else {
result.status = 'not_supported';
}
this.debug(`Firmware update for '${devLabel(this.adapter, ieeeAddr)}' is ${result.status}`);
this.debug(`Firmware update for '${devLabel(this.adapter, ieeeAddr, entity?.mapped?.model)}' is ${result.status}`);
} catch (error) {
const message = `Failed to check if update available for '${devLabel(this.adapter, ieeeAddr)}' ${error.message}`;
const message = `Failed to check if update available for '${devLabel(this.adapter, ieeeAddr, entity?.mapped?.model)}' ${error.message}`;
result.status = 'fail';
result.msg = message;
if (!message.includes(`Device didn't respond to OTA request`)) this.warn(message);
Expand Down
Loading
Loading