Refactor device options retrieval

This commit is contained in:
Koen Kanters
2020-08-17 20:57:12 +02:00
parent 9148977b39
commit d167b149ad
6 changed files with 53 additions and 72 deletions
+9 -17
View File
@@ -121,14 +121,10 @@ class Controller {
logger.info(`Currently ${devices.length} devices are joined:`);
for (const device of devices) {
const entity = this.zigbee.resolveEntity(device);
logger.info(
(entity.settings ? entity.settings.friendlyName : entity.device.ieeeAddr) +
` (${entity.device.ieeeAddr}): ` +
(entity.definition ?
`${entity.definition.model} - ${entity.definition.vendor} ${entity.definition.description} ` :
'Not supported ') +
`(${entity.device.type})`,
);
const model = entity.definition ?
`${entity.definition.model} - ${entity.definition.vendor} ${entity.definition.description}` :
'Not supported';
logger.info(`${entity.name} (${entity.device.ieeeAddr}): ${model} (${entity.device.type})`);
}
// Enable zigbee join.
@@ -209,9 +205,9 @@ class Controller {
async onZigbeeEvent(type, data) {
const resolvedEntity = this.zigbee.resolveEntity(data.device || data.ieeeAddr);
if (data.device && !resolvedEntity.settings && data.device.type !== 'Coordinator') {
if (data.device && !settings.getDevice(data.device.ieeeAddr) && data.device.type !== 'Coordinator') {
// Only deviceLeave doesn't have a device (not interesting to add to settings)
resolvedEntity.settings = settings.addDevice(data.device.ieeeAddr);
resolvedEntity.settings = {...settings.get().device_options, ...settings.addDevice(data.device.ieeeAddr)};
}
const name = resolvedEntity && resolvedEntity.settings ? resolvedEntity.settings.friendlyName : null;
@@ -286,13 +282,12 @@ class Controller {
messagePayload = newState;
}
const deviceOptions = settings.get().device_options;
const options = {
retain: utils.getObjectsProperty([resolvedEntity.settings, deviceOptions], 'retain', false),
qos: utils.getObjectsProperty([resolvedEntity.settings, deviceOptions], 'qos', 0),
retain: utils.getObjectProperty(resolvedEntity.settings, 'retain', false),
qos: utils.getObjectProperty(resolvedEntity.settings, 'qos', 0),
};
const retention = utils.getObjectsProperty([resolvedEntity.settings, deviceOptions], 'retention', false);
const retention = utils.getObjectProperty(resolvedEntity.settings, 'retention', false);
if (retention !== false) {
options.properties = {messageExpiryInterval: retention};
}
@@ -318,9 +313,6 @@ class Controller {
}
// filter mqtt message attributes
if (deviceOptions.filtered_attributes) {
deviceOptions.filtered_attributes.forEach((a) => delete messagePayload[a]);
}
if (resolvedEntity.settings.filtered_attributes) {
resolvedEntity.settings.filtered_attributes.forEach((a) => delete messagePayload[a]);
}
+25 -33
View File
@@ -1,4 +1,3 @@
const zigbeeHerdsmanConverters = require('zigbee-herdsman-converters');
const settings = require('../util/settings');
const logger = require('../util/logger');
const utils = require('../util/utils');
@@ -1921,15 +1920,12 @@ class HomeAssistant extends Extension {
}
onDeviceRemoved(device) {
logger.debug(`Clearing Home Assistant discovery topic for '${device.ieeeAddr}'`);
delete this.discovered[device.ieeeAddr];
const resolvedEntity = this.zigbee.resolveEntity(device);
if (resolvedEntity.definition) {
logger.info(`Clearing Home Assistant discovery topic for '${device.ieeeAddr}'`);
const deviceSettings = {...settings.get().device_options, ...resolvedEntity.settings};
this.getConfigs(resolvedEntity.definition, deviceSettings).forEach((config) => {
const topic = this.getDiscoveryTopic(config, device);
this.mqtt.publish(topic, null, {retain: true, qos: 0}, this.discoveryTopic);
});
for (const config of this.getConfigs(resolvedEntity)) {
const topic = this.getDiscoveryTopic(config, device);
this.mqtt.publish(topic, null, {retain: true, qos: 0}, this.discoveryTopic);
}
}
@@ -2043,17 +2039,14 @@ class HomeAssistant extends Extension {
}
onDeviceRenamed(device) {
logger.info(`Refreshing Home Assistant discovery topic for '${device.ieeeAddr}'`);
logger.debug(`Refreshing Home Assistant discovery topic for '${device.ieeeAddr}'`);
// Clear before rename so Home Assistant use new friendly_name
// https://github.com/Koenkk/zigbee2mqtt/issues/4096#issuecomment-674044916
const resolvedEntity = this.zigbee.resolveEntity(device);
if (resolvedEntity.definition) {
const deviceSettings = {...settings.get().device_options, ...resolvedEntity.settings};
this.getConfigs(resolvedEntity.definition, deviceSettings).forEach((config) => {
const topic = this.getDiscoveryTopic(config, device);
this.mqtt.publish(topic, null, {retain: true, qos: 0}, this.discoveryTopic);
});
for (const config of this.getConfigs(resolvedEntity)) {
const topic = this.getDiscoveryTopic(config, device);
this.mqtt.publish(topic, null, {retain: true, qos: 0}, this.discoveryTopic);
}
this.discover(resolvedEntity, true);
@@ -2071,11 +2064,13 @@ class HomeAssistant extends Extension {
}
}
getConfigs(definition, deviceSettings) {
let configs = mapping[definition.model].slice();
getConfigs(resolvedEntity) {
if (!resolvedEntity || !resolvedEntity.definition) return [];
let configs = mapping[resolvedEntity.definition.model].slice();
configs.push(cfg.sensor_linkquality);
if (definition.hasOwnProperty('ota')) {
if (resolvedEntity.definition.hasOwnProperty('ota')) {
if (this.legacyApi) {
configs.push(cfg.binary_sensor_update_available);
}
@@ -2085,7 +2080,7 @@ class HomeAssistant extends Extension {
}
}
if (deviceSettings.hasOwnProperty('legacy') && !deviceSettings.legacy) {
if (resolvedEntity.settings.hasOwnProperty('legacy') && !resolvedEntity.settings.legacy) {
configs = configs.filter((c) => c !== cfg.sensor_click);
}
@@ -2099,18 +2094,17 @@ class HomeAssistant extends Extension {
discover(resolvedEntity, force=false) {
// Check if already discoverd and check if there are configs.
const {device, definition} = resolvedEntity;
const deviceSettings = {...settings.get().device_options, ...resolvedEntity.settings};
const discover = force || !this.discovered[device.ieeeAddr];
if (!discover || !device || !definition || !mapping[definition.model] || !deviceSettings ||
(deviceSettings.hasOwnProperty('homeassistant') && !deviceSettings.homeassistant)) {
if (!discover || !device || !definition || !mapping[definition.model] ||
(resolvedEntity.settings.hasOwnProperty('homeassistant') && !resolvedEntity.settings.homeassistant)) {
return;
}
const friendlyName = deviceSettings.friendlyName;
this.getConfigs(definition, deviceSettings).forEach((config) => {
const friendlyName = resolvedEntity.settings.friendlyName;
this.getConfigs(resolvedEntity).forEach((config) => {
const topic = this.getDiscoveryTopic(config, device);
const payload = {...config.discovery_payload};
let stateTopic = `${settings.get().mqtt.base_topic}/${deviceSettings.friendlyName}`;
let stateTopic = `${settings.get().mqtt.base_topic}/${friendlyName}`;
if (payload.state_topic_postfix) {
stateTopic += `/${payload.state_topic_postfix}`;
delete payload.state_topic_postfix;
@@ -2140,7 +2134,7 @@ class HomeAssistant extends Extension {
payload.name = `${friendlyName}${nameSeparator}${config.object_id}`;
// Set unique_id
payload.unique_id = `${deviceSettings.ID}_${config.object_id}_${settings.get().mqtt.base_topic}`;
payload.unique_id = `${resolvedEntity.settings.ID}_${config.object_id}_${settings.get().mqtt.base_topic}`;
// Attributes for device registry
payload.device = this.getDevicePayload(resolvedEntity);
@@ -2237,7 +2231,7 @@ class HomeAssistant extends Extension {
}
// Override configuration with user settings.
if (deviceSettings.hasOwnProperty('homeassistant')) {
if (resolvedEntity.settings.hasOwnProperty('homeassistant')) {
const add = (obj) => {
Object.keys(obj).forEach((key) => {
if (['number', 'string', 'boolean'].includes(typeof obj[key])) {
@@ -2252,10 +2246,10 @@ class HomeAssistant extends Extension {
});
};
add(deviceSettings.homeassistant);
add(resolvedEntity.settings.homeassistant);
if (deviceSettings.homeassistant.hasOwnProperty(config.object_id)) {
add(deviceSettings.homeassistant[config.object_id]);
if (resolvedEntity.settings.homeassistant.hasOwnProperty(config.object_id)) {
add(resolvedEntity.settings.homeassistant[config.object_id]);
}
}
@@ -2285,11 +2279,9 @@ class HomeAssistant extends Extension {
let clear = !resolvedEntity || !resolvedEntity.definition;
if (!clear) {
const deviceSettings = {...settings.get().device_options, ...resolvedEntity.settings};
const configs = this.getConfigs(resolvedEntity.definition, deviceSettings);
const type = discoveryMatch[1];
const objectID = discoveryMatch[3];
clear = !configs.find((c) => c.type === type && c.object_id === objectID);
clear = !this.getConfigs(resolvedEntity).find((c) => c.type === type && c.object_id === objectID);
}
if (clear) {
+2 -2
View File
@@ -92,11 +92,11 @@ class EntityPublish extends Extension {
definition = resolvedEntity.definition;
target = resolvedEntity.endpoint;
converters = resolvedEntity.definition.toZigbee;
options = {...settings.get().device_options, ...resolvedEntity.settings};
options = resolvedEntity.settings;
} else {
converters = groupConverters;
target = resolvedEntity.group;
options = {...settings.get().device_options, ...resolvedEntity.settings};
options = resolvedEntity.settings;
definition = resolvedEntity.group.members.map((e) => zigbeeHerdsmanConverters.findByDevice(e.getDevice()));
}
+8 -7
View File
@@ -131,9 +131,6 @@ class Receive extends Extension {
return;
}
const debounce = resolvedEntity.settings.debounce || settings.get().device_options.debounce;
const debounceIgnore = resolvedEntity.settings.debounce_ignore || settings.get().device_options.debounce_ignore;
// Convert this Zigbee message to a MQTT message.
// Get payload for the message.
// - If a payload is returned publish it to the MQTT broker
@@ -155,8 +152,11 @@ class Receive extends Extension {
}
// Check if we have to debounce
if (debounce) {
this.publishDebounce(data.device.ieeeAddr, payload, debounce, debounceIgnore);
if (resolvedEntity.settings.debounce) {
this.publishDebounce(
data.device.ieeeAddr, payload, resolvedEntity.settings.debounce,
resolvedEntity.settings.debounce_ignore,
);
} else {
this.publishEntityState(data.device.ieeeAddr, payload);
}
@@ -165,8 +165,9 @@ class Receive extends Extension {
const meta = {device: data.device, logger};
let payload = {};
converters.forEach((converter) => {
const options = {...settings.get().device_options, ...settings.getDevice(data.device.ieeeAddr)};
const converted = converter.convert(resolvedEntity.definition, data, publish, options, meta);
const converted = converter.convert(
resolvedEntity.definition, data, publish, resolvedEntity.settings, meta,
);
if (converted) {
payload = {...payload, ...converted};
}
+3 -9
View File
@@ -111,14 +111,8 @@ function equalsPartial(object, expected) {
return true;
}
function getObjectsProperty(objects, key, defaultValue) {
for (const object of objects) {
if (object.hasOwnProperty(key)) {
return object[key];
}
}
return defaultValue;
function getObjectProperty(object, key, defaultValue) {
return object.hasOwnProperty(key) ? object[key] : defaultValue;
}
function getResponse(request, data, error) {
@@ -180,7 +174,7 @@ module.exports = {
getZigbee2mqttVersion,
objectHasProperties,
toSnakeCase,
getObjectsProperty,
getObjectProperty,
getEndpointNames: () => endpointNames,
isXiaomiDevice: (device) => {
return device.modelID !== 'lumi.router' && xiaomiManufacturerID.includes(device.manufacturerID) &&
+6 -4
View File
@@ -162,6 +162,7 @@ class Zigbee extends events.EventEmitter {
`Wrong type '${typeof key}'`,
);
const deviceOptions = settings.get().device_options;
if (typeof key === 'string' || typeof key === 'number') {
if (typeof key === 'number') {
key = key.toString();
@@ -216,12 +217,13 @@ class Zigbee extends events.EventEmitter {
}
return {
type: 'device', device, endpoint, settings: entity, name: entity.friendlyName, definition,
type: 'device', device, endpoint, settings: {...deviceOptions, ...entity},
name: entity.friendlyName, definition,
};
} else {
let group = this.getGroupByID(entity.ID);
if (!group) group = this.createGroup(entity.ID);
return {type: 'group', group, settings: entity, name: entity.friendlyName};
return {type: 'group', group, settings: {...deviceOptions, ...entity}, name: entity.friendlyName};
}
} else if (key.constructor.name === 'Device') {
const setting = settings.getEntity(key.ieeeAddr);
@@ -229,7 +231,7 @@ class Zigbee extends events.EventEmitter {
type: 'device',
device: key,
endpoint: key.endpoints[0],
settings: setting,
settings: {...deviceOptions, ...(setting || {})},
name: setting ? setting.friendlyName : (key.type === 'Coordinator' ? 'Coordinator' : key.ieeeAddr),
definition: zigbeeHerdsmanConverters.findByDevice(key),
};
@@ -238,7 +240,7 @@ class Zigbee extends events.EventEmitter {
return {
type: 'group',
group: key,
settings: setting,
settings: {...deviceOptions, ...(setting || {})},
name: setting ? setting.friendlyName : key.groupID,
};
}