From b4473d6e24de8dc2db0ae7cb7bbb014788854ae4 Mon Sep 17 00:00:00 2001 From: Oleksandr Masliuchenko Date: Sat, 10 Feb 2024 17:50:44 +0200 Subject: [PATCH] fix: Remove predefined endpoint list, remove limits on device friendly name (#21325) * Get rid of predefined list of endpoints, correct friend name validations * Fix minor bug while parsing a topic for an unknown device --- lib/extension/publish.ts | 2 +- lib/util/utils.ts | 24 +----------------------- test/bridge.test.js | 6 +++--- test/settings.test.js | 12 ------------ 4 files changed, 5 insertions(+), 39 deletions(-) diff --git a/lib/extension/publish.ts b/lib/extension/publish.ts index 064a1c60..755ad938 100644 --- a/lib/extension/publish.ts +++ b/lib/extension/publish.ts @@ -63,7 +63,7 @@ export default class Publish extends Extension { // There can be some ambiguoty between 'device_name/endpoint' and 'device/name/with/slashes' with no endpoint // Try to ensure the device with one of these names exist const re = this.zigbee.resolveEntity(deviceName); - if (re == null) { + if (re == null && endpointName) { // Possibly the last before get/set is just a continuation of the device name deviceName = `${deviceName}/${endpointName}`; endpointName = null; diff --git a/lib/util/utils.ts b/lib/util/utils.ts index a161928d..78b53e3f 100644 --- a/lib/util/utils.ts +++ b/lib/util/utils.ts @@ -30,22 +30,6 @@ function toLocalISOString(date: Date): string { ':' + pad(tzOffset % 60); } -const endpointNames = [ - 'left', 'right', 'center', 'bottom_left', 'bottom_right', 'default', - 'top_left', 'top_right', 'white', 'rgb', 'cct', 'system', 'top', 'bottom', 'center_left', 'center_right', - 'ep1', 'ep2', 'row_1', 'row_2', 'row_3', 'row_4', 'relay', 'usb', - 'l1', 'l2', 'l3', 'l4', 'l5', 'l6', 'l7', 'l8', - 'l9', 'l10', 'l11', 'l12', 'l13', 'l14', 'l15', 'l16', - 'l17', 'l18', 'l19', 'l20', 'l21', 'l22', 'l23', 'l24', - 'th1', 'th2', 'th3', 'th4', 'th5', 'th6', 'th7', 'th8', 'th9', 'th10', - 'button_1', 'button_2', 'button_3', 'button_4', 'button_5', - 'button_6', 'button_7', 'button_8', 'button_9', 'button_10', - 'button_11', 'button_12', 'button_13', 'button_14', 'button_15', - 'button_16', 'button_17', 'button_18', 'button_19', 'button_20', - 'button_light', 'button_fan_high', 'button_fan_med', 'button_fan_low', - 'heat', 'cool', 'water', 'meter', 'wifi', 'no_occupancy_since', -]; - function capitalize(s: string): string { return s[0].toUpperCase() + s.slice(1); } @@ -252,16 +236,10 @@ function getAllFiles(path_: string): string[] { function validateFriendlyName(name: string, throwFirstError=false): string[] { const errors = []; - for (const endpointName of endpointNames) { - if (name.toLowerCase().endsWith('/' + endpointName)) { - errors.push(`friendly_name is not allowed to end with: '/${endpointName}'`); - } - } if (name.length === 0) errors.push(`friendly_name must be at least 1 char long`); if (name.endsWith('/') || name.startsWith('/')) errors.push(`friendly_name is not allowed to end or start with /`); if (containsControlCharacter(name)) errors.push(`friendly_name is not allowed to contain control char`); - if (endpointNames.includes(name)) errors.push(`Following friendly_name are not allowed: '${endpointNames}'`); if (name.match(/.*\/\d*$/)) errors.push(`Friendly name cannot end with a "/DIGIT" ('${name}')`); if (name.includes('#') || name.includes('+')) { errors.push(`MQTT wildcard (+ and #) not allowed in friendly_name ('${name}')`); @@ -427,7 +405,7 @@ function getScenes(entity: zh.Endpoint | zh.Group): Scene[] { } export default { - endpointNames, capitalize, getZigbee2MQTTVersion, getDependencyVersion, formatDate, objectHasProperties, + capitalize, getZigbee2MQTTVersion, getDependencyVersion, formatDate, objectHasProperties, equalsPartial, getObjectProperty, getResponse, parseJSON, loadModuleFromText, loadModuleFromFile, removeNullPropertiesFromObject, toNetworkAddressHex, toSnakeCase, isEndpoint, isZHGroup, hours, minutes, seconds, validateFriendlyName, sleep, diff --git a/test/bridge.test.js b/test/bridge.test.js index 6ca218d7..a609f0ca 100644 --- a/test/bridge.test.js +++ b/test/bridge.test.js @@ -586,13 +586,13 @@ describe('Bridge', () => { ); }); - it('Shouldnt allow rename device with to now allowed name', async () => { + it('Shouldnt allow rename device with to not allowed name containing a wildcard', async () => { MQTT.publish.mockClear(); - MQTT.events.message('zigbee2mqtt/bridge/request/device/rename', stringify({from: 'bulb', to: 'living_room/blinds/center'})); + MQTT.events.message('zigbee2mqtt/bridge/request/device/rename', stringify({from: 'bulb', to: 'living_room/blinds#'})); await flushPromises(); expect(MQTT.publish).toHaveBeenCalledWith( 'zigbee2mqtt/bridge/response/device/rename', - stringify({"data":{},"status":"error","error":"friendly_name is not allowed to end with: '/center'"}), + stringify({"data":{},"status":"error","error":"MQTT wildcard (+ and #) not allowed in friendly_name ('living_room/blinds#')"}), {retain: false, qos: 0}, expect.any(Function) ); }); diff --git a/test/settings.test.js b/test/settings.test.js index ecb07453..5841a542 100644 --- a/test/settings.test.js +++ b/test/settings.test.js @@ -882,18 +882,6 @@ describe('Settings', () => { expect(settings.validate()).toEqual(expect.arrayContaining([error])); }); - it('Configuration shouldnt be valid when friendly_name is a postfix', async () => { - write(configurationFile, { - ...minimalConfig, - devices: {'0x0017880104e45519': {friendly_name: 'left', retain: false}}, - }); - - settings.reRead(); - - const error = `Following friendly_name are not allowed: '${utils.endpointNames}'`; - expect(settings.validate()).toEqual(expect.arrayContaining([error])); - }); - it('Configuration shouldnt be valid when duplicate friendly_name are used', async () => { write(configurationFile, { devices: {