diff --git a/.travis.yml b/.travis.yml index 3fc9e13a..aafa0428 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,9 @@ install: - npm install script: + - npm run verify-homeassistant-mapping + +after_script: - ".travis/docker.sh" - ".travis/wiki.sh" diff --git a/lib/controller.js b/lib/controller.js index 0f3ae72f..123d3ad3 100644 --- a/lib/controller.js +++ b/lib/controller.js @@ -49,7 +49,7 @@ class Controller { // MQTT discovery of all paired devices on startup. this.zigbee.getAllClients().forEach((device) => { if (deviceMapping[device.modelId]) { - homeassistant.discover(device.ieeeAddr, deviceMapping[device.modelId].homeassistant, this.mqtt); + homeassistant.discover(device.ieeeAddr, deviceMapping[device.modelId].model, this.mqtt); } }); } @@ -127,7 +127,7 @@ class Controller { // Home Assistant MQTT discovery if (settings.get().homeassistant) { - homeassistant.discover(device.ieeeAddr, mappedModel.homeassistant, this.mqtt); + homeassistant.discover(device.ieeeAddr, mappedModel.model, this.mqtt); } // After this point we cant handle message withoud cid anymore. diff --git a/lib/devices.js b/lib/devices.js index 26760616..43c795d0 100644 --- a/lib/devices.js +++ b/lib/devices.js @@ -1,11 +1,8 @@ -const homeassistant = require('./homeassistant').configurations; - const LED1623G12 = { model: 'LED1623G12', vendor: 'IKEA', description: 'TRADFRI LED bulb E27 1000 lumen, dimmable, opal white', supports: 'on/off, brightness', - homeassistant: [homeassistant.light_brightness] }; const devices = { @@ -15,28 +12,24 @@ const devices = { vendor: 'Xiaomi', description: 'MiJia wireless switch', supports: 'single, double, triple, quadruple, many and long click', - homeassistant: [homeassistant.sensor_click] }, 'lumi.sensor_switch.aq2': { model: 'WXKG11LM', vendor: 'Xiaomi', description: 'Aqara wireless switch', supports: 'single, double, triple, quadruple click', - homeassistant: [homeassistant.sensor_click] }, 'lumi.sensor_86sw1\u0000lu': { model: 'WXKG03LM', vendor: 'Xiaomi', description: 'Aqara single key wireless wall switch', supports: 'single click', - homeassistant: [homeassistant.sensor_click] }, 'lumi.sensor_86sw2\u0000Un': { model: 'WXKG02LM', vendor: 'Xiaomi', description: 'Aqara double key wireless wall switch', supports: 'left, right and both click', - homeassistant: [homeassistant.sensor_click] }, 'lumi.ctrl_neutral1': { model: 'QBKG04LM', @@ -44,7 +37,6 @@ const devices = { description: 'Aqara single key wired wall switch', supports: 'on/off', ep: {'': 2}, - homeassistant: [homeassistant.switch] }, 'lumi.ctrl_neutral2': { model: 'QBKG03LM', @@ -52,77 +44,66 @@ const devices = { description: 'Aqara double key wired wall switch', supports: 'l1 and l2 on/off', ep: {'l1': 2, 'l2': 3}, - homeassistant: [homeassistant.switch_l1, homeassistant.switch_l2] }, 'lumi.sens': { model: 'WSDCGQ01LM', vendor: 'Xiaomi', description: 'MiJia temperature & humidity sensor ', supports: 'temperature and humidity', - homeassistant: [homeassistant.sensor_temperature, homeassistant.sensor_humidity] }, 'lumi.weather': { model: 'WSDCGQ11LM', vendor: 'Xiaomi', description: 'Aqara temperature, humidity and pressure sensor', supports: 'temperature, humidity and pressure', - homeassistant: [homeassistant.sensor_temperature, homeassistant.sensor_humidity, homeassistant.sensor_pressure] }, 'lumi.sensor_motion': { model: 'RTCGQ01LM', vendor: 'Xiaomi', description: 'MiJia human body movement sensor', supports: 'occupancy', - homeassistant: [homeassistant.binary_sensor_occupancy] }, 'lumi.sensor_motion.aq2': { model: 'RTCGQ11LM', vendor: 'Xiaomi', description: 'Aqara human body movement and illuminance sensor', supports: 'occupancy and illuminance', - homeassistant: [homeassistant.binary_sensor_occupancy, homeassistant.sensor_illuminance] }, 'lumi.sensor_magnet': { model: 'MCCGQ01LM', vendor: 'Xiaomi', description: 'MiJia door & window contact sensor', supports: 'contact', - homeassistant: [homeassistant.binary_sensor_contact] }, 'lumi.sensor_magnet.aq2': { model: 'MCCGQ11LM', vendor: 'Xiaomi', description: 'Aqara door & window contact sensor', supports: 'contact', - homeassistant: [homeassistant.binary_sensor_contact] }, 'lumi.sensor_wleak.aq1': { model: 'SJCGQ11LM', vendor: 'Xiaomi', description: 'Aqara water leak sensor', supports: 'water leak true/false', - homeassistant: [homeassistant.binary_sensor_water_leak] }, 'lumi.sensor_cube': { model: 'MFKZQ01LM', vendor: 'Xiaomi', description: 'Mi smart home cube', supports: 'shake, wakeup, fall, tap, slide, flip180, flip90, rotate_left and rotate_right', - homeassistant: [homeassistant.sensor_action] }, 'lumi.plug': { model: 'ZNCZ02LM', description: 'Mi power plug ZigBee', supports: 'on/off, power measurement', vendor: 'Xiaomi', - homeassistant: [homeassistant.switch, homeassistant.sensor_power] }, 'lumi.ctrl_86plug': { model: 'QBCZ11LM', description: 'Aqara socket Zigbee', supports: 'on/off, power measurement', vendor: 'Xiaomi', - homeassistant: [homeassistant.switch, homeassistant.sensor_power] }, // IKEA @@ -131,7 +112,6 @@ const devices = { vendor: 'IKEA', description: 'TRADFRI LED bulb E27 980 lumen, dimmable, white spectrum, opal white', supports: 'on/off, brightness, color temperature', - homeassistant: [homeassistant.light_brightness_colortemp] }, // LED1623G12 uses 2 model IDs, see https://github.com/Koenkk/zigbee2mqtt/issues/21 'TRADFRI bulb E27 opal 1000lm': LED1623G12, @@ -141,21 +121,18 @@ const devices = { vendor: 'IKEA', description: 'TRADFRI LED bulb GU10 400 lumen, dimmable, white spectrum', supports: 'on/off, brightness, color temperature', - homeassistant: [homeassistant.light_brightness_colortemp] }, 'TRADFRI bulb GU10 W 400lm': { model: 'LED1650R5', vendor: 'IKEA', description: 'TRADFRI LED bulb GU10 400 lumen, dimmable', supports: 'on/off, brightness', - homeassistant: [homeassistant.light_brightness] }, 'TRADFRI bulb E14 WS opal 400lm': { model: 'LED1536G5', vendor: 'IKEA', description: 'TRADFRI LED bulb E14 400 lumen, dimmable, white spectrum, opal white', supports: 'on/off, brightness, color temperature', - homeassistant: [homeassistant.light_brightness_colortemp] }, // Philips @@ -164,7 +141,6 @@ const devices = { vendor: 'Philips', description: 'Hue Go', supports: 'on/off, brightness, color temperature, color xy', - homeassistant: [homeassistant.light_brightness_colortemp_xy] }, } diff --git a/lib/homeassistant.js b/lib/homeassistant.js index c517f0a5..a5dd7ce7 100644 --- a/lib/homeassistant.js +++ b/lib/homeassistant.js @@ -172,29 +172,51 @@ const configurations = { }, }; +// Map homeassitant configurations to devices. +const mapping = { + 'WXKG01LM': [configurations.sensor_click], + 'WXKG11LM': [configurations.sensor_click], + 'WXKG03LM': [configurations.sensor_click], + 'WXKG02LM': [configurations.sensor_click], + 'QBKG04LM': [configurations.switch], + 'QBKG03LM': [configurations.switch_l1, configurations.switch_l2], + 'WSDCGQ01LM': [configurations.sensor_temperature, configurations.sensor_humidity], + 'WSDCGQ11LM': [configurations.sensor_temperature, configurations.sensor_humidity, configurations.sensor_pressure], + 'RTCGQ01LM': [configurations.binary_sensor_occupancy], + 'RTCGQ11LM': [configurations.binary_sensor_occupancy, configurations.sensor_illuminance], + 'MCCGQ01LM': [configurations.binary_sensor_contact], + 'MCCGQ11LM': [configurations.binary_sensor_contact], + 'SJCGQ11LM': [configurations.binary_sensor_water_leak], + 'MFKZQ01LM': [configurations.sensor_action], + 'ZNCZ02LM': [configurations.switch, configurations.sensor_power], + 'QBCZ11LM': [configurations.switch, configurations.sensor_power], + 'LED1545G12': [configurations.light_brightness_colortemp], + 'LED1623G12': [configurations.light_brightness], + 'LED1537R6': [configurations.light_brightness_colortemp], + 'LED1650R5': [configurations.light_brightness], + 'LED1536G5': [configurations.light_brightness_colortemp], + '7146060PH': [configurations.light_brightness_colortemp_xy], +}; + // A map of all discoverd devices const discovered = {}; -function discover(deviceID, configs, mqtt) { +function discover(deviceID, model, mqtt) { // Check if already discoverd and check if there are configs. - if (discovered[deviceID] || !configs) { + if (discovered[deviceID] || !mapping[model]) { return; } const friendlyName = settings.getDevice(deviceID).friendly_name; - configs.forEach((config) => { + mapping[model].forEach((config) => { const topic = `${config.type}/${deviceID}/${config.object_id}/config`; const payload = config.discovery_payload; payload.state_topic = `${settings.get().mqtt.base_topic}/${friendlyName}`; payload.availability_topic = `${settings.get().mqtt.base_topic}/bridge/state`; // Set unique names in cases this device produces multiple entities in homeassistant. - if (configs.length > 1) { - payload.name = `${friendlyName}_${config.object_id}`; - } else { - payload.name = friendlyName; - } + payload.name = mapping[model].length > 1 ? `${friendlyName}_${config.object_id}` : friendlyName; if (payload.command_topic) { payload.command_topic = `${settings.get().mqtt.base_topic}/${friendlyName}/`; @@ -213,6 +235,6 @@ function discover(deviceID, configs, mqtt) { } module.exports = { - configurations: configurations, - discover: (deviceID, configs, mqtt) => discover(deviceID, configs, mqtt), + mapping: mapping, + discover: (deviceID, model, mqtt) => discover(deviceID, model, mqtt), }; diff --git a/package.json b/package.json index 38fb9ebf..e5bbb645 100644 --- a/package.json +++ b/package.json @@ -18,7 +18,8 @@ ], "scripts": { "start": "node index.js", - "docgen": "node support/docgen.js" + "docgen": "node support/docgen.js", + "verify-homeassistant-mapping": "node support/verify-homeassistant-mapping.js" }, "author": "Koen Kanters", "license": "GPL-3.0", diff --git a/support/docgen.js b/support/docgen.js index 3d0f4d24..53038fbe 100644 --- a/support/docgen.js +++ b/support/docgen.js @@ -7,6 +7,7 @@ const zigbee2mqtt = require('../lib/converters/zigbee2mqtt'); const deviceMapping = require('../lib/devices'); const fs = require('fs'); const YAML = require('json2yaml'); +const homeassistant = require('../lib/homeassistant'); // Sanity check if all supported devices are in deviceMapping const supportedDevices = new Set(); @@ -106,9 +107,10 @@ Object.values(deviceMapping).forEach((device) => { text += `### ${device.model}\n`; text += '```yaml\n' - device.homeassistant.forEach((d, i) => { + const configurations = homeassistant.mapping[device.model] + configurations.forEach((d, i) => { text += homeassistantConfig(d); - if (device.homeassistant.length > 1 && i < device.homeassistant.length - 1) { + if (configurations.length > 1 && i < configurations.length - 1) { text += '\n'; } }) diff --git a/support/verify-homeassistant-mapping.js b/support/verify-homeassistant-mapping.js new file mode 100644 index 00000000..15ae7565 --- /dev/null +++ b/support/verify-homeassistant-mapping.js @@ -0,0 +1,13 @@ +// Verify that there are homeassistant mappings for every device. +const devices = require('../lib/devices'); +const homeassistant = require('../lib/homeassistant'); + +let failed = false; +Object.values(devices).forEach((d) => { + if (!homeassistant.mapping[d.model]) { + console.error(`Missing homeassistant mapping for '${d.model}'`); + failed = true; + } +}); + +process.exit(failed ? 1 : 0); \ No newline at end of file