mirror of
https://github.com/Koenkk/zigbee2mqtt.git
synced 2026-07-02 01:51:38 +00:00
Support Home Assistant configuration for external converters. https://github.com/Koenkk/zigbee-herdsman-converters/issues/1343
This commit is contained in:
@@ -1,30 +1,17 @@
|
||||
const zigbeeHerdsmanConverters = require('zigbee-herdsman-converters');
|
||||
const settings = require('../util/settings');
|
||||
const Extension = require('./extension');
|
||||
const data = require('../util/data');
|
||||
const utils = require('../util/utils');
|
||||
|
||||
class ExternalConverters extends Extension {
|
||||
constructor(zigbee, mqtt, state, publishEntityState, eventBus) {
|
||||
super(zigbee, mqtt, state, publishEntityState, eventBus);
|
||||
|
||||
const externalConverters = settings.get().external_converters;
|
||||
|
||||
externalConverters.forEach((moduleName) => {
|
||||
let converterModule = moduleName;
|
||||
|
||||
if (moduleName.endsWith('.js')) {
|
||||
converterModule = data.joinPath(moduleName.split('.')[0]);
|
||||
}
|
||||
|
||||
const converter = require(converterModule);
|
||||
if (Array.isArray(converter)) {
|
||||
converter.forEach((mod) => {
|
||||
zigbeeHerdsmanConverters.addDeviceDefinition(mod);
|
||||
});
|
||||
} else {
|
||||
zigbeeHerdsmanConverters.addDeviceDefinition(converter);
|
||||
}
|
||||
});
|
||||
for (const definition of utils.getExternalConvertersDefinitions(settings)) {
|
||||
const toAdd = {...definition};
|
||||
delete toAdd['homeassistant'];
|
||||
zigbeeHerdsmanConverters.addDeviceDefinition(toAdd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const zigbeeHerdsmanConverters = require('zigbee-herdsman-converters');
|
||||
const settings = require('../util/settings');
|
||||
const logger = require('../util/logger');
|
||||
const utils = require('../util/utils');
|
||||
const zigbee2mqttVersion = require('../../package.json').version;
|
||||
const Extension = require('./extension');
|
||||
const objectAssignDeep = require(`object-assign-deep`);
|
||||
@@ -1776,6 +1777,12 @@ class HomeAssistant extends Extension {
|
||||
this.eventBus.on('deviceRemoved', (data) => this.onDeviceRemoved(data.device));
|
||||
this.eventBus.on('publishEntityState', (data) => this.onPublishEntityState(data));
|
||||
this.eventBus.on('deviceRenamed', (data) => this.onDeviceRenamed(data.device));
|
||||
|
||||
for (const definition of utils.getExternalConvertersDefinitions(settings)) {
|
||||
if (definition.hasOwnProperty('homeassistant')) {
|
||||
mapping[definition.model] = definition.homeassistant;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
onDeviceRemoved(device) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const zigbeeHerdsmanConverters = require('zigbee-herdsman-converters');
|
||||
const equals = require('fast-deep-equal');
|
||||
const humanizeDuration = require('humanize-duration');
|
||||
const data = require('./data');
|
||||
|
||||
// Xiaomi uses 4151 and 4447 (lumi.plug) as manufacturer ID.
|
||||
const xiaomiManufacturerID = [4151, 4447];
|
||||
@@ -150,6 +151,27 @@ function parseJSON(value, failedReturnValue) {
|
||||
}
|
||||
}
|
||||
|
||||
function* getExternalConvertersDefinitions(settings) {
|
||||
const externalConverters = settings.get().external_converters;
|
||||
|
||||
for (const moduleName of externalConverters) {
|
||||
let converterModule = moduleName;
|
||||
|
||||
if (moduleName.endsWith('.js')) {
|
||||
converterModule = data.joinPath(moduleName.split('.')[0]);
|
||||
}
|
||||
|
||||
const converter = require(converterModule);
|
||||
if (Array.isArray(converter)) {
|
||||
for (const item of converter) {
|
||||
yield item;
|
||||
}
|
||||
} else {
|
||||
yield converter;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
millisecondsToSeconds: (milliseconds) => milliseconds / 1000,
|
||||
secondsToMilliseconds: (seconds) => seconds * 1000,
|
||||
@@ -169,4 +191,5 @@ module.exports = {
|
||||
getResponse,
|
||||
capitalize,
|
||||
parseJSON,
|
||||
getExternalConvertersDefinitions,
|
||||
};
|
||||
|
||||
@@ -1,5 +1,18 @@
|
||||
const homeassistantSwitch = {
|
||||
type: 'switch',
|
||||
object_id: 'switch',
|
||||
discovery_payload: {
|
||||
payload_off: 'OFF',
|
||||
payload_on: 'ON',
|
||||
value_template: '{{ value_json.state }}',
|
||||
command_topic: true,
|
||||
},
|
||||
};
|
||||
|
||||
const mockDevices = [{
|
||||
mock: 1
|
||||
mock: 1,
|
||||
model: 'external_converters_device',
|
||||
homeassistant: [homeassistantSwitch],
|
||||
}, {
|
||||
mock: 2
|
||||
}];
|
||||
|
||||
@@ -80,7 +80,8 @@ describe('Loads external converters', () => {
|
||||
await flushPromises();
|
||||
expect(zigbeeHerdsmanConverters.addDeviceDefinition).toHaveBeenCalledTimes(2);
|
||||
expect(zigbeeHerdsmanConverters.addDeviceDefinition).toHaveBeenNthCalledWith(1, {
|
||||
mock: 1
|
||||
mock: 1,
|
||||
model: 'external_converters_device',
|
||||
});
|
||||
expect(zigbeeHerdsmanConverters.addDeviceDefinition).toHaveBeenNthCalledWith(2, {
|
||||
mock: 2
|
||||
|
||||
@@ -5,6 +5,9 @@ const zigbeeHerdsman = require('./stub/zigbeeHerdsman');
|
||||
const flushPromises = () => new Promise(setImmediate);
|
||||
const MQTT = require('./stub/mqtt');
|
||||
const Controller = require('../lib/controller');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const HomeAssistant = require('../lib/extension/homeassistant');
|
||||
|
||||
describe('HomeAssistant extension', () => {
|
||||
beforeEach(async () => {
|
||||
@@ -20,7 +23,6 @@ describe('HomeAssistant extension', () => {
|
||||
|
||||
it('Should have mapping for all devices supported by zigbee-herdsman-converters', () => {
|
||||
const missing = [];
|
||||
const HomeAssistant = require('../lib/extension/homeassistant');
|
||||
const ha = new HomeAssistant(null, null, null, null, {on: () => {}});
|
||||
|
||||
require('zigbee-herdsman-converters').devices.forEach((d) => {
|
||||
@@ -34,7 +36,6 @@ describe('HomeAssistant extension', () => {
|
||||
|
||||
it('Should not have duplicate type/object_ids in a mapping', () => {
|
||||
const duplicated = [];
|
||||
const HomeAssistant = require('../lib/extension/homeassistant');
|
||||
const ha = new HomeAssistant(null, null, null, null, {on: () => {}});
|
||||
|
||||
require('zigbee-herdsman-converters').devices.forEach((d) => {
|
||||
@@ -960,4 +961,28 @@ describe('HomeAssistant extension', () => {
|
||||
expect(MQTT.publish.mock.calls[2][0]).toStrictEqual('homeassistant/device_automation/0x0017880104e45520/click_single/config');
|
||||
expect(MQTT.publish.mock.calls[3][0]).toStrictEqual('zigbee2mqtt/button/click');
|
||||
});
|
||||
|
||||
it('Load Home Assistant mapping from external converters', async () => {
|
||||
fs.copyFileSync(path.join(__dirname, 'assets', 'mock-external-converter-multiple.js'), path.join(data.mockDir, 'mock-external-converter-multiple.js'));
|
||||
const beforeCount = Object.entries((new HomeAssistant(null, null, null, null, {on: () => {}}))._getMapping()).length;
|
||||
settings.set(['external_converters'], ['mock-external-converter-multiple.js']);
|
||||
controller = new Controller();
|
||||
const ha = controller.extensions.find((e) => e.constructor.name === 'HomeAssistant');
|
||||
await controller.start();
|
||||
await flushPromises();
|
||||
const afterCount = Object.entries(ha._getMapping()).length;
|
||||
expect(beforeCount + 1).toStrictEqual(afterCount);
|
||||
|
||||
const homeassistantSwitch = {
|
||||
type: 'switch',
|
||||
object_id: 'switch',
|
||||
discovery_payload: {
|
||||
payload_off: 'OFF',
|
||||
payload_on: 'ON',
|
||||
value_template: '{{ value_json.state }}',
|
||||
command_topic: true,
|
||||
},
|
||||
};
|
||||
expect(ha._getMapping()['external_converters_device']).toStrictEqual([homeassistantSwitch]);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user