From 97100b0fd81fb9c6edfbf6a1bacf99158952c44c Mon Sep 17 00:00:00 2001
From: atrovato <1839717+atrovato@users.noreply.github.com>
Date: Sun, 19 Sep 2021 08:35:22 +0200
Subject: [PATCH 1/9] Zigbee2mqtt remove device list
---
server/services/zigbee2mqtt/model/AXIS.js | 15 -
server/services/zigbee2mqtt/model/Adeo.js | 17 --
.../services/zigbee2mqtt/model/AduroSmart.js | 16 --
server/services/zigbee2mqtt/model/Airam.js | 16 --
server/services/zigbee2mqtt/model/Anchor.js | 15 -
server/services/zigbee2mqtt/model/Belkin.js | 15 -
server/services/zigbee2mqtt/model/Bitron.js | 18 --
.../services/zigbee2mqtt/model/Blaupunkt.js | 15 -
server/services/zigbee2mqtt/model/Bosch.js | 16 --
server/services/zigbee2mqtt/model/Calex.js | 16 --
.../services/zigbee2mqtt/model/Centralite.js | 15 -
server/services/zigbee2mqtt/model/Climax.js | 17 --
.../zigbee2mqtt/model/CommercialElectric.js | 15 -
server/services/zigbee2mqtt/model/Danalock.js | 15 -
.../zigbee2mqtt/model/DresdenElektronik.js | 16 --
server/services/zigbee2mqtt/model/EDP.js | 16 --
server/services/zigbee2mqtt/model/ELKO.js | 15 -
server/services/zigbee2mqtt/model/EcoSmart.js | 18 --
.../services/zigbee2mqtt/model/Eurotronic.js | 15 -
server/services/zigbee2mqtt/model/GE.js | 19 --
.../zigbee2mqtt/model/GMYSmartBulb.js | 15 -
server/services/zigbee2mqtt/model/Gira.js | 15 -
server/services/zigbee2mqtt/model/Gledopto.js | 26 --
server/services/zigbee2mqtt/model/HEIMAN.js | 27 --
.../services/zigbee2mqtt/model/HamptonBay.js | 15 -
server/services/zigbee2mqtt/model/Hive.js | 19 --
server/services/zigbee2mqtt/model/Honyar.js | 15 -
server/services/zigbee2mqtt/model/IKEA.js | 43 ---
.../services/zigbee2mqtt/model/Iluminize.js | 15 -
server/services/zigbee2mqtt/model/Immax.js | 15 -
server/services/zigbee2mqtt/model/Innr.js | 42 ---
server/services/zigbee2mqtt/model/Iris.js | 17 --
server/services/zigbee2mqtt/model/JIAWEN.js | 15 -
server/services/zigbee2mqtt/model/KeenHome.js | 16 --
.../zigbee2mqtt/model/KsentryElectronics.js | 15 -
.../services/zigbee2mqtt/model/Leedarson.js | 17 --
server/services/zigbee2mqtt/model/Lidl.js | 25 --
.../services/zigbee2mqtt/model/LivingWise.js | 16 --
server/services/zigbee2mqtt/model/Livolo.js | 15 -
server/services/zigbee2mqtt/model/Lonsonho.js | 16 --
server/services/zigbee2mqtt/model/Lupus.js | 16 --
server/services/zigbee2mqtt/model/Meazon.js | 16 --
.../services/zigbee2mqtt/model/MullerLicht.js | 17 --
server/services/zigbee2mqtt/model/NET2GRID.js | 15 -
server/services/zigbee2mqtt/model/Nanoleaf.js | 15 -
server/services/zigbee2mqtt/model/Netvox.js | 15 -
.../services/zigbee2mqtt/model/NinjaBlocks.js | 15 -
server/services/zigbee2mqtt/model/Nue_3A.js | 31 --
server/services/zigbee2mqtt/model/Nyce.js | 18 --
server/services/zigbee2mqtt/model/ORVIBO.js | 15 -
server/services/zigbee2mqtt/model/OSRAM.js | 37 ---
server/services/zigbee2mqtt/model/Oujiabao.js | 15 -
.../services/zigbee2mqtt/model/PaulNeuhaus.js | 17 --
server/services/zigbee2mqtt/model/Paulmann.js | 18 --
server/services/zigbee2mqtt/model/Philips.js | 51 ----
server/services/zigbee2mqtt/model/RGBGenie.js | 15 -
server/services/zigbee2mqtt/model/ROBB.js | 15 -
server/services/zigbee2mqtt/model/SONOFF.js | 18 --
server/services/zigbee2mqtt/model/Salus.js | 15 -
server/services/zigbee2mqtt/model/Securifi.js | 15 -
server/services/zigbee2mqtt/model/Sengled.js | 21 --
server/services/zigbee2mqtt/model/Sercomm.js | 15 -
.../zigbee2mqtt/model/ShenzhenHoma.js | 17 --
.../zigbee2mqtt/model/SmartHomePty.js | 16 --
.../services/zigbee2mqtt/model/SmartThings.js | 29 --
server/services/zigbee2mqtt/model/Stelpro.js | 15 -
.../services/zigbee2mqtt/model/Sunricher.js | 15 -
server/services/zigbee2mqtt/model/Swann.js | 16 --
server/services/zigbee2mqtt/model/Sylvania.js | 25 --
server/services/zigbee2mqtt/model/TUYATEC.js | 15 -
.../zigbee2mqtt/model/ThirdReality.js | 15 -
server/services/zigbee2mqtt/model/Trust.js | 18 --
server/services/zigbee2mqtt/model/TuYa.js | 21 --
server/services/zigbee2mqtt/model/Visonic.js | 16 --
server/services/zigbee2mqtt/model/Xiaomi.js | 45 ---
server/services/zigbee2mqtt/model/Yale.js | 18 --
server/services/zigbee2mqtt/model/eCosy.js | 15 -
server/services/zigbee2mqtt/model/iCasa.js | 15 -
server/services/zigbee2mqtt/model/ilux.js | 15 -
server/services/zigbee2mqtt/model/index.js | 102 -------
server/services/zigbee2mqtt/utils/features.js | 272 ------------------
.../zigbee2mqtt/utils/loadFeatures.js | 33 ---
.../zigbee2mqtt/utils/loadFeatures.test.js | 59 ----
83 files changed, 1936 deletions(-)
delete mode 100644 server/services/zigbee2mqtt/model/AXIS.js
delete mode 100644 server/services/zigbee2mqtt/model/Adeo.js
delete mode 100644 server/services/zigbee2mqtt/model/AduroSmart.js
delete mode 100644 server/services/zigbee2mqtt/model/Airam.js
delete mode 100644 server/services/zigbee2mqtt/model/Anchor.js
delete mode 100644 server/services/zigbee2mqtt/model/Belkin.js
delete mode 100644 server/services/zigbee2mqtt/model/Bitron.js
delete mode 100644 server/services/zigbee2mqtt/model/Blaupunkt.js
delete mode 100644 server/services/zigbee2mqtt/model/Bosch.js
delete mode 100644 server/services/zigbee2mqtt/model/Calex.js
delete mode 100644 server/services/zigbee2mqtt/model/Centralite.js
delete mode 100644 server/services/zigbee2mqtt/model/Climax.js
delete mode 100644 server/services/zigbee2mqtt/model/CommercialElectric.js
delete mode 100644 server/services/zigbee2mqtt/model/Danalock.js
delete mode 100644 server/services/zigbee2mqtt/model/DresdenElektronik.js
delete mode 100644 server/services/zigbee2mqtt/model/EDP.js
delete mode 100644 server/services/zigbee2mqtt/model/ELKO.js
delete mode 100644 server/services/zigbee2mqtt/model/EcoSmart.js
delete mode 100644 server/services/zigbee2mqtt/model/Eurotronic.js
delete mode 100644 server/services/zigbee2mqtt/model/GE.js
delete mode 100644 server/services/zigbee2mqtt/model/GMYSmartBulb.js
delete mode 100644 server/services/zigbee2mqtt/model/Gira.js
delete mode 100644 server/services/zigbee2mqtt/model/Gledopto.js
delete mode 100644 server/services/zigbee2mqtt/model/HEIMAN.js
delete mode 100644 server/services/zigbee2mqtt/model/HamptonBay.js
delete mode 100644 server/services/zigbee2mqtt/model/Hive.js
delete mode 100644 server/services/zigbee2mqtt/model/Honyar.js
delete mode 100644 server/services/zigbee2mqtt/model/IKEA.js
delete mode 100644 server/services/zigbee2mqtt/model/Iluminize.js
delete mode 100644 server/services/zigbee2mqtt/model/Immax.js
delete mode 100644 server/services/zigbee2mqtt/model/Innr.js
delete mode 100644 server/services/zigbee2mqtt/model/Iris.js
delete mode 100644 server/services/zigbee2mqtt/model/JIAWEN.js
delete mode 100644 server/services/zigbee2mqtt/model/KeenHome.js
delete mode 100644 server/services/zigbee2mqtt/model/KsentryElectronics.js
delete mode 100644 server/services/zigbee2mqtt/model/Leedarson.js
delete mode 100644 server/services/zigbee2mqtt/model/Lidl.js
delete mode 100644 server/services/zigbee2mqtt/model/LivingWise.js
delete mode 100644 server/services/zigbee2mqtt/model/Livolo.js
delete mode 100644 server/services/zigbee2mqtt/model/Lonsonho.js
delete mode 100644 server/services/zigbee2mqtt/model/Lupus.js
delete mode 100644 server/services/zigbee2mqtt/model/Meazon.js
delete mode 100644 server/services/zigbee2mqtt/model/MullerLicht.js
delete mode 100644 server/services/zigbee2mqtt/model/NET2GRID.js
delete mode 100644 server/services/zigbee2mqtt/model/Nanoleaf.js
delete mode 100644 server/services/zigbee2mqtt/model/Netvox.js
delete mode 100644 server/services/zigbee2mqtt/model/NinjaBlocks.js
delete mode 100644 server/services/zigbee2mqtt/model/Nue_3A.js
delete mode 100644 server/services/zigbee2mqtt/model/Nyce.js
delete mode 100644 server/services/zigbee2mqtt/model/ORVIBO.js
delete mode 100644 server/services/zigbee2mqtt/model/OSRAM.js
delete mode 100644 server/services/zigbee2mqtt/model/Oujiabao.js
delete mode 100644 server/services/zigbee2mqtt/model/PaulNeuhaus.js
delete mode 100644 server/services/zigbee2mqtt/model/Paulmann.js
delete mode 100644 server/services/zigbee2mqtt/model/Philips.js
delete mode 100644 server/services/zigbee2mqtt/model/RGBGenie.js
delete mode 100644 server/services/zigbee2mqtt/model/ROBB.js
delete mode 100644 server/services/zigbee2mqtt/model/SONOFF.js
delete mode 100644 server/services/zigbee2mqtt/model/Salus.js
delete mode 100644 server/services/zigbee2mqtt/model/Securifi.js
delete mode 100644 server/services/zigbee2mqtt/model/Sengled.js
delete mode 100644 server/services/zigbee2mqtt/model/Sercomm.js
delete mode 100644 server/services/zigbee2mqtt/model/ShenzhenHoma.js
delete mode 100644 server/services/zigbee2mqtt/model/SmartHomePty.js
delete mode 100644 server/services/zigbee2mqtt/model/SmartThings.js
delete mode 100644 server/services/zigbee2mqtt/model/Stelpro.js
delete mode 100644 server/services/zigbee2mqtt/model/Sunricher.js
delete mode 100644 server/services/zigbee2mqtt/model/Swann.js
delete mode 100644 server/services/zigbee2mqtt/model/Sylvania.js
delete mode 100644 server/services/zigbee2mqtt/model/TUYATEC.js
delete mode 100644 server/services/zigbee2mqtt/model/ThirdReality.js
delete mode 100644 server/services/zigbee2mqtt/model/Trust.js
delete mode 100644 server/services/zigbee2mqtt/model/TuYa.js
delete mode 100644 server/services/zigbee2mqtt/model/Visonic.js
delete mode 100644 server/services/zigbee2mqtt/model/Xiaomi.js
delete mode 100644 server/services/zigbee2mqtt/model/Yale.js
delete mode 100644 server/services/zigbee2mqtt/model/eCosy.js
delete mode 100644 server/services/zigbee2mqtt/model/iCasa.js
delete mode 100644 server/services/zigbee2mqtt/model/ilux.js
delete mode 100644 server/services/zigbee2mqtt/model/index.js
delete mode 100644 server/services/zigbee2mqtt/utils/features.js
delete mode 100644 server/services/zigbee2mqtt/utils/loadFeatures.js
delete mode 100644 server/test/services/zigbee2mqtt/utils/loadFeatures.test.js
diff --git a/server/services/zigbee2mqtt/model/AXIS.js b/server/services/zigbee2mqtt/model/AXIS.js
deleted file mode 100644
index ad300030f1..0000000000
--- a/server/services/zigbee2mqtt/model/AXIS.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * AXIS managed models.
- */
-const AXIS = {
- brand: 'AXIS',
- models: {
- 'GR-ZB01-W': [features.door], // curtain / shuttle
- },
-};
-
-module.exports = {
- AXIS,
-};
diff --git a/server/services/zigbee2mqtt/model/Adeo.js b/server/services/zigbee2mqtt/model/Adeo.js
deleted file mode 100644
index df787d860a..0000000000
--- a/server/services/zigbee2mqtt/model/Adeo.js
+++ /dev/null
@@ -1,17 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Adeo managed models.
- */
-const Adeo = {
- brand: 'Adeo',
- models: {
- '9CZA-A806ST-Q1A': [features.light, features.brightness, features.color_temperature, features.color],
- '9CZA-M350ST-Q1A': [features.light, features.brightness, features.color_temperature, features.color],
- '9CZA-G1521-Q1A': [features.light, features.brightness, features.color_temperature, features.color],
- },
-};
-
-module.exports = {
- Adeo,
-};
diff --git a/server/services/zigbee2mqtt/model/AduroSmart.js b/server/services/zigbee2mqtt/model/AduroSmart.js
deleted file mode 100644
index 062761fc3a..0000000000
--- a/server/services/zigbee2mqtt/model/AduroSmart.js
+++ /dev/null
@@ -1,16 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * AduroSmart managed models.
- */
-const AduroSmart = {
- brand: 'AduroSmart',
- models: {
- '81809': [features.light, features.brightness, features.color_temperature, features.color],
- '81825': [features.switch_sensor],
- },
-};
-
-module.exports = {
- AduroSmart,
-};
diff --git a/server/services/zigbee2mqtt/model/Airam.js b/server/services/zigbee2mqtt/model/Airam.js
deleted file mode 100644
index 319ac33644..0000000000
--- a/server/services/zigbee2mqtt/model/Airam.js
+++ /dev/null
@@ -1,16 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Airam managed models.
- */
-const Airam = {
- brand: 'Airam',
- models: {
- '4713407': [features.light, features.brightness],
- 'AIRAM-CTR.U': [features.switch_sensor],
- },
-};
-
-module.exports = {
- Airam,
-};
diff --git a/server/services/zigbee2mqtt/model/Anchor.js b/server/services/zigbee2mqtt/model/Anchor.js
deleted file mode 100644
index dbd130523e..0000000000
--- a/server/services/zigbee2mqtt/model/Anchor.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Anchor managed models.
- */
-const Anchor = {
- brand: 'Anchor',
- models: {
- '67200BL': [features.switch],
- },
-};
-
-module.exports = {
- Anchor,
-};
diff --git a/server/services/zigbee2mqtt/model/Belkin.js b/server/services/zigbee2mqtt/model/Belkin.js
deleted file mode 100644
index 2b253fce2c..0000000000
--- a/server/services/zigbee2mqtt/model/Belkin.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Belkin managed models.
- */
-const Belkin = {
- brand: 'Belkin',
- models: {
- F7C033: [features.light, features.brightness],
- },
-};
-
-module.exports = {
- Belkin,
-};
diff --git a/server/services/zigbee2mqtt/model/Bitron.js b/server/services/zigbee2mqtt/model/Bitron.js
deleted file mode 100644
index c11f906f00..0000000000
--- a/server/services/zigbee2mqtt/model/Bitron.js
+++ /dev/null
@@ -1,18 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Bitron managed models.
- */
-const Bitron = {
- brand: 'Bitron',
- models: {
- 'AV2010/34': [features.switch_sensor],
- 'AV2010/22': [features.motion],
- 'AV2010/25': [features.switch, features.power],
- 'AV2010/32': [features.switch_sensor], // features.heating],
- },
-};
-
-module.exports = {
- Bitron,
-};
diff --git a/server/services/zigbee2mqtt/model/Blaupunkt.js b/server/services/zigbee2mqtt/model/Blaupunkt.js
deleted file mode 100644
index c007b762fa..0000000000
--- a/server/services/zigbee2mqtt/model/Blaupunkt.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Blaupunkt managed models.
- */
-const Blaupunkt = {
- brand: 'Blaupunkt',
- models: {
- 'SCM-S1': [features.door], // curtain / shutter
- },
-};
-
-module.exports = {
- Blaupunkt,
-};
diff --git a/server/services/zigbee2mqtt/model/Bosch.js b/server/services/zigbee2mqtt/model/Bosch.js
deleted file mode 100644
index c9139ad90e..0000000000
--- a/server/services/zigbee2mqtt/model/Bosch.js
+++ /dev/null
@@ -1,16 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Bosch managed models.
- */
-const Bosch = {
- brand: 'Bosch',
- models: {
- 'RADON TriTech ZB': [features.temperature, features.motion],
- 'ISW-ZPR1-WP13': [features.temperature, features.motion],
- },
-};
-
-module.exports = {
- Bosch,
-};
diff --git a/server/services/zigbee2mqtt/model/Calex.js b/server/services/zigbee2mqtt/model/Calex.js
deleted file mode 100644
index 5a1c2d1f1f..0000000000
--- a/server/services/zigbee2mqtt/model/Calex.js
+++ /dev/null
@@ -1,16 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Calex managed models.
- */
-const Calex = {
- brand: 'Calex',
- models: {
- '421786': [features.light, features.brightness],
- '421792': [features.light, features.brightness, features.color_temperature, features.color],
- },
-};
-
-module.exports = {
- Calex,
-};
diff --git a/server/services/zigbee2mqtt/model/Centralite.js b/server/services/zigbee2mqtt/model/Centralite.js
deleted file mode 100644
index 12d03fcfd9..0000000000
--- a/server/services/zigbee2mqtt/model/Centralite.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Centralite managed models.
- */
-const Centralite = {
- brand: 'Centralite',
- models: {
- '4256251-RZHAC': [features.switch, features.power],
- },
-};
-
-module.exports = {
- Centralite,
-};
diff --git a/server/services/zigbee2mqtt/model/Climax.js b/server/services/zigbee2mqtt/model/Climax.js
deleted file mode 100644
index 72fb32f4c6..0000000000
--- a/server/services/zigbee2mqtt/model/Climax.js
+++ /dev/null
@@ -1,17 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Climax managed models.
- */
-const Climax = {
- brand: 'Climax',
- models: {
- 'PSS-23ZBS': [features.switch],
- 'SCM-5ZBS': [features.door], // curtain / shutter
- 'PSM-29ZBSR': [features.switch],
- },
-};
-
-module.exports = {
- Climax,
-};
diff --git a/server/services/zigbee2mqtt/model/CommercialElectric.js b/server/services/zigbee2mqtt/model/CommercialElectric.js
deleted file mode 100644
index 2ee9878d72..0000000000
--- a/server/services/zigbee2mqtt/model/CommercialElectric.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Commercial Electric managed models.
- */
-const CommercialElectric = {
- brand: 'Commercial Electric',
- models: {
- '53170161': [features.light, features.brightness, features.color_temperature],
- },
-};
-
-module.exports = {
- CommercialElectric,
-};
diff --git a/server/services/zigbee2mqtt/model/Danalock.js b/server/services/zigbee2mqtt/model/Danalock.js
deleted file mode 100644
index b7a820b9c7..0000000000
--- a/server/services/zigbee2mqtt/model/Danalock.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Danalock managed models.
- */
-const Danalock = {
- brand: 'Danalock',
- models: {
- 'V3-BTZB': [features.door],
- },
-};
-
-module.exports = {
- Danalock,
-};
diff --git a/server/services/zigbee2mqtt/model/DresdenElektronik.js b/server/services/zigbee2mqtt/model/DresdenElektronik.js
deleted file mode 100644
index 6db98273b4..0000000000
--- a/server/services/zigbee2mqtt/model/DresdenElektronik.js
+++ /dev/null
@@ -1,16 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Dresden Elektronik managed models.
- */
-const DresdenElektronik = {
- brand: 'Dresden Elektronik',
- models: {
- Mega23M12: [features.light, features.brightness, features.color_temperature, features.color],
- 'XVV-Mega23M12': [features.light, features.brightness, features.color_temperature],
- },
-};
-
-module.exports = {
- DresdenElektronik,
-};
diff --git a/server/services/zigbee2mqtt/model/EDP.js b/server/services/zigbee2mqtt/model/EDP.js
deleted file mode 100644
index 09c52c2026..0000000000
--- a/server/services/zigbee2mqtt/model/EDP.js
+++ /dev/null
@@ -1,16 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * EDP managed models.
- */
-const EDP = {
- brand: 'EDP',
- models: {
- 'PLUG EDP RE:DY': [features.switch, features.power],
- 'SWITCH EDP RE:DY': [features.switch],
- },
-};
-
-module.exports = {
- EDP,
-};
diff --git a/server/services/zigbee2mqtt/model/ELKO.js b/server/services/zigbee2mqtt/model/ELKO.js
deleted file mode 100644
index 1253354f19..0000000000
--- a/server/services/zigbee2mqtt/model/ELKO.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * ELKO managed models.
- */
-const ELKO = {
- brand: 'ELKO',
- models: {
- '316GLEDRF': [features.light, features.brightness],
- },
-};
-
-module.exports = {
- ELKO,
-};
diff --git a/server/services/zigbee2mqtt/model/EcoSmart.js b/server/services/zigbee2mqtt/model/EcoSmart.js
deleted file mode 100644
index 8a46c86477..0000000000
--- a/server/services/zigbee2mqtt/model/EcoSmart.js
+++ /dev/null
@@ -1,18 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * EcoSmart managed models.
- */
-const EcoSmart = {
- brand: 'EcoSmart',
- models: {
- D1821: [features.light, features.brightness, features.color_temperature, features.color],
- D1531: [features.light, features.brightness],
- D1532: [features.light, features.brightness],
- D1542: [features.light, features.brightness, features.color_temperature],
- },
-};
-
-module.exports = {
- EcoSmart,
-};
diff --git a/server/services/zigbee2mqtt/model/Eurotronic.js b/server/services/zigbee2mqtt/model/Eurotronic.js
deleted file mode 100644
index 176c5c4802..0000000000
--- a/server/services/zigbee2mqtt/model/Eurotronic.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Eurotronic managed models.
- */
-const Eurotronic = {
- brand: 'Eurotronic',
- models: {
- SPZB0001: [features.temperature], // features.heating],
- },
-};
-
-module.exports = {
- Eurotronic,
-};
diff --git a/server/services/zigbee2mqtt/model/GE.js b/server/services/zigbee2mqtt/model/GE.js
deleted file mode 100644
index 9a70d6fae0..0000000000
--- a/server/services/zigbee2mqtt/model/GE.js
+++ /dev/null
@@ -1,19 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * GE managed models.
- */
-const GE = {
- brand: 'GE',
- models: {
- '22670': [features.light, features.brightness],
- '45852GE': [features.light, features.brightness],
- '45853GE': [features.switch, features.power],
- '45856GE': [features.switch],
- '45857GE': [features.light, features.brightness],
- },
-};
-
-module.exports = {
- GE,
-};
diff --git a/server/services/zigbee2mqtt/model/GMYSmartBulb.js b/server/services/zigbee2mqtt/model/GMYSmartBulb.js
deleted file mode 100644
index b03b809c12..0000000000
--- a/server/services/zigbee2mqtt/model/GMYSmartBulb.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * GMY Smart Bulb managed models.
- */
-const GMYSmartBulb = {
- brand: 'GMY Smart Bulb',
- models: {
- B07KG5KF5R: [features.light, features.brightness, features.color_temperature],
- },
-};
-
-module.exports = {
- GMYSmartBulb,
-};
diff --git a/server/services/zigbee2mqtt/model/Gira.js b/server/services/zigbee2mqtt/model/Gira.js
deleted file mode 100644
index c67ae10670..0000000000
--- a/server/services/zigbee2mqtt/model/Gira.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Gira managed models.
- */
-const Gira = {
- brand: 'Gira',
- models: {
- '2430-100': [features.switch_sensor],
- },
-};
-
-module.exports = {
- Gira,
-};
diff --git a/server/services/zigbee2mqtt/model/Gledopto.js b/server/services/zigbee2mqtt/model/Gledopto.js
deleted file mode 100644
index a2b46a7748..0000000000
--- a/server/services/zigbee2mqtt/model/Gledopto.js
+++ /dev/null
@@ -1,26 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Gledopto managed models.
- */
-const Gledopto = {
- brand: 'Gledopto',
- models: {
- 'GL-C-008': [features.light, features.brightness, features.color_temperature, features.color],
- 'GL-S-004Z': [features.light, features.brightness, features.color_temperature],
- 'GL-C-006/GL-C-009': [features.light, features.brightness, features.color_temperature],
- 'GL-S-007Z': [features.light, features.brightness, features.color_temperature],
- 'GL-B-001Z': [features.light, features.brightness, features.color_temperature],
- 'GL-G-001Z': [features.light, features.brightness, features.color_temperature, features.color],
- 'GL-B-007Z': [features.light, features.brightness, features.color_temperature, features.color],
- 'GL-B-008Z': [features.light, features.brightness, features.color_temperature, features.color],
- 'GL-D-003Z': [features.light, features.brightness, features.color_temperature, features.color],
- 'GL-S-003Z': [features.light, features.brightness, features.color_temperature, features.color],
- 'GD-CZ-006': [features.light, features.brightness],
- 'GL-FL-004TZ': [features.light, features.brightness, features.color_temperature, features.color],
- },
-};
-
-module.exports = {
- Gledopto,
-};
diff --git a/server/services/zigbee2mqtt/model/HEIMAN.js b/server/services/zigbee2mqtt/model/HEIMAN.js
deleted file mode 100644
index 544dfdf96b..0000000000
--- a/server/services/zigbee2mqtt/model/HEIMAN.js
+++ /dev/null
@@ -1,27 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * HEIMAN managed models.
- */
-const HEIMAN = {
- brand: 'HEIMAN',
- models: {
- 'HS1CA-M': [features.smoke],
- HS3MS: [features.motion],
- HS2SK: [features.switch, features.power],
- HS1SA: [features.smoke],
- HS3SA: [features.smoke],
- HS3CG: [features.smoke],
- 'HS1DS/HS3DS': [features.door],
- 'HEIMAN-M1': [features.door],
- 'HS1DS-E': [features.door],
- 'HS1WL/HS3WL': [features.water],
- 'HS1-WL-E': [features.water],
- 'HS1RC-M': [features.switch_sensor],
- 'HS1CA-E': [features.smoke],
- },
-};
-
-module.exports = {
- HEIMAN,
-};
diff --git a/server/services/zigbee2mqtt/model/HamptonBay.js b/server/services/zigbee2mqtt/model/HamptonBay.js
deleted file mode 100644
index 97a53a86e5..0000000000
--- a/server/services/zigbee2mqtt/model/HamptonBay.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Hampton Bay managed models.
- */
-const HamptonBay = {
- brand: 'Hampton Bay',
- models: {
- '99432': [features.switch_sensor],
- },
-};
-
-module.exports = {
- HamptonBay,
-};
diff --git a/server/services/zigbee2mqtt/model/Hive.js b/server/services/zigbee2mqtt/model/Hive.js
deleted file mode 100644
index a3a7810579..0000000000
--- a/server/services/zigbee2mqtt/model/Hive.js
+++ /dev/null
@@ -1,19 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Hive managed models.
- */
-const Hive = {
- brand: 'Hive',
- models: {
- HALIGHTDIMWWE27: [features.light, features.brightness],
- HALIGHTDIMWWB22: [features.light, features.brightness],
- '1613V': [features.switch, features.power],
- 'HV-GSCXZB269': [features.light, features.brightness, features.color_temperature],
- 'HV-GSCXZB279_HV-GSCXZB229': [features.light, features.brightness, features.color_temperature],
- },
-};
-
-module.exports = {
- Hive,
-};
diff --git a/server/services/zigbee2mqtt/model/Honyar.js b/server/services/zigbee2mqtt/model/Honyar.js
deleted file mode 100644
index ca031e265a..0000000000
--- a/server/services/zigbee2mqtt/model/Honyar.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Honyar managed models.
- */
-const Honyar = {
- brand: 'Honyar',
- models: {
- U86K31ND6: [features.switch],
- },
-};
-
-module.exports = {
- Honyar,
-};
diff --git a/server/services/zigbee2mqtt/model/IKEA.js b/server/services/zigbee2mqtt/model/IKEA.js
deleted file mode 100644
index a152dcb20a..0000000000
--- a/server/services/zigbee2mqtt/model/IKEA.js
+++ /dev/null
@@ -1,43 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * IKEA managed models.
- */
-const IKEA = {
- brand: 'IKEA',
- models: {
- LED1545G12: [features.light, features.brightness, features.color_temperature],
- LED1546G12: [features.light, features.brightness, features.color_temperature],
- LED1623G12: [features.light, features.brightness],
- LED1537R6: [features.light, features.brightness, features.color_temperature],
- LED1650R5: [features.light, features.brightness],
- LED1536G5: [features.light, features.brightness, features.color_temperature],
- LED1733G7: [features.light, features.brightness, features.color_temperature],
- LED1622G12: [features.light, features.brightness],
- LED1624G9: [features.light, features.brightness, features.color],
- LED1649C5: [features.light, features.brightness],
- LED1934G3: [features.light, features.brightness],
- LED1732G11: [features.light, features.brightness, features.color_temperature],
- LED1924G9: [features.light, features.brightness, features.color_temperature, features.color],
- 'ICTC-G-1': [features.brightness, features.switch_sensor],
- 'ICPSHC24-10EU-IL-1': [features.light, features.brightness],
- 'ICPSHC24-30EU-IL-1': [features.light, features.brightness],
- L1527: [features.light, features.brightness, features.color_temperature],
- L1529: [features.light, features.brightness, features.color_temperature],
- L1528: [features.light, features.brightness, features.color_temperature],
- L1531: [features.light, features.brightness, features.color_temperature],
- 'E1603/E1702': [features.switch],
- 'E1524/E1810': [features.switch_sensor],
- E1743: [features.button],
- 'E1525/E1745': [features.motion],
- 'E1603/E1702/E1708': [features.switch],
- // E1746: [], // Signal repeater
- 'E2001/E2002': [features.button],
- LED1836G9: [features.light, features.brightness],
- LED1837R5: [features.light],
- },
-};
-
-module.exports = {
- IKEA,
-};
diff --git a/server/services/zigbee2mqtt/model/Iluminize.js b/server/services/zigbee2mqtt/model/Iluminize.js
deleted file mode 100644
index eb46c1aac3..0000000000
--- a/server/services/zigbee2mqtt/model/Iluminize.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Iluminize managed models.
- */
-const Iluminize = {
- brand: 'Iluminize',
- models: {
- '511.10': [features.light, features.brightness],
- },
-};
-
-module.exports = {
- Iluminize,
-};
diff --git a/server/services/zigbee2mqtt/model/Immax.js b/server/services/zigbee2mqtt/model/Immax.js
deleted file mode 100644
index 43930a74d0..0000000000
--- a/server/services/zigbee2mqtt/model/Immax.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Immax managed models.
- */
-const Immax = {
- brand: 'Immax',
- models: {
- 'IM-Z3.0-DIM': [features.light, features.brightness],
- },
-};
-
-module.exports = {
- Immax,
-};
diff --git a/server/services/zigbee2mqtt/model/Innr.js b/server/services/zigbee2mqtt/model/Innr.js
deleted file mode 100644
index 2971643d24..0000000000
--- a/server/services/zigbee2mqtt/model/Innr.js
+++ /dev/null
@@ -1,42 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Innr managed models.
- */
-const Innr = {
- brand: 'Innr',
- models: {
- 'RB 185 C': [features.light, features.brightness, features.color_temperature, features.color],
- 'BY 185 C': [features.light, features.brightness, features.color_temperature, features.color],
- 'RB 250 C': [features.light, features.brightness, features.color_temperature, features.color],
- 'RB 265': [features.light, features.brightness],
- 'RB 278 T': [features.light, features.brightness],
- 'RB 285 C': [features.light, features.brightness, features.color_temperature, features.color],
- 'BY 285 C': [features.light, features.brightness, features.color_temperature, features.color],
- 'RB 165': [features.light, features.brightness],
- 'RB 175 W': [features.light, features.brightness],
- 'RB 178 T': [features.light, features.brightness, features.color_temperature],
- 'RS 122': [features.light, features.brightness],
- 'RS 125': [features.light, features.brightness],
- 'RS 225': [features.light, features.brightness],
- 'RS 128 T': [features.light, features.brightness, features.color_temperature],
- 'RS 228 T': [features.light, features.brightness, features.color_temperature],
- 'RB 145': [features.light, features.brightness],
- 'RB 245': [features.light, features.brightness],
- 'RB 248 T': [features.light, features.brightness, features.color_temperature],
- 'BY 165': [features.light, features.brightness],
- 'PL 110': [features.light, features.brightness],
- 'ST 110': [features.light, features.brightness],
- 'UC 110': [features.light, features.brightness],
- 'DL 110 N': [features.light, features.brightness],
- 'DL 110 W': [features.light, features.brightness],
- 'SL 110 N': [features.light, features.brightness],
- 'SL 110 M': [features.light, features.brightness],
- 'SL 110 W': [features.light, features.brightness],
- 'SP 120': [features.switch, features.power],
- },
-};
-
-module.exports = {
- Innr,
-};
diff --git a/server/services/zigbee2mqtt/model/Iris.js b/server/services/zigbee2mqtt/model/Iris.js
deleted file mode 100644
index b2d92496d6..0000000000
--- a/server/services/zigbee2mqtt/model/Iris.js
+++ /dev/null
@@ -1,17 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Iris managed models.
- */
-const Iris = {
- brand: 'Iris',
- models: {
- '3210-L': [features.switch],
- '3326-L': [features.temperature, features.motion],
- '3320-L': [features.door],
- },
-};
-
-module.exports = {
- Iris,
-};
diff --git a/server/services/zigbee2mqtt/model/JIAWEN.js b/server/services/zigbee2mqtt/model/JIAWEN.js
deleted file mode 100644
index 684e31de96..0000000000
--- a/server/services/zigbee2mqtt/model/JIAWEN.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * JIAWEN managed models.
- */
-const JIAWEN = {
- brand: 'JIAWEN',
- models: {
- K2RGBW01: [features.light, features.brightness, features.color_temperature, features.color],
- },
-};
-
-module.exports = {
- JIAWEN,
-};
diff --git a/server/services/zigbee2mqtt/model/KeenHome.js b/server/services/zigbee2mqtt/model/KeenHome.js
deleted file mode 100644
index 1871ea801f..0000000000
--- a/server/services/zigbee2mqtt/model/KeenHome.js
+++ /dev/null
@@ -1,16 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Keen Home managed models.
- */
-const KeenHome = {
- brand: 'Keen Home',
- models: {
- SV01: [features.door, features.temperature, features.pressure],
- SV02: [features.door, features.temperature, features.pressure],
- },
-};
-
-module.exports = {
- KeenHome,
-};
diff --git a/server/services/zigbee2mqtt/model/KsentryElectronics.js b/server/services/zigbee2mqtt/model/KsentryElectronics.js
deleted file mode 100644
index a4222f3f6b..0000000000
--- a/server/services/zigbee2mqtt/model/KsentryElectronics.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Ksentry Electronics managed models.
- */
-const KsentryElectronics = {
- brand: 'Ksentry Electronics',
- models: {
- 'KS-SM001': [features.switch],
- },
-};
-
-module.exports = {
- KsentryElectronics,
-};
diff --git a/server/services/zigbee2mqtt/model/Leedarson.js b/server/services/zigbee2mqtt/model/Leedarson.js
deleted file mode 100644
index 8f736fdf9c..0000000000
--- a/server/services/zigbee2mqtt/model/Leedarson.js
+++ /dev/null
@@ -1,17 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Leedarson managed models.
- */
-const Leedarson = {
- brand: 'Leedarson',
- models: {
- ZM350STW1TCF: [features.light, features.brightness, features.color_temperature],
- M350STW1: [features.light, features.brightness],
- 'A806S-Q1R': [features.light, features.brightness],
- },
-};
-
-module.exports = {
- Leedarson,
-};
diff --git a/server/services/zigbee2mqtt/model/Lidl.js b/server/services/zigbee2mqtt/model/Lidl.js
deleted file mode 100644
index 5422bbc598..0000000000
--- a/server/services/zigbee2mqtt/model/Lidl.js
+++ /dev/null
@@ -1,25 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Lidl managed models.
- */
-const Lidl = {
- brand: 'Lidl',
- models: {
- HG06337: [features.switch],
- HG06104A: [features.light, features.brightness, features.color_temperature, features.color],
- HG06492C: [features.light, features.brightness, features.color_temperature],
- HG06492B: [features.light, features.brightness, features.color_temperature],
- HG06492A: [features.light, features.brightness, features.color_temperature],
- HG06106C: [features.light, features.brightness, features.color_temperature, features.color],
- HG06106A: [features.light, features.brightness, features.color_temperature, features.color],
- HG06106B: [features.light, features.brightness, features.color_temperature, features.color],
- '14147206L': [features.light, features.brightness, features.color_temperature, features.color],
- '14148906L': [features.light, features.brightness, features.color_temperature, features.color],
- '14149505L/14149506L': [features.light, features.brightness, features.color_temperature, features.color],
- },
-};
-
-module.exports = {
- Lidl,
-};
diff --git a/server/services/zigbee2mqtt/model/LivingWise.js b/server/services/zigbee2mqtt/model/LivingWise.js
deleted file mode 100644
index 3711faa0ff..0000000000
--- a/server/services/zigbee2mqtt/model/LivingWise.js
+++ /dev/null
@@ -1,16 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * LivingWise managed models.
- */
-const LivingWise = {
- brand: 'LivingWise',
- models: {
- 'LVS-ZB500D': [features.light, features.brightness],
- 'LVS-SM10ZW': [features.door],
- },
-};
-
-module.exports = {
- LivingWise,
-};
diff --git a/server/services/zigbee2mqtt/model/Livolo.js b/server/services/zigbee2mqtt/model/Livolo.js
deleted file mode 100644
index ea583aeaa3..0000000000
--- a/server/services/zigbee2mqtt/model/Livolo.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Livolo managed models.
- */
-const Livolo = {
- brand: 'Livolo',
- models: {
- TI0001: [features.switch_sensor],
- },
-};
-
-module.exports = {
- Livolo,
-};
diff --git a/server/services/zigbee2mqtt/model/Lonsonho.js b/server/services/zigbee2mqtt/model/Lonsonho.js
deleted file mode 100644
index f20c3d7852..0000000000
--- a/server/services/zigbee2mqtt/model/Lonsonho.js
+++ /dev/null
@@ -1,16 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Leedarson managed models.
- */
-const Lonsonho = {
- brand: 'Lonsonho',
- models: {
- 'QS-Zigbee-D02-TRIAC-L': [features.light, features.brightness],
- 'QS-Zigbee-D02-TRIAC-LN': [features.light, features.brightness],
- },
-};
-
-module.exports = {
- Lonsonho,
-};
diff --git a/server/services/zigbee2mqtt/model/Lupus.js b/server/services/zigbee2mqtt/model/Lupus.js
deleted file mode 100644
index 8b87c0df0a..0000000000
--- a/server/services/zigbee2mqtt/model/Lupus.js
+++ /dev/null
@@ -1,16 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Lupus managed models.
- */
-const Lupus = {
- brand: 'Lupus',
- models: {
- '12031': [features.switch], // curtain / shutter
- '12050': [features.switch, features.power],
- },
-};
-
-module.exports = {
- Lupus,
-};
diff --git a/server/services/zigbee2mqtt/model/Meazon.js b/server/services/zigbee2mqtt/model/Meazon.js
deleted file mode 100644
index 72e4553854..0000000000
--- a/server/services/zigbee2mqtt/model/Meazon.js
+++ /dev/null
@@ -1,16 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Meazon managed models.
- */
-const Meazon = {
- brand: 'Meazon',
- models: {
- MEAZON_BIZY_PLUG: [features.switch, features.power, features.temperature],
- MEAZON_DINRAIL: [features.switch, features.power, features.temperature],
- },
-};
-
-module.exports = {
- Meazon,
-};
diff --git a/server/services/zigbee2mqtt/model/MullerLicht.js b/server/services/zigbee2mqtt/model/MullerLicht.js
deleted file mode 100644
index a413c28ec8..0000000000
--- a/server/services/zigbee2mqtt/model/MullerLicht.js
+++ /dev/null
@@ -1,17 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Müller Licht managed models.
- */
-const MullerLicht = {
- brand: 'Müller Licht',
- models: {
- '404000/404005/404012': [features.light, features.brightness, features.color_temperature, features.color],
- '404006/404008/404004': [features.light, features.brightness, features.color_temperature],
- 'MLI-404011': [features.switch_sensor],
- },
-};
-
-module.exports = {
- MullerLicht,
-};
diff --git a/server/services/zigbee2mqtt/model/NET2GRID.js b/server/services/zigbee2mqtt/model/NET2GRID.js
deleted file mode 100644
index 5e8c8d30d0..0000000000
--- a/server/services/zigbee2mqtt/model/NET2GRID.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * NET2GRID managed models.
- */
-const NET2GRID = {
- brand: 'NET2GRID',
- models: {
- 'N2G-SP': [features.switch, features.power],
- },
-};
-
-module.exports = {
- NET2GRID,
-};
diff --git a/server/services/zigbee2mqtt/model/Nanoleaf.js b/server/services/zigbee2mqtt/model/Nanoleaf.js
deleted file mode 100644
index 9f0e01956a..0000000000
--- a/server/services/zigbee2mqtt/model/Nanoleaf.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Nanoleaf managed models.
- */
-const Nanoleaf = {
- brand: 'Nanoleaf',
- models: {
- 'NL08-0800': [features.light, features.brightness],
- },
-};
-
-module.exports = {
- Nanoleaf,
-};
diff --git a/server/services/zigbee2mqtt/model/Netvox.js b/server/services/zigbee2mqtt/model/Netvox.js
deleted file mode 100644
index aeb68b5707..0000000000
--- a/server/services/zigbee2mqtt/model/Netvox.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Netvox managed models.
- */
-const Netvox = {
- brand: 'Netvox',
- models: {
- Z809A: [features.switch, features.power],
- },
-};
-
-module.exports = {
- Netvox,
-};
diff --git a/server/services/zigbee2mqtt/model/NinjaBlocks.js b/server/services/zigbee2mqtt/model/NinjaBlocks.js
deleted file mode 100644
index b877835972..0000000000
--- a/server/services/zigbee2mqtt/model/NinjaBlocks.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Ninja Blocks managed models.
- */
-const NinjaBlocks = {
- brand: 'Ninja Blocks',
- models: {
- Z809AF: [features.switch, features.power],
- },
-};
-
-module.exports = {
- NinjaBlocks,
-};
diff --git a/server/services/zigbee2mqtt/model/Nue_3A.js b/server/services/zigbee2mqtt/model/Nue_3A.js
deleted file mode 100644
index ce938befd1..0000000000
--- a/server/services/zigbee2mqtt/model/Nue_3A.js
+++ /dev/null
@@ -1,31 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Nue / 3A managed models.
- */
-const Nue3A = {
- brand: 'Nue / 3A',
- models: {
- 'HGZB-1S': [features.switch, features.switch_sensor],
- 'HGZB-02S': [features.switch, features.switch_sensor],
- 'HGZB-045': [features.switch, features.switch_sensor],
- 'LXZB-02A': [features.light, features.brightness],
- 'HGZB-43': [features.switch],
- 'HGZB-043': [features.switch],
- 'HGZB-04D': [features.light, features.brightness],
- 'HGZB-042': [features.switch],
- 'HGZB-42': [features.switch],
- 'HGZB-01A/02A': [features.switch],
- 'HGZB-41': [features.switch],
- 'MG-AUWS01': [features.switch],
- 'HGZB-01A': [features.light, features.brightness],
- 'XY12S-15': [features.light, features.brightness, features.color_temperature, features.color],
- 'HGZB-02A': [features.light, features.brightness],
- 'HGZB-42-UK / HGZB-41': [features.switch],
- 'HGZB-06A': [features.light, features.brightness, features.color_temperature, features.color],
- },
-};
-
-module.exports = {
- Nue3A,
-};
diff --git a/server/services/zigbee2mqtt/model/Nyce.js b/server/services/zigbee2mqtt/model/Nyce.js
deleted file mode 100644
index 1a55cb52de..0000000000
--- a/server/services/zigbee2mqtt/model/Nyce.js
+++ /dev/null
@@ -1,18 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Nyce managed models.
- */
-const Nyce = {
- brand: 'Nyce',
- models: {
- 'NCZ-3011-HA': [features.temperature, features.motion, features.humidity],
- 'NCZ-3043-HA': [features.temperature, features.motion],
- 'NCZ-3041-HA': [features.temperature, features.motion],
- 'NCZ-3045-HA': [features.temperature, features.motion],
- },
-};
-
-module.exports = {
- Nyce,
-};
diff --git a/server/services/zigbee2mqtt/model/ORVIBO.js b/server/services/zigbee2mqtt/model/ORVIBO.js
deleted file mode 100644
index 840b0e29ad..0000000000
--- a/server/services/zigbee2mqtt/model/ORVIBO.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * ORVIBO managed models.
- */
-const ORVIBO = {
- brand: 'ORVIBO',
- models: {
- SN10ZW: [features.motion],
- },
-};
-
-module.exports = {
- ORVIBO,
-};
diff --git a/server/services/zigbee2mqtt/model/OSRAM.js b/server/services/zigbee2mqtt/model/OSRAM.js
deleted file mode 100644
index c843ec42cd..0000000000
--- a/server/services/zigbee2mqtt/model/OSRAM.js
+++ /dev/null
@@ -1,37 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * OSRAM managed models.
- */
-const OSRAM = {
- brand: 'OSRAM',
- models: {
- '4058075816718': [features.light, features.brightness, features.color_temperature, features.color],
- AA69697: [features.light, features.brightness, features.color_temperature, features.color],
- AC03645: [features.light, features.brightness, features.color_temperature, features.color],
- AC03642: [features.light, features.brightness, features.color_temperature],
- AC03647: [features.light, features.brightness, features.color_temperature, features.color],
- AA70155: [features.light, features.brightness, features.color_temperature],
- AA68199: [features.light, features.brightness, features.color_temperature],
- AB32840: [features.light, features.brightness, features.color_temperature],
- '4058075816794': [features.light, features.brightness, features.color_temperature],
- AC03641: [features.light, features.brightness],
- '4052899926158': [features.light, features.brightness],
- AB401130055: [features.light, features.brightness, features.color_temperature],
- AB3257001NJ: [features.switch],
- '4052899926110': [features.light, features.brightness, features.color_temperature, features.color],
- '4058075036185': [features.light, features.brightness, features.color_temperature, features.color],
- '4058075036147': [features.light, features.brightness, features.color_temperature, features.color],
- AC0363900NJ: [features.light, features.brightness, features.color_temperature, features.color],
- AB35996: [features.light, features.brightness, features.color_temperature, features.color],
- AC08562: [features.light, features.brightness],
- AC01353010G: [features.temperature, features.motion],
- AC03648: [features.light, features.brightness, features.color_temperature],
- AC0251100NJ: [features.switch_sensor],
- 'ST8AU-CON': [features.light, features.brightness],
- },
-};
-
-module.exports = {
- OSRAM,
-};
diff --git a/server/services/zigbee2mqtt/model/Oujiabao.js b/server/services/zigbee2mqtt/model/Oujiabao.js
deleted file mode 100644
index 5a39c2f9f0..0000000000
--- a/server/services/zigbee2mqtt/model/Oujiabao.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Oujiabao managed models.
- */
-const Oujiabao = {
- brand: 'Oujiabao',
- models: {
- 'CR701-YZ': [features.smoke, features.smoke],
- },
-};
-
-module.exports = {
- Oujiabao,
-};
diff --git a/server/services/zigbee2mqtt/model/PaulNeuhaus.js b/server/services/zigbee2mqtt/model/PaulNeuhaus.js
deleted file mode 100644
index 2320f8a3ee..0000000000
--- a/server/services/zigbee2mqtt/model/PaulNeuhaus.js
+++ /dev/null
@@ -1,17 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Paul Neuhaus managed models.
- */
-const PaulNeuhaus = {
- brand: 'Paul Neuhaus',
- models: {
- '100.424.11': [features.light, features.brightness, features.color_temperature],
- '100.110.39': [features.light, features.brightness, features.color_temperature, features.color],
- '100.425.90': [features.switch],
- },
-};
-
-module.exports = {
- PaulNeuhaus,
-};
diff --git a/server/services/zigbee2mqtt/model/Paulmann.js b/server/services/zigbee2mqtt/model/Paulmann.js
deleted file mode 100644
index bf03bf8a7a..0000000000
--- a/server/services/zigbee2mqtt/model/Paulmann.js
+++ /dev/null
@@ -1,18 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Paulmann managed models.
- */
-const Paulmann = {
- brand: 'Paulmann',
- models: {
- '50043': [features.switch],
- '50045': [features.light, features.brightness],
- '50049': [features.light, features.brightness, features.color_temperature, features.color],
- '50064': [features.light, features.brightness, features.color_temperature],
- },
-};
-
-module.exports = {
- Paulmann,
-};
diff --git a/server/services/zigbee2mqtt/model/Philips.js b/server/services/zigbee2mqtt/model/Philips.js
deleted file mode 100644
index ed0127c652..0000000000
--- a/server/services/zigbee2mqtt/model/Philips.js
+++ /dev/null
@@ -1,51 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Philips managed models.
- */
-const Philips = {
- brand: 'Philips',
- models: {
- '7299760PH': [features.light, features.brightness, features.color],
- '7146060PH': [features.light, features.brightness, features.color_temperature, features.color],
- '4090531P7': [features.light, features.brightness, features.color_temperature, features.color],
- '433714': [features.light, features.brightness],
- '8718696449691': [features.light, features.brightness],
- '9290018195': [features.light, features.brightness],
- '7299355PH': [features.light, features.brightness, features.color],
- '915005106701': [features.light, features.brightness, features.color_temperature, features.color],
- '9290012573A': [features.light, features.brightness, features.color_temperature, features.color],
- '9290002579A': [features.light, features.brightness, features.color_temperature, features.color],
- '8718696485880': [features.light, features.brightness, features.color_temperature, features.color],
- '915005733701': [features.light, features.brightness, features.color_temperature, features.color],
- '464800': [features.light, features.brightness, features.color_temperature],
- '8718696695203': [features.light, features.brightness, features.color_temperature],
- '8718696598283': [features.light, features.brightness, features.color_temperature],
- '9290011998B': [features.light, features.brightness, features.color_temperature],
- '8718696548738': [features.light, features.brightness, features.color_temperature],
- '4090130P7': [features.light, features.brightness, features.color_temperature, features.color],
- '3261030P7': [features.light, features.brightness, features.color_temperature],
- '3261331P7': [features.light, features.brightness, features.color_temperature],
- '4096730U7': [features.light, features.brightness, features.color_temperature],
- '3216131P5': [features.light, features.brightness, features.color_temperature],
- '3216331P5': [features.light, features.brightness, features.color_temperature],
- '3216431P5': [features.light, features.brightness, features.color_temperature],
- '4033930P7': [features.light, features.brightness, features.color_temperature],
- '9290011370B': [features.light, features.brightness],
- '046677476816': [features.light, features.brightness],
- '7199960PH': [features.light, features.brightness, features.color],
- '324131092621': [features.switch_sensor],
- '9290012607': [features.temperature, features.motion, features.illuminance],
- '9290019758': [features.temperature, features.motion, features.illuminance],
- '7099860PH': [features.light, features.brightness, features.color],
- '3216231P5': [features.light, features.brightness, features.color_temperature],
- '8718696170625': [features.light, features.brightness],
- '8718699673147': [features.light, features.brightness],
- '9290022166': [features.light, features.brightness, features.color_temperature], // color xy
- '929002241201': [features.light, features.brightness],
- },
-};
-
-module.exports = {
- Philips,
-};
diff --git a/server/services/zigbee2mqtt/model/RGBGenie.js b/server/services/zigbee2mqtt/model/RGBGenie.js
deleted file mode 100644
index 77418405b1..0000000000
--- a/server/services/zigbee2mqtt/model/RGBGenie.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * RGBGenie managed models.
- */
-const RGBGenie = {
- brand: 'RGB Genie',
- models: {
- 'ZGRC-KEY-013': [features.switch_sensor],
- },
-};
-
-module.exports = {
- RGBGenie,
-};
diff --git a/server/services/zigbee2mqtt/model/ROBB.js b/server/services/zigbee2mqtt/model/ROBB.js
deleted file mode 100644
index 7ddc5b531f..0000000000
--- a/server/services/zigbee2mqtt/model/ROBB.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * ROBB managed models.
- */
-const ROBB = {
- brand: 'ROBB',
- models: {
- 'ROB_200-004-0': [features.light, features.brightness],
- },
-};
-
-module.exports = {
- ROBB,
-};
diff --git a/server/services/zigbee2mqtt/model/SONOFF.js b/server/services/zigbee2mqtt/model/SONOFF.js
deleted file mode 100644
index 616448e8ae..0000000000
--- a/server/services/zigbee2mqtt/model/SONOFF.js
+++ /dev/null
@@ -1,18 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * SONOFF managed models.
- */
-const SONOFF = {
- brand: 'SONOFF',
- models: {
- 'SNZB-01': [features.button],
- 'SNZB-02': [features.temperature, features.humidity],
- 'SNZB-03': [features.motion],
- 'SNZB-04': [features.door],
- },
-};
-
-module.exports = {
- SONOFF,
-};
diff --git a/server/services/zigbee2mqtt/model/Salus.js b/server/services/zigbee2mqtt/model/Salus.js
deleted file mode 100644
index 8584e79022..0000000000
--- a/server/services/zigbee2mqtt/model/Salus.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Salus managed models.
- */
-const Salus = {
- brand: 'Salus',
- models: {
- SP600: [features.switch, features.power],
- },
-};
-
-module.exports = {
- Salus,
-};
diff --git a/server/services/zigbee2mqtt/model/Securifi.js b/server/services/zigbee2mqtt/model/Securifi.js
deleted file mode 100644
index ad80ea8c96..0000000000
--- a/server/services/zigbee2mqtt/model/Securifi.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Securifi managed models.
- */
-const Securifi = {
- brand: 'Securifi',
- models: {
- 'PP-WHT-US': [features.switch, features.power, features.current, features.voltage],
- },
-};
-
-module.exports = {
- Securifi,
-};
diff --git a/server/services/zigbee2mqtt/model/Sengled.js b/server/services/zigbee2mqtt/model/Sengled.js
deleted file mode 100644
index 0cf92ae916..0000000000
--- a/server/services/zigbee2mqtt/model/Sengled.js
+++ /dev/null
@@ -1,21 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Sengled managed models.
- */
-const Sengled = {
- brand: 'Sengled',
- models: {
- 'E11-G13': [features.light, features.brightness],
- 'E11-G23/E11-G33': [features.light, features.brightness],
- 'Z01-CIA19NAE26': [features.light, features.brightness],
- 'Z01-A19NAE26': [features.light, features.brightness, features.color_temperature],
- 'E11-N1EA': [features.light, features.brightness, features.color_temperature, features.color],
- 'E12-N14': [features.light, features.brightness],
- E1ACA4ABE38A: [features.light, features.brightness],
- },
-};
-
-module.exports = {
- Sengled,
-};
diff --git a/server/services/zigbee2mqtt/model/Sercomm.js b/server/services/zigbee2mqtt/model/Sercomm.js
deleted file mode 100644
index 4401b382e7..0000000000
--- a/server/services/zigbee2mqtt/model/Sercomm.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Sercomm managed models.
- */
-const Sercomm = {
- brand: 'Sercomm',
- models: {
- 'SZ-ESW01-AU': [features.switch, features.power],
- },
-};
-
-module.exports = {
- Sercomm,
-};
diff --git a/server/services/zigbee2mqtt/model/ShenzhenHoma.js b/server/services/zigbee2mqtt/model/ShenzhenHoma.js
deleted file mode 100644
index ffb9086be8..0000000000
--- a/server/services/zigbee2mqtt/model/ShenzhenHoma.js
+++ /dev/null
@@ -1,17 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Shenzhen Homa managed models.
- */
-const ShenzhenHoma = {
- brand: 'Shenzhen Homa',
- models: {
- 'HLD812-Z-SC': [features.light, features.brightness],
- 'HLC610-Z': [features.light, features.brightness],
- 'HLC821-Z-SC': [features.light, features.brightness],
- },
-};
-
-module.exports = {
- ShenzhenHoma,
-};
diff --git a/server/services/zigbee2mqtt/model/SmartHomePty.js b/server/services/zigbee2mqtt/model/SmartHomePty.js
deleted file mode 100644
index d21d080d60..0000000000
--- a/server/services/zigbee2mqtt/model/SmartHomePty.js
+++ /dev/null
@@ -1,16 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Smart Home Pty managed models.
- */
-const SmartHomePty = {
- brand: 'Smart Home Pty',
- models: {
- 'HGZB-07A': [features.switch, features.color_temperature],
- 'HGZB-20-DE': [features.switch],
- },
-};
-
-module.exports = {
- SmartHomePty,
-};
diff --git a/server/services/zigbee2mqtt/model/SmartThings.js b/server/services/zigbee2mqtt/model/SmartThings.js
deleted file mode 100644
index 3ac1f0e763..0000000000
--- a/server/services/zigbee2mqtt/model/SmartThings.js
+++ /dev/null
@@ -1,29 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * SmartThings managed models.
- */
-const SmartThings = {
- brand: 'SmartThings',
- models: {
- 'STSS-MULT-001': [features.door],
- 'STS-PRS-251': [features.motion],
- '3325-S': [features.temperature, features.motion],
- '3321-S': [features.temperature, features.door],
- 'IM6001-OTP05': [features.switch],
- 'IM6001-MTP01': [features.temperature, features.motion],
- 'STS-IRM-250': [features.temperature, features.motion],
- '3305-S': [features.temperature, features.motion],
- '3300-S': [features.temperature, features.door],
- 'F-MLT-US-2': [features.temperature, features.door],
- 'IM6001-MPP01': [features.temperature, features.door],
- '3310-S': [features.temperature],
- '3315-S': [features.temperature, features.water],
- '3315-G': [features.temperature, features.water],
- 'IM6001-BTP01': [features.switch_sensor, features.temperature],
- },
-};
-
-module.exports = {
- SmartThings,
-};
diff --git a/server/services/zigbee2mqtt/model/Stelpro.js b/server/services/zigbee2mqtt/model/Stelpro.js
deleted file mode 100644
index cc8de5bfcb..0000000000
--- a/server/services/zigbee2mqtt/model/Stelpro.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Stelpro managed models.
- */
-const Stelpro = {
- brand: 'Stelpro',
- models: {
- ST218: [features.temperature],
- },
-};
-
-module.exports = {
- Stelpro,
-};
diff --git a/server/services/zigbee2mqtt/model/Sunricher.js b/server/services/zigbee2mqtt/model/Sunricher.js
deleted file mode 100644
index 93cae3b753..0000000000
--- a/server/services/zigbee2mqtt/model/Sunricher.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Sunricher managed models.
- */
-const Sunricher = {
- brand: 'Sunricher',
- models: {
- 'ZG9101SAC-HP': [features.light, features.brightness],
- },
-};
-
-module.exports = {
- Sunricher,
-};
diff --git a/server/services/zigbee2mqtt/model/Swann.js b/server/services/zigbee2mqtt/model/Swann.js
deleted file mode 100644
index 9535e5f352..0000000000
--- a/server/services/zigbee2mqtt/model/Swann.js
+++ /dev/null
@@ -1,16 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Swann managed models.
- */
-const Swann = {
- brand: 'Swann',
- models: {
- 'SWO-KEF1PA': [features.switch_sensor],
- 'SWO-WDS1PA': [features.door],
- },
-};
-
-module.exports = {
- Swann,
-};
diff --git a/server/services/zigbee2mqtt/model/Sylvania.js b/server/services/zigbee2mqtt/model/Sylvania.js
deleted file mode 100644
index 311cd44b6b..0000000000
--- a/server/services/zigbee2mqtt/model/Sylvania.js
+++ /dev/null
@@ -1,25 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Sylvania managed models.
- */
-const Sylvania = {
- brand: 'Sylvania',
- models: {
- '73742': [features.light, features.brightness, features.color_temperature],
- '73740': [features.light, features.brightness, features.color_temperature],
- '73739': [features.light, features.brightness, features.color_temperature, features.color],
- '73693': [features.light, features.brightness, features.color_temperature, features.color],
- '74283': [features.light, features.brightness],
- '74696': [features.light, features.brightness],
- '72922-A': [features.switch],
- '71831': [features.light, features.brightness, features.color_temperature],
- '74282': [features.light, features.brightness, features.color_temperature],
- LTFY004: [features.light, features.brightness, features.color],
- '74580': [features.light, features.brightness],
- },
-};
-
-module.exports = {
- Sylvania,
-};
diff --git a/server/services/zigbee2mqtt/model/TUYATEC.js b/server/services/zigbee2mqtt/model/TUYATEC.js
deleted file mode 100644
index a11a53cb20..0000000000
--- a/server/services/zigbee2mqtt/model/TUYATEC.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * TUYATEC managed models.
- */
-const TUYATEC = {
- brand: 'TUYATEC',
- models: {
- RH3040: [features.motion],
- },
-};
-
-module.exports = {
- TUYATEC,
-};
diff --git a/server/services/zigbee2mqtt/model/ThirdReality.js b/server/services/zigbee2mqtt/model/ThirdReality.js
deleted file mode 100644
index 6757d33e8e..0000000000
--- a/server/services/zigbee2mqtt/model/ThirdReality.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Third Reality managed models.
- */
-const ThirdReality = {
- brand: 'Third Reality',
- models: {
- '3RSS008Z': [features.switch_sensor],
- },
-};
-
-module.exports = {
- ThirdReality,
-};
diff --git a/server/services/zigbee2mqtt/model/Trust.js b/server/services/zigbee2mqtt/model/Trust.js
deleted file mode 100644
index c174821116..0000000000
--- a/server/services/zigbee2mqtt/model/Trust.js
+++ /dev/null
@@ -1,18 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Trust managed models.
- */
-const Trust = {
- brand: 'Trust',
- models: {
- 'ZYCT-202': [features.switch_sensor],
- 'ZLED-2709': [features.light, features.brightness],
- 'ZPIR-8000': [features.motion],
- 'ZCTS-808': [features.door],
- },
-};
-
-module.exports = {
- Trust,
-};
diff --git a/server/services/zigbee2mqtt/model/TuYa.js b/server/services/zigbee2mqtt/model/TuYa.js
deleted file mode 100644
index d64c32b384..0000000000
--- a/server/services/zigbee2mqtt/model/TuYa.js
+++ /dev/null
@@ -1,21 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * TuYa managed models.
- */
-const TuYa = {
- brand: 'TuYa',
- models: {
- TS0121_plug: [features.switch, features.power, features.current, features.voltage, features.energy],
- TS0201: [features.temperature, features.humidity, features.voltage],
- TS0011: [features.switch],
- TS0601_air_quality_sensor: [features.temperature, features.humidity, features.co2],
- TT001ZAV20: [features.temperature, features.humidity],
- SNTZ007: [features.door],
- TS0503B: [features.light, features.brightness, features.color],
- },
-};
-
-module.exports = {
- TuYa,
-};
diff --git a/server/services/zigbee2mqtt/model/Visonic.js b/server/services/zigbee2mqtt/model/Visonic.js
deleted file mode 100644
index c5d1b70eef..0000000000
--- a/server/services/zigbee2mqtt/model/Visonic.js
+++ /dev/null
@@ -1,16 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Visonic managed models.
- */
-const Visonic = {
- brand: 'Visonic',
- models: {
- 'MCT-350 SMA': [features.door],
- 'MCT-340 E': [features.door],
- },
-};
-
-module.exports = {
- Visonic,
-};
diff --git a/server/services/zigbee2mqtt/model/Xiaomi.js b/server/services/zigbee2mqtt/model/Xiaomi.js
deleted file mode 100644
index 2f721d9da6..0000000000
--- a/server/services/zigbee2mqtt/model/Xiaomi.js
+++ /dev/null
@@ -1,45 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Xiaomi managed models.
- */
-const Xiaomi = {
- brand: 'Xiaomi',
- models: {
- ZNLDP12LM: [features.light, features.brightness, features.color_temperature],
- WXKG01LM: [features.button],
- WXKG11LM: [features.button],
- WXKG12LM: [features.button],
- WXKG03LM_rev1: [features.button],
- WXKG03LM_rev2: [features.button],
- WXKG02LM_rev1: [features.button],
- WXKG02LM_rev2: [features.button],
- QBKG04LM: [features.switch],
- QBKG11LM: [features.switch, features.power],
- QBKG03LM: [features.switch_sensor],
- QBKG12LM: [features.switch, features.power],
- WSDCGQ01LM: [features.temperature, features.humidity],
- WSDCGQ11LM: [features.temperature, features.humidity, features.pressure],
- RTCGQ01LM: [features.motion],
- RTCGQ11LM: [features.motion, features.illuminance, features.temperature, features.voltage],
- MCCGQ01LM: [features.door],
- MCCGQ11LM: [features.door, features.temperature],
- SJCGQ11LM: [features.water],
- MFKZQ01LM: [features.button],
- ZNCZ02LM: [features.switch, features.power],
- QBCZ11LM: [features.switch, features.power],
- 'JTYJ-GD-01LM/BW': [features.smoke],
- 'JTQJ-BF-01LM/BW': [features.smoke, features.gas_density],
- A6121: [features.door],
- DJT11LM: [features.button],
- // ZNCLDJ11LM: [features.curtain]
- LLKZMK11LM: [features.switch, features.power],
- ZNMS12LM: [features.switch_sensor, features.door],
- WXKG06LM: [features.button],
- GZCGQ01LM: [features.illuminance, features.illuminance_lux],
- },
-};
-
-module.exports = {
- Xiaomi,
-};
diff --git a/server/services/zigbee2mqtt/model/Yale.js b/server/services/zigbee2mqtt/model/Yale.js
deleted file mode 100644
index e27b60edcf..0000000000
--- a/server/services/zigbee2mqtt/model/Yale.js
+++ /dev/null
@@ -1,18 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * Yale managed models.
- */
-const Yale = {
- brand: 'Yale',
- models: {
- YRD426NRSC: [features.door],
- YRD226HA2619: [features.door],
- YRD256HA20BP: [features.door],
- YMF40: [features.door],
- },
-};
-
-module.exports = {
- Yale,
-};
diff --git a/server/services/zigbee2mqtt/model/eCosy.js b/server/services/zigbee2mqtt/model/eCosy.js
deleted file mode 100644
index 4ab856efbf..0000000000
--- a/server/services/zigbee2mqtt/model/eCosy.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * eCosy managed models.
- */
-const eCosy = {
- brand: 'eCosy',
- models: {
- '1TST-EU': [features.temperature, features.motion], // heating + schedule,
- },
-};
-
-module.exports = {
- eCosy,
-};
diff --git a/server/services/zigbee2mqtt/model/iCasa.js b/server/services/zigbee2mqtt/model/iCasa.js
deleted file mode 100644
index ac52cfd3af..0000000000
--- a/server/services/zigbee2mqtt/model/iCasa.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * iCasa managed models.
- */
-const iCasa = {
- brand: 'iCasa',
- models: {
- 'ICZB-IW11D': [features.light, features.brightness],
- },
-};
-
-module.exports = {
- iCasa,
-};
diff --git a/server/services/zigbee2mqtt/model/ilux.js b/server/services/zigbee2mqtt/model/ilux.js
deleted file mode 100644
index 8ebd330aa3..0000000000
--- a/server/services/zigbee2mqtt/model/ilux.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const { features } = require('../utils/features');
-
-/**
- * ilux managed models.
- */
-const ilux = {
- brand: 'ilux',
- models: {
- '900008-WW': [features.light, features.brightness],
- },
-};
-
-module.exports = {
- ilux,
-};
diff --git a/server/services/zigbee2mqtt/model/index.js b/server/services/zigbee2mqtt/model/index.js
deleted file mode 100644
index 1ec3392fa1..0000000000
--- a/server/services/zigbee2mqtt/model/index.js
+++ /dev/null
@@ -1,102 +0,0 @@
-const models = [];
-models.push(require('./AduroSmart').AduroSmart);
-models.push(require('./Airam').Airam);
-models.push(require('./Anchor').Anchor);
-models.push(require('./Belkin').Belkin);
-models.push(require('./Bitron').Bitron);
-models.push(require('./Blaupunkt').Blaupunkt);
-models.push(require('./Bosch').Bosch);
-models.push(require('./Calex').Calex);
-models.push(require('./Centralite').Centralite);
-models.push(require('./Climax').Climax);
-models.push(require('./CommercialElectric').CommercialElectric);
-models.push(require('./Danalock').Danalock);
-models.push(require('./DresdenElektronik').DresdenElektronik);
-models.push(require('./EDP').EDP);
-models.push(require('./ELKO').ELKO);
-models.push(require('./EcoSmart').EcoSmart);
-models.push(require('./Eurotronic').Eurotronic);
-models.push(require('./GE').GE);
-models.push(require('./GMYSmartBulb').GMYSmartBulb);
-models.push(require('./Gira').Gira);
-models.push(require('./Gledopto').Gledopto);
-models.push(require('./HEIMAN').HEIMAN);
-models.push(require('./HamptonBay').HamptonBay);
-models.push(require('./Hive').Hive);
-models.push(require('./Honyar').Honyar);
-models.push(require('./IKEA').IKEA);
-models.push(require('./Iluminize').Iluminize);
-models.push(require('./Immax').Immax);
-models.push(require('./Innr').Innr);
-models.push(require('./Iris').Iris);
-models.push(require('./JIAWEN').JIAWEN);
-models.push(require('./KeenHome').KeenHome);
-models.push(require('./KsentryElectronics').KsentryElectronics);
-models.push(require('./Leedarson').Leedarson);
-models.push(require('./LivingWise').LivingWise);
-models.push(require('./Livolo').Livolo);
-models.push(require('./Lupus').Lupus);
-models.push(require('./Meazon').Meazon);
-models.push(require('./MullerLicht').MullerLicht);
-models.push(require('./NET2GRID').NET2GRID);
-models.push(require('./Nanoleaf').Nanoleaf);
-models.push(require('./Netvox').Netvox);
-models.push(require('./NinjaBlocks').NinjaBlocks);
-models.push(require('./Nue_3A').Nue3A);
-models.push(require('./Nyce').Nyce);
-models.push(require('./ORVIBO').ORVIBO);
-models.push(require('./OSRAM').OSRAM);
-models.push(require('./Oujiabao').Oujiabao);
-models.push(require('./PaulNeuhaus').PaulNeuhaus);
-models.push(require('./Paulmann').Paulmann);
-models.push(require('./Philips').Philips);
-models.push(require('./RGBGenie').RGBGenie);
-models.push(require('./ROBB').ROBB);
-models.push(require('./Salus').Salus);
-models.push(require('./Securifi').Securifi);
-models.push(require('./Sengled').Sengled);
-models.push(require('./Sercomm').Sercomm);
-models.push(require('./ShenzhenHoma').ShenzhenHoma);
-models.push(require('./SmartHomePty').SmartHomePty);
-models.push(require('./SmartThings').SmartThings);
-models.push(require('./SONOFF').SONOFF);
-models.push(require('./Stelpro').Stelpro);
-models.push(require('./Sunricher').Sunricher);
-models.push(require('./Swann').Swann);
-models.push(require('./Sylvania').Sylvania);
-models.push(require('./TUYATEC').TUYATEC);
-models.push(require('./ThirdReality').ThirdReality);
-models.push(require('./Trust').Trust);
-models.push(require('./Visonic').Visonic);
-models.push(require('./Xiaomi').Xiaomi);
-models.push(require('./Yale').Yale);
-models.push(require('./eCosy').eCosy);
-models.push(require('./iCasa').iCasa);
-models.push(require('./ilux').ilux);
-models.push(require('./TuYa').TuYa);
-models.push(require('./Lonsonho').Lonsonho);
-models.push(require('./Lidl').Lidl);
-models.push(require('./Adeo').Adeo);
-
-/**
- * @description Get features by model name.
- * @param {string} modelName - Model name to find.
- * @returns {Array} Related features.
- * @example
- * getFeaturesByModel('1TST-EU');
- */
-function getFeaturesByModel(modelName) {
- const model = models.find((m) => {
- return m.models[modelName];
- });
-
- if (model) {
- return model.models[modelName];
- }
-
- return [];
-}
-
-module.exports = {
- getFeaturesByModel,
-};
diff --git a/server/services/zigbee2mqtt/utils/features.js b/server/services/zigbee2mqtt/utils/features.js
deleted file mode 100644
index 884741a248..0000000000
--- a/server/services/zigbee2mqtt/utils/features.js
+++ /dev/null
@@ -1,272 +0,0 @@
-const {
- DEVICE_FEATURE_CATEGORIES,
- DEVICE_FEATURE_TYPES,
- DEVICE_FEATURE_UNITS,
-} = require('../../../../server/utils/constants');
-
-const features = {
- presence: {
- category: DEVICE_FEATURE_CATEGORIES.PRESENCE_SENSOR,
- type: DEVICE_FEATURE_TYPES.SENSOR.BINARY,
- name: 'Presence Sensor',
- read_only: true,
- has_feedback: false,
- min: 0,
- max: 1,
- zigbeeField: 'presence',
- },
- motion: {
- category: DEVICE_FEATURE_CATEGORIES.MOTION_SENSOR,
- type: DEVICE_FEATURE_TYPES.SENSOR.BINARY,
- name: 'Motion Sensor',
- read_only: true,
- has_feedback: false,
- min: 0,
- max: 1,
- zigbeeField: 'occupancy',
- },
- door: {
- category: DEVICE_FEATURE_CATEGORIES.OPENING_SENSOR,
- type: DEVICE_FEATURE_TYPES.SENSOR.BINARY,
- name: 'Opening Sensor',
- read_only: true,
- has_feedback: false,
- min: 0,
- max: 1,
- zigbeeField: 'contact',
- },
- water: {
- category: DEVICE_FEATURE_CATEGORIES.LEAK_SENSOR,
- type: DEVICE_FEATURE_TYPES.SENSOR.BINARY,
- name: 'Water Leak',
- read_only: true,
- has_feedback: false,
- min: 0,
- max: 1,
- zigbeeField: 'water_leak',
- },
- smoke: {
- category: DEVICE_FEATURE_CATEGORIES.SMOKE_SENSOR,
- type: DEVICE_FEATURE_TYPES.SENSOR.BINARY,
- name: 'Smoke Sensor',
- read_only: true,
- has_feedback: false,
- min: 0,
- max: 1,
- zigbeeField: 'smoke',
- },
- battery: {
- category: DEVICE_FEATURE_CATEGORIES.BATTERY,
- type: DEVICE_FEATURE_TYPES.SENSOR.INTEGER,
- unit: DEVICE_FEATURE_UNITS.PERCENT,
- name: 'Battery',
- read_only: true,
- has_feedback: false,
- min: 0,
- max: 100,
- zigbeeField: 'battery',
- },
- illuminance: {
- category: DEVICE_FEATURE_CATEGORIES.LIGHT_SENSOR,
- type: DEVICE_FEATURE_TYPES.SENSOR.DECIMAL,
- unit: DEVICE_FEATURE_UNITS.LUX,
- name: 'Light Sensor',
- read_only: true,
- has_feedback: false,
- min: 0,
- max: 1000,
- zigbeeField: 'illuminance',
- },
- illuminance_lux: {
- category: DEVICE_FEATURE_CATEGORIES.LIGHT_SENSOR,
- type: DEVICE_FEATURE_TYPES.SENSOR.DECIMAL,
- unit: DEVICE_FEATURE_UNITS.LUX,
- name: 'Light Sensor',
- read_only: true,
- has_feedback: false,
- min: 0,
- max: 100000,
- zigbeeField: 'illuminance_lux',
- },
- humidity: {
- category: DEVICE_FEATURE_CATEGORIES.HUMIDITY_SENSOR,
- type: DEVICE_FEATURE_TYPES.SENSOR.DECIMAL,
- unit: DEVICE_FEATURE_UNITS.PERCENT,
- name: 'Humidity',
- read_only: true,
- has_feedback: false,
- min: 0,
- max: 100,
- zigbeeField: 'humidity',
- },
- temperature: {
- category: DEVICE_FEATURE_CATEGORIES.TEMPERATURE_SENSOR,
- type: DEVICE_FEATURE_TYPES.SENSOR.DECIMAL,
- unit: DEVICE_FEATURE_UNITS.CELSIUS,
- name: 'Temperature',
- read_only: true,
- has_feedback: false,
- min: -50,
- max: 125,
- zigbeeField: 'temperature',
- },
- pressure: {
- category: DEVICE_FEATURE_CATEGORIES.PRESSURE_SENSOR,
- type: DEVICE_FEATURE_TYPES.SENSOR.DECIMAL,
- unit: DEVICE_FEATURE_UNITS.HECTO_PASCAL,
- name: 'Pressure Sensor',
- read_only: true,
- has_feedback: false,
- min: 0,
- max: 10000,
- zigbeeField: 'pressure',
- },
- button: {
- category: DEVICE_FEATURE_CATEGORIES.BUTTON,
- type: DEVICE_FEATURE_TYPES.BUTTON.CLICK,
- name: 'Button',
- read_only: true,
- has_feedback: false,
- min: 0,
- max: 1,
- zigbeeField: 'action',
- },
- switch: {
- category: DEVICE_FEATURE_CATEGORIES.SWITCH,
- type: DEVICE_FEATURE_TYPES.SENSOR.BINARY,
- name: 'Switch (On/Off)',
- read_only: false,
- has_feedback: true,
- min: 0,
- max: 1,
- zigbeeField: 'state',
- },
- switch_sensor: {
- category: DEVICE_FEATURE_CATEGORIES.SWITCH,
- type: DEVICE_FEATURE_TYPES.SENSOR.BINARY,
- name: 'Switch Sensor',
- read_only: true,
- has_feedback: false,
- min: 0,
- max: 1,
- zigbeeField: 'state',
- },
- power: {
- category: DEVICE_FEATURE_CATEGORIES.SWITCH,
- type: DEVICE_FEATURE_TYPES.SWITCH.POWER,
- unit: DEVICE_FEATURE_UNITS.WATT,
- name: 'Power consumption',
- read_only: true,
- has_feedback: false,
- min: 0,
- max: 1,
- zigbeeField: 'power',
- },
- current: {
- category: DEVICE_FEATURE_CATEGORIES.SWITCH,
- type: DEVICE_FEATURE_TYPES.SWITCH.CURRENT,
- unit: DEVICE_FEATURE_UNITS.AMPERE,
- name: 'Switch Current',
- read_only: true,
- has_feedback: false,
- min: 0,
- max: 1000,
- zigbeeField: 'current',
- },
- voltage: {
- category: DEVICE_FEATURE_CATEGORIES.SWITCH,
- type: DEVICE_FEATURE_TYPES.SWITCH.VOLTAGE,
- unit: DEVICE_FEATURE_UNITS.VOLT,
- name: 'Switch Voltage',
- read_only: true,
- has_feedback: false,
- min: 0,
- max: 1000,
- zigbeeField: 'voltage',
- },
- energy: {
- category: DEVICE_FEATURE_CATEGORIES.SWITCH,
- type: DEVICE_FEATURE_TYPES.SWITCH.ENERGY,
- unit: DEVICE_FEATURE_UNITS.KILOWATT_HOUR,
- name: 'Energy consumption',
- read_only: true,
- has_feedback: false,
- min: 0,
- max: 10000,
- zigbeeField: 'energy',
- },
- light: {
- category: DEVICE_FEATURE_CATEGORIES.LIGHT,
- type: DEVICE_FEATURE_TYPES.SENSOR.BINARY,
- name: 'Light',
- read_only: false,
- has_feedback: true,
- min: 0,
- max: 1,
- zigbeeField: 'state',
- },
- brightness: {
- category: DEVICE_FEATURE_CATEGORIES.LIGHT,
- type: DEVICE_FEATURE_TYPES.LIGHT.BRIGHTNESS,
- name: 'Light Brightness',
- read_only: false,
- has_feedback: false,
- min: 0,
- max: 255,
- zigbeeField: 'brightness',
- },
- color_temperature: {
- category: DEVICE_FEATURE_CATEGORIES.LIGHT,
- type: DEVICE_FEATURE_TYPES.LIGHT.TEMPERATURE,
- name: 'Light Temperature',
- read_only: false,
- has_feedback: false,
- min: 150,
- max: 500,
- zigbeeField: 'color_temp',
- },
- color: {
- category: DEVICE_FEATURE_CATEGORIES.LIGHT,
- type: DEVICE_FEATURE_TYPES.LIGHT.COLOR,
- name: 'Light Color',
- read_only: false,
- has_feedback: false,
- min: 0,
- max: 16777215,
- zigbeeField: 'color',
- },
- gas: {
- category: DEVICE_FEATURE_CATEGORIES.SMOKE_SENSOR,
- type: DEVICE_FEATURE_TYPES.SENSOR.BINARY,
- name: 'Smoke Sensor',
- read_only: true,
- has_feedback: false,
- min: 0,
- max: 1,
- zigbeeField: 'gas',
- },
- gas_density: {
- category: DEVICE_FEATURE_CATEGORIES.SMOKE_SENSOR,
- type: DEVICE_FEATURE_TYPES.SENSOR.DECIMAL,
- name: 'Gas Density',
- read_only: true,
- has_feedback: false,
- min: 0,
- max: 1000,
- zigbeeField: 'gas',
- },
- co2: {
- category: DEVICE_FEATURE_CATEGORIES.CO2_SENSOR,
- type: DEVICE_FEATURE_TYPES.SENSOR.DECIMAL,
- name: 'CO2 Concentration',
- read_only: true,
- has_feedback: false,
- min: 0,
- max: 10000,
- zigbeeField: 'co2',
- },
-};
-
-module.exports = {
- features,
-};
diff --git a/server/services/zigbee2mqtt/utils/loadFeatures.js b/server/services/zigbee2mqtt/utils/loadFeatures.js
deleted file mode 100644
index fe72e670a2..0000000000
--- a/server/services/zigbee2mqtt/utils/loadFeatures.js
+++ /dev/null
@@ -1,33 +0,0 @@
-const { features } = require('./features');
-const { getFeaturesByModel } = require('../model');
-
-/**
- * @description Retreive feature related to device.
- * @param {string} name - Device name.
- * @param {string} model - Device model.
- * @param {boolean} addBattery - Automatically add battery feature.
- * @returns {Object} Device for Gladys.
- * @example
- * loadFeatures('MyDevice', 'MODEL', true);
- */
-function loadFeatures(name, model, addBattery) {
- const matchingFeatures = getFeaturesByModel(model);
- const loadedFeatures = matchingFeatures.map((f) => {
- return Object.assign({}, f);
- });
-
- if (addBattery) {
- loadedFeatures.push(Object.assign({}, features.battery));
- }
-
- loadedFeatures.forEach((feature) => {
- feature.external_id = `zigbee2mqtt:${name}:${feature.category}:${feature.type}:${feature.zigbeeField}`;
- feature.selector = feature.external_id;
- });
-
- return loadedFeatures;
-}
-
-module.exports = {
- loadFeatures,
-};
diff --git a/server/test/services/zigbee2mqtt/utils/loadFeatures.test.js b/server/test/services/zigbee2mqtt/utils/loadFeatures.test.js
deleted file mode 100644
index de2d16d7ed..0000000000
--- a/server/test/services/zigbee2mqtt/utils/loadFeatures.test.js
+++ /dev/null
@@ -1,59 +0,0 @@
-const { assert } = require('chai');
-const { loadFeatures } = require('../../../../services/zigbee2mqtt/utils/loadFeatures');
-
-const name = 'Device';
-const model = 'WXKG11LM';
-
-const expectedFeaturesWithBattery = [
- {
- category: 'button',
- type: 'click',
- read_only: true,
- has_feedback: false,
- min: 0,
- max: 1,
- name: 'Button',
- external_id: 'zigbee2mqtt:Device:button:click:action',
- selector: 'zigbee2mqtt:Device:button:click:action',
- zigbeeField: 'action',
- },
- {
- category: 'battery',
- type: 'integer',
- unit: 'percent',
- read_only: true,
- has_feedback: false,
- min: 0,
- max: 100,
- name: 'Battery',
- external_id: 'zigbee2mqtt:Device:battery:integer:battery',
- selector: 'zigbee2mqtt:Device:battery:integer:battery',
- zigbeeField: 'battery',
- },
-];
-
-const expectedFeatures = [
- {
- category: 'button',
- type: 'click',
- read_only: true,
- has_feedback: false,
- min: 0,
- max: 1,
- name: 'Button',
- external_id: 'zigbee2mqtt:Device:button:click:action',
- selector: 'zigbee2mqtt:Device:button:click:action',
- zigbeeField: 'action',
- },
-];
-
-describe('zigbee2mqttService loadFeatures', () => {
- it('should return features with battery', () => {
- const features = loadFeatures(name, model, true);
- return assert.deepEqual(features, expectedFeaturesWithBattery);
- });
- it('should return features without battery', () => {
- const features = loadFeatures(name, model, false);
- return assert.deepEqual(features, expectedFeatures);
- });
-});
From 576dcc17ddf6c0e677e38a92fd8067eb70b31986 Mon Sep 17 00:00:00 2001
From: atrovato <1839717+atrovato@users.noreply.github.com>
Date: Sun, 19 Sep 2021 14:34:37 +0200
Subject: [PATCH 2/9] Zigbee2mqtt auto-build features
---
front/src/config/i18n/en.json | 2 +
front/src/config/i18n/fr.json | 2 +
.../zigbee2mqtt/exposes/binaryType.js | 91 +++++++
.../zigbee2mqtt/exposes/compositeType.js | 15 ++
.../services/zigbee2mqtt/exposes/enumType.js | 39 +++
server/services/zigbee2mqtt/exposes/index.js | 9 +
.../zigbee2mqtt/exposes/numericType.js | 238 +++++++++++++++++
.../zigbee2mqtt/lib/handleMqttMessage.js | 4 +-
.../zigbee2mqtt/utils/convertDevice.js | 36 +--
.../utils/features/buildFeature.js | 88 +++++++
.../utils/features/completeFeature.js | 24 ++
.../utils/features/mapDefinition.js | 20 ++
.../zigbee2mqtt/utils/features/mapExpose.js | 31 +++
.../zigbee2mqtt/utils/features/mapUnit.js | 41 +++
.../zigbee2mqtt/lib/handleMqttMessage.test.js | 101 +------
.../lib/payloads/event_device_result.json | 106 ++++++++
.../lib/payloads/mqtt_devices_get.json | 246 ++++++++++++++++++
.../zigbee2mqtt/utils/convertDevice.test.js | 96 +++----
.../utils/feature/buildFeature.test.js | 227 ++++++++++++++++
.../utils/feature/completeFeature.test.js | 16 ++
.../zigbee2mqtt/utils/feature/mapUnit.test.js | 31 +++
server/utils/constants.js | 1 +
22 files changed, 1297 insertions(+), 167 deletions(-)
create mode 100644 server/services/zigbee2mqtt/exposes/binaryType.js
create mode 100644 server/services/zigbee2mqtt/exposes/compositeType.js
create mode 100644 server/services/zigbee2mqtt/exposes/enumType.js
create mode 100644 server/services/zigbee2mqtt/exposes/index.js
create mode 100644 server/services/zigbee2mqtt/exposes/numericType.js
create mode 100644 server/services/zigbee2mqtt/utils/features/buildFeature.js
create mode 100644 server/services/zigbee2mqtt/utils/features/completeFeature.js
create mode 100644 server/services/zigbee2mqtt/utils/features/mapDefinition.js
create mode 100644 server/services/zigbee2mqtt/utils/features/mapExpose.js
create mode 100644 server/services/zigbee2mqtt/utils/features/mapUnit.js
create mode 100644 server/test/services/zigbee2mqtt/lib/payloads/event_device_result.json
create mode 100644 server/test/services/zigbee2mqtt/lib/payloads/mqtt_devices_get.json
create mode 100644 server/test/services/zigbee2mqtt/utils/feature/buildFeature.test.js
create mode 100644 server/test/services/zigbee2mqtt/utils/feature/completeFeature.test.js
create mode 100644 server/test/services/zigbee2mqtt/utils/feature/mapUnit.test.js
diff --git a/front/src/config/i18n/en.json b/front/src/config/i18n/en.json
index 80dec54b5e..acf5805f53 100644
--- a/front/src/config/i18n/en.json
+++ b/front/src/config/i18n/en.json
@@ -1525,6 +1525,7 @@
"kilowatt": "Kilowatt (kW)",
"kilowatt-hour": "Kilowatt hour (kWh)",
"ampere": "Ampere (A)",
+ "millivolt": "Millivolt (mV)",
"volt": "Volt (V)",
"ppm": "Parts per million (ppm)",
"cm": "Centimeter (cm)",
@@ -1541,6 +1542,7 @@
"kilowatt": "kW",
"kilowatt-hour": "kWh",
"ampere": "A",
+ "millivolt": "mV",
"volt": "V",
"ppm": "ppm",
"cm": "cm",
diff --git a/front/src/config/i18n/fr.json b/front/src/config/i18n/fr.json
index 6d9c1dec74..6bc240ca73 100644
--- a/front/src/config/i18n/fr.json
+++ b/front/src/config/i18n/fr.json
@@ -1525,6 +1525,7 @@
"kilowatt": "Kilowatt",
"kilowatt-hour": "Kilowatt heure (kWh)",
"ampere": "Ampère (A)",
+ "millivolt": "Millivolt (mV)",
"volt": "Volt (V)",
"ppm": "Partie par million (ppm)",
"cm": "Centimètre (cm)",
@@ -1541,6 +1542,7 @@
"kilowatt": "kW",
"kilowatt-hour": "kWh",
"ampere": "A",
+ "millivolt": "mV",
"volt": "V",
"ppm": "ppm",
"cm": "cm",
diff --git a/server/services/zigbee2mqtt/exposes/binaryType.js b/server/services/zigbee2mqtt/exposes/binaryType.js
new file mode 100644
index 0000000000..949c97db1a
--- /dev/null
+++ b/server/services/zigbee2mqtt/exposes/binaryType.js
@@ -0,0 +1,91 @@
+const { DEVICE_FEATURE_CATEGORIES, DEVICE_FEATURE_TYPES } = require('../../../utils/constants');
+
+module.exports = {
+ type: 'binary',
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.SWITCH,
+ type: DEVICE_FEATURE_TYPES.SWITCH.BINARY,
+ min: 0,
+ max: 1,
+ },
+ names: {
+ /*
+ auto_lock: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.SWITCH,
+ type: DEVICE_FEATURE_TYPES.SENSOR.BINARY,
+ },
+ },
+ away_mode: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.FAN,
+ type: DEVICE_FEATURE_TYPES.FAN.BINARY,
+ },
+ },
+ carbon_monoxide: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.MONOXIDE_SENSOR,
+ type: DEVICE_FEATURE_TYPES.SENSOR.DECIMAL,
+ },
+ },
+ */
+ contact: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.OPENING_SENSOR,
+ type: DEVICE_FEATURE_TYPES.SENSOR.BINARY,
+ },
+ },
+ eco_mode: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.SWITCH,
+ type: DEVICE_FEATURE_TYPES.SENSOR.BINARY,
+ },
+ },
+ occupancy: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.MOTION_SENSOR,
+ type: DEVICE_FEATURE_TYPES.SENSOR.BINARY,
+ },
+ },
+ interlock: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.SWITCH,
+ type: DEVICE_FEATURE_TYPES.SENSOR.BINARY,
+ },
+ },
+ presence: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.MOTION_SENSOR,
+ type: DEVICE_FEATURE_TYPES.SENSOR.BINARY,
+ },
+ },
+ smoke: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.SMOKE_SENSOR,
+ type: DEVICE_FEATURE_TYPES.SENSOR.BINARY,
+ },
+ },
+ state: {
+ types: {
+ light: {
+ category: DEVICE_FEATURE_CATEGORIES.LIGHT,
+ type: DEVICE_FEATURE_TYPES.LIGHT.BINARY,
+ },
+ lock: {
+ category: DEVICE_FEATURE_CATEGORIES.ACCESS_CONTROL,
+ type: DEVICE_FEATURE_TYPES.ACCESS_CONTROL.MODE,
+ },
+ switch: {
+ category: DEVICE_FEATURE_CATEGORIES.SWITCH,
+ type: DEVICE_FEATURE_TYPES.SWITCH.BINARY,
+ },
+ },
+ },
+ water_leak: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.LEAK_SENSOR,
+ type: DEVICE_FEATURE_TYPES.SENSOR.BINARY,
+ },
+ },
+ },
+};
diff --git a/server/services/zigbee2mqtt/exposes/compositeType.js b/server/services/zigbee2mqtt/exposes/compositeType.js
new file mode 100644
index 0000000000..2db3ea9adc
--- /dev/null
+++ b/server/services/zigbee2mqtt/exposes/compositeType.js
@@ -0,0 +1,15 @@
+const { DEVICE_FEATURE_CATEGORIES, DEVICE_FEATURE_TYPES } = require('../../../utils/constants');
+
+module.exports = {
+ type: 'composite',
+ names: {
+ color_xy: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.LIGHT,
+ type: DEVICE_FEATURE_TYPES.LIGHT.COLOR,
+ min: 0,
+ max: 16777215,
+ },
+ },
+ },
+};
diff --git a/server/services/zigbee2mqtt/exposes/enumType.js b/server/services/zigbee2mqtt/exposes/enumType.js
new file mode 100644
index 0000000000..1ddf759394
--- /dev/null
+++ b/server/services/zigbee2mqtt/exposes/enumType.js
@@ -0,0 +1,39 @@
+const { DEVICE_FEATURE_CATEGORIES, DEVICE_FEATURE_TYPES } = require('../../../utils/constants');
+
+module.exports = {
+ type: 'enum',
+ feature: {
+ min: 0,
+ max: 1,
+ },
+ names: {
+ action: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.BUTTON,
+ type: DEVICE_FEATURE_TYPES.BUTTON.CLICK,
+ },
+ },
+ /*
+ fan_mode: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.FAN,
+ type: DEVICE_FEATURE_TYPES.FAN.SPEED,
+ },
+ },
+ state: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.CURTAIN,
+ type: DEVICE_FEATURE_TYPES.CURTAIN.STATE,
+ min: 0,
+ max: 2,
+ },
+ }
+ system_mode: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.FAN,
+ type: DEVICE_FEATURE_TYPES.FAN.MODE,
+ },
+ },
+ */
+ },
+};
diff --git a/server/services/zigbee2mqtt/exposes/index.js b/server/services/zigbee2mqtt/exposes/index.js
new file mode 100644
index 0000000000..6e5e303293
--- /dev/null
+++ b/server/services/zigbee2mqtt/exposes/index.js
@@ -0,0 +1,9 @@
+const binaryType = require('./binaryType');
+const numericType = require('./numericType');
+const enumType = require('./enumType');
+
+module.exports = {
+ [binaryType.type]: binaryType,
+ [numericType.type]: numericType,
+ [enumType.type]: enumType,
+};
diff --git a/server/services/zigbee2mqtt/exposes/numericType.js b/server/services/zigbee2mqtt/exposes/numericType.js
new file mode 100644
index 0000000000..7d0b0e07dc
--- /dev/null
+++ b/server/services/zigbee2mqtt/exposes/numericType.js
@@ -0,0 +1,238 @@
+const { DEVICE_FEATURE_CATEGORIES, DEVICE_FEATURE_TYPES, DEVICE_FEATURE_UNITS } = require('../../../utils/constants');
+
+module.exports = {
+ type: 'numeric',
+ feature: {
+ min: 0,
+ max: 10000,
+ },
+ names: {
+ battery: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.BATTERY,
+ type: DEVICE_FEATURE_TYPES.SENSOR.INTEGER,
+ unit: DEVICE_FEATURE_UNITS.PERCENT,
+ min: 0,
+ max: 100,
+ },
+ },
+ brightness: {
+ types: {
+ light: {
+ category: DEVICE_FEATURE_CATEGORIES.LIGHT,
+ type: DEVICE_FEATURE_TYPES.LIGHT.BRIGHTNESS,
+ min: 0,
+ max: 255,
+ },
+ },
+ },
+ co2: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.CO2_SENSOR,
+ type: DEVICE_FEATURE_TYPES.SENSOR.DECIMAL,
+ unit: DEVICE_FEATURE_UNITS.PPM,
+ },
+ },
+ color_temp: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.LIGHT,
+ type: DEVICE_FEATURE_TYPES.LIGHT.TEMPERATURE,
+ min: 150,
+ max: 500,
+ },
+ },
+ /*
+ confort_temperature: {
+ feature: {
+ },
+ },
+ */
+ current: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.SWITCH,
+ type: DEVICE_FEATURE_TYPES.SWITCH.CURRENT,
+ unit: DEVICE_FEATURE_UNITS.AMPERE,
+ min: 0,
+ max: 1000,
+ },
+ },
+ current_phase_b: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.SWITCH,
+ type: DEVICE_FEATURE_TYPES.SWITCH.CURRENT,
+ unit: DEVICE_FEATURE_UNITS.AMPERE,
+ min: 0,
+ max: 1000,
+ },
+ },
+ current_phase_c: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.SWITCH,
+ type: DEVICE_FEATURE_TYPES.SWITCH.CURRENT,
+ unit: DEVICE_FEATURE_UNITS.AMPERE,
+ min: 0,
+ max: 1000,
+ },
+ },
+ cpu_temperature: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.TEMPERATURE_SENSOR,
+ type: DEVICE_FEATURE_TYPES.SENSOR.DECIMAL,
+ unit: DEVICE_FEATURE_UNITS.CELSIUS,
+ min: -100,
+ max: 150,
+ },
+ },
+ device_temperature: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.TEMPERATURE_SENSOR,
+ type: DEVICE_FEATURE_TYPES.SENSOR.DECIMAL,
+ unit: DEVICE_FEATURE_UNITS.CELSIUS,
+ min: -100,
+ max: 150,
+ },
+ },
+ eco2: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.CO2_SENSOR,
+ type: DEVICE_FEATURE_TYPES.SENSOR.DECIMAL,
+ unit: DEVICE_FEATURE_UNITS.PPM,
+ },
+ },
+ energy: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.SWITCH,
+ type: DEVICE_FEATURE_TYPES.SWITCH.ENERGY,
+ unit: DEVICE_FEATURE_UNITS.KILOWATT_HOUR,
+ },
+ },
+ formaldehyd: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.SMOKE_SENSOR,
+ type: DEVICE_FEATURE_TYPES.SENSOR.DECIMAL,
+ },
+ },
+ gas: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.SMOKE_SENSOR,
+ type: DEVICE_FEATURE_TYPES.SENSOR.DECIMAL,
+ },
+ },
+ /*
+ hue: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.LIGHT,
+ type: DEVICE_FEATURE_TYPES.LIGHT.HUE,
+ min: 150?,
+ max: 500?,
+ },
+ },
+ */
+ humidity: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.HUMIDITY_SENSOR,
+ type: DEVICE_FEATURE_TYPES.SENSOR.DECIMAL,
+ unit: DEVICE_FEATURE_UNITS.PERCENT,
+ min: 0,
+ max: 100,
+ },
+ },
+ illuminance: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.LIGHT_SENSOR,
+ type: DEVICE_FEATURE_TYPES.SENSOR.DECIMAL,
+ min: 0,
+ max: 10000,
+ },
+ },
+ illuminance_lux: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.LIGHT_SENSOR,
+ type: DEVICE_FEATURE_TYPES.SENSOR.DECIMAL,
+ unit: DEVICE_FEATURE_UNITS.LUX,
+ min: 0,
+ max: 10000,
+ },
+ },
+ local_temperature: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.TEMPERATURE_SENSOR,
+ type: DEVICE_FEATURE_TYPES.SENSOR.DECIMAL,
+ unit: DEVICE_FEATURE_UNITS.CELSIUS,
+ min: -100,
+ max: 150,
+ },
+ },
+ /*
+ position: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.CURTAIN,
+ type: DEVICE_FEATURE_TYPES.CURTAIN.POSITION,
+ unit: DEVICE_FEATURE_UNITS.PERCENT,
+ min: 0,
+ max: 100,
+ },
+ },
+ */
+ power: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.SWITCH,
+ type: DEVICE_FEATURE_TYPES.SWITCH.POWER,
+ unit: DEVICE_FEATURE_UNITS.WATT,
+ },
+ },
+ pressure: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.PRESSURE_SENSOR,
+ type: DEVICE_FEATURE_TYPES.SENSOR.DECIMAL,
+ unit: DEVICE_FEATURE_UNITS.HECTO_PASCAL,
+ },
+ },
+ /*
+ saturation: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.LIGHT,
+ type: DEVICE_FEATURE_TYPES.LIGHT.SATURATION,
+ min: 150?,
+ max: 500?,
+ },
+ },
+ */
+ temperature: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.TEMPERATURE_SENSOR,
+ type: DEVICE_FEATURE_TYPES.SENSOR.DECIMAL,
+ unit: DEVICE_FEATURE_UNITS.CELSIUS,
+ min: -100,
+ max: 150,
+ },
+ },
+ vibration: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.VIBRATION_SENSOR,
+ type: DEVICE_FEATURE_TYPES.SENSOR.BINARY,
+ },
+ },
+ voltage: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.SWITCH,
+ type: DEVICE_FEATURE_TYPES.SWITCH.VOLTAGE,
+ unit: DEVICE_FEATURE_UNITS.VOLT,
+ },
+ },
+ voltage_phase_b: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.SWITCH,
+ type: DEVICE_FEATURE_TYPES.SWITCH.VOLTAGE,
+ unit: DEVICE_FEATURE_UNITS.VOLT,
+ },
+ },
+ voltage_phase_c: {
+ feature: {
+ category: DEVICE_FEATURE_CATEGORIES.SWITCH,
+ type: DEVICE_FEATURE_TYPES.SWITCH.VOLTAGE,
+ unit: DEVICE_FEATURE_UNITS.VOLT,
+ },
+ },
+ },
+};
diff --git a/server/services/zigbee2mqtt/lib/handleMqttMessage.js b/server/services/zigbee2mqtt/lib/handleMqttMessage.js
index af1231b1c5..0e3a3a51a1 100644
--- a/server/services/zigbee2mqtt/lib/handleMqttMessage.js
+++ b/server/services/zigbee2mqtt/lib/handleMqttMessage.js
@@ -21,14 +21,12 @@ function handleMqttMessage(topic, message) {
});
switch (topic) {
- case 'zigbee2mqtt/bridge/config/devices': {
+ case 'zigbee2mqtt/bridge/devices': {
logger.log('Getting config devices from Zigbee2mqtt');
const devices = JSON.parse(message);
const convertedDevices = devices
// Remove Coordinator
.filter((d) => d.type !== TYPE_COORDINATOR)
- // Remove Empty models
- .filter((d) => d.model && d.model !== '')
// Remove existing devices
.filter((d) => {
const existingDevice = this.gladys.stateManager.get('deviceByExternalId', `zigbee2mqtt:${d.friendly_name}`);
diff --git a/server/services/zigbee2mqtt/utils/convertDevice.js b/server/services/zigbee2mqtt/utils/convertDevice.js
index 393d99e6c7..7f3afe0836 100644
--- a/server/services/zigbee2mqtt/utils/convertDevice.js
+++ b/server/services/zigbee2mqtt/utils/convertDevice.js
@@ -1,6 +1,6 @@
-const { loadFeatures } = require('./loadFeatures');
const logger = require('../../../utils/logger');
const { DEVICE_FEATURE_CATEGORIES } = require('../../../../server/utils/constants');
+const { mapDefinition } = require('./features/mapDefinition');
/**
* @description Converts an MQTT device to a Gladys device.
@@ -8,37 +8,27 @@ const { DEVICE_FEATURE_CATEGORIES } = require('../../../../server/utils/constant
* @param {string} serviceId - Service ID.
* @returns {Object} Device for Gladys.
* @example
- * convertDevice({ friendly_name: 'name', model: 'featureMapper' }, '6a37dd9d-48c7-4d09-a7bb-33f257edb78d');
+ * convertDevice({ friendly_name: 'name', definition: {} }, '6a37dd9d-48c7-4d09-a7bb-33f257edb78d');
*/
function convertDevice(device, serviceId) {
- const features = loadFeatures(device.friendly_name, device.model, device.powerSource === 'Battery');
+ const { friendly_name: name, definition = {} } = device;
+ const { model } = definition;
+ const features = mapDefinition(name, definition);
- // Not managed device
- if (features.length === 0 || (features.length === 1 && features[0].category === DEVICE_FEATURE_CATEGORIES.BATTERY)) {
- const gladysDevice = {
- name: device.friendly_name,
- external_id: `zigbee2mqtt:${device.friendly_name}`,
- model: device.model,
- features,
- should_poll: false,
- service_id: serviceId,
- supported: false,
- };
- logger.debug(`Device ${device.friendly_name} / model ${device.model} NOT managed by Gladys`);
- logger.debug(gladysDevice);
- return gladysDevice;
- }
+ // Device is not managed if no feature found, or only battery feature is available.
+ const supported = features.findIndex((f) => f.category !== DEVICE_FEATURE_CATEGORIES.BATTERY) >= 0;
const gladysDevice = {
- name: device.friendly_name,
- external_id: `zigbee2mqtt:${device.friendly_name}`,
- model: device.model,
+ name,
+ model,
+ external_id: `zigbee2mqtt:${name}`,
features,
should_poll: false,
service_id: serviceId,
- supported: true,
+ supported,
};
- logger.debug(`Device ${device.friendly_name} / model ${device.model} managed by Gladys`);
+
+ logger.debug(`Device ${name} / model ${model} ${supported ? '' : 'NOT'} managed by Gladys`);
logger.debug(gladysDevice);
return gladysDevice;
}
diff --git a/server/services/zigbee2mqtt/utils/features/buildFeature.js b/server/services/zigbee2mqtt/utils/features/buildFeature.js
new file mode 100644
index 0000000000..1e3e5ec839
--- /dev/null
+++ b/server/services/zigbee2mqtt/utils/features/buildFeature.js
@@ -0,0 +1,88 @@
+const exposesMap = require('../../exposes');
+const { mapUnit } = require('./mapUnit');
+const { completeFeature } = require('./completeFeature');
+
+/**
+ * @description Load feature from parent type.
+ * @param {Object} types - Zigbee "expose" parent type features.
+ * @param {string} parentType - Requested parent type.
+ * @returns {Object} The related Gladys feature, or undefined.
+ *
+ * @example buildByParentType({ switch: {}, light: {}}, 'light');
+ */
+function buildByParentType(types = {}, parentType) {
+ return types[parentType];
+}
+
+/**
+ * @description Load feature from property name, completed by parent type.
+ *
+ * @param {Object} names - Zigbee "expose" proerty name features.
+ * @param {string} name - Zigbee "expose" property name.
+ * @param {string} parentType - Requested parent type.
+ * @returns {Object} The related Gladys feature, or undefined.
+ *
+ * @example buildByName({ state: {}}, 'state', 'light');
+ */
+function buildByName(names = {}, name, parentType) {
+ const { types = {}, feature } = names[name] || {};
+ const byType = buildByParentType(types, parentType);
+
+ if (!byType && !feature) {
+ return undefined;
+ }
+
+ return { ...(feature || {}), ...(byType || {}) };
+}
+
+/**
+ * @description Build a Gladys feature according to Zigbee "expose" values.
+ * @param {string} deviceName - Device friendly name.
+ * @param {Object} expose - Zigbee "expose" values.
+ * @param {string} parentType - Requested parent type.
+ * @returns {Object} The related Gladys feature, or undefined.
+ *
+ * @example buildFeature('MyDevice', {}, 'light');
+ */
+function buildFeature(deviceName, expose = {}, parentType) {
+ const { type, name, property, access, value_min: minValue, value_max: maxValue, unit: deviceUnit, values } = expose;
+ const { names = {}, feature } = exposesMap[type] || {};
+ const byName = buildByName(names, name, parentType);
+
+ if (!byName) {
+ return undefined;
+ }
+
+ // Read only ?
+ // eslint-disable-next-line no-bitwise
+ const readOnly = (access & 2) === 0;
+
+ // Has feedback ?
+ // eslint-disable-next-line no-bitwise
+ const hasFeedback = !readOnly && (access & 1) === 1;
+
+ const createdFeature = { read_only: readOnly, has_feedback: hasFeedback, ...(feature || {}), ...(byName || {}) };
+
+ // Min value
+ const min = minValue !== undefined ? minValue : createdFeature.min;
+
+ // Max value
+ let { max } = createdFeature;
+ if (maxValue !== undefined) {
+ max = maxValue;
+ } else if (values !== undefined) {
+ max = values.length;
+ }
+
+ // Unit
+ const unit = mapUnit(deviceUnit, createdFeature.unit);
+
+ // Add missing properties
+ return completeFeature(deviceName, { ...createdFeature, min, max, unit }, property);
+}
+
+module.exports = {
+ buildByParentType,
+ buildByName,
+ buildFeature,
+};
diff --git a/server/services/zigbee2mqtt/utils/features/completeFeature.js b/server/services/zigbee2mqtt/utils/features/completeFeature.js
new file mode 100644
index 0000000000..6929716921
--- /dev/null
+++ b/server/services/zigbee2mqtt/utils/features/completeFeature.js
@@ -0,0 +1,24 @@
+const { addSelector } = require('../../../../utils/addSelector');
+
+/**
+ * @description Complete feature with externalId and selector generated values.
+ *
+ * @param {string} deviceName - Zigbee friendly device name.
+ * @param {Object} feature - Related Gladys feature.
+ * @param {string} property - Related Zigbee property.
+ * @returns {Object} Completed Galdys feature.
+ *
+ * @example completeFeature('MyDevice', { category: 'light', type: 'binary' }, 'state');
+ */
+function completeFeature(deviceName, feature, property) {
+ const { category, type } = feature;
+ const externalId = `zigbee2mqtt:${deviceName}:${category}:${type}:${property}`;
+ const name = `${property.charAt(0).toUpperCase() + property.slice(1).replace(/_/g, ' ')}`;
+ const completedFeature = { name, ...feature, external_id: externalId, selector: externalId };
+ addSelector(completedFeature);
+ return completedFeature;
+}
+
+module.exports = {
+ completeFeature,
+};
diff --git a/server/services/zigbee2mqtt/utils/features/mapDefinition.js b/server/services/zigbee2mqtt/utils/features/mapDefinition.js
new file mode 100644
index 0000000000..301b4a603a
--- /dev/null
+++ b/server/services/zigbee2mqtt/utils/features/mapDefinition.js
@@ -0,0 +1,20 @@
+const { mapExpose } = require('./mapExpose');
+
+/**
+ * @description Build Gladys features according to Zigbee device.
+ * @param {string} deviceName - Device name.
+ * @param {Object} definition - Zigbee device definition.
+ * @returns {Array} The related Gladys features.
+ *
+ * @example mapDefinition('MyDevice', {});
+ */
+function mapDefinition(deviceName, definition = {}) {
+ const { exposes = [] } = definition;
+
+ // Build feature according to device
+ return exposes.flatMap((e) => mapExpose(deviceName, e));
+}
+
+module.exports = {
+ mapDefinition,
+};
diff --git a/server/services/zigbee2mqtt/utils/features/mapExpose.js b/server/services/zigbee2mqtt/utils/features/mapExpose.js
new file mode 100644
index 0000000000..e4ed686d64
--- /dev/null
+++ b/server/services/zigbee2mqtt/utils/features/mapExpose.js
@@ -0,0 +1,31 @@
+const { buildFeature } = require('./buildFeature');
+
+/**
+ * @description Build a Gladys feature according to Zigbee "expose" and "features" values.
+ * @param {string} deviceName - Device friendly name.
+ * @param {Object} expose - Zigbee "expose" values.
+ * @param {string} parentType - Requested parent type.
+ * @returns {Object} The related Gladys feature, or undefined.
+ *
+ * @example mapExpose('MyDevice', {}, 'light');
+ */
+function mapExpose(deviceName, expose, parentType = undefined) {
+ const { type, features = [] } = expose;
+
+ const matchingFeatures = [];
+
+ // Merge default with specific
+ const feature = buildFeature(deviceName, expose, parentType);
+ if (feature) {
+ matchingFeatures.push(feature);
+ }
+
+ // Map exposed sub-features recursivly
+ features.flatMap((f) => mapExpose(deviceName, f, parentType || type)).forEach((f) => matchingFeatures.push(f));
+
+ return matchingFeatures;
+}
+
+module.exports = {
+ mapExpose,
+};
diff --git a/server/services/zigbee2mqtt/utils/features/mapUnit.js b/server/services/zigbee2mqtt/utils/features/mapUnit.js
new file mode 100644
index 0000000000..bf6c258445
--- /dev/null
+++ b/server/services/zigbee2mqtt/utils/features/mapUnit.js
@@ -0,0 +1,41 @@
+const { DEVICE_FEATURE_UNITS } = require('../../../../utils/constants');
+
+/**
+ * @description Transform Zigbee unit to Gladys unit.
+ *
+ * @param {string} deviceUnit - Zigbee unit.
+ * @param {string} featureUnit - Default unit.
+ * @returns {string} Tranformed unit.
+ *
+ * @example mapUnit('°C', 'celsius');
+ */
+function mapUnit(deviceUnit, featureUnit) {
+ switch (deviceUnit) {
+ case '%':
+ return DEVICE_FEATURE_UNITS.PERCENT;
+ case 'hPa':
+ return DEVICE_FEATURE_UNITS.HECTO_PASCAL;
+ case 'ppm':
+ return DEVICE_FEATURE_UNITS.PPM;
+ case 'A':
+ return DEVICE_FEATURE_UNITS.AMPERE;
+ case 'V':
+ return DEVICE_FEATURE_UNITS.VOLT;
+ case 'mV':
+ return DEVICE_FEATURE_UNITS.MILLI_VOLT;
+ case 'W':
+ return DEVICE_FEATURE_UNITS.WATT;
+ case 'kWh':
+ return DEVICE_FEATURE_UNITS.KILOWATT_HOUR;
+ case '°C':
+ return DEVICE_FEATURE_UNITS.CELSIUS;
+ case '°F':
+ return DEVICE_FEATURE_UNITS.FAHRENHEIT;
+ default:
+ return featureUnit;
+ }
+}
+
+module.exports = {
+ mapUnit,
+};
diff --git a/server/test/services/zigbee2mqtt/lib/handleMqttMessage.test.js b/server/test/services/zigbee2mqtt/lib/handleMqttMessage.test.js
index 4cde5b8c2d..795f90b011 100644
--- a/server/test/services/zigbee2mqtt/lib/handleMqttMessage.test.js
+++ b/server/test/services/zigbee2mqtt/lib/handleMqttMessage.test.js
@@ -3,6 +3,9 @@ const sinon = require('sinon');
const { assert, fake } = sinon;
const proxyquire = require('proxyquire').noCallThru();
+const zigbeeDevices = require('./payloads/mqtt_devices_get.json');
+const expectedDevicesPayload = require('./payloads/event_device_result.json');
+
const { EVENTS, WEBSOCKET_MESSAGE_TYPES } = require('../../../../utils/constants');
const Zigbee2mqttManager = proxyquire('../../../../services/zigbee2mqtt/lib', {});
@@ -21,103 +24,7 @@ const gladys = {
},
};
-const zigbeeDevices = `[
- {
- "type":"Coordinator"
- },
- {
- "friendly_name":"0x00158d0005828ece",
- "model":"WSDCGQ11LM",
- "powerSource":"Battery",
- "type":"EndDevice"
- },
- {
- "friendly_name":"0x00158d0005828eca",
- "model":"fakeModel",
- "type":"EndDevice"
- },
- {
- "friendly_name":"0x00158d0005828ece",
- "model":"WSDCGQ11LM",
- "powerSource":"Battery",
- "type":"EndDevice"
- }
- ]`;
-
const serviceId = 'f87b7af2-ca8e-44fc-b754-444354b42fee';
-const expectedDevicesPayload = [
- {
- external_id: 'zigbee2mqtt:0x00158d0005828eca',
- features: [],
- model: 'fakeModel',
- name: '0x00158d0005828eca',
- service_id: 'f87b7af2-ca8e-44fc-b754-444354b42fee',
- should_poll: false,
- supported: false,
- },
- {
- external_id: 'zigbee2mqtt:0x00158d0005828ece',
- features: [
- {
- category: 'temperature-sensor',
- external_id: 'zigbee2mqtt:0x00158d0005828ece:temperature-sensor:decimal:temperature',
- has_feedback: false,
- max: 125,
- min: -50,
- read_only: true,
- name: 'Temperature',
- selector: 'zigbee2mqtt:0x00158d0005828ece:temperature-sensor:decimal:temperature',
- type: 'decimal',
- unit: 'celsius',
- zigbeeField: 'temperature',
- },
- {
- category: 'humidity-sensor',
- external_id: 'zigbee2mqtt:0x00158d0005828ece:humidity-sensor:decimal:humidity',
- has_feedback: false,
- max: 100,
- min: 0,
- read_only: true,
- name: 'Humidity',
- selector: 'zigbee2mqtt:0x00158d0005828ece:humidity-sensor:decimal:humidity',
- type: 'decimal',
- unit: 'percent',
- zigbeeField: 'humidity',
- },
- {
- category: 'pressure-sensor',
- external_id: 'zigbee2mqtt:0x00158d0005828ece:pressure-sensor:decimal:pressure',
- has_feedback: false,
- max: 10000,
- min: 0,
- name: 'Pressure Sensor',
- read_only: true,
- selector: 'zigbee2mqtt:0x00158d0005828ece:pressure-sensor:decimal:pressure',
- type: 'decimal',
- unit: 'hPa',
- zigbeeField: 'pressure',
- },
- {
- category: 'battery',
- external_id: 'zigbee2mqtt:0x00158d0005828ece:battery:integer:battery',
- has_feedback: false,
- max: 100,
- min: 0,
- read_only: true,
- name: 'Battery',
- selector: 'zigbee2mqtt:0x00158d0005828ece:battery:integer:battery',
- type: 'integer',
- unit: 'percent',
- zigbeeField: 'battery',
- },
- ],
- model: 'WSDCGQ11LM',
- name: '0x00158d0005828ece',
- service_id: 'f87b7af2-ca8e-44fc-b754-444354b42fee',
- should_poll: false,
- supported: true,
- },
-];
describe('zigbee2mqtt handleMqttMessage', () => {
// PREPARE
@@ -141,7 +48,7 @@ describe('zigbee2mqtt handleMqttMessage', () => {
.returns(false);
zigbee2mqttManager.gladys.stateManager.get = stateManagerGetStub;
// EXECUTE
- await zigbee2mqttManager.handleMqttMessage('zigbee2mqtt/bridge/config/devices', zigbeeDevices);
+ await zigbee2mqttManager.handleMqttMessage('zigbee2mqtt/bridge/devices', JSON.stringify(zigbeeDevices));
// ASSERT
assert.calledWith(gladys.event.emit, EVENTS.WEBSOCKET.SEND_ALL, {
type: WEBSOCKET_MESSAGE_TYPES.ZIGBEE2MQTT.STATUS_CHANGE,
diff --git a/server/test/services/zigbee2mqtt/lib/payloads/event_device_result.json b/server/test/services/zigbee2mqtt/lib/payloads/event_device_result.json
new file mode 100644
index 0000000000..ac77dc0037
--- /dev/null
+++ b/server/test/services/zigbee2mqtt/lib/payloads/event_device_result.json
@@ -0,0 +1,106 @@
+[
+ {
+ "name": "0x00158d0004019127",
+ "model": "WXKG11LM",
+ "external_id": "zigbee2mqtt:0x00158d0004019127",
+ "features": [
+ {
+ "name": "Battery",
+ "read_only": true,
+ "has_feedback": false,
+ "min": 0,
+ "max": 100,
+ "category": "battery",
+ "type": "integer",
+ "unit": "percent",
+ "external_id": "zigbee2mqtt:0x00158d0004019127:battery:integer:battery",
+ "selector": "zigbee2mqtt-0x00158d0004019127-battery-integer-battery"
+ },
+ {
+ "name": "Voltage",
+ "read_only": true,
+ "has_feedback": false,
+ "min": 0,
+ "max": 10000,
+ "category": "switch",
+ "type": "voltage",
+ "unit": "millivolt",
+ "external_id": "zigbee2mqtt:0x00158d0004019127:switch:voltage:voltage",
+ "selector": "zigbee2mqtt-0x00158d0004019127-switch-voltage-voltage"
+ }
+ ],
+ "should_poll": false,
+ "service_id": "f87b7af2-ca8e-44fc-b754-444354b42fee",
+ "supported": true
+ },
+ {
+ "name": "0x00158d00045b2740",
+ "model": "WSDCGQ11LM",
+ "external_id": "zigbee2mqtt:0x00158d00045b2740",
+ "features": [
+ {
+ "name": "Battery",
+ "read_only": true,
+ "has_feedback": false,
+ "min": 0,
+ "max": 100,
+ "category": "battery",
+ "type": "integer",
+ "unit": "percent",
+ "external_id": "zigbee2mqtt:0x00158d00045b2740:battery:integer:battery",
+ "selector": "zigbee2mqtt-0x00158d00045b2740-battery-integer-battery"
+ },
+ {
+ "name": "Temperature",
+ "read_only": true,
+ "has_feedback": false,
+ "min": -100,
+ "max": 150,
+ "category": "temperature-sensor",
+ "type": "decimal",
+ "unit": "celsius",
+ "external_id": "zigbee2mqtt:0x00158d00045b2740:temperature-sensor:decimal:temperature",
+ "selector": "zigbee2mqtt-0x00158d00045b2740-temperature-sensor-decimal-temperature"
+ },
+ {
+ "name": "Humidity",
+ "read_only": true,
+ "has_feedback": false,
+ "min": 0,
+ "max": 100,
+ "category": "humidity-sensor",
+ "type": "decimal",
+ "unit": "percent",
+ "external_id": "zigbee2mqtt:0x00158d00045b2740:humidity-sensor:decimal:humidity",
+ "selector": "zigbee2mqtt-0x00158d00045b2740-humidity-sensor-decimal-humidity"
+ },
+ {
+ "name": "Pressure",
+ "read_only": true,
+ "has_feedback": false,
+ "min": 0,
+ "max": 10000,
+ "category": "pressure-sensor",
+ "type": "decimal",
+ "unit": "hPa",
+ "external_id": "zigbee2mqtt:0x00158d00045b2740:pressure-sensor:decimal:pressure",
+ "selector": "zigbee2mqtt-0x00158d00045b2740-pressure-sensor-decimal-pressure"
+ },
+ {
+ "name": "Voltage",
+ "read_only": true,
+ "has_feedback": false,
+ "min": 0,
+ "max": 10000,
+ "category": "switch",
+ "type": "voltage",
+ "unit": "millivolt",
+ "external_id": "zigbee2mqtt:0x00158d00045b2740:switch:voltage:voltage",
+ "selector": "zigbee2mqtt-0x00158d00045b2740-switch-voltage-voltage"
+ }
+ ],
+ "should_poll": false,
+ "service_id": "f87b7af2-ca8e-44fc-b754-444354b42fee",
+ "supported": true
+ }
+]
diff --git a/server/test/services/zigbee2mqtt/lib/payloads/mqtt_devices_get.json b/server/test/services/zigbee2mqtt/lib/payloads/mqtt_devices_get.json
new file mode 100644
index 0000000000..574aa5d2ec
--- /dev/null
+++ b/server/test/services/zigbee2mqtt/lib/payloads/mqtt_devices_get.json
@@ -0,0 +1,246 @@
+[
+ {
+ "definition": null,
+ "endpoints": {
+ "1": {
+ "bindings": [],
+ "clusters": {
+ "input": ["genBasic", "genTime", "genOta"],
+ "output": ["genPowerCfg", "genPollCtrl", "ssIasZone"]
+ },
+ "configured_reportings": []
+ },
+ "242": {
+ "bindings": [],
+ "clusters": {
+ "input": [],
+ "output": ["greenPower"]
+ },
+ "configured_reportings": []
+ }
+ },
+ "friendly_name": "Coordinator",
+ "ieee_address": "0x00212effff06ddd8",
+ "interview_completed": true,
+ "interviewing": false,
+ "network_address": 0,
+ "supported": false,
+ "type": "Coordinator"
+ },
+ {
+ "definition": {
+ "description": "MiJia wireless switch",
+ "exposes": [
+ {
+ "access": 1,
+ "description": "Remaining battery in %",
+ "name": "battery",
+ "property": "battery",
+ "type": "numeric",
+ "unit": "%",
+ "value_max": 100,
+ "value_min": 0
+ },
+ {
+ "access": 1,
+ "description": "Triggered action (e.g. a button click)",
+ "name": "action",
+ "property": "action",
+ "type": "enum",
+ "values": ["single", "double", "triple", "quadruple", "hold", "release", "many"]
+ },
+ {
+ "access": 1,
+ "description": "Voltage of the battery in millivolts",
+ "name": "voltage",
+ "property": "voltage",
+ "type": "numeric",
+ "unit": "mV"
+ },
+ {
+ "access": 1,
+ "description": "Link quality (signal strength)",
+ "name": "linkquality",
+ "property": "linkquality",
+ "type": "numeric",
+ "unit": "lqi",
+ "value_max": 255,
+ "value_min": 0
+ }
+ ],
+ "model": "WXKG01LM",
+ "supports_ota": false,
+ "vendor": "Xiaomi"
+ },
+ "endpoints": {
+ "1": {
+ "bindings": [],
+ "clusters": {
+ "input": [],
+ "output": []
+ },
+ "configured_reportings": []
+ }
+ },
+ "friendly_name": "0x00158d00033e88d5",
+ "ieee_address": "0x00158d00033e88d5",
+ "interview_completed": true,
+ "interviewing": false,
+ "manufacturer": "LUMI",
+ "model_id": "lumi.sensor_switch",
+ "network_address": 44173,
+ "power_source": "Battery",
+ "supported": true,
+ "type": "EndDevice"
+ },
+ {
+ "date_code": "20180525",
+ "definition": {
+ "description": "Aqara wireless switch",
+ "exposes": [
+ {
+ "access": 1,
+ "description": "Remaining battery in %",
+ "name": "battery",
+ "property": "battery",
+ "type": "numeric",
+ "unit": "%",
+ "value_max": 100,
+ "value_min": 0
+ },
+ {
+ "access": 1,
+ "description": "Voltage of the battery in millivolts",
+ "name": "voltage",
+ "property": "voltage",
+ "type": "numeric",
+ "unit": "mV"
+ },
+ {
+ "access": 1,
+ "description": "Link quality (signal strength)",
+ "name": "linkquality",
+ "property": "linkquality",
+ "type": "numeric",
+ "unit": "lqi",
+ "value_max": 255,
+ "value_min": 0
+ }
+ ],
+ "model": "WXKG11LM",
+ "supports_ota": false,
+ "vendor": "Xiaomi"
+ },
+ "endpoints": {
+ "1": {
+ "bindings": [],
+ "clusters": {
+ "input": ["genBasic", "genMultistateInput", "genIdentify"],
+ "output": ["genBasic"]
+ },
+ "configured_reportings": []
+ }
+ },
+ "friendly_name": "0x00158d0004019127",
+ "ieee_address": "0x00158d0004019127",
+ "interview_completed": true,
+ "interviewing": false,
+ "manufacturer": "LUMI",
+ "model_id": "lumi.remote.b1acn01",
+ "network_address": 47250,
+ "power_source": "Battery",
+ "software_build_id": "3000-0001",
+ "supported": true,
+ "type": "EndDevice"
+ },
+ {
+ "date_code": "20161129",
+ "definition": {
+ "description": "Aqara temperature, humidity and pressure sensor",
+ "exposes": [
+ {
+ "access": 1,
+ "description": "Remaining battery in %",
+ "name": "battery",
+ "property": "battery",
+ "type": "numeric",
+ "unit": "%",
+ "value_max": 100,
+ "value_min": 0
+ },
+ {
+ "access": 1,
+ "description": "Measured temperature value",
+ "name": "temperature",
+ "property": "temperature",
+ "type": "numeric",
+ "unit": "°C"
+ },
+ {
+ "access": 1,
+ "description": "Measured relative humidity",
+ "name": "humidity",
+ "property": "humidity",
+ "type": "numeric",
+ "unit": "%"
+ },
+ {
+ "access": 1,
+ "description": "The measured atmospheric pressure",
+ "name": "pressure",
+ "property": "pressure",
+ "type": "numeric",
+ "unit": "hPa"
+ },
+ {
+ "access": 1,
+ "description": "Voltage of the battery in millivolts",
+ "name": "voltage",
+ "property": "voltage",
+ "type": "numeric",
+ "unit": "mV"
+ },
+ {
+ "access": 1,
+ "description": "Link quality (signal strength)",
+ "name": "linkquality",
+ "property": "linkquality",
+ "type": "numeric",
+ "unit": "lqi",
+ "value_max": 255,
+ "value_min": 0
+ }
+ ],
+ "model": "WSDCGQ11LM",
+ "supports_ota": false,
+ "vendor": "Xiaomi"
+ },
+ "endpoints": {
+ "1": {
+ "bindings": [],
+ "clusters": {
+ "input": [
+ "genBasic",
+ "genIdentify",
+ "msTemperatureMeasurement",
+ "msPressureMeasurement",
+ "msRelativeHumidity"
+ ],
+ "output": ["genBasic", "genGroups"]
+ },
+ "configured_reportings": []
+ }
+ },
+ "friendly_name": "0x00158d00045b2740",
+ "ieee_address": "0x00158d00045b2740",
+ "interview_completed": true,
+ "interviewing": false,
+ "manufacturer": "LUMI",
+ "model_id": "lumi.weather",
+ "network_address": 23007,
+ "power_source": "Battery",
+ "software_build_id": "3000-0001",
+ "supported": true,
+ "type": "EndDevice"
+ }
+]
diff --git a/server/test/services/zigbee2mqtt/utils/convertDevice.test.js b/server/test/services/zigbee2mqtt/utils/convertDevice.test.js
index d4f6f57196..54c299ed07 100644
--- a/server/test/services/zigbee2mqtt/utils/convertDevice.test.js
+++ b/server/test/services/zigbee2mqtt/utils/convertDevice.test.js
@@ -2,57 +2,65 @@ const { assert } = require('chai');
const { convertDevice } = require('../../../../services/zigbee2mqtt/utils/convertDevice');
const serviceId = '6a37dd9d-48c7-4d09-a7bb-33f257edb78d';
-
-const notManagedDevice = {
- friendly_name: 'Not supported device',
- model: 'not_supported_device',
-};
-
-const managedDevice = {
- friendly_name: 'Xiaomi Aqara Sensor',
- model: 'WXKG11LM',
-};
-
-const notManagedGladysDevice = {
- name: notManagedDevice.friendly_name,
- external_id: `zigbee2mqtt:${notManagedDevice.friendly_name}`,
- model: notManagedDevice.model,
- features: [],
- should_poll: false,
- service_id: serviceId,
- supported: false,
-};
-
-const managedGladysDevice = {
- name: managedDevice.friendly_name,
- external_id: `zigbee2mqtt:${managedDevice.friendly_name}`,
- model: managedDevice.model,
- features: [
- {
- category: 'button',
- external_id: `zigbee2mqtt:${managedDevice.friendly_name}:button:click:action`,
- has_feedback: false,
- max: 1,
- min: 0,
- read_only: true,
- name: 'Button',
- selector: `zigbee2mqtt:${managedDevice.friendly_name}:button:click:action`,
- type: 'click',
- zigbeeField: 'action',
- },
- ],
- should_poll: false,
- service_id: serviceId,
- supported: true,
-};
-
describe('zigbee2mqtt convertDevice', () => {
it('should return not managed device', () => {
+ const notManagedDevice = {
+ friendly_name: 'Not supported device',
+ };
+
const result = convertDevice(notManagedDevice, serviceId);
+
+ const notManagedGladysDevice = {
+ name: notManagedDevice.friendly_name,
+ external_id: `zigbee2mqtt:${notManagedDevice.friendly_name}`,
+ model: undefined,
+ features: [],
+ should_poll: false,
+ service_id: serviceId,
+ supported: false,
+ };
return assert.deepEqual(result, notManagedGladysDevice);
});
+
it('should return managed device', () => {
+ const managedDevice = {
+ friendly_name: 'Xiaomi Aqara Sensor',
+ definition: {
+ exposes: [
+ {
+ type: 'enum',
+ name: 'action',
+ property: 'action',
+ },
+ ],
+ model: 'WXKG11LM',
+ },
+ };
+
const result = convertDevice(managedDevice, serviceId);
+
+ const managedGladysDevice = {
+ name: managedDevice.friendly_name,
+ external_id: `zigbee2mqtt:${managedDevice.friendly_name}`,
+ model: 'WXKG11LM',
+ features: [
+ {
+ category: 'button',
+ external_id: `zigbee2mqtt:${managedDevice.friendly_name}:button:click:action`,
+ has_feedback: false,
+ max: 1,
+ min: 0,
+ read_only: true,
+ name: 'Action',
+ selector: `zigbee2mqtt-xiaomi-aqara-sensor-button-click-action`,
+ type: 'click',
+ unit: undefined,
+ },
+ ],
+ should_poll: false,
+ service_id: serviceId,
+ supported: true,
+ };
return assert.deepEqual(result, managedGladysDevice);
});
});
diff --git a/server/test/services/zigbee2mqtt/utils/feature/buildFeature.test.js b/server/test/services/zigbee2mqtt/utils/feature/buildFeature.test.js
new file mode 100644
index 0000000000..dda5974d88
--- /dev/null
+++ b/server/test/services/zigbee2mqtt/utils/feature/buildFeature.test.js
@@ -0,0 +1,227 @@
+const { expect } = require('chai');
+
+const {
+ buildByParentType,
+ buildByName,
+ buildFeature,
+} = require('../../../../../services/zigbee2mqtt/utils/features/buildFeature');
+
+describe('zigbee2mqtt buildByParentType', () => {
+ it(`no type map`, () => {
+ const result = buildByParentType(undefined, undefined);
+ expect(result).eq(undefined);
+ });
+
+ it(`no selected type`, () => {
+ const types = {
+ binary: 'binary',
+ };
+ const result = buildByParentType(types, undefined);
+ expect(result).eq(undefined);
+ });
+
+ it(`get selected type`, () => {
+ const types = {
+ binary: 'binary',
+ };
+ const result = buildByParentType(types, 'binary');
+ expect(result).eq('binary');
+ });
+});
+
+describe('zigbee2mqtt buildByName', () => {
+ it(`all empty`, () => {
+ const result = buildByName(undefined, 'binary', 'light');
+ expect(result).eq(undefined);
+ });
+
+ it(`only by name`, () => {
+ const names = {
+ binary: {
+ feature: {
+ type: 'binary',
+ },
+ },
+ };
+ const result = buildByName(names, 'binary', 'light');
+
+ const expectedResult = { type: 'binary' };
+ expect(result).deep.eq(expectedResult);
+ });
+
+ it(`name and type`, () => {
+ const names = {
+ binary: {
+ feature: {
+ type: 'binary',
+ },
+ types: {
+ light: {
+ category: 'light',
+ },
+ },
+ },
+ };
+ const result = buildByName(names, 'binary', 'light');
+
+ const expectedResult = { type: 'binary', category: 'light' };
+ expect(result).deep.eq(expectedResult);
+ });
+});
+
+describe('zigbee2mqtt buildFeature', () => {
+ it(`no data`, () => {
+ const result = buildFeature('deviceName', undefined, undefined);
+ expect(result).eq(undefined);
+ });
+
+ it(`readOnly = true / hasFeedback = false`, () => {
+ const expose = {
+ type: 'binary',
+ name: 'state',
+ property: 'property',
+ access: 1,
+ };
+ const result = buildFeature('deviceName', expose, 'switch');
+
+ const expectedResult = {
+ category: 'switch',
+ type: 'binary',
+ min: 0,
+ max: 1,
+ read_only: true,
+ has_feedback: false,
+ name: 'Property',
+ external_id: 'zigbee2mqtt:deviceName:switch:binary:property',
+ selector: 'zigbee2mqtt-devicename-switch-binary-property',
+ unit: undefined,
+ };
+
+ expect(result).deep.eq(expectedResult);
+ });
+
+ it(`readOnly = false / hasFeedback = false`, () => {
+ const expose = {
+ type: 'binary',
+ name: 'state',
+ property: 'property',
+ access: 2,
+ };
+ const result = buildFeature('deviceName', expose, 'switch');
+
+ const expectedResult = {
+ category: 'switch',
+ type: 'binary',
+ min: 0,
+ max: 1,
+ read_only: false,
+ has_feedback: false,
+ name: 'Property',
+ external_id: 'zigbee2mqtt:deviceName:switch:binary:property',
+ selector: 'zigbee2mqtt-devicename-switch-binary-property',
+ unit: undefined,
+ };
+
+ expect(result).deep.eq(expectedResult);
+ });
+
+ it(`readOnly = false / hasFeedback = true`, () => {
+ const expose = {
+ type: 'binary',
+ name: 'state',
+ property: 'property',
+ access: 7,
+ };
+ const result = buildFeature('deviceName', expose, 'switch');
+
+ const expectedResult = {
+ category: 'switch',
+ type: 'binary',
+ min: 0,
+ max: 1,
+ read_only: false,
+ has_feedback: true,
+ name: 'Property',
+ external_id: 'zigbee2mqtt:deviceName:switch:binary:property',
+ selector: 'zigbee2mqtt-devicename-switch-binary-property',
+ unit: undefined,
+ };
+
+ expect(result).deep.eq(expectedResult);
+ });
+
+ it(`override min value`, () => {
+ const expose = {
+ type: 'binary',
+ name: 'state',
+ property: 'property',
+ value_min: -1,
+ };
+ const result = buildFeature('deviceName', expose, 'switch');
+
+ const expectedResult = {
+ category: 'switch',
+ type: 'binary',
+ min: -1,
+ max: 1,
+ read_only: true,
+ has_feedback: false,
+ name: 'Property',
+ external_id: 'zigbee2mqtt:deviceName:switch:binary:property',
+ selector: 'zigbee2mqtt-devicename-switch-binary-property',
+ unit: undefined,
+ };
+
+ expect(result).deep.eq(expectedResult);
+ });
+
+ it(`override max value`, () => {
+ const expose = {
+ type: 'binary',
+ name: 'state',
+ property: 'property',
+ value_max: 10,
+ };
+ const result = buildFeature('deviceName', expose, 'switch');
+
+ const expectedResult = {
+ category: 'switch',
+ type: 'binary',
+ min: 0,
+ max: 10,
+ read_only: true,
+ has_feedback: false,
+ name: 'Property',
+ external_id: 'zigbee2mqtt:deviceName:switch:binary:property',
+ selector: 'zigbee2mqtt-devicename-switch-binary-property',
+ unit: undefined,
+ };
+
+ expect(result).deep.eq(expectedResult);
+ });
+
+ it(`override max by values`, () => {
+ const expose = {
+ type: 'binary',
+ name: 'state',
+ property: 'property',
+ values: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9], // length 10
+ };
+ const result = buildFeature('deviceName', expose, 'switch');
+
+ const expectedResult = {
+ category: 'switch',
+ type: 'binary',
+ min: 0,
+ max: 10,
+ read_only: true,
+ has_feedback: false,
+ name: 'Property',
+ external_id: 'zigbee2mqtt:deviceName:switch:binary:property',
+ selector: 'zigbee2mqtt-devicename-switch-binary-property',
+ unit: undefined,
+ };
+
+ expect(result).deep.eq(expectedResult);
+ });
+});
diff --git a/server/test/services/zigbee2mqtt/utils/feature/completeFeature.test.js b/server/test/services/zigbee2mqtt/utils/feature/completeFeature.test.js
new file mode 100644
index 0000000000..aebbb3bea0
--- /dev/null
+++ b/server/test/services/zigbee2mqtt/utils/feature/completeFeature.test.js
@@ -0,0 +1,16 @@
+const { expect } = require('chai');
+
+const { completeFeature } = require('../../../../../services/zigbee2mqtt/utils/features/completeFeature');
+
+describe('zigbee2mqtt completeFeature', () => {
+ it(`completeFeature`, () => {
+ const result = completeFeature('device name', {}, 'property');
+
+ const expected = {
+ name: 'Property',
+ external_id: 'zigbee2mqtt:device name:undefined:undefined:property',
+ selector: 'zigbee2mqtt-device-name-undefined-undefined-property',
+ };
+ expect(result).deep.eq(expected);
+ });
+});
diff --git a/server/test/services/zigbee2mqtt/utils/feature/mapUnit.test.js b/server/test/services/zigbee2mqtt/utils/feature/mapUnit.test.js
new file mode 100644
index 0000000000..e7d2e03d1b
--- /dev/null
+++ b/server/test/services/zigbee2mqtt/utils/feature/mapUnit.test.js
@@ -0,0 +1,31 @@
+const { expect } = require('chai');
+
+const { mapUnit } = require('../../../../../services/zigbee2mqtt/utils/features/mapUnit');
+const { DEVICE_FEATURE_UNITS } = require('../../../../../utils/constants');
+
+describe('zigbee2mqtt mapUnit', () => {
+ const defaultFeatureUnit = 'default';
+
+ const values = [
+ { input: null, expected: defaultFeatureUnit },
+ { input: '%', expected: DEVICE_FEATURE_UNITS.PERCENT },
+ { input: 'hPa', expected: DEVICE_FEATURE_UNITS.HECTO_PASCAL },
+ { input: 'ppm', expected: DEVICE_FEATURE_UNITS.PPM },
+ { input: 'A', expected: DEVICE_FEATURE_UNITS.AMPERE },
+ { input: 'V', expected: DEVICE_FEATURE_UNITS.VOLT },
+ { input: 'mV', expected: DEVICE_FEATURE_UNITS.MILLI_VOLT },
+ { input: 'W', expected: DEVICE_FEATURE_UNITS.WATT },
+ { input: 'kWh', expected: DEVICE_FEATURE_UNITS.KILOWATT_HOUR },
+ { input: '°C', expected: DEVICE_FEATURE_UNITS.CELSIUS },
+ { input: '°F', expected: DEVICE_FEATURE_UNITS.FAHRENHEIT },
+ ];
+
+ values.forEach((value) => {
+ const { input, expected } = value;
+
+ it(`map "${input}" to ${expected}`, () => {
+ const result = mapUnit(input, defaultFeatureUnit);
+ expect(result).eq(expected);
+ });
+ });
+});
diff --git a/server/utils/constants.js b/server/utils/constants.js
index b7057e5834..455c77b6ae 100644
--- a/server/utils/constants.js
+++ b/server/utils/constants.js
@@ -392,6 +392,7 @@ const DEVICE_FEATURE_UNITS = {
KILOWATT: 'kilowatt',
KILOWATT_HOUR: 'kilowatt-hour',
AMPERE: 'ampere',
+ MILLI_VOLT: 'millivolt',
VOLT: 'volt',
PPM: 'ppm',
MM: 'mm',
From 080a02624653931db152aad3ed795440f5066995 Mon Sep 17 00:00:00 2001
From: atrovato <1839717+atrovato@users.noreply.github.com>
Date: Sun, 3 Oct 2021 23:17:19 +0200
Subject: [PATCH 3/9] Handle discovered devices
---
front/src/config/i18n/en.json | 1 -
front/src/config/i18n/fr.json | 1 -
.../zigbee2mqtt/discover-page/DiscoverTab.jsx | 9 ------
.../all/zigbee2mqtt/discover-page/actions.js | 28 +++++--------------
.../all/zigbee2mqtt/discover-page/index.js | 1 +
.../zigbee2mqtt/api/zigbee2mqtt.controller.js | 16 +++++------
.../zigbee2mqtt/lib/discoverDevices.js | 15 ----------
.../zigbee2mqtt/lib/getDiscoveredDevices.js | 13 +++++++++
.../zigbee2mqtt/lib/handleMqttMessage.js | 6 ++--
server/services/zigbee2mqtt/lib/index.js | 5 ++--
.../api/zigbee2mqtt.controller.test.js | 10 +++----
.../zigbee2mqtt/lib/discoverDevices.test.js | 27 ------------------
.../lib/getDiscoveredDevices.test.js | 18 ++++++++++++
13 files changed, 58 insertions(+), 92 deletions(-)
delete mode 100644 server/services/zigbee2mqtt/lib/discoverDevices.js
create mode 100644 server/services/zigbee2mqtt/lib/getDiscoveredDevices.js
delete mode 100644 server/test/services/zigbee2mqtt/lib/discoverDevices.test.js
create mode 100644 server/test/services/zigbee2mqtt/lib/getDiscoveredDevices.test.js
diff --git a/front/src/config/i18n/en.json b/front/src/config/i18n/en.json
index acf5805f53..c3e75fae88 100644
--- a/front/src/config/i18n/en.json
+++ b/front/src/config/i18n/en.json
@@ -505,7 +505,6 @@
"device": "({{nbDevices}}) Devices",
"permitJoin": "Permit joining",
"noDeviceDiscovered": "No new device discovered, please click on scan button.",
- "scanButton": "Scan",
"serverNoResponse": "Gladys server is not available.",
"serverNoResponseWebSocker": "Gladys server is not available. Pleash refresh the page.",
"deviceNotHandled": "Device not handled yet, please contact us to help us connect it in Gladys!",
diff --git a/front/src/config/i18n/fr.json b/front/src/config/i18n/fr.json
index 6bc240ca73..9107b74e83 100644
--- a/front/src/config/i18n/fr.json
+++ b/front/src/config/i18n/fr.json
@@ -632,7 +632,6 @@
"device": "({{nbDevices}}) Appareils",
"permitJoin": "Autoriser l'association",
"noDeviceDiscovered": "Aucun nouvel appareil trouvé. Veuillez autoriser l'association des appareils et les appairer.\nATTENTION : Pour la sécurité de votre installation, n'oubliez pas d'interdire l'association après appairage.",
- "scanButton": "Scanner",
"serverNoResponse": "Gladys n'est pas accessible.",
"serverNoResponseWebSocker": "Gladys n'est pas accessible. Veuillez actualiser la page.",
"deviceNotHandled": "L'appareil n'est pas encore géré, veuillez nous contacter pour nous aider à le connecter dans Gladys !",
diff --git a/front/src/routes/integration/all/zigbee2mqtt/discover-page/DiscoverTab.jsx b/front/src/routes/integration/all/zigbee2mqtt/discover-page/DiscoverTab.jsx
index 0b8e0acf15..968c9246ab 100644
--- a/front/src/routes/integration/all/zigbee2mqtt/discover-page/DiscoverTab.jsx
+++ b/front/src/routes/integration/all/zigbee2mqtt/discover-page/DiscoverTab.jsx
@@ -45,15 +45,6 @@ const DiscoverTab = ({ children, ...props }) => (
-
-
-
diff --git a/front/src/routes/integration/all/zigbee2mqtt/discover-page/actions.js b/front/src/routes/integration/all/zigbee2mqtt/discover-page/actions.js
index fe1bf6f6da..2a49403f6e 100644
--- a/front/src/routes/integration/all/zigbee2mqtt/discover-page/actions.js
+++ b/front/src/routes/integration/all/zigbee2mqtt/discover-page/actions.js
@@ -2,42 +2,28 @@ import update from 'immutability-helper';
import createActionsIntegration from '../../../../../actions/integration';
import createActionsHouse from '../../../../../actions/house';
-let scanTimer;
-
function createActions(store) {
const integrationActions = createActionsIntegration(store);
const houseActions = createActionsHouse(store);
const actions = {
- async discover(state) {
+ async getDiscoveredDevices(state) {
store.setState({
discoverZigbee2mqtt: true,
discoverZigbee2mqttError: null
});
- if (state.session.websocketConnected) {
- try {
- await state.httpClient.post('/api/v1/service/zigbee2mqtt/discover');
- scanTimer = setTimeout(store.setState, 5000, {
- discoverZigbee2mqtt: false,
- discoverZigbee2mqttError: null
- });
- } catch (e) {
- clearTimeout(scanTimer);
- store.setState({
- zigbee2mqttDevices: [],
- discoverZigbee2mqtt: false,
- discoverZigbee2mqttError: 'integration.zigbee2mqtt.discover.serverNoResponse'
- });
- }
- } else {
+
+ try {
+ const { devices: zigbee2mqttDevices } = await state.httpClient.get('/api/v1/service/zigbee2mqtt/devices');
+ store.setState({ zigbee2mqttDevices, discoverZigbee2mqtt: false });
+ } catch (e) {
store.setState({
zigbee2mqttDevices: [],
discoverZigbee2mqtt: false,
- discoverZigbee2mqttError: 'integration.zigbee2mqtt.discover.serverNoResponseWebSocker'
+ discoverZigbee2mqttError: 'integration.zigbee2mqtt.discover.serverNoResponse'
});
}
},
setDiscoveredDevices(state, zigbee2mqttDevices) {
- clearTimeout(scanTimer);
store.setState({
zigbee2mqttDevices,
discoverZigbee2mqtt: false,
diff --git a/front/src/routes/integration/all/zigbee2mqtt/discover-page/index.js b/front/src/routes/integration/all/zigbee2mqtt/discover-page/index.js
index a27d8ffcdc..ca8bf79c95 100644
--- a/front/src/routes/integration/all/zigbee2mqtt/discover-page/index.js
+++ b/front/src/routes/integration/all/zigbee2mqtt/discover-page/index.js
@@ -26,6 +26,7 @@ class Zigbee2mqttIntegration extends Component {
this.props.setDiscoveredDevices(undefined);
this.props.getHouses();
this.props.getIntegrationByName('zigbee2mqtt');
+ this.props.getDiscoveredDevices();
}
componentWillUnmount() {
diff --git a/server/services/zigbee2mqtt/api/zigbee2mqtt.controller.js b/server/services/zigbee2mqtt/api/zigbee2mqtt.controller.js
index ba37cceee2..8f5fbbc0cb 100644
--- a/server/services/zigbee2mqtt/api/zigbee2mqtt.controller.js
+++ b/server/services/zigbee2mqtt/api/zigbee2mqtt.controller.js
@@ -3,14 +3,14 @@ const logger = require('../../../utils/logger');
module.exports = function Zigbee2mqttController(gladys, zigbee2mqttManager) {
/**
- * @api {post} /api/v1/service/zigbee2mqtt/discover Launch Zigbee2mqtt devices discovery
- * @apiName discover
+ * @api {get} /api/v1/service/zigbee2mqtt/devices Get discovered Zigbee2mqtt devices
+ * @apiName getDiscoveredDevices
* @apiGroup Zigbee2mqtt
*/
- async function discover(req, res) {
- logger.log('Launching devices discovery');
- await zigbee2mqttManager.discoverDevices();
- res.json({ status: 'discovering' });
+ async function getDiscoveredDevices(req, res) {
+ logger.log('Get discovered devices');
+ const devices = zigbee2mqttManager.getDiscoveredDevices();
+ res.json({ devices });
}
/**
@@ -101,9 +101,9 @@ module.exports = function Zigbee2mqttController(gladys, zigbee2mqttManager) {
}
return {
- 'post /api/v1/service/zigbee2mqtt/discover': {
+ 'get /api/v1/service/zigbee2mqtt/devices': {
authenticated: true,
- controller: asyncMiddleware(discover),
+ controller: asyncMiddleware(getDiscoveredDevices),
},
'get /api/v1/service/zigbee2mqtt/status': {
authenticated: true,
diff --git a/server/services/zigbee2mqtt/lib/discoverDevices.js b/server/services/zigbee2mqtt/lib/discoverDevices.js
deleted file mode 100644
index 8f07c08b61..0000000000
--- a/server/services/zigbee2mqtt/lib/discoverDevices.js
+++ /dev/null
@@ -1,15 +0,0 @@
-const logger = require('../../../utils/logger');
-
-/**
- * @description Publish message on discover topic.
- * @example
- * discoverDevices();
- */
-function discoverDevices() {
- logger.log('Ask for devices enumeration');
- this.mqttClient.publish('zigbee2mqtt/bridge/config/devices/get');
-}
-
-module.exports = {
- discoverDevices,
-};
diff --git a/server/services/zigbee2mqtt/lib/getDiscoveredDevices.js b/server/services/zigbee2mqtt/lib/getDiscoveredDevices.js
new file mode 100644
index 0000000000..8f9d544d6c
--- /dev/null
+++ b/server/services/zigbee2mqtt/lib/getDiscoveredDevices.js
@@ -0,0 +1,13 @@
+/**
+ * @description Get discovered devices.
+ * @returns {Array} Array of discovered devices.
+ * @example
+ * getDiscoveredDevices();
+ */
+function getDiscoveredDevices() {
+ return this.discoveredDevices;
+}
+
+module.exports = {
+ getDiscoveredDevices,
+};
diff --git a/server/services/zigbee2mqtt/lib/handleMqttMessage.js b/server/services/zigbee2mqtt/lib/handleMqttMessage.js
index 0e3a3a51a1..944ca85e8d 100644
--- a/server/services/zigbee2mqtt/lib/handleMqttMessage.js
+++ b/server/services/zigbee2mqtt/lib/handleMqttMessage.js
@@ -4,8 +4,6 @@ const { convertDevice } = require('../utils/convertDevice');
const { convertValue } = require('../utils/convertValue');
const { convertFeature } = require('../utils/convertFeature');
-const TYPE_COORDINATOR = 'Coordinator';
-
/**
* @description Handle a new message receive in MQTT.
* @param {string} topic - MQTT topic.
@@ -26,7 +24,7 @@ function handleMqttMessage(topic, message) {
const devices = JSON.parse(message);
const convertedDevices = devices
// Remove Coordinator
- .filter((d) => d.type !== TYPE_COORDINATOR)
+ .filter((d) => d.supported)
// Remove existing devices
.filter((d) => {
const existingDevice = this.gladys.stateManager.get('deviceByExternalId', `zigbee2mqtt:${d.friendly_name}`);
@@ -38,6 +36,8 @@ function handleMqttMessage(topic, message) {
// Add features
.map((d) => convertDevice(d, this.serviceId));
+ this.discoveredDevices = convertedDevices;
+
this.gladys.event.emit(EVENTS.WEBSOCKET.SEND_ALL, {
type: WEBSOCKET_MESSAGE_TYPES.ZIGBEE2MQTT.DISCOVER,
payload: convertedDevices,
diff --git a/server/services/zigbee2mqtt/lib/index.js b/server/services/zigbee2mqtt/lib/index.js
index 8ff2c5a88e..329820060a 100644
--- a/server/services/zigbee2mqtt/lib/index.js
+++ b/server/services/zigbee2mqtt/lib/index.js
@@ -3,7 +3,7 @@ const { connect } = require('./connect');
const { getConfiguration } = require('./getConfiguration');
const { disconnect } = require('./disconnect');
const { handleMqttMessage } = require('./handleMqttMessage');
-const { discoverDevices } = require('./discoverDevices');
+const { getDiscoveredDevices } = require('./getDiscoveredDevices');
const { setValue } = require('./setValue');
const { status } = require('./status');
const { subscribe } = require('./subscribe');
@@ -27,6 +27,7 @@ const Zigbee2mqttManager = function Zigbee2mqttManager(gladys, mqttLibrary, serv
this.serviceId = serviceId;
this.mqttClient = null;
+ this.discoveredDevices = [];
this.topicBinds = {};
this.usbConfigured = false;
this.mqttExist = false;
@@ -48,7 +49,7 @@ Zigbee2mqttManager.prototype.getConfiguration = getConfiguration;
Zigbee2mqttManager.prototype.basePath = basePath;
Zigbee2mqttManager.prototype.disconnect = disconnect;
Zigbee2mqttManager.prototype.handleMqttMessage = handleMqttMessage;
-Zigbee2mqttManager.prototype.discoverDevices = discoverDevices;
+Zigbee2mqttManager.prototype.getDiscoveredDevices = getDiscoveredDevices;
Zigbee2mqttManager.prototype.setValue = setValue;
Zigbee2mqttManager.prototype.status = status;
Zigbee2mqttManager.prototype.subscribe = subscribe;
diff --git a/server/test/services/zigbee2mqtt/api/zigbee2mqtt.controller.test.js b/server/test/services/zigbee2mqtt/api/zigbee2mqtt.controller.test.js
index 62efc2ff97..c49a886711 100644
--- a/server/test/services/zigbee2mqtt/api/zigbee2mqtt.controller.test.js
+++ b/server/test/services/zigbee2mqtt/api/zigbee2mqtt.controller.test.js
@@ -11,7 +11,7 @@ const gladys = {
event,
};
const zigbee2mqttManager = {
- discoverDevices: fake.resolves(true),
+ getDiscoveredDevices: fake.returns(['device']),
status: fake.returns(true),
init: fake.returns(true),
installMqttContainer: fake.returns(true),
@@ -29,16 +29,16 @@ describe('zigbee2mqtt API', () => {
sinon.reset();
});
- it('post /api/v1/service/zigbee2mqtt/discover', async () => {
+ it('get /api/v1/service/zigbee2mqtt/devices', async () => {
const req = {};
const res = {
json: fake.returns(null),
};
- await controller['post /api/v1/service/zigbee2mqtt/discover'].controller(req, res);
+ await controller['get /api/v1/service/zigbee2mqtt/devices'].controller(req, res);
- assert.calledOnce(zigbee2mqttManager.discoverDevices);
- assert.calledWith(res.json, { status: 'discovering' });
+ assert.calledOnce(zigbee2mqttManager.getDiscoveredDevices);
+ assert.calledWith(res.json, { devices: ['device'] });
});
it('get /api/v1/service/zigbee2mqtt/status', async () => {
diff --git a/server/test/services/zigbee2mqtt/lib/discoverDevices.test.js b/server/test/services/zigbee2mqtt/lib/discoverDevices.test.js
deleted file mode 100644
index 9851e06db1..0000000000
--- a/server/test/services/zigbee2mqtt/lib/discoverDevices.test.js
+++ /dev/null
@@ -1,27 +0,0 @@
-const sinon = require('sinon');
-
-const { assert, fake } = sinon;
-const proxyquire = require('proxyquire').noCallThru();
-
-const Zigbee2MqttService = proxyquire('../../../../services/zigbee2mqtt', {});
-
-const gladys = {};
-
-const serviceId = 'f87b7af2-ca8e-44fc-b754-444354b42fee';
-
-const mqtt = {
- publish: fake.resolves(true),
-};
-
-describe('zigbee2mqtt discoverDevices', () => {
- // PREPARE
- const zigbee2MqttService = Zigbee2MqttService(gladys, serviceId);
- zigbee2MqttService.device.mqttClient = mqtt;
-
- it('discover devices', async () => {
- // EXECUTE
- await zigbee2MqttService.device.discoverDevices();
- // ASSERT
- assert.calledWith(mqtt.publish, 'zigbee2mqtt/bridge/config/devices/get');
- });
-});
diff --git a/server/test/services/zigbee2mqtt/lib/getDiscoveredDevices.test.js b/server/test/services/zigbee2mqtt/lib/getDiscoveredDevices.test.js
new file mode 100644
index 0000000000..c338c4f256
--- /dev/null
+++ b/server/test/services/zigbee2mqtt/lib/getDiscoveredDevices.test.js
@@ -0,0 +1,18 @@
+const { expect } = require('chai');
+
+const Zigbee2MqttService = require('../../../../services/zigbee2mqtt');
+
+const gladys = {};
+const serviceId = 'f87b7af2-ca8e-44fc-b754-444354b42fee';
+
+describe('zigbee2mqtt getDiscoveredDevices', () => {
+ // PREPARE
+ const zigbee2MqttService = Zigbee2MqttService(gladys, serviceId);
+
+ it('get discovered devices', async () => {
+ // EXECUTE
+ const devices = zigbee2MqttService.device.getDiscoveredDevices();
+ // ASSERT
+ expect(devices).deep.eq([]);
+ });
+});
From 49d76fdd2688dd0a9910ebe1901ce19eba917882 Mon Sep 17 00:00:00 2001
From: atrovato <1839717+atrovato@users.noreply.github.com>
Date: Mon, 18 Oct 2021 21:39:07 +0200
Subject: [PATCH 4/9] Fix review comments
---
.../all/zigbee2mqtt/discover-page/actions.js | 2 +-
.../zigbee2mqtt/api/zigbee2mqtt.controller.js | 6 +--
.../zigbee2mqtt/exposes/binaryType.js | 20 ---------
.../services/zigbee2mqtt/exposes/enumType.js | 22 ----------
.../zigbee2mqtt/exposes/numericType.js | 41 +------------------
.../zigbee2mqtt/utils/convertDevice.js | 1 -
.../api/zigbee2mqtt.controller.test.js | 6 +--
7 files changed, 9 insertions(+), 89 deletions(-)
diff --git a/front/src/routes/integration/all/zigbee2mqtt/discover-page/actions.js b/front/src/routes/integration/all/zigbee2mqtt/discover-page/actions.js
index 2a49403f6e..79859ca114 100644
--- a/front/src/routes/integration/all/zigbee2mqtt/discover-page/actions.js
+++ b/front/src/routes/integration/all/zigbee2mqtt/discover-page/actions.js
@@ -13,7 +13,7 @@ function createActions(store) {
});
try {
- const { devices: zigbee2mqttDevices } = await state.httpClient.get('/api/v1/service/zigbee2mqtt/devices');
+ const zigbee2mqttDevices = await state.httpClient.get('/api/v1/service/zigbee2mqtt/device');
store.setState({ zigbee2mqttDevices, discoverZigbee2mqtt: false });
} catch (e) {
store.setState({
diff --git a/server/services/zigbee2mqtt/api/zigbee2mqtt.controller.js b/server/services/zigbee2mqtt/api/zigbee2mqtt.controller.js
index 8f5fbbc0cb..31a1e85915 100644
--- a/server/services/zigbee2mqtt/api/zigbee2mqtt.controller.js
+++ b/server/services/zigbee2mqtt/api/zigbee2mqtt.controller.js
@@ -3,14 +3,14 @@ const logger = require('../../../utils/logger');
module.exports = function Zigbee2mqttController(gladys, zigbee2mqttManager) {
/**
- * @api {get} /api/v1/service/zigbee2mqtt/devices Get discovered Zigbee2mqtt devices
+ * @api {get} /api/v1/service/zigbee2mqtt/device Get discovered Zigbee2mqtt devices
* @apiName getDiscoveredDevices
* @apiGroup Zigbee2mqtt
*/
async function getDiscoveredDevices(req, res) {
logger.log('Get discovered devices');
const devices = zigbee2mqttManager.getDiscoveredDevices();
- res.json({ devices });
+ res.json(devices);
}
/**
@@ -101,7 +101,7 @@ module.exports = function Zigbee2mqttController(gladys, zigbee2mqttManager) {
}
return {
- 'get /api/v1/service/zigbee2mqtt/devices': {
+ 'get /api/v1/service/zigbee2mqtt/device': {
authenticated: true,
controller: asyncMiddleware(getDiscoveredDevices),
},
diff --git a/server/services/zigbee2mqtt/exposes/binaryType.js b/server/services/zigbee2mqtt/exposes/binaryType.js
index 949c97db1a..df9d9dd7f6 100644
--- a/server/services/zigbee2mqtt/exposes/binaryType.js
+++ b/server/services/zigbee2mqtt/exposes/binaryType.js
@@ -9,26 +9,6 @@ module.exports = {
max: 1,
},
names: {
- /*
- auto_lock: {
- feature: {
- category: DEVICE_FEATURE_CATEGORIES.SWITCH,
- type: DEVICE_FEATURE_TYPES.SENSOR.BINARY,
- },
- },
- away_mode: {
- feature: {
- category: DEVICE_FEATURE_CATEGORIES.FAN,
- type: DEVICE_FEATURE_TYPES.FAN.BINARY,
- },
- },
- carbon_monoxide: {
- feature: {
- category: DEVICE_FEATURE_CATEGORIES.MONOXIDE_SENSOR,
- type: DEVICE_FEATURE_TYPES.SENSOR.DECIMAL,
- },
- },
- */
contact: {
feature: {
category: DEVICE_FEATURE_CATEGORIES.OPENING_SENSOR,
diff --git a/server/services/zigbee2mqtt/exposes/enumType.js b/server/services/zigbee2mqtt/exposes/enumType.js
index 1ddf759394..0cd27aef48 100644
--- a/server/services/zigbee2mqtt/exposes/enumType.js
+++ b/server/services/zigbee2mqtt/exposes/enumType.js
@@ -13,27 +13,5 @@ module.exports = {
type: DEVICE_FEATURE_TYPES.BUTTON.CLICK,
},
},
- /*
- fan_mode: {
- feature: {
- category: DEVICE_FEATURE_CATEGORIES.FAN,
- type: DEVICE_FEATURE_TYPES.FAN.SPEED,
- },
- },
- state: {
- feature: {
- category: DEVICE_FEATURE_CATEGORIES.CURTAIN,
- type: DEVICE_FEATURE_TYPES.CURTAIN.STATE,
- min: 0,
- max: 2,
- },
- }
- system_mode: {
- feature: {
- category: DEVICE_FEATURE_CATEGORIES.FAN,
- type: DEVICE_FEATURE_TYPES.FAN.MODE,
- },
- },
- */
},
};
diff --git a/server/services/zigbee2mqtt/exposes/numericType.js b/server/services/zigbee2mqtt/exposes/numericType.js
index 7d0b0e07dc..5212593530 100644
--- a/server/services/zigbee2mqtt/exposes/numericType.js
+++ b/server/services/zigbee2mqtt/exposes/numericType.js
@@ -41,12 +41,6 @@ module.exports = {
max: 500,
},
},
- /*
- confort_temperature: {
- feature: {
- },
- },
- */
current: {
feature: {
category: DEVICE_FEATURE_CATEGORIES.SWITCH,
@@ -76,7 +70,7 @@ module.exports = {
},
cpu_temperature: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.TEMPERATURE_SENSOR,
+ category: DEVICE_FEATURE_CATEGORIES.DEVICE_TEMPERATURE_SENSOR,
type: DEVICE_FEATURE_TYPES.SENSOR.DECIMAL,
unit: DEVICE_FEATURE_UNITS.CELSIUS,
min: -100,
@@ -85,7 +79,7 @@ module.exports = {
},
device_temperature: {
feature: {
- category: DEVICE_FEATURE_CATEGORIES.TEMPERATURE_SENSOR,
+ category: DEVICE_FEATURE_CATEGORIES.DEVICE_TEMPERATURE_SENSOR,
type: DEVICE_FEATURE_TYPES.SENSOR.DECIMAL,
unit: DEVICE_FEATURE_UNITS.CELSIUS,
min: -100,
@@ -118,16 +112,6 @@ module.exports = {
type: DEVICE_FEATURE_TYPES.SENSOR.DECIMAL,
},
},
- /*
- hue: {
- feature: {
- category: DEVICE_FEATURE_CATEGORIES.LIGHT,
- type: DEVICE_FEATURE_TYPES.LIGHT.HUE,
- min: 150?,
- max: 500?,
- },
- },
- */
humidity: {
feature: {
category: DEVICE_FEATURE_CATEGORIES.HUMIDITY_SENSOR,
@@ -163,17 +147,6 @@ module.exports = {
max: 150,
},
},
- /*
- position: {
- feature: {
- category: DEVICE_FEATURE_CATEGORIES.CURTAIN,
- type: DEVICE_FEATURE_TYPES.CURTAIN.POSITION,
- unit: DEVICE_FEATURE_UNITS.PERCENT,
- min: 0,
- max: 100,
- },
- },
- */
power: {
feature: {
category: DEVICE_FEATURE_CATEGORIES.SWITCH,
@@ -188,16 +161,6 @@ module.exports = {
unit: DEVICE_FEATURE_UNITS.HECTO_PASCAL,
},
},
- /*
- saturation: {
- feature: {
- category: DEVICE_FEATURE_CATEGORIES.LIGHT,
- type: DEVICE_FEATURE_TYPES.LIGHT.SATURATION,
- min: 150?,
- max: 500?,
- },
- },
- */
temperature: {
feature: {
category: DEVICE_FEATURE_CATEGORIES.TEMPERATURE_SENSOR,
diff --git a/server/services/zigbee2mqtt/utils/convertDevice.js b/server/services/zigbee2mqtt/utils/convertDevice.js
index 7f3afe0836..375c1da7d4 100644
--- a/server/services/zigbee2mqtt/utils/convertDevice.js
+++ b/server/services/zigbee2mqtt/utils/convertDevice.js
@@ -29,7 +29,6 @@ function convertDevice(device, serviceId) {
};
logger.debug(`Device ${name} / model ${model} ${supported ? '' : 'NOT'} managed by Gladys`);
- logger.debug(gladysDevice);
return gladysDevice;
}
diff --git a/server/test/services/zigbee2mqtt/api/zigbee2mqtt.controller.test.js b/server/test/services/zigbee2mqtt/api/zigbee2mqtt.controller.test.js
index c49a886711..8397994f81 100644
--- a/server/test/services/zigbee2mqtt/api/zigbee2mqtt.controller.test.js
+++ b/server/test/services/zigbee2mqtt/api/zigbee2mqtt.controller.test.js
@@ -29,16 +29,16 @@ describe('zigbee2mqtt API', () => {
sinon.reset();
});
- it('get /api/v1/service/zigbee2mqtt/devices', async () => {
+ it('get /api/v1/service/zigbee2mqtt/device', async () => {
const req = {};
const res = {
json: fake.returns(null),
};
- await controller['get /api/v1/service/zigbee2mqtt/devices'].controller(req, res);
+ await controller['get /api/v1/service/zigbee2mqtt/device'].controller(req, res);
assert.calledOnce(zigbee2mqttManager.getDiscoveredDevices);
- assert.calledWith(res.json, { devices: ['device'] });
+ assert.calledWith(res.json, ['device']);
});
it('get /api/v1/service/zigbee2mqtt/status', async () => {
From f7fd24896508c3adb666745af16d5b039f74135e Mon Sep 17 00:00:00 2001
From: atrovato <1839717+atrovato@users.noreply.github.com>
Date: Thu, 21 Oct 2021 20:59:36 +0200
Subject: [PATCH 5/9] Load composite type
---
server/services/zigbee2mqtt/exposes/index.js | 2 ++
1 file changed, 2 insertions(+)
diff --git a/server/services/zigbee2mqtt/exposes/index.js b/server/services/zigbee2mqtt/exposes/index.js
index 6e5e303293..47088da97b 100644
--- a/server/services/zigbee2mqtt/exposes/index.js
+++ b/server/services/zigbee2mqtt/exposes/index.js
@@ -1,9 +1,11 @@
const binaryType = require('./binaryType');
const numericType = require('./numericType');
const enumType = require('./enumType');
+const compositeType = require('./compositeType');
module.exports = {
[binaryType.type]: binaryType,
[numericType.type]: numericType,
[enumType.type]: enumType,
+ [compositeType.type]: compositeType,
};
From e3d90bdbebbd6174c84eefef44452ecdd23d3426 Mon Sep 17 00:00:00 2001
From: atrovato <1839717+atrovato@users.noreply.github.com>
Date: Thu, 21 Oct 2021 21:04:41 +0200
Subject: [PATCH 6/9] Illuminance max value
---
server/services/zigbee2mqtt/exposes/numericType.js | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/server/services/zigbee2mqtt/exposes/numericType.js b/server/services/zigbee2mqtt/exposes/numericType.js
index 5212593530..ce2cd9b9bd 100644
--- a/server/services/zigbee2mqtt/exposes/numericType.js
+++ b/server/services/zigbee2mqtt/exposes/numericType.js
@@ -126,7 +126,7 @@ module.exports = {
category: DEVICE_FEATURE_CATEGORIES.LIGHT_SENSOR,
type: DEVICE_FEATURE_TYPES.SENSOR.DECIMAL,
min: 0,
- max: 10000,
+ max: 100000,
},
},
illuminance_lux: {
@@ -135,7 +135,7 @@ module.exports = {
type: DEVICE_FEATURE_TYPES.SENSOR.DECIMAL,
unit: DEVICE_FEATURE_UNITS.LUX,
min: 0,
- max: 10000,
+ max: 100000,
},
},
local_temperature: {
From 0e2cfdfc28c9a6cf58ee568f1a7a5b3342daf45b Mon Sep 17 00:00:00 2001
From: atrovato <1839717+atrovato@users.noreply.github.com>
Date: Sat, 23 Oct 2021 08:21:27 +0200
Subject: [PATCH 7/9] Force composite color as actuator
---
server/services/zigbee2mqtt/exposes/compositeType.js | 2 ++
1 file changed, 2 insertions(+)
diff --git a/server/services/zigbee2mqtt/exposes/compositeType.js b/server/services/zigbee2mqtt/exposes/compositeType.js
index 2db3ea9adc..82bc42b1f7 100644
--- a/server/services/zigbee2mqtt/exposes/compositeType.js
+++ b/server/services/zigbee2mqtt/exposes/compositeType.js
@@ -7,6 +7,8 @@ module.exports = {
feature: {
category: DEVICE_FEATURE_CATEGORIES.LIGHT,
type: DEVICE_FEATURE_TYPES.LIGHT.COLOR,
+ has_feedback: true,
+ read_only: false,
min: 0,
max: 16777215,
},
From ce829792acdb63384d926d0654973cf61f6e3b50 Mon Sep 17 00:00:00 2001
From: atrovato <1839717+atrovato@users.noreply.github.com>
Date: Sun, 24 Oct 2021 09:12:19 +0200
Subject: [PATCH 8/9] Fix zigbee2mqtt discovered path
---
front/src/config/demo.json | 2175 +++++++++++++++++
.../all/zigbee2mqtt/discover-page/actions.js | 2 +-
.../zigbee2mqtt/api/zigbee2mqtt.controller.js | 4 +-
.../api/zigbee2mqtt.controller.test.js | 4 +-
4 files changed, 2180 insertions(+), 5 deletions(-)
create mode 100644 front/src/config/demo.json
diff --git a/front/src/config/demo.json b/front/src/config/demo.json
new file mode 100644
index 0000000000..0273dfff32
--- /dev/null
+++ b/front/src/config/demo.json
@@ -0,0 +1,2175 @@
+{
+ "post /api/v1/login": {
+ "id": "215811c9-c0aa-4148-8a4b-e02892d7446f",
+ "firstname": "tony",
+ "lastname": "Stark",
+ "email": "tony.stark@gladysassistant.com",
+ "language": "en",
+ "birthdate": "2011-02-04",
+ "role": "admin",
+ "created_at": "2019-02-20T04:26:47.811Z",
+ "updated_at": "2019-02-20T04:26:47.811Z",
+ "refresh_token": "15535ed55088d46b9a01738bfb2b96f982fb16edb2a5241d078775a7db8aa38a8ae59e73f81aa5367b62b1daef8aea5e3b7de4ff66dc8fb00f6ed02b6c3eb14ac68b1716e9cdb9425f88bf2eeb5b8cc3b4eb66913bbd8e5084381dc22fe1ff092c0efd80f2ec766511f03121bdffcc02202a20d5916e6e58c6aed4a84fb9980a99b828c8ded74d17e3c91108f7e50dccb80281720b6b37fe26345371cd2b4a1134abfbc63689814375aee968af15dc24379c7c95200c0c1740817806abfca934ccb4fb183e4c95e19f55a2e4c8a3bb453cf0700a6f7baa7088b24297d212f2ccfc3586093c28e731e9909addbead2b9c095f1a7f8993f4ddd405",
+ "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiOTJiZjk0NDEtYzljMC00YTVmLWI3YmItNGY3NmYwZWM0Yzk1Iiwic2NvcGUiOlsiZGFzaGJvYXJkOndyaXRlIiwiZGFzaGJvYXJkOnJlYWQiXSwic2Vzc2lvbl9pZCI6IjZhOTYyNzk2LTZlMGQtNDRiNC04Y2Y2LWRkMmJhYjhjY2M0ZiIsImlhdCI6MTU1MTA2NzM5MywiZXhwIjoxNTUxMTUzNzkzLCJhdWQiOiJ1c2VyIiwiaXNzIjoiZ2xhZHlzIn0.JfiRsTn4cyARIMElD5DgyFt7xKHPcTNnaMLKznbfVc4"
+ },
+ "get /api/v1/me": {
+ "id": "215811c9-c0aa-4148-8a4b-e02892d7446f",
+ "firstname": "Tony",
+ "lastname": "Stark",
+ "selector": "tony",
+ "email": "tony.stark@gladysassistant.com",
+ "language": "en",
+ "birthdate": "2011-02-04",
+ "role": "admin",
+ "created_at": "2019-02-20T04:26:47.811Z",
+ "updated_at": "2019-02-20T04:26:47.811Z",
+ "refresh_token": "15535ed55088d46b9a01738bfb2b96f982fb16edb2a5241d078775a7db8aa38a8ae59e73f81aa5367b62b1daef8aea5e3b7de4ff66dc8fb00f6ed02b6c3eb14ac68b1716e9cdb9425f88bf2eeb5b8cc3b4eb66913bbd8e5084381dc22fe1ff092c0efd80f2ec766511f03121bdffcc02202a20d5916e6e58c6aed4a84fb9980a99b828c8ded74d17e3c91108f7e50dccb80281720b6b37fe26345371cd2b4a1134abfbc63689814375aee968af15dc24379c7c95200c0c1740817806abfca934ccb4fb183e4c95e19f55a2e4c8a3bb453cf0700a6f7baa7088b24297d212f2ccfc3586093c28e731e9909addbead2b9c095f1a7f8993f4ddd405",
+ "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiOTJiZjk0NDEtYzljMC00YTVmLWI3YmItNGY3NmYwZWM0Yzk1Iiwic2NvcGUiOlsiZGFzaGJvYXJkOndyaXRlIiwiZGFzaGJvYXJkOnJlYWQiXSwic2Vzc2lvbl9pZCI6IjZhOTYyNzk2LTZlMGQtNDRiNC04Y2Y2LWRkMmJhYjhjY2M0ZiIsImlhdCI6MTU1MTA2NzM5MywiZXhwIjoxNTUxMTUzNzkzLCJhdWQiOiJ1c2VyIiwiaXNzIjoiZ2xhZHlzIn0.JfiRsTn4cyARIMElD5DgyFt7xKHPcTNnaMLKznbfVc4"
+ },
+ "get /api/v1/me/picture": "data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAA8AAD/4QN3aHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjYtYzEzOCA3OS4xNTk4MjQsIDIwMTYvMDkvMTQtMDE6MDk6MDEgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6MTI2MGJlNWQtZGNmNS00ZjQ4LWFlMDktMGEyMmMyMTk5ODRhIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjA1OEYwOUNGNzU0NzExRTk4QUQyQjRBMzgwQkI2MUUwIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjA1OEYwOUNFNzU0NzExRTk4QUQyQjRBMzgwQkI2MUUwIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE3IChXaW5kb3dzKSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjhENDY0NEYzRjU2MTExRTZCRDFDRjlEQkVEMTk5NEU3IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjhENDY0NEY0RjU2MTExRTZCRDFDRjlEQkVEMTk5NEU3Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpS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",
+ "get /api/v1/user?fields=id,firstname,selector,picture,last_latitude,last_longitude,last_altitude,last_accuracy,last_location_changed": [
+ {
+ "firstname": "Tony",
+ "last_latitude": 41.93425385676557,
+ "last_longitude": 12.402756238310928,
+ "picture": "data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAA8AAD/4QN3aHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjYtYzEzOCA3OS4xNTk4MjQsIDIwMTYvMDkvMTQtMDE6MDk6MDEgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6MTI2MGJlNWQtZGNmNS00ZjQ4LWFlMDktMGEyMmMyMTk5ODRhIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjA1OEYwOUNGNzU0NzExRTk4QUQyQjRBMzgwQkI2MUUwIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjA1OEYwOUNFNzU0NzExRTk4QUQyQjRBMzgwQkI2MUUwIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE3IChXaW5kb3dzKSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjhENDY0NEYzRjU2MTExRTZCRDFDRjlEQkVEMTk5NEU3IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjhENDY0NEY0RjU2MTExRTZCRDFDRjlEQkVEMTk5NEU3Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpS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"
+ }
+ ],
+ "post /api/v1/access-token": {
+ "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiOTJiZjk0NDEtYzljMC00YTVmLWI3YmItNGY3NmYwZWM0Yzk1Iiwic2NvcGUiOlsiZGFzaGJvYXJkOndyaXRlIiwiZGFzaGJvYXJkOnJlYWQiXSwic2Vzc2lvbl9pZCI6IjZhOTYyNzk2LTZlMGQtNDRiNC04Y2Y2LWRkMmJhYjhjY2M0ZiIsImlhdCI6MTU1MTA2NzM5MywiZXhwIjoxNTUxMTUzNzkzLCJhdWQiOiJ1c2VyIiwiaXNzIjoiZ2xhZHlzIn0.JfiRsTn4cyARIMElD5DgyFt7xKHPcTNnaMLKznbfVc4"
+ },
+ "post /api/v1/user": {
+ "id": "215811c9-c0aa-4148-8a4b-e02892d7446f",
+ "firstname": "tony",
+ "lastname": "Stark",
+ "email": "tony.stark@gladysassistant.com",
+ "language": "en",
+ "birthdate": "2011-02-04",
+ "role": "admin",
+ "created_at": "2019-02-20T04:26:47.811Z",
+ "updated_at": "2019-02-20T04:26:47.811Z",
+ "refresh_token": "15535ed55088d46b9a01738bfb2b96f982fb16edb2a5241d078775a7db8aa38a8ae59e73f81aa5367b62b1daef8aea5e3b7de4ff66dc8fb00f6ed02b6c3eb14ac68b1716e9cdb9425f88bf2eeb5b8cc3b4eb66913bbd8e5084381dc22fe1ff092c0efd80f2ec766511f03121bdffcc02202a20d5916e6e58c6aed4a84fb9980a99b828c8ded74d17e3c91108f7e50dccb80281720b6b37fe26345371cd2b4a1134abfbc63689814375aee968af15dc24379c7c95200c0c1740817806abfca934ccb4fb183e4c95e19f55a2e4c8a3bb453cf0700a6f7baa7088b24297d212f2ccfc3586093c28e731e9909addbead2b9c095f1a7f8993f4ddd405",
+ "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiOTJiZjk0NDEtYzljMC00YTVmLWI3YmItNGY3NmYwZWM0Yzk1Iiwic2NvcGUiOlsiZGFzaGJvYXJkOndyaXRlIiwiZGFzaGJvYXJkOnJlYWQiXSwic2Vzc2lvbl9pZCI6IjZhOTYyNzk2LTZlMGQtNDRiNC04Y2Y2LWRkMmJhYjhjY2M0ZiIsImlhdCI6MTU1MTA2NzM5MywiZXhwIjoxNTUxMTUzNzkzLCJhdWQiOiJ1c2VyIiwiaXNzIjoiZ2xhZHlzIn0.JfiRsTn4cyARIMElD5DgyFt7xKHPcTNnaMLKznbfVc4"
+ },
+ "patch /api/v1/user": {
+ "id": "215811c9-c0aa-4148-8a4b-e02892d7446f",
+ "firstname": "tony",
+ "lastname": "Stark",
+ "email": "tony.stark@gladysassistant.com",
+ "language": "en",
+ "birthdate": "2011-02-04",
+ "role": "admin",
+ "created_at": "2019-02-20T04:26:47.811Z",
+ "updated_at": "2019-02-20T04:26:47.811Z",
+ "refresh_token": "15535ed55088d46b9a01738bfb2b96f982fb16edb2a5241d078775a7db8aa38a8ae59e73f81aa5367b62b1daef8aea5e3b7de4ff66dc8fb00f6ed02b6c3eb14ac68b1716e9cdb9425f88bf2eeb5b8cc3b4eb66913bbd8e5084381dc22fe1ff092c0efd80f2ec766511f03121bdffcc02202a20d5916e6e58c6aed4a84fb9980a99b828c8ded74d17e3c91108f7e50dccb80281720b6b37fe26345371cd2b4a1134abfbc63689814375aee968af15dc24379c7c95200c0c1740817806abfca934ccb4fb183e4c95e19f55a2e4c8a3bb453cf0700a6f7baa7088b24297d212f2ccfc3586093c28e731e9909addbead2b9c095f1a7f8993f4ddd405",
+ "access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoiOTJiZjk0NDEtYzljMC00YTVmLWI3YmItNGY3NmYwZWM0Yzk1Iiwic2NvcGUiOlsiZGFzaGJvYXJkOndyaXRlIiwiZGFzaGJvYXJkOnJlYWQiXSwic2Vzc2lvbl9pZCI6IjZhOTYyNzk2LTZlMGQtNDRiNC04Y2Y2LWRkMmJhYjhjY2M0ZiIsImlhdCI6MTU1MTA2NzM5MywiZXhwIjoxNTUxMTUzNzkzLCJhdWQiOiJ1c2VyIiwiaXNzIjoiZ2xhZHlzIn0.JfiRsTn4cyARIMElD5DgyFt7xKHPcTNnaMLKznbfVc4"
+ },
+ "get /api/v1/user?fields=firstname,lastname,role,selector,picture,current_house_id,last_house_changed": [
+ {
+ "firstname": "Tony",
+ "lastname": "Stark",
+ "role": "admin",
+ "selector": "tony",
+ "picture": "data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAA8AAD/4QN3aHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjYtYzEzOCA3OS4xNTk4MjQsIDIwMTYvMDkvMTQtMDE6MDk6MDEgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bXBNTTpPcmlnaW5hbERvY3VtZW50SUQ9InhtcC5kaWQ6MTI2MGJlNWQtZGNmNS00ZjQ4LWFlMDktMGEyMmMyMTk5ODRhIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjA1OEYwOUNGNzU0NzExRTk4QUQyQjRBMzgwQkI2MUUwIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjA1OEYwOUNFNzU0NzExRTk4QUQyQjRBMzgwQkI2MUUwIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE3IChXaW5kb3dzKSI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSJ4bXAuaWlkOjhENDY0NEYzRjU2MTExRTZCRDFDRjlEQkVEMTk5NEU3IiBzdFJlZjpkb2N1bWVudElEPSJ4bXAuZGlkOjhENDY0NEY0RjU2MTExRTZCRDFDRjlEQkVEMTk5NEU3Ii8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpS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",
+ "current_house_id": "8fe7acf2-f27b-46d4-9f8e-c871ab1e6780",
+ "last_house_changed": "2021-07-12T07:22:19.014Z"
+ },
+ {
+ "firstname": "Pepper",
+ "lastname": "Pots",
+ "role": "admin",
+ "selector": "pepper",
+ "picture": "data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAA8AAD/4QMfaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjYtYzEzOCA3OS4xNTk4MjQsIDIwMTYvMDkvMTQtMDE6MDk6MDEgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjA1OEYwOUQzNzU0NzExRTk4QUQyQjRBMzgwQkI2MUUwIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjA1OEYwOUQyNzU0NzExRTk4QUQyQjRBMzgwQkI2MUUwIiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE3IE1hY2ludG9zaCI+IDx4bXBNTTpEZXJpdmVkRnJvbSBzdFJlZjppbnN0YW5jZUlEPSIxRDA4OTdGQUMxQ0RFMEFBMzRFMTMwQzJBOUY0OUEzRiIgc3RSZWY6ZG9jdW1lbnRJRD0iMUQwODk3RkFDMUNERTBBQTM0RTEzMEMyQTlGNDlBM0YiLz4gPC9yZGY6RGVzY3JpcHRpb24+IDwvcmRmOlJERj4gPC94OnhtcG1ldGE+IDw/eHBhY2tldCBlbmQ9InIiPz7/7gAOQWRvYmUAZMAAAAAB/9sAhAAGBAQEBQQGBQUGCQYFBgkLCAYGCAsMCgoLCgoMEAwM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",
+ "current_house_id": "",
+ "last_house_changed": "2021-07-12T07:22:19.014Z"
+ }
+ ],
+ "get /api/v1/dashboard": [
+ {
+ "id": "329897d2-0620-458c-addf-4009ff5bc205",
+ "name": "Home",
+ "type": "main",
+ "selector": "home"
+ }
+ ],
+ "get /api/v1/dashboard/home": {
+ "id": "329897d2-0620-458c-addf-4009ff5bc205",
+ "name": "Home",
+ "type": "main",
+ "selector": "home",
+ "boxes": [
+ [
+ {
+ "type": "weather",
+ "house": "main-house"
+ },
+ {
+ "type": "camera",
+ "camera": "living-room-camera",
+ "name": "Garden"
+ }
+ ],
+ [
+ {
+ "type": "temperature-in-room",
+ "room": "living-room"
+ },
+ {
+ "type": "devices-in-room",
+ "room": "living-room",
+ "device_features": [
+ "main-lamp-binary",
+ "tv-lamp-binary",
+ "tv-lamp-color",
+ "tv-lamp-brightness",
+ "mqtt-living-room-switch",
+ "mqtt-living-room-dimmer",
+ "mqtt-living-room-temp"
+ ]
+ }
+ ],
+ [
+ {
+ "type": "devices-in-room",
+ "room": "kitchen",
+ "device_features": ["main-presence-sensor"]
+ },
+ {
+ "type": "user-presence"
+ }
+ ]
+ ],
+ "created_at": "2019-05-15T08:48:20.275Z",
+ "updated_at": "2019-05-16T06:29:44.767Z"
+ },
+ "patch /api/v1/dashboard/home": {
+ "id": "329897d2-0620-458c-addf-4009ff5bc205",
+ "name": "Home",
+ "type": "main",
+ "selector": "home",
+ "boxes": [
+ [
+ {
+ "type": "weather",
+ "house": "main-house"
+ },
+ {
+ "type": "camera",
+ "camera": "living-room-camera",
+ "name": "Garden"
+ }
+ ],
+ [
+ {
+ "type": "temperature-in-room",
+ "room": "living-room"
+ },
+ {
+ "type": "user-presence"
+ },
+ {
+ "type": "devices-in-room",
+ "room": "living-room"
+ }
+ ],
+ [
+ {
+ "type": "devices-in-room",
+ "room": "kitchen"
+ }
+ ]
+ ],
+ "created_at": "2019-05-15T08:48:20.275Z",
+ "updated_at": "2019-05-16T06:29:44.767Z"
+ },
+ "get /api/v1/house/main-house/weather": {
+ "temperature": 27.9,
+ "humidity": 0.99,
+ "pressure": 1005.09,
+ "datetime": "2019-05-09T04:27:57.000Z",
+ "units": "metric",
+ "wind_speed": 1.96,
+ "weather": "rain",
+ "house": {
+ "id": "6a29f33b-e5c9-4b08-9d3f-ced2cab80a87",
+ "name": "Main house",
+ "selector": "main-house",
+ "created_at": "2019-02-20T04:26:47.811Z",
+ "updated_at": "2019-02-20T04:26:47.811Z"
+ },
+ "options": {
+ "latitude": 12,
+ "longitude": 12,
+ "language": "en"
+ },
+ "hours": [
+ {
+ "temperature": 27.9,
+ "humidity": 0.99,
+ "pressure": 1005.09,
+ "datetime": "2019-05-09T04:27:57.000Z",
+ "units": "metric",
+ "wind_speed": 1.96,
+ "wind_direction": 1.96,
+ "weather": "rain"
+ }
+ ],
+ "days": [
+ {
+ "temperature_min": 20.9,
+ "temperature_max": 27.9,
+ "humidity": 0.99,
+ "pressure": 1005.09,
+ "datetime": "2019-05-09T04:27:57.000Z",
+ "units": "metric",
+ "wind_speed": 1.96,
+ "wind_direction": 1.96,
+ "weather": "rain"
+ }
+ ]
+ },
+ "get /api/v1/room/living-room?expand=temperature": {
+ "id": "1c634ff4-0476-4733-a084-b4a43d649c84",
+ "name": "Living Room",
+ "selector": "living-room",
+ "temperature": {
+ "temperature": 26.5,
+ "unit": "celsius"
+ }
+ },
+ "get /api/v1/camera/living-room-camera/image": "data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAA1AAD/4QMJaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjYtYzEzOCA3OS4xNTk4MjQsIDIwMTYvMDkvMTQtMDE6MDk6MDEgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjRFMTgwODcwNzU0MjExRTk5Nzc5RkZBMTY3OTgyRDBEIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjRFMTgwODZGNzU0MjExRTk5Nzc5RkZBMTY3OTgyRDBEIiB4bXA6Q3JlYXRvclRvb2w9IlZlci4xLjAuMDAwIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9IkYzN0JCRDNCMzkwRTdEQ0NEMkQ5ODI4MDFGNTkwMTZBIiBzdFJlZjpkb2N1bWVudElEPSJGMzdCQkQzQjM5MEU3RENDRDJEOTgyODAxRjU5MDE2QSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pv/tAEhQaG90b3Nob3AgMy4wADhCSU0EBAAAAAAADxwBWgADGyVHHAIAAAIAAgA4QklNBCUAAAAAABD84R+JyLfJeC80YjQHWHfr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mUgIL2HDcptx537RXyPsbduJzXs011UM7MizJx6zmRtwWN4zqF5buI48a4bdu/nP+WppFFHhxAViViAfPc7XbcOFtNOym2l7JnwS+qGaZnjSI3VV1UjVAdTt8vPgKa6zz8nlVy+s5674k8qtY70J2gXsWsON++t9f19PKXaoMSdJXsyqrEbEY6gNb4mGpPZXXfXEZlNfp+fPneiVLynU3IO0ct2psK69W0s4Tb9XS9O6ZFgxWB3ysPPIefcOwV2kc7VlmABJ0A4mqyz8jMeV/Sgub8TUtawmxen7fNJq1JEtPy8jHxEu583JRxrSMPKz5MhuxeQFFw9ARNK9jzJVSqJAlA4LQHbVB20UttAdtAttAttQLbQHbQLbQLbRR20C20B20C20B21AttAdtAttAdtAttFHbRB20UttAdtAttAttAdtELbQHbUC20C20C20Acqi7mNgOdZ22kma1JmuK+o3xcrPMfpWaJQLptUE637eBr43b2bbbZ8PbprJMObyMibFbZFLtYteQjmp107q1JN/MTOFoT408AlVHaS/AG9ral728puNBXHaevDXnkmzMNg2R+4Utdo18ouQNfLY+81j038cLMeVKdlzGX5dP2pHALPzYDdtL2sLc666/s83lm8pB9N5hlURMhhfWQ6+Q+77q30d38nH4Z2mG/h4EGFEEj1NhvdviYjmf4V7JMOVuT5po4l3ObD761lGcWyM59qDbCDxqZXDRxcKKBL2AtqWNWapazeqfUUMF4cTzyc35DwqkjAfJlncvIxZjzNFPU1B6kiV7XmSqlEPC1Q4LRR20C20B21QttAttAdtQLbQLbQLbUB20UdtAttAdtAttAttAdtAttAdtQHbQLbVUdtQLZRB20B20C20UttEHZQLZQHbRS21ELbVC21BjfUz5sUCNj3EZO1yNtrntD8fZXl+xrvcert1WfLleodVeMOzYyDITdGZVPmsLhdOAFr614tr41+Y9Enz8OZRhkTmSclkj1Y3F72v7tK1tPWcJOUCZTpklVnMSX+NQe46DTUV0mks5T2pkmS4ILMxTduZQdu7ne9udT0/BltdMxuo5sscin08Jk2yk/mPD4f1W51x16Zc/wBWrvY6SOJIo1jTREFgCb/aa9OusnhytyrZubFji3xSclH41rKYVIcPIzJBLk3CHgndSTK24XcnJwemwb5mCgDyoPiPgK3jDHly3VfqXJzSY4v2oOSjn41LWpGYpudaNJYzUROtB60iV7XlSqtVDgtVTgtAdtQLbQLbVB20C20C20C21FHbQLbRB20UgtAdtAdtAttQHbQLbQHbQLbQHbRS2VAdtAdtAttEHZQLZQHZQLZQHZRS2UQtlAtlFLZQZ/X8SCfprrNG0yIQ4jVgt2XVfi0OtY2sk5WeXnX1LNmxTp691knRJNgOgQrZFY9vGvL26TPjl202rOfHhlLKsAiliBCxsbr5luzMeZ8PdXj9rPnMrthQbGMWKZpbbWYqg11I4kPa1dffNxEk4XeifTs/ULTZJZMG+4C5Bk/w9g7/AHV2jNdikUcSBUUKiiwA0AAqIz8vqJZ/QxB6kh4sOAoYOwuk7T62Qd8h1JPAVqa/lm7KXWfqrFwgYMO00/AtxVf41rKTVyOTm5OXMZZ3Ls2utZtbkMFMrhMFcJvI8vbTIkjFyO+iLUaaUR68qV7nlSBKB4WqDtoDtoFtoFtoDtoIHnVctYDoGQtfvB4Vx23vvI6TX9uU+2uzmO2gWyoDsqqW2gOyoFtoDsoDsopbKIOyilsoDsqBbKIOyijsoFsoDsoDsoI5JYI3WN3Cu2qqeJ8KxtvJ5Wa2pQlayhbKIOyrlR2VMhbKIGyrlS2VBk/U0uRj4PqRxmaI+WZLX8p56WKnvFef7FuOJl06pMvPc7q+N1GKOPMgjmycSMxnJZmViR/p7gOO0dndXO9kxy3688M7MzhuhZT6ikb1Vio8x8qnTRtRrevFp1eXe1sRdFbLkSXqJEka2ZIALC/EBtttBwtXT6/X6zLO22WrJJFDHuchEXTsHgK7sMySfK6ixjxwY8bm54mk5LwsEdO6RjerkOEHG51Zj3V0muGbbXKdc+rsnOvBi3hxuGnFvGpas1YYuTc63rLSWKJ5DZBc8zyqZVo4vTwNW8x+wVm0XHwhLjOF8xsSD3irEtUoEugPZrW2VtEqD15Ur3PKeEqhwSgISqDsoFtoFtoI8iaOGFpCwAC7hrxrG+81mWtdc1j9Fh+cIyZHLgElkbirAnboRqrA15ujTXb93muvZtZw3QgHdXrcR2UB2UB2UQtlFHZQLZQHZUB2UC2UB2UUdlMhbKA7KA7KmQtlAdlAdlAtlBznVs5pPqHFxNhEMNyzgXJJFxpZtNOzWvn93Znsk/D06a/tdAJYAUUuu+T4FBBJtxsB2V7ZvPy4XWpQlaZHZQLZQLZQLZQAqALnQd9BzH1n1DqONFEMcbsKQ2kljuSGB/0yRpr/AG4V5fs6b7Th26rJeXnPU3fI6hudWmlbcvoRAqQSb7dy/Fxrh0SScx13aPRfpyPGK5WYobIGqRjVU7+9q72sNTLzocZRu80jfCg4ms1YrRYOTnSCbM8sY1WIaADvqzXKXbCr1f6pwOmIcfDCz5IFtPgX+Na8JjLi87qGZnzmXJkLseF+A8Kza3IhRCWAAuTwArNq4X8XpjuQZP6R+NZtVoBMfHTWwC8uAHiamEyrzZ0jC0S+XkxFh7F5+2tYTLa6LeTEG/V1Nm8a1his9oPQy5oOSsbeB1FVUiDS3ZpRHsCpXteY8JQOCVQdlAtlAdlMirm5KwvFEGCyzMFUHmK5dm+MSea3rPlz3VPncJ8jGnkkOJJd4NR8Z8za8gOIrzdul8c4/wCTtpfkemwCBoo3hhkncb2JcyEMSTdtuluy57q6a6+vhna5dRDEVjANu4DgB2V6I5VJsqoOygOygWymQdlMqOyohbKA7KKOygOygWygOygWygOyoDsoDsoFsoGSvDCm+V1jT9TGwqbbSeVkteefUNn65FNHmEK7bEIZmBJ127yPhNuw18rt31tuOXr0ldV0SDpuPkJ/3Jnzplt6ZFigsCVIA09tev6+vXP9fLl2Xa+W9sr1uA7KA7KBbKAbKKgzsFMzDmxXJVZ0KFha4vzFwal5I8t63i9YwsvG6ZFJK6QFnAjvtSRxZyxa3C/HsrlnDp5WsLETFhVAdzgC55A8wnMCuV1mct5RTZryOYMNfUl/M/5VoGvHg9LiOZ1CUGU63bViexBWpr+Uty5brf1dmZ26DFvj4p0sPiYfzGlqzVhWJNzqTXPLYhCSKmVbPTcRBimfbfbfdbibVnBlKWyXJSJNijQs3D+LVvXS1i7F8oiWeS8sg4E8B4LwFdppI53bKCZieNx3VmrGj9MyD1pYL8bMB9hqLU3W4fTzophwlTafFf7jVqRXX4j361lXsipXteY8JQOCUC20CKgC54VMrFWbOxkjE6yB4Ua0pQg2vpqOOlY23k5+GpqodWkEnUMXYgyIYwJW22I8xspLHlbhXHt2vtMN6TisvrzYzBDaVYSx3Kw8y31JS50HcKx2b65b0lSdHmxQruJY4xK9k3XsNb+RRttx1pptnOeDaYdJjZeHJ+2k6SyLo21gTevVrY42VZ2VpkdlAdlAdlFHZQLZUB2UB2UC2UB2UB2UUdlEH06A+nQL06ZB9OmVNlGyMtqLcwL277Vm1ZGF1bqWfhwt6kSZ+HlXMcqIWEaW1Eka6yDn5a47b2eOctzWON+omzcgpJF8qsgO5shGCOFXg2y5C+XkPbXh7N5nF/6f9XfTWpun9Tn6T+2rgzPZ9h3SyyFh5yxvt00te/ZWNd8ePLVn5dt0zq/zUYmklSKAWQKx3Ss9r62G32LXv6u22c159tGwq3AI4HWvRlywOygXp0C2UVU6l1DE6dj+tkta+iRj4nPYopaSOF6z1mTNmORklY410RRwUdl+JNcbcusmGSseT1A+W8GJzY6Mw/AVnyvhn9T+p+ndKjOL01VnyBoX4op8fzGr4TGXH5ubl505mypDI57eA8BUtakQBLjSsWtJkx2YXt31kWo8PS9u+mDLd6JArRzQnnqPaLGt6xi01Estjxtr4jSuujnsgmUkaGxFapGdKzBjcXPbyrm3Fjo0/p9RibgGuh9vD7RUWxvfUMO7BWUcYXDexvKa1WYylPwn2e+sq9sVK9bzHBKB2yoDsoqOeAumjMhHApb7jofbUqxyv1FLkxSxfMemxAIZ4gQqqbm7cr399eL7GXfrUOndXwsRGndnWBxs2gabuAktofGuOm+OLnLdiDq+b03JPpY7+oRtCRAsN3EknX361iyZ44n5al4R9LOK+SScOaIGwlCXf4TZmiLWbU8deFd7p7Y4/a5+2P6u66Xi9OxYV9JfQBXyCZl3WOvbXt1xI43NaKqCARqDqCK2ydsoDsoDsoDsoF6dFER1Mh3p0yF6dMg+nTIIjpkH06gPp0B9OgXp0UfTohriNbK5A3aAHnUtjUjk/rBP/FQZE+JNMkky7jjL5Ua3ZccO3bXi79Mca5mXbrv5cVPnZIQynG9ORRG7RhbEk2V7RixOnM14rpt4txHabTymizOnYvUIomjBmdC04a7NZjZdw5GxueFY67xmzx/ha6noMsXUesLhwxwRYuKisMe11jZRptttu51v+Nero7b2bccRz319Y7ZY1WyC1wOA008K+m8p3p0QvToMvrnXMXpUe0/u5bC6Qg8P5n7BWbthqTLz7qvV58nJMs7GfJk0SNeQ5AD8q1ztdJFDKbEwoxmdYlAPGLHXX+lefjTH5XP4cv1v6qzeo3ggvjYfDYp8zD+c0tJGRDjSzG0a37+VYuzUjTxekxo6+sQ0jEADvPdWM2qi+QEeZNERqjnTuOtawmVmHFAFuzSmEtSxxDaPdVTK90U7cpV/WpX2j/hWtUo54EE0vZvNv843CtZwzjLKknkWVlc+3kL1n2awpS5DPoOJ0tUyuE+F03qLyxyrHsVWDbn8o0N+etIWuuyYxkdOkj4l4yB4jh91bYc3C26G/MC/urKvdVSvS4HhKoISgTBVF2IUDmTYVMmFLI6rixX2lXsbHcwQH/CzeU++sXsnw36sHr3XY3xXx3xTEso1bcL2Guu08O+vJ3d9xZh1005ce4iMqwPt9LYNSSw1OteWbcZ+cuuDMpmxgHx1O0kHiGG6+p4A29ldNfXe8JcyL+LHnKG3ypi7gvp+k5jDI93tvIf9OvLXxr3SONdX0ifBgUjLx3jyRtZVlZJGZmFtG/SbX1t7az7ay4xyYtdLiiZ490qCK/woOIHfXbW35YuE+yrlktlMg7KKIjoD6dFH06BwjqAiOgPp0QvToHenQERUBEVFH0qBelUEeVjRywOkib0I1XhfuvU2ksxVlctldNyoYMhn+fx8exARZUKgMCCV8x0txrz7/tluL/l0nNcPkCffHNIiARK3oOv+mAL7RuHmDEHW4r5nZt7TGeHp1mGYqyfOiaKR4mLNLPNYguQOCyX+C3brXX0nr+7+0Zzzw3/o76nTD9eTExjLK24My7rNxs9rG1u869tSdt6riRbp7eXpH05DkNgxzZUdp3XcZXbdI19fPcCvpdMuOfLy74zw1fTrtlhz/wBQ/VEODuxcMiTLGjvxWP8Ai33VjbfHhvXR5/Pk5WfM7QtuJJM2VIbqO3U8TXOXLpcRhdT+qOn9MDQdLtl5h0kyn1UHu/V91anCeXJ5OVlZk7T5MjSytxZjf3VLVkW8XpkWxZchvK4BVO3+Nc7a038HoebMo2RjEgPB5B5yP5UGv3VqaMXeNJuiY2FjGREMswteV7Ei2txwC+ytba4jM2zWN1aBY+tOQNJo0f8A9v4UayYiWJHgaiAFsWHYfv1oJMR/Tykb9Lg+w1Yi/wBYx3aUiO2+RBt3cLqbfdVqRlSdKxIAGzsgIP07gv3+Y+6serWUZ6t0jE0xIi7fqRbX/wA8mv2VeIYU8j6hz5D+3tgQG9k1Y+Lt+Fqey4dhguHhuPh0I8G1rcYrnBH6U80J/wDjdl9l6zVr3hUru4HhKuVOCUyGyxIyEOu5eY41Kscf1vpfTgjZODFvjP7eRCjhXsOxeR7zx+2vNZr8eHSZY07YDZCvgyvFFHb9nKJJUgAG6XbTvrzfY3/Dr1xm50bNIxaVYlFgnlFrC3mFjfieArhrePzXWxjZczxTyLMzuxNkdBuUsOPkPKvX1f4ctlrHb53D9NEdWj3B1HwrGOO4WAAXXtPYOddtdceGLXa/SOHiYiK8eUuQToYlQSAMQSQHfZ8PZuNXXMtSuqfreLDgw5IR5I5H9LygAgjntvw05Vdu+TWVn15W4OoYk0LzAlERmU7xtPlNiQD3mt/yRn1WBJAZzjhx66qHMf5tpNg3hWvaZwmEnp1Q2F4pkV42BV77e3TQ6d1Zm0q2WJRHVBEYoA5ijXdIyovaxsKl2k8klp6qpFwQQeBFXJg7YKZC2imTA7RUyg7RTKjtFMg7R2VMhbe40yIJcrBB9KaRFLabZCFv/VWL2a/LU1rnvqGKTFw2yMHLl9OQk2FpoVGmm0ghRXDskxmX/wBHTW88vMj1XMjzZ4TB66REJKkl1e4/MoYak8bAV87s+txzw9Gu50eXJKJozBC8LmxxoCpCtw/cfTcfD3Vy2t45v92lnoWf8gyyz4/pZEhKw48sBfH2g67dQAw7R7a9OkuvM5Y2xeHf9J+p8nN6jH0+IIuwKrQxH4e93sLm35VtavT1/Yu1/Ry265IZ9V/VrwpLi4bMiJuWWYA7yV+JYxx0txr0Xf4jOvX81xseLk9Qnjg9KSVp9YcCAbppB+qQ8ETtJIHfUk/LV2cT9RfUHU8ueXp+35PFx3aI40Z5odp3sPi4eFbykjJixJHOg0rNrTSxelcCw51EtdL0bGRJMJrDhJHqOBBuK3o57+HSpFpW8uSt1aH/ALCU8wLis7eGtfLluvr+7gZH60ZD7LH8ajorj4vEVA0jznvANAODnwv7qo3MuzrjTcjx/wAwBrTLz6dGiypo2N2SRlJOp0JFc66heoDVHb/Ts3qYER4kxgHxXyfhW45bM/qien1aa3Bwr+8a0qvd1SuuXE8JTIcEplUU82NDZZ3EYchQW0BJ0tu4VLYuGH1zoWK6+tiJeUG7sjqABz3bjXl7unW845dNN64DrWM+8vGpEqNtSWIX8i34nmNa8mtsuLeHfDDOdNCjpOgMTrtO0XAt+Yg63B4a109JfHkzYkhxMeZ45GdkR3VRNGNjqLqHJjP5hf8Auq9fZJcbJtr+E2X0IYyXnRpfMrJMrlCysxEe4MWTW/LWvVNtcOeKvxy5pwBgyTNGZLBoCQgOtlaW2rEjRRpXnvf5ki+ny6H55mxsfHyHcjGjkTGSE7NgOkfnXcd/LzcK5bd8m2s/4izXyb1fIzooNodsKQkgQS31BA/bBtqSUX31i732xtxrGpjDd6Z1fKOS8mTLGsqQ+o8aAEv6fwxLwt7O+tdP287W2+Izv1+JGj1PrcTdDhy4SEjyxb1b2CMvxKVOpvXb7H2sdc2nynXp+7n4ZHQeqZQ6jhYhZW9P1FtI1l2uf+pr5tCbVy+v3+2HXs0mK7oQivpZeQ70dKZGD1iCRmjM21ch0Ebop3IA7WvY/pBr4v2trc3b4fT6eqcSJugGYZL4w2tjImpuxbeDbS+lrV3/APzuzi6uH2+vFy3BCP7Wr6WXjH0RUyHCEUyYEQipkwIhFMmB9EdlTJgvRHZTJhBndMhzIfTcAEEMr7VYqw4EBgRUuL5anDz3656DjdCxhknKlk9diHiUDQN8R9IWTbpbzcOVfP7fryeHfTs/LgZosR8GR1T5KIG6qXYCUWPmQHQBv1EeHbXD221uL+6/9HTi+GJ0JvTlOW6SRrGGfdGAQO3VjZRXq75cYjOroul9fxpGZMwGPcTdgBG6K2rx8iRfQ8yK8l69tbw3mV2f0p1TDkyPlelQQHMit63UAG2KvLdt2k2/m48676du2cSY/Vi6/l1vUPoiDOyYswSRpknf8zMULGQSC3kXcAte6Rx9lNfpbrH070zIk6X1fHxwimSR8jEQmQqLj1Zi7Oe6pvtiZSc14f1TEzJus5E04T5meR5JvTsFLFtSq8hetS5bWcbD26Mlj/dRFv0wBoNDY1UaGAQsUbnQQ5Gvg61qM1dH1JHfakYd1LB9p8ot8Nm51PdPUOqdWx58RYFW8kliwv5VtyN7X91Lcwk5YvXk3dLxpecM1vYwIpPDfyoj8p/twogN8Q77igB+Ie0UGvu3dJhPNSNfAla3llxnXY/T6zkjk5Eg/wAwBrns6RTqKIoOt+kpd2Iq/oZ199m/Gumrnsd9QJtzoZP1oV/pP99Wke7KlXLkeEpkwqdUlycaMSwB5DfaY0Xde/PxrG1vw1I4r6hfqrkTJN85A+g3giO4+JRuIsRXj22s5ty7SOck6o0DBYEeVZL3WQPIQVHFGG0sL+ys+vtnhrOEC5+RKsuSwlVIpAtmAjc21XXhXHs01lxG9bVVFyhkRgtGykCUiU2C7iQwD37tRal7JI1IXWMjEkzotyo5G4sTogYDQlgQ3AeFOr2uvlNsIo+sdRyGEEf+m9mKMLapqPS823iL8q66dcnNrN2bZl6DkZUD+pLHn5UUcpN/UHrJcNFsj7bDaeXOt7ek0uGP3WtOLr+PjzyZ24xTQETKqgSGSRSWPq2PAgW04XrzdX2J7e1a20uMM7J6hkPI+azgBDvEUpO7zny8ONl+6vNvf5Oa3OFSfJkhVJQvpsA5R1GoLm6kXvceaprc1qyxEvUMjLlkiyXEZUBJAWZwWPmLWvxOgrrtr6yY5jM5a/ResRydb6c0T3SOaFZZmACkF9tyoYG1+Av7K6fX67rZk32zOHtPp619fLyYER1MmGF9Q/Tj5SNkYjmKbzO73IPAcCP8Nq+f9n68z7z+/wCr3fX7v+2rfQegxYCtkG7ZOSFaU94UD316Pr6emuHH7G/ts1hHXfLhgfTqZMD6dTK4H06ZMDsqZMIp8nGxxeV1XxIqXaLNcudzvrKFHMeOLsON9dL8q82/25PD16fVt8rWF9RY2YVQPvLMV0FgRpx53rpp367Mb9F1cx/uBH02aAlXYzo4/wC3csFIGhswa6nstXm+zvrLxbKaaVwMvpSzvkZMMxcBSctZZJWkUDcFUuW4DgATXi27Nr85dJJFbCmhljdDgzY+PIW9MKbo0brt/cQtcbha5Xjzrpv2ba8TYxKdPkdGw8iV8pY5pEjZVglu8mgBRQLP5hwGoFOrft28JddVr6ei61l7Ien4YxunykMu+QorOLE7ptxVjfkWBHZXXbq3xm7Mzafh6p0L6hmxcAYXV5CuYilNyH1bMLixew1pr93XWY2vKXqzzHNdf+pc/Pw2wMmWN1kYqsLRhg9uW23nIrwX73bfl2/h1cHmxlOpoXXYzxoWW1rHmPtr9B13Osv6PHtMWw8291vxFbQxrbfZ91UT4vnxspBy2OPft/GrCqS9T6bjbfTmvIi7HEK6FuDam3Gs4MIZeux6tDBc9rn+FXMPVNJkyZ301kySAB4pAbLwABX+Na+EU0N4lPgagc/LxqKa3LxH8KI18ICTpMinjGWI9lmrcSuV+qI7dRik/wCpCPepIqbNasoAmsNHrDK3BSfZVwOk+kxJGZEcW86ke0EH7q1HPZf+pE8kEn6XK+8f3VqpHuLyxxxM5NwovprWMs4R4nUMRwytOjOhN9QunLjSVbqb1XPhgiMcizKJBtEkS31PK9Z22xCRw2RnZmNkO2M65MRP7qSKNhHZZbWaw4rXg27Lrt+XeTMYOb1Cb1JDE3yjzAArCrNcFr7QCNvHWn8tsvK+qjmHJVQFAEjJuuQwJ2gv5j+o9lefSyulYEaNIjGQrCQCys99bn2m9evbbF/LLQbp2HLhxyGOTIADOq7ipNjZiUJvsPdqbV5522Xzhuw6DJXLmWUOELgRx3BXboFABUbgtu0U11xwi1ixrgZGyMtku5FwTZbM3EX/AE6304Vz27ddub/rD1pqufnJg8gmhAJlY23EHcV17dK5b75mZxbVkM6nNMkBmiCk3vFvFyVsQGA/lv8AbV6MZxf7liWTNiWJ/WLEpGjFbCwa2mmh46kVNdLbx+W5cSsOTJj9Z3j88Z4g38xPM8L619LTXjlxrb6NIcfCklijQ+ntZ3ZvKSjK1+ILcOArzd1zvOXbTX9tdPjf7hfVOXG2ZHKFEZbbAU2x2cbRyF1HI8q7b91m0mXGaTGcO1+mvrbp6dGxY+rb4OoXSIwM3rSsHtaUhRcKS2l9bdtej+WTiufra6+eO8EgHHa33Vu3hNZykWMEA24irkwPpL2VMmB9JeymTA+kvYKmVwPpr2CmTCtnZuPh40k7gER6WHM23WrO2+JlZq846r1PM6jkmVyfRXyqCf0m4tbjrXy+3uu1e3p6flm5TSNJ5SN50ufwNcsvXUWDlGBC6k778OZF+NS7VZODur9dycWIZibZ3BA9EqZCf09pt3cK9XTv+Xl7tY5Prc3Wes5HzsryY+LACWM22NUJsQFWJTwuLW15Xrpt2aT9bXlkp2L085CpDlzxSRybgFhJiYxEX8rEHW+vm1Fq887dNeZLlvFPm6B0rAyIcl1zDkZLf9tkG7LvAVkUOm/W3C4rp/LtjOvETH5WsvFSLNl6nmZriVmKRx/tIjMBwYRhE153FeXbv234w364X8HqOZJj7FHpY+vqWXawHAB21HZXl3kblNhkly8zHixm+VkDAxROpdvUBI3iSTt0GvCks/q1peVH6pxczF6rCmanp5aptlW99QF1vzvxr9D9O/8A1avH3zG9U2PGvQ54MPZ4iiJ+nG7TL+qEn+kg1rVK5SRfTzZ4+Syv/wAxpVWFAK+UVlWr0oF+j9RhP6Cw/pP8K6RmqUBvjg91REj/AA37LH7agD/Ce7X3UGt0Yg42Qnff3i34VvVKo5PR2zzFI6snpAjVQb3t2sOFqGTl+nYo1ud5Hiq/cGpgymXoUAH+mP8AO7H/AJQtXCZSDA+X88QSO2pCKSTbhcs1SgdfG7p2/wDS6t79KtNXsHW8zHjgMDTRrIRcxswBIPDylkNebbbhvWMj6Smx/nZUYxBSoChytz5ifLXLr3dOzXhD/uH9SLiSL0yNkBZN8pK3YX1WzEED2U7dr4jGmrhsqc5L+pC2wuNzFbKeHlNh99eL2s8u3qo5EszgCVvV2qNpCbCr7gLXIA4UmJ4VWyuoR48RGQVeUn9xQxJPdcaU167bx4XODscS5W3LkiKtGpMCsbKyIL7lVtdLWPAVne+v7ZVxk2L57NSSd02SAurkv6anbcKqSa67uVW3XW4RnS9RgihhRAPm4juPqHdo1732aH761Ova234qLuD1CKTKd0I3su617sbKNwS4Ohvyrz9nVZrI6RXmyo0i3Y2shlZp7cFD2G0nmbcK66623n8cMJ+qZBjkGwK8SADaDpb4hu14C9T6+uZ+q7cKBzmymZ5HCsgIU/FytwtXpmnr4TOTxBATCu5bMt8iYiyrru2rc+ZrCr73n/kuIfndbmI9CLywlQFQG4VTa3t0q9XRJzfKb73w6Dpc0cPQY2Lq+QwVyoY38raKR23NrV5OyW9vEd5J/G7SD6c/+xbc2DOxsPqzEN8uWuFSMARi92u4Ki97+Nez1l5eZ6cs7R4AbKkjeZIh6zIQFLhfNtB7TwrtduGddeUHRuvdP6pi+tjuAUPpyRyeVlZeIII18RU13li7aYqfJ6lDBNjxkoRkOUJ3Dy2Utc+6rdiam9R6xgdOwpc3JmRYIRdyDuPZwXWl2hhh/SH1thdZOVG0qgo7SREn8jH4T3rXPTfPlbq3cnrfS8WL1sjKjii4bmvbXsrd3k8k1cX1f6tizMmSCAloCSyub6/l0B5WH214e37GeI9PV088sPIl3XYgbuIvx8a8r2K59IugC+pbUEam/I+FZyRBnZ4xztskj7QxBsLaE6En2Vz9bXLsyzMTrpnMmNIioWj3MwJC8bW3C99DyrrdNtZmXhwxap9V+ocOOcY+SXTGVgkbQ6MCQAPMo07STepp1XaZjFp2PmTZWOfksVpMeW/7uYxQXt+XeDcacqzdPW83n9Fhxz+qwY3p/Ir6ttqhJERFI0Ugk/prMmtv+3C28MbF6p1KBvQ6srsLXl9cFwxFypUlbX0sLNXq369bzoxL+XSfT+fizI0TOjQtIHBdwkgBuB5X468Na+b9nrvy6Tlayf8AxuQ88gmSEYIKlbj1y58wCX8tza5Nc+nXaT+q4xXPZmdmdRxos3KBEnzEsVyCNF+H4teBFfqvqSTrkjyd1ztkAbr/AG7K6sQwn7/wqiXpjf8AeKv6kdf/AE1rVmua6raLq+SCbAuG96g1b5J4NXJhHFxag2/peWOZ8uBSDuh1A9o7O+rqmylh644HdapRMdY/ZQJtVPhUFrBz1w1kJjMnqAWAIGo8fGtS4LEg+oDsG3GPtcD8Ke6epv8A9hyCSFxlFtNXP/409j1Mfr2bcAQxi5tqWP8ACntT1iN+sdQYW2xr4An8al2tMRXkzM/Jh9KaQGM8VVQOB7eNXNOHfSfX3zsKRzKq5JBR7KrK3LRm1W9ePeWR20kywM7q0sEsbRpcnQk8QQx4Wtr2Vy16/aXlve4wZmZcmUwefHaQX85mAuFHAKxrnMz5ZQN1dEjPowqYNoBABDcbsthw07qx/Fzz5XJskuJPhRvkvuNvOgYoFBsRobajwrEzNrJGmWMPBjm9WfcIjcxb9sg9gBHxG/Gu132sxEkjahXHkZJmeR2cXjRRYlDYG5IAAPOvFbZw6zBdZnx48Nog7mFdGdF3EWI5No2pHfTpltTbw5nqPSZjjnLji9HE3bUkKWd76qdo1ANq93X2zOPli6svHnyA6kSlbG1zdrDvtrau91lSVbw0yGb5hpH2yXLtGTfw3Nzrn2YnBGj1LqsbwRNHZmRlIR1AKlbLqLa1w6OizOW9qqxtHkFjI6w2JOxPzE9ulzfnXa5nhPKTMMOOIxjNvLHcqqQygkW1A51evN8m3DS6b0SQxJK7xvkZSXDS/CuoG3dqN1q5bd2biTiV206eM/l0GBgR4EDQiSOd5AT5nLxqw3G221rX415eybb3Ph201msXejZk3T5EzvmYWy4X3IpDldltuzypzFd5cWYcv48xo9V+qOo9R9NmmSNkGse1jESrbi9mAI4DnWr2bbeUnVhRw+odX6dlRdQ6fNHLMrO7oU9MOr2JXzMd32VZvM+DbrtbWJ9Y5XVcnHlbIR2wyZJPTIR4idytu1A2+yuW3b2S4prpL4cj9ZfX2b1aEYKyuI4XkRijsEmjLXTcvMi3OvT1Tb5efsv4YfTfqTL6NMJsF/RlKkE33E3G08dK3628pNsNvpP1pmZoxsTq0u7pmOTG8zIXkRXJZdbjgx9grz93Vb8uvXu9YxvpP6aiwkchMiVkDrkl2AcHUMqhrcCK4fx64dptbVb/AOuQbixgCISv+qeR14E/fXLa4d5sunpnSsaMStjK0OwRhtmrszEqiXG2xvWbc/0Zm3+R6R0X6fixYsjLaBsmBFjMr7LqQAW27uBuePOu3T6eubcOXZvtLh571/oH0703qmT1HAy1bGlfcYY2KhN+pHmtax4WrHZ328TlrXaSZ+XO5HSOnZpZcfDGQoHqbzJ5g7BWK7Lk391Ynbtr84crJRhxeo+tF6+JNkhCG3MybFBO7bs4Ei3Os++uOLhZFyfEQ3knjjxyGPpqDZBGy7X3aHW1c9d8NXBkOJjPjtCk65MEt7rIQ0e8nidwLC44GtbbXOcYTyixOk9LgyEaDFjnSE7pWN3fYhIOy/Zx4cOQqdv2LJi010dJ1GLBbFXL6bPFjLKykQFVEcptyv8AC1uR0rwdVvjby6bRzGfnfNdPmDxiJ4cpdqooVNUAYgDtr9N/+drjr8vF33lTRvLXtrnDC3H2GqJOntbPhPa5HvBFa18s1k9b6Rmz9SlmiRwhCgMFJ1Asa3YzKono/UQOMlv8DVMLlrfSONk43VGEzMVkiK2ZSNQQedXWJUOMNpdP0uy+41KJV1S3daopDVB3igC/APAUQEA2+/76AAeZvZVAfivjRBqhqcD4n76C9mYqJMTAQyE8tQCeXgK8nX25nLr6hkxZpERVSDEpNyAbWJuT4Vmba8tbZ4CefPlVASS+2+9iF0BF+B5ca4yaROVrG6fly4l8h7RuE0Rt5Kg3JJNuPdXn37dZeHSa1VycPpwYh3JliUu6pHvS40sBflzvpWtd9quFRQJpFHzb3B3q1gpFtNpU8dNBYVbcfBhswkPDGqsyPa7Etd+0gn9XO1ePa4reEObJ1NIZMjGlkljUEotlbQGxdg19K6dfrbixKw8zqeTIF+bTfG5DRyOxuCBrtavXp1SeGbk1kxDJAmMImWb4vTJLLbXzAha3M45a9ZlonFfJzcbp+KyBHRpJnCbglzbyN5Q9/dXPiS7V09M3EN6r0DJhxfVyo5fVikiiV3K7djMFHweNOvu1ziU26+DcrouS8xsqKF/b2voLAcdq66ca1pvrhL11o4HRYcdd8MX7tvTd387C+psDovjWNt7fNdNdJGokAgACDUC7O2vHst3dlYzltYWON1IUFVAsQmhLcCCf7Wrl2dvrP1SqsmTDBvRrIENgrC10HMac6mndmRmbw+fqCSQ74DudLKCBwDDTdu0sa4abXW2T5Lv+GZ/9pkwlnjlCyNOGHpHUIT5dDe+lq9+nXly/mw5dsmSOZZAdo3XuvG/GvXiV55nKLL6nLK5f4mtbfatTQtyjGRfgxItqSOHhUwh8WRxRPJzvw99SxY9/+h48U/SuPNBJPkTZao8uTmOrXZl2+lEN7FQtrDQXr5Xdt8fL39UbDQR4xm9SJZmijMm4jQso+EH4tO6uWs5dNrmcLQkxc7F6evU2Ax5N049QlVJUFFjJJ1tuvrXqxLNZt/r/AMcPPZ5s8uM6u3QPl8xoo5I2jm3RRi6SSL5vKgkYeS4BuL1wumsrf9XIw9W6F02TOkzsKXITIXfjws0cm2UXB1vYdvOuuJt4Zlkcz0zMz3zZciGDbj3LSIr7ZCRbXd9la7ddZMW8ucvPDYGX1nLnaNs1Y4lKsyRnbYfmtIeOt7ivNddJPC1PHh5RhWWLKhmjuwb/AFE8t+RYsVsR7a52yXGBXzcNTjzJmzxwxXCrlQklyt7pv2mxtW9Ozmes/stnBvQOu/TXR+oRzmSaaNY3gkyAAABo3lU6szWtW+3623bLLP1w309s1rO+rPryXqTjH6djx9PwTJvUAj1Xa1t0j8PZXo+v9DXTm807fse0xPCLonU8nO6XnDIbc0MkRXSxsdP/AG19P6/VNZcPB2XNXFeutSAX0PhUCjlaORZF+JGDC/dWkq4Ov5g+KKNtbaXH8avvWfWCPqDjvxgQP0sD94rXueqROv4IYFoHQ9oVT9xp7nqxEF55nAIR5Gdb8drEkVnJg9OFu8/fQJPgHhUU1fhFVCU6HxP30A/OfAfjQCTl4iqhUAU8fE0Hd4EWH0r6dbquZAMmeR/Sjx5kCqrG+uouRYV8/ae+/rOJHpn7dcubk6mXyHyFREkuSUWMLELjTaBaum3TLMMeySCKMIZJAkG7zBlbeOPmsFGhNtda8HZeceXSYPPUIHiczJK21tjFbABbaLutxJrndLnhvKs+S0srtjwAqRokittA4ai4LHuvWpMeaZZj4bfNhczQygbpyGN9fhW9tpAFd/5P25guxL0/p2LIsKSSmRrN6xsWF/NqQNPvrzX232ysxDmzdmOwtvu4EdxbipXYde7hU10zTKq3RcbPxY51kbECt5jOdyhgBdNot399ejXuutxeUsyZ07A6ZD1bFYxyZEQ0kx5EBYnUeVgdptpY11vZbqazl1PQIFxsjL6h1CKR3nZlgxLhhHGo8gLsrC262g7K8/Zc4k8PTpL8rGUkmYbTAKm7cIlXQcwL6cDzrlrpJc/LWES4cQkBVRu4WH9uNdQ9sYDzKLtbU+NMhjGSNSWH7hv5rgXHad1VnJk7fNY/pxssUS3EjAEtcA627K8PbrZvm8uXZaxsuPK3qfTWWGMBXU3Dhja2p+Lw7K6aXXHnFcrayeovkwAqz7EdgxVb3J7/APDXs6vXbmRna4Ys0rMWkDG/Ak17J+HND+6zgDRSeJ4fbVzBOJURSosUOvtFMtZR+vwP5u3kNKmEyhWRjuDMot+r8KtGp0/qHUYZ4oYJmB3CRVRzYGPUHThauG2ut5w66bXw6uH/AHTysJrKjyLYbrzv8QFiwtbUiuP/AIefl6L3xbi/3OzczAmZo4Gx8QB40ndyxYMLDzMxJ1rnt9XFkzW9e2c2MLq311nZQ27IRkG6kxKNAxLkhyC5NzxvXTX6s/s479lrlszqmVlNaZ2ZQeBPbXp165PDz21f6Xm4hUoW9DdZSSSfYAe2uPbpWta6SGbHlUQplLtFlEYAUkgjcAdL9mlfP21s5sdYi6r9R9P6dGxdzmZVrJAtlhXTi35uNa6vrbb/AKRNtpHHdQ67lZ9zkNZA26NEAVFJ4+WvqdfRrp4crbfKlkZSvkhoixhS2wPx4a6a867a64S+eD8ty2wWsD5h7asK3/o//wDk6pHe94o3/pLV10ct2uDVqQiePtoAf4UCPD20QD+Yd1A39P8AblVBFtx8BUAHPxNUJPh/t20AU+X3/fRDVPHxNUL858B95oGycPaPvog3qoC8W8aK9F/3ExVg6L03JgcNjdRllydDwYqtgLFltqeBr5/1Pm/2enucE7qRZtRXrrgsYEGXGjBNhRtpX1GJCtfS6rw7da+b9m65dtZwt5TxyY7wTMbsCXCaEWNxpxFeTTMuY6KcGDGkJabmolszHaB+XffXlyq7d1t4amiu/VMpARuSJGULI+m4kfm2W7Lcq6zrjOUOTl5L5EcaSGRiLjcu5VuA1rEcvEVdNJhS6fDlTyRZDFUindiqAgjyHgCRcX1q9lklnzCNLMzUxgism+GaRXSxAVBc3O23HdrXLr0zmra3+hdb+n+kYjY8vTcfqDO4cSPK8b667TYkbezhW9Nr865XOPFeidG6b07qmBgZ0PS8ZI+oxtJq8x9Pb+Vj/wAK9HrrxxOS9l/K5n/TXR8fHLHCw7gqCD6uiswDNo19Bc1q6az8J72n5X0thJ8uY8TBSISAzF0c+Wx+E7u23Greufon8lOzMHoGAduQvTYHPJ4bn+nfetfx/pP8J/JfywetfUHQMXppyIoMHIZJIw0KYh3mMnzlbtytzNZvXtjx/wAj3/VsdP6d0nq+DjLIuMWyIhOojxViO0m9gUbS3Dvrl6a78XH+FtcB9WYrdNz8lDaKFLvElla624p5udr18rs6pN8Yay4Pq/WMWeIRCFTKV8x4bbXvbvNe7p6LLnLntZXLzMha0dwnZX0JHIxmK7QdeWp1q4DJC7G3LgBSGA9QJGBt3E/ZTHLRiysLlhqe4VbBKuTKSu3SwtfQcrVJoqMJO+p0XtNbVIjmJWXddXtcipVlR7ATuvcjiBQRNG5bQXPIUZw1um9D6xkohjhUKWFpXNrWvxrz9ndpPNejTo2roI4+n4mIcHNBWXIuFnXhEzEXZQL24XNq8tu21zHp9NZMVynW8RMbPmhx9YL+RzruH6gTrqa9vTtnXNePu0k2xGeIZCa7ZcsJFxXNTJhZaFnCA6bBtFqZLHQ/RmKXnzIAdpmg23428wF/trr1Vz3jZn6VmwC5X1FH5o9f/Txrd1YyqX4+2ook6e6gDHQ+IogE6nwoG8l9n3VQb2b2UAU8fGiEh09p++gap09p++qGjifGiFfz+z8aAOdPaPvqg3oAp+LxoOh+ofrwda6Ri9L+UjxIOnSKuL6TX8nplG3Xte5sdBXg6dLrz+Xp3uXOSTbRdgVFyL944139nP1S4rdUmlX5eVo8coSSRdRrbcF5nS1eXu9Pny3rKsxdGEuZEHyHYhCzrqNxtcg7TcV5du/E4jc1X+oZEfovGBdUBVEAuCWXy7QOWluNefq05y6WuZzOgdbnlM+NiEQsQE2MltB3t3V9LTs1kxlz/jt+Dofp/r0ayNkYzRhQrozlfiDDQebsNX31+GppZ5X8P5rEx40yQloVIRFG6xJvct8P31x365bx8rJ+TczqKFmcWLkebb5iQNeJrXX1YMxVEnqHc3CxKj7de2u2MM5e9/7Y9Xxp/obDxo50GZDHMgj/ADDbI+1tvMaiuW9wWIer/V0eR9L5uVgZEfzeG+yaU23EpLaxurWBU+F9BT2zwqPqn1fJnYWA2I/oucZZZwu1iJHUWUPr8PH++vT1ae0lrltthzyPvdmlJYtqWOpv416rMOMpLGpVm3bSvAHnTJhpdO6rmdIAy8R1IA2ywsTtb2cj3iuN0lv6uk2xHK/XWL1brbNmYUjSdFwE9V1laNDBK/mlDa387XZe3lwrxba3W4vl1tzMx5nOq+sVLnYeDkXI110rtPDmjmVFkKwuZBye23cB48L1YYQvES19upOi1qACDIkkWKJDvZggFrEseWtFwsYuNsnVH8zFtrfdWpBVkCmZiRrw92lWxYAjHBiQeQFRVmDDlcH00LAanXSs3aRqaWpo+nOUMrqqqptY8SeysXsjU66a0UQIHlX9RFzVyYOWFGcHeAF+EhbVm2rE0mVmPGEOQ7KARYaC3jWZpPw1ey/k2GV433yJ62lgG4dx9lNtMrOzC1PnxZOF8tlY6s66pMpCsp5cuHdXPXpuu2ZW9u72mLGaIlXQGvS85wUcxeiH2UW0HfTCNf6XkZM6YpYH0Hse8EGuvV5cuzw3sPr6ui/NLsYgXdNV9o4iu/s5YXpMfCzE3lVkB4SLx/qGtXyjPyehuLnGk3fySaH+ofwqeq5Z2RBPBcTRtHfgTwPgw0qYXKL83sqAX0X2UQifN7KAA8fGqEp09p++mAFOh8T99A1eJ8aIV/P7PxooOdPaPvqoNEBTx8aAdYxulxZCfJ5Pro4DSWUjYTxUX42rwdW21nMeveSXiqaRCY23FrG7W4gHS9dGcuhhjEMUKC/l8ircFihAIL8OGleDvkm1bhz5Gz1VtseIE+UX3Hs/4V55M2fquVWR5CpSVwQU3Iu4kgL510FjcKbG5rvrop8nWGTCEaJHs+Jbou4aAfEQey9b16eW7vwyJOrFQzA75G0NuXE6V3/jYuyt8zNkIpZrAlvKP5bGuk1kTOQj8viQR7r1WRim0A7RarRtdP8AqDLwMLHMcpAxpZNgGjIJNrMVYai9qxtrLE9j8T6t6jFmTuhjtnRtjZIaMEMknlLdza3uKzOvwnvXZJtiRY00VAFXwGlfSkxHmyQlIJNzrTCg0xN9TrVQDK1rXNjxqYW1n9fieTpkrNJJFCoBn9M23xbhdWB0O0+YX4Vx7tJZ+sb0tlL6ZxuhdX6xjdE2JO2XaQTemW2b1DS3L84wnHh5u6vl424eqWPYD9D/AEQkJyD0XDfyG5WBGJvxsLamvVxJljnLyL/df6V6Z9PdUxZUw2i6fkI3pyxKqjyPGdraX3olx/MLHjuprK1w5DovTch3j6pJDeJ3JhZmC7U3HdJqedaz8Jhn5Ajh6g1yAqzHXlYNXSMM6SO80pXVd7bT2i+lXKwQjM42DQAbqxtWtYtLIVG2K8ajjre9c8fl0z+EkInZgAxtxudfdUsiyhJDIrXAO0nQW10qzlKYSV0IsauGcm7zfjargyQZiO8UwhpPafdVwgK3Z20wDvfjYkeFMJklDO20EA9+lXBlrfTIC9SK3vuhkB58hXTr8ufZ4WIz+0ngPurbmlhnmgffC5RuduB8RwNUaeL18Gy5SW//AGJw9q/wrU2TDSjkhnj3RsskZ421HtrbOFTI6Lhy3aMGBzzTh/SdKlhlmZPR86EXUCdBzT4v6D+FT1XKkT59p0YDUHQj2GphQB1PjQAHT2n76BKdPafvogA8fGgF/OfAUCbl4j76A0AXn4mqiHqeL8vKQuq8RbS1+RHKvn9W/tHpswhhmyAu2MaKQ19BwPM11ySNDGy8yMo7APdfTJIsG234ue5q83b167TDpDM3OkY7pJViUabUFjbx+L7anX1yeIWst+rvHpBpptLHjY+Nd/Rn2VJ8maRipbyg6DlWsJksc3Nj2jj36fjSqt4aO0YRRrvt7xY61mrFuXFEcAZv9RuA4aGpNmvVFHhrIwC37kFW7JNRy+nTRlV3bdxsw5AngTUmzG2qP0ZirKL+tADvX+VOY8KsrOHfdM61g9RhRoJVMpUF4ibOptrdT317td5XCzCy8qr8ZCjtJAH21oilD1rps+R8vHNeUgkAggEDjY8KzNpWrpY00QNjNJxCkDv41LeTHDS+rZuiY/0jKMmaOHImgZY4iR6jsy2UKnE615JtcvRZMPKuhdYHTOpx5RkaJYtT6Z85/lHCuPbp7a4OvbFzXVyf7v8AWJNiRM8OPCUHpqQ+2NDdLF7+YGvNfrXHl2/mn4ZH1T9dZ31BhRY+SzSmI790hBF7Wa3frW+nqut8p2dmZiMH57JyY1UMyRooQDQDyi2gFevXrc9t1V45mY7XDAffXT1ZycsGSeBAPM3q+qex64WRbzlfZoKl61m6xiQSQzLIy70U+bbc207KzZiteYs4+dmCVHEaBLea9+PMCtX2sY4lMy5c9pm+WIEfItcm9a19scpt654Zs7zjJkDC5B1N7VjbXlrXbggH2/DZ78b/AIUwtp93ICnYttS2tzemDJpUEDXXwtxphMgEU2G7TjxNXCZHbGeADd5vQIbbWAGvLvqjU+mrHqwtp+24t2+Wt9fljfwnjP7a+FaYOvQC+nsqhyTSwuXicxuOam3voNPG6+wOzKS4/wConH2r/CtTZmxpw5EGQm+Fw693LxHKtRk3IxcfIFpow/YTxHgeNUZuR0G1zjSWv+STUf1DWp6rlmz4uVjf68ZUX+MeZf6hWcLlEtitxw1oAOfiagQ+I+AoE3Lxqg0DV4e0/fRFqYerG4NryMrAsL8QT8Ir42txXrrKkm9O5Y3twvy/y8q9cmTKFupzFCiGyrdgedzodas0ie1UJZXc3YknvreEWMDpsmYya7Udwm4akE8yvG1ce3tmsaky0c3oXT8fcfmmeRYwfSCgNv0vvufKD2ca8/X9nbb/ALeGrrIycaNmfb26adoPKvaw0/mY8aAwgBnLbgQbActTXPGa2bjrkZUplc6MfM54ewVcGWkkSQxt6a2Y8XOpv31MGVR5ZJJWjB9RJeWhAfTRjRjKkmQnrD1vhFg++5DbeXlse6rYmQgC75Sd0e0D0zwIfit+Y07KuTVoY/WM8IrqwkJNrsC5uNNGOv21013sLMoj1aSDJXI2IsjsdzKp7Bfnar785L4wu9V691ePp8Bjn9NcjXdELbl4XB1I1rW2/DE1YDTtNMrTSElz55XJY25nWvPlqGZT4yzsMd2eE/C0gAb3AmkzguPhXWQ7rC9jxF+NLFicugYA/DcXHdV1ja68v7ZSJCpHlHDwrtlywbFCyi+vaashasbWVRZbseAvbQcTWsIkDAMFO0MRfbRFjB6scOWZCqsZQoA2346V5e/T2r1dG3rGpLg4EOHkZJn9QBgIrgxkHYXcEN/NwrPV3W4h29czawfn4P8Aqk+AFe3LyYVGR553lRWKm1mbS5HZXPby6anDHnJNwNddTUU75OXkVAPbrUBGA1viA8AbX99DJDDXizM3IjTlWsM5OGLF2Xt2mmDIiNLbdoHsqplf6CgHUUaw0V/+Wt6TlNrwCnyiqwIOtAr6eygRPGgV9aBRySRlXjYo4t5lNjVGli9fkU7MpN6/9RNG9q8DWpsmGpBlY+Qu6Bw45gcR4jjWpWTzwsaop5HScKa52+m5/NH5fs4UsMs6fo2XHrCRMvZ8LfwrPquVIo8chWRTG3YwtWcBMNV8fwoFQNX4RRS9QtEJEa2whm5cPLXybOeXoU+qSB3O1NgIBI7Wrr0zESs5lKPY8/xFd5yqIDza0osLmTImxHKg2uF0GnDhXK6SmTHncvcnU6n/AI1ZrBPBkDaAgs9rX4n2Uw1KsY+GpYNLy4J/Gt4LV9WAFlsAOQ0phMnB7gqToeypgZnU2USAAlH13W7Cbg1MM1AuQ0KSMm1xOuxxJYgE68O3TQ1LySot1pEIHG264AvYa0yN/GyI+orvSKPdh46vM6gIGKkR3Kj4jd9TXHe3Wf1r3fVmu23P4ZGfkJIdoB+K1wBxArppnCfbuuePLSXpsuX9EnPhO6PCzPQkuRuUSKrIbdhJNdZtMWfLx4+WXMMOPHicWaRybRqdRbtrzS7W2LVCZt0jHQLe9uPgK7TwySgcT7zVw1GpgdPVlGROLINY1PFv5mHZ2VuQtWiBqbWueyusc6Srt8zHhrWkCLzXlk0HHwAoiid2RMZCLbjpc8uVctq66xawWxociX1bNcBUJGg01Ncd5b4ddbIZLLoY4jtQ6ntJ7a6a6fLntsiiba4JINdGE0chsTxG42oqYOhF7687UwhyuD/xqCE9Rx1LBzt2FgTx+HjwoMo9XzZpdsW2MSEAWFyO+5qZXDWDoABcsQLXPPxrWWcAZRyBpkwudCfd1JNLeV/+U1vTym3gkPlH9udaYEGoEoLMFGhaw99USZGPNjyGOVdrcuwjtBphMo76mgF9F/tyoFfU+ygKMyNvRirAmzKbGqNDE67OigZK+qv610b2jga1NjDUx8zGyV3QuG7V4MPEGtZZwkNEMkRJF2uoZewi4oKM/SMdjeImJuwar7jUwuVCfAyor+X1B2pr9nGs4XKtw05jlQUDkPs22uDx7xcGxrwekehFPM0mnIG4qzXAqyA3vW4Gsp1t40DCHA3EEDheoAHLN29tMKmjlaNgy200sasGlDJ6iqw0DCqLCLfQ8qItwwSHVVJvounEnkO2s2xZHVJ9AdOk6WW6pJ6OdKoKMLftc7FeLd+teHb7Nu3Hh6Z0zHPl551no2Z07Jkx2Xcl/wBtgQdwGt/dXq02ljz7a4ZzSfsgEebh4VccsrmB6UOLNPJOqbgF+V13TBXUkacLEA61L5b1QT5olT1HGpfcEHBe3Xta+tXCWt76XyMeT6U+osCUkSFIcvHHaYyyt9hFWTlM8OWaVrcSbi2vKmESY0QlYH8g07ya1rqLywwoyXUXuLKeFyeYrp6wzWkZbmwN+/8AhUi0iDoDxPLurUrFMcF29P8AKvmc/cK3lEWUxMYiU2MnHuUVLSQ3Hw1JsG1HdXOtxK2LGpte5HO1ItMOOl7E+6qyb8tHfS5FA25Tcg0UHhWinIWbiLDjREqgWuBQyoZcBOMykAMCx3DsZr/dUpEOPhiNw4BZgfsOh+youV9QPhPH7xRCNhoaKvdDP/8ApIf5X/5TW9PLO/gkPlFbZG9EOh1mj72X76sK2M/NwlnGJmj9uW5SQ/lN7Wvy8a3WZGfndPlxbyA+rAeEg4j/ABW++s3VcqvZUCB1NAAfL7zQK/k9lAQSvmUlWXgRoRQX8XrORGAs49Zf1cG/gaTZMNLHzcbJF4nueanRvdW8phITREbmoqrkQwyjzqCe3n76DlGN/GvHh6UZ947KYQxl3N31VOVgtza5XQdlRYhcs5JOpq4DVQ+FBZgxGlP6U/V/CmC1pRoEUACwGgrTLQwsOVx6xIjiGoduZ7r8a5b744b11bn09HC2YMt7LHDf0pHtq3N/N2cq83dbjDtpJ5avWeu9LRdzZBd7eVU1Y9/dXLr6tvw3tvHBdakXqDFhuBF/TJJJ8DXu10xHm2uWFNi5ER/cTQ8CuopYyryuzN6lrkDab68rCkMowp2fFqSLju5mqrZ+l8tm6hNjE7lyMWWHzd1nFvdW+ucsbXhkpjPJL6d7HUXPDy6GsfOFi9AiQbhfdaw9tta3qU5AZQSe29/CtfIvRNoPdTBk/wBQIrOb/ie4VcJk7Dx5JSxPD4nNW3CSZT4/SnmxzmPosxKwg/pXS/tNefbu5w769fCq21CRe9ja4rq5mmW/5r0wAJSTRBZzbSggYG8g7wb1QwSstteFMmBMzEaHj2VUAl2FtT9tARC/hUU4rYC7guvC5+yiHABhfke6mBf6MpGerWNgram3ZW9JyzteEaHyCtMnXoJMXXJiH86ffVhTfqxrzxj+X7ya1smqPo3W5sVFimvLjHSx1Kju7u6pKtjUm6fBkxjJwGDKdTGOH+XsPdWsM5Z2oZgRZgbFToRbtrChfyeygR4fZQFuBoHUDV0APAjnQXMfquTH5ZP3UGmvxe+rlMLsedBNorWb9LaGrKmAkag5Nu+vK9BhFQNOlFNKljVD1gJIubfbQytQ4sQ83E9p/hVTKyAL2H2URJHGt7tcqOypViy+WzrsBIXge23ZWZ14au5rZVwBc7QLAVZqmUDyXJJPHuq4TKtM7f8AxkFgOYBFMKzJ5p3ZlIOzmvZ4VhFN/UJKgE+zWoIwXUWF7twrWFaX0+PR6zhudA0qofB/Jr/VVlxSpupwvidSycWxUpK24nS1zfSrfPCK8N99j8NtD31ZBajU6BRxrSVajQDjxqolxMaTOzEhiHlB+3t9lTbbEysma2+sYEHTcXHww1sjOba1jqsY1kb3V5f5Lc38O80k4Y3WuupPN6GIvp4kQEaKDptGlvCr1deOb5Ozf4nhR9cbPhAY8716MORokHPj3mrhMj65XUAe+pgFco80U++gAyNzm9he3EUEqqrWIYf00yAYxfUn7BQMIiGmvvogMY7aVFMUgcKomgI3beAbge/sqxK0ulgjJJJ1CPb3V018sbK0Z8i+A+6iHXoJ8DXNhH86/ZrVnlKr/U77stR2IPxrWxqz4RdRUW1qdBkmTqMcaMRHJfevIgAmrGabM+/LyX/VK/2G1SqR4W8BUBOth2mgtZfT58cbrb49CWXl/iFWxMqzHymoo0QF4eNAG4+FFPXLmjFidy9h/jQZhW4vzNed2REEUCWMt4UwJ1jUDXhWkPVFvoNaCRV9lEPWPUWN/GipmNtLjwFQMLE6D21Q0k9nuoIpDrYA27aKjIVRubSoK0+QjaEX7DUXCq0qQKXGgPADmamFSdO6dLlQvk3DOWsVva1rHhzqxKn+WfHIlbQxkMLdoNxWrqzKv/VaSTdYfIdSnzaJN2X3KNaiqEcN7WHCtRKtquxbW8xqocwYINP3JDtQfjVyi5i5LYAAxyBKPici/jx7axdPby1NseGR1LquZ1HNaeeQuwX01bQeX2VmaScRr2quFrSHWv7KA2NADe9qB694oGG4kA7aKnSwFxyqFShxoGOnfRDGCHneqDtIGup5VBGyWN6BRtZrHS/DxqwrU6W4Zne5JWJw3jXTVz2QIfIo7h91Ab1UWum650fcSfcpq6+Uql1yUf8AkpFbVQqCtUimLoRzB4d9RWv9PWbOMnKONm99hWozVWJtylv1sT7zesKkPEUEmOu/JiTtYffViN2TJ2SsGt6YAue81rKKuX02KYepjkRvxK/lP8KlMsyRHiYpIpRxyP4VFN4AUU0nU1Ax20oKRPLsrg7CFLG5pIZSqAB4VUOHfVDkHuqIkFA4EjupgK/IceZqgF1Xy6CoI2mjOl6KhfI26Lr32oqvM80mpJ10FTK4RtG3wk2I435VnK4UbGeW/FF0UfjVRZwR55YlNy0Z2gGx3A6VcJat+lP6TLIWYm1he9WRLWx1VjmYnTm2EyRwLA9tblPLc+6rJiGc1SjhkV7WBPAKNTemfm+DHxEyxFXG5GcXG4AakfpFZvZrjixqde2eZVzqUeDJ6XyGDmRZTWH7xBUKeIAsNe+vD0/Z3z++64/R7e362uP2y5/Vk507RtLj8JlJRjyuNDXtndLOHjvTZWeiBQOdJtkuuEyWAZiNB99W1JADA8qqDfSgXK1AVFhagY9hIoOtBKSQdOdQPCktd/cdKoeFHAC/dREgUGoGuo9oqZVWk8pqquYM8EGNkZLyqrMvpLF+Yk/m8BXTSue0FGBUeAqoN6IudK1y7/pRj9lvxrWvlKyervv6jOf5wPcKt8k8Gxny7TqKDV6MPRxs6f8ATHYH2E1qJVaIWjQVhUl/N7KCz0xN2cp5IC1WJU3VZSIJLW/cbb7B5atIzMDrsuO+yXzw307VFZlaurcE2Lmwg6SIeB5j+FaZwoZOHJFqnnj+0VMCoTpUVE5oqkpri6JkYWoJAaIcKoIagepue+gcWN9Bc0DDItiB2a0FfaTqQQvaaKekBcWUbr8SNLD21m1ZDpvRjjH5n+6s5taxhWEpBvargyhcu6yAC7MpF/GrhMqaLtXhY1lrCzgBI5bMNxkOh5g1uVmxoTNDB8TMCOQ1q5iXSxqdLzoB06SUSBjAStmHKQezmKm3Mwa8VD0zNjxsz1pQksZ+JTbS5+JdeIrl9jW3SyN9FxvLVvq+dhv/AN3hOCy2LKD+FfJ6NNv9dn1+3aeYrL9TCZ1M0eqjy27a6f8Ai48Vzn2c+WNmzerlSS83Ysb99e3SYmHk3ublNKuK3SRLHcZSNZ/8JNhU69r/ACY+Ds1n8eflXDsYlj/KNSe816sPLkbAC3ZVQVHhVCOuoItQIG2t6gY9mcXNvDjQWEMFgS1z22JoC88OnG/gaIIyAOEZFvAUwEZ2PBbeJ/hUwZMeWU8No95q4MoWidtS/HsFMGTfk42PMnvNa9TK5jkhQjcV59tVmpgarK50maOPJtIbCRdoPeSDW9alU+sdNOPlM5O6Ocl0fsbmpq2EqlGSDtbRhUVrQ3j6BM3OZwg8LgVb4Z+UC8u4VhRHE1RodHFjNMfyi39vdV1Sq3WJNsCqePH28atXVhAVltZxsmbHfdG1u0cj40ZrZxepLkLYja44iqliHOEYXeNHJtpzpUigzVGlO+lcXRJG2tBMrVUSLaqHA699A4G3jUCYkDT20EYtvux1oEzB2sPhGtu2op7taOyXUd3bWcNZVHV73AJJ43FaiZIoQNaBtjfQ2oDIkRALqNeBHGio1xLMJEkGliAf4ik1WIcvIZpwHNwNLjgas0re0XOm5OMkGTATdZo7WP6gdPvq3WxiymiBFxJMqay7R5QDxJ0ArnkV48iPYdCDwIGt71nEb9r+RinLyhUjFrXLm4I7+NWyfhn2v5SzopbcTepNIXegY1Oh1XTSrNcF2p+1FTgOVbZHbGQCFGmhBogj0yvAA8Bz1oHiMH4AO06UQGUA2sLchRUQe06+UcwCPZSJU8j2UsOI5VpFcTszWtrRQLsONA4MRzqIY8lud6oIkGnK9Amk2tpVE8Lkjdz4VUSRlgShuRxUns7PZREnKqjUxpY+o4rYmQf3FGjc9ODDvHOt63LNYmRjSRytDINs0eg7COXvpWmjlXj6VhwHi7b2H+EfxNL4ZiAcTWVIHS/toNTCXZgd8rf3VqM1l9WkWTIMZNgBe/Lj/dStRntGV0I15VGsgKg0umLtRpDz0FVmm5st2C9mtKRUZqiqatXJ0SI2ooJ1agkVqIepFA4HnVB3UDWIIsNWoGb1UcLueJqKaAxW5NuypgyYd+gJIHOrgP2e/vqKPogatUyGxxNM7qSNsSFyTzANLcNa65StJjxYwidQrnW/eRevRrcR7+ua664UFWD1D6hHdTLEkzySBjk+tCRaCxZjwt+k+NctrJHPfFrSkmgyUB2K68SGAuDXPWPPtUPyOFILhQveCRW8MZqNceOKYiO5sALk86mFyDofzjj7fdUEbkkHYSTyv3UBja5JuSAbcKokBcLqNT3UQ0uotpuPDWgMcgI1G23C3D7aBpN+BPOgaS3rRggg3P2irCnu1tDVRGDbUaGgLcLk0oaSCbigYw1oG8+6gkCqfGguRBSugrTJ/wALW5Hh40D6qDHI8bq6Gzqbg0GhlQx9Txknj0njNmH3qfwrflnwh6sf+5gi/wClFcjvY/3VNlirfy3rIdysOelUbDD0oY0/6a3Pja1aZc1mS75ZG7W2jwXSpXSGRyWG1tV5doqRDiltRqDwNUaUQ9OBV7rmkRQlk3OzdtKsQu9RVVb1zbSLe9RUy7qIlW9ESC96CQfDyqhrbtptUEQ+2qEbc+NFPN9o28O+oIm3283DuoQRv3C178r1FGT5jbSFNwfU+djta+4bt3C35t3dWez/AFdOr/aL/wBRbP8AyGu35fZ5Ntr8OffXP6mfXl6+7/ef/FzWT8flvblXrrzbp+ler6klv9Lb+5fh3VjbDnWhjejtP4cKzGblOm3lwrUYqOC27z3tc7rVmtQ3J3+obce78KzGqi823nx5/hWmSh46fBVD5N2zS26+lqCuu7fr7aB7fDrf4vbaoDru8v8AYVQmv8wnDj/7TSFPktY1plCPioonv4VKAeVqBrXoI9aCRd19KInx/UvpwqlTvfT9VA8XtVZIcvCgu9I9f5oen8Fv3b8LfxvWtUqLqO//AMlNu4+Xb4bdKu3knhDyHZUEsFvXj3fDuF6Faebv2vbjYW/t41pmOXk/L4fbzrNdAFBNBu3D9Fxe9Cr8+/0zbs0qss5r1FQybqK//9k=",
+ "get /api/v1/room/living-room?expand=devices": {
+ "id": "1c634ff4-0476-4733-a084-b4a43d649c84",
+ "name": "Living Room",
+ "selector": "living-room",
+ "devices": [
+ {
+ "id": "b32daa9a-8f77-4394-b4f3-ffea215062d2",
+ "name": "Main Lamp",
+ "selector": "main-lamp",
+ "features": [
+ {
+ "name": "Main Lamp",
+ "selector": "main-lamp-binary",
+ "category": "light",
+ "type": "binary",
+ "min": 0,
+ "max": 1,
+ "read_only": false,
+ "last_value": 1,
+ "last_value_changed": "2019-02-12 07:49:07.556 +00:00"
+ },
+ {
+ "name": "TV Lamp color",
+ "selector": "tv-lamp-color",
+ "category": "light",
+ "type": "color",
+ "min": 0,
+ "max": 16777215,
+ "read_only": false,
+ "last_value": 65000,
+ "last_value_changed": "2019-02-12 07:49:07.556 +00:00"
+ },
+ {
+ "name": "TV Lamp brightness",
+ "selector": "tv-lamp-brightness",
+ "category": "light",
+ "type": "brightness",
+ "min": 0,
+ "max": 100,
+ "read_only": false,
+ "last_value": 55,
+ "last_value_changed": "2019-02-12 07:49:07.556 +00:00"
+ }
+ ]
+ },
+ {
+ "id": "b32daa9a-8f77-4394-b4f3-ffea215062d2",
+ "name": "TV Lamp",
+ "selector": "tv-lamp",
+ "features": [
+ {
+ "name": "TV Lamp feature",
+ "selector": "tv-lamp-binary",
+ "category": "light",
+ "type": "binary",
+ "min": 0,
+ "max": 1,
+ "read_only": false,
+ "last_value": 1,
+ "last_value_changed": "2019-02-12 07:49:07.556 +00:00"
+ }
+ ]
+ },
+ {
+ "id": "adefb484-223e-478a-8330-8fb1b3a20920",
+ "selector": "temperature-living-room",
+ "features": [
+ {
+ "name": "Temperature",
+ "selector": "temperature-living-room-celsius",
+ "category": "temperature-sensor",
+ "type": "decimal",
+ "unit": "celsius",
+ "min": -200,
+ "max": 200,
+ "read_only": true,
+ "last_value": 27,
+ "last_value_changed": "2019-02-12 07:49:07.556 +00:00"
+ }
+ ]
+ },
+ {
+ "id": "81d637d2-b7f5-4cc3-a39e-2270fd069ee2",
+ "selector": "mqtt-living-room",
+ "name": "MQTT device",
+ "service": {
+ "name": "mqtt"
+ },
+ "features": [
+ {
+ "name": "Window Temp",
+ "selector": "mqtt-living-room-temp",
+ "category": "temperature-sensor",
+ "type": "decimal",
+ "unit": "celsius",
+ "min": -200,
+ "max": 200,
+ "read_only": true,
+ "last_value": 27,
+ "last_value_changed": "2019-02-12 07:49:07.556 +00:00"
+ }
+ ]
+ }
+ ]
+ },
+ "get /api/v1/room/kitchen?expand=devices": {
+ "id": "be6ba391-ebb3-472d-81af-d75d710a8430",
+ "name": "Kitchen",
+ "selector": "kitchen",
+ "devices": [
+ {
+ "id": "adefb484-223e-478a-8330-8fb1b3a20920",
+ "selector": "sensor-kitchen",
+ "features": [
+ {
+ "name": "Temperature",
+ "selector": "temperature-living-room-celsius",
+ "category": "temperature-sensor",
+ "type": "decimal",
+ "unit": "celsius",
+ "min": -200,
+ "max": 200,
+ "read_only": true,
+ "last_value": 30,
+ "last_value_changed": "2019-02-12 07:49:07.556 +00:00"
+ },
+ {
+ "name": "Humidity",
+ "selector": "temperature-living-room-celsius",
+ "category": "humidity-sensor",
+ "type": "decimal",
+ "unit": "percent",
+ "min": -200,
+ "max": 200,
+ "read_only": true,
+ "last_value": 70,
+ "last_value_changed": "2019-02-12 07:49:07.556 +00:00"
+ },
+ {
+ "name": "Co2",
+ "selector": "co2-kitchen",
+ "category": "co2-sensor",
+ "type": "decimal",
+ "unit": "ppm",
+ "min": 0,
+ "max": 5000,
+ "read_only": true,
+ "last_value": 340,
+ "last_value_changed": "2019-02-12 07:49:07.556 +00:00"
+ },
+ {
+ "name": "Presence",
+ "selector": "main-presence-sensor",
+ "category": "presence-sensor",
+ "type": "push",
+ "unit": null,
+ "min": 0,
+ "max": 1,
+ "read_only": true,
+ "last_value": 0,
+ "last_value_changed": "2021-07-13 13:49:07.556 +01:00"
+ },
+ {
+ "name": "Kitchen door",
+ "selector": "temperature-living-room-celsius",
+ "category": "opening-sensor",
+ "type": "binary",
+ "unit": null,
+ "min": -200,
+ "max": 200,
+ "read_only": true,
+ "last_value": 0,
+ "last_value_changed": "2019-02-12 07:49:07.556 +00:00"
+ }
+ ]
+ }
+ ]
+ },
+ "post /api/v1/variable/DEVICE_STATE_HISTORY_IN_DAYS": {
+ "id": "18da1930-abe9-4c99-ab9c-7ddd61aef692",
+ "name": "DEVICE_STATE_HISTORY_IN_DAYS",
+ "value": 90,
+ "created_at": "2019-02-20T04:26:47.811Z",
+ "updated_at": "2019-02-20T04:26:47.811Z"
+ },
+ "post /api/v1/house": {
+ "id": "6a29f33b-e5c9-4b08-9d3f-ced2cab80a87",
+ "name": "My House",
+ "selector": "my-house",
+ "created_at": "2019-02-20T04:26:47.811Z",
+ "updated_at": "2019-02-20T04:26:47.811Z"
+ },
+ "post /api/v1/house/my-house/room": {
+ "id": "1bdc3614-6082-43c3-9e4a-3b00781013a4",
+ "name": "My room",
+ "house_id": "6a29f33b-e5c9-4b08-9d3f-ced2cab80a87",
+ "created_at": "2019-02-20T04:26:47.811Z",
+ "updated_at": "2019-02-20T04:26:47.811Z"
+ },
+ "get /api/v1/room?expand=devices": [
+ {
+ "id": "1c634ff4-0476-4733-a084-b4a43d649c84",
+ "name": "Living Room",
+ "selector": "living-room",
+ "devices": [
+ {
+ "id": "b32daa9a-8f77-4394-b4f3-ffea215062d2",
+ "name": "Multi-sensor",
+ "selector": "sensors",
+ "features": [
+ {
+ "name": "Temperature",
+ "selector": "temperature-sensor",
+ "category": "temperature-sensor",
+ "type": "decimal",
+ "min": -20,
+ "max": 255,
+ "read_only": true,
+ "last_value": 25,
+ "unit": "celsius",
+ "last_value_changed": "2019-02-12 07:49:07.556 +00:00"
+ },
+ {
+ "name": "Humidity",
+ "selector": "humidity-sensor",
+ "category": "humidity-sensor",
+ "type": "decimal",
+ "min": 0,
+ "max": 100,
+ "read_only": true,
+ "last_value": 56,
+ "unit": "percent",
+ "last_value_changed": "2019-02-12 07:49:07.556 +00:00"
+ },
+ {
+ "name": "Co2",
+ "selector": "co2-sensor",
+ "category": "co2-sensor",
+ "type": "decimal",
+ "min": 0,
+ "max": 5000,
+ "read_only": true,
+ "last_value": 410,
+ "unit": "ppm",
+ "last_value_changed": "2019-02-12 07:49:07.556 +00:00"
+ },
+ {
+ "name": "Door",
+ "selector": "door-opening-sensor",
+ "category": "door-opening-sensor",
+ "type": "binary",
+ "min": 0,
+ "max": 1,
+ "read_only": true,
+ "last_value": 0,
+ "unit": "percent",
+ "last_value_changed": "2019-02-12 07:49:07.556 +00:00"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "id": "ab42585c-415d-4696-8f4c-ff0283dcb954",
+ "name": "Kitchen",
+ "selector": "kitchen",
+ "devices": [
+ {
+ "id": "b32daa9a-8f77-4394-b4f3-ffea215062d2",
+ "name": "Kitchen Light",
+ "selector": "sensors",
+ "features": [
+ {
+ "name": "Light",
+ "selector": "main-lamp-binary",
+ "category": "light",
+ "type": "binary",
+ "min": 0,
+ "max": 100,
+ "read_only": true,
+ "last_value": 60,
+ "unit": " lux",
+ "last_value_changed": "2019-02-12 07:49:07.556 +00:00"
+ }
+ ]
+ },
+ {
+ "id": "284d8f68-220c-45fd-a73a-eccb547aff24",
+ "name": "Sensor",
+ "selector": "humidity-sensor",
+ "features": [
+ {
+ "name": "Humidity",
+ "selector": "kitchen-humidity-sensor",
+ "category": "humidity-sensor",
+ "type": "decimal",
+ "min": 0,
+ "max": 100,
+ "read_only": true,
+ "last_value": 74,
+ "unit": "percent",
+ "last_value_changed": "2019-02-12 07:49:07.556 +00:00"
+ }
+ ]
+ }
+ ]
+ }
+ ],
+ "post /api/v1/light/main-lamp/on": {
+ "type": "light.turn-on",
+ "device": "main-lamp",
+ "status": "pending"
+ },
+ "get /api/v1/service/philips-hue/bridge": [
+ {
+ "name": "Philips hue",
+ "ipaddress": "192.168.2.245"
+ }
+ ],
+ "get /api/v1/message": [
+ {
+ "id": "247b1dd0-6fab-47a8-a9c8-1405deae0ae8",
+ "sender_id": null,
+ "receiver_id": "0cd30aef-9c4e-4a23-88e3-3547971296e5",
+ "text": "It's a clear day today. Temperature outside is 26°C.",
+ "is_read": true,
+ "created_at": "2019-02-12T07:45:07.556Z"
+ },
+ {
+ "id": "247b1dd0-6fab-47a8-a9c8-1405deae0ae8",
+ "sender_id": "0cd30aef-9c4e-4a23-88e3-3547971296e5",
+ "receiver_id": null,
+ "text": "What's the weather like?",
+ "is_read": true,
+ "created_at": "2019-02-12T07:44:07.556Z"
+ },
+ {
+ "id": "247b1dd0-6fab-47a8-a9c8-1405deae0ae8",
+ "sender_id": null,
+ "receiver_id": "0cd30aef-9c4e-4a23-88e3-3547971296e5",
+ "text": "It's 24°C in the kitchen.",
+ "is_read": true,
+ "created_at": "2019-02-12T07:49:07.557Z"
+ },
+ {
+ "id": "247b1dd0-6fab-47a8-a9c8-1405deae0ae8",
+ "sender_id": "0cd30aef-9c4e-4a23-88e3-3547971296e5",
+ "receiver_id": null,
+ "text": "What's the temperature in the kitchen?",
+ "is_read": true,
+ "created_at": "2019-02-12T07:49:07.556Z"
+ }
+ ],
+ "post /api/v1/message": {
+ "id": "247b1dd0-6fab-47a8-a9c8-1405deae0ae8",
+ "sender_id": "0cd30aef-9c4e-4a23-88e3-3547971296e5",
+ "receiver_id": null,
+ "text": "What time is it ?",
+ "is_read": true,
+ "created_at": "2019-02-12T07:49:07.556Z"
+ },
+ "get /api/v1/scene": [
+ {
+ "id": "5f515235-2a00-45f7-993f-cb24b463feec",
+ "selector": "wake-up",
+ "icon": "fe fe-bell",
+ "active": true,
+ "name": "Wake Up",
+ "description": "Tony's wake up scene"
+ }
+ ],
+ "get /api/v1/user": [
+ {
+ "id": "d84ced32-d937-4cf6-a32e-105ffb584226",
+ "firstname": "Tony",
+ "lastname": "Stark",
+ "selector": "tony",
+ "role": "admin"
+ },
+ {
+ "id": "2a16e6bb-34a8-46b9-90d3-275e4d059b41",
+ "firstname": "Pepper",
+ "lastname": "Pots",
+ "selector": "pepper",
+ "role": "user"
+ }
+ ],
+ "get /api/v1/user/tony": {
+ "id": "d84ced32-d937-4cf6-a32e-105ffb584226",
+ "firstname": "Tony",
+ "lastname": "Stark",
+ "selector": "tony",
+ "email": "tony.stark@gladysassistant.com",
+ "birthdate": "2011-02-04",
+ "language": "en",
+ "role": "admin"
+ },
+ "get /api/v1/user/pepper": {
+ "id": "d84ced32-d937-4cf6-a32e-105ffb584226",
+ "firstname": "Pepper",
+ "lastname": "Pots",
+ "selector": "pepper",
+ "email": "pepper.pots@gladysassistant.com",
+ "birthdate": "2011-02-04",
+ "language": "en",
+ "role": "admin"
+ },
+ "get /api/v1/scene/wake-up": {
+ "id": "5f515235-2a00-45f7-993f-cb24b463feec",
+ "selector": "wake-up",
+ "icon": "fe fe-bell",
+ "active": true,
+ "name": "Wake Up",
+ "triggers": [
+ {
+ "type": "device.new-state",
+ "device_feature": "main-lamp-binary",
+ "operator": "=",
+ "value": 1
+ }
+ ],
+ "actions": [
+ [
+ {
+ "type": "delay",
+ "value": 2,
+ "unit": "seconds"
+ }
+ ],
+ [
+ {
+ "type": "light.turn-on",
+ "devices": ["light"]
+ }
+ ]
+ ]
+ },
+ "get /api/v1/service/zwave/node": [
+ {
+ "name": "ZME_UZB1 USB Stick",
+ "features": [],
+ "params": [],
+ "rawZwaveNode": {
+ "id": 1,
+ "manufacturer": "Z-Wave.Me",
+ "manufacturerid": "0x0115",
+ "product": "ZME_UZB1 USB Stick",
+ "producttype": "0x0400",
+ "productid": "0x0001",
+ "type": "Static PC Controller"
+ }
+ }
+ ],
+ "get /api/v1/service/zwave/neighbor": [
+ {
+ "id": "1",
+ "manufacturer": "Z-Wave.Me",
+ "product": "ZME_UZB1 USB Stick",
+ "neighbors": [2, 3, 4, 5, 6, 7, 8, 10]
+ },
+ {
+ "id": "2",
+ "manufacturer": "",
+ "product": "",
+ "neighbors": []
+ },
+ {
+ "id": "3",
+ "manufacturer": "",
+ "product": "",
+ "neighbors": []
+ },
+ {
+ "id": "4",
+ "manufacturer": "",
+ "product": "",
+ "neighbors": []
+ },
+ {
+ "id": "5",
+ "manufacturer": "",
+ "product": "",
+ "neighbors": []
+ },
+ {
+ "id": "6",
+ "manufacturer": "",
+ "product": "",
+ "neighbors": []
+ },
+ {
+ "id": "7",
+ "manufacturer": "",
+ "product": "",
+ "neighbors": []
+ },
+ {
+ "id": "8",
+ "manufacturer": "",
+ "product": "",
+ "neighbors": []
+ },
+ {
+ "id": "10",
+ "manufacturer": "FIBARO System",
+ "product": "FGMS001-ZW5 Motion Sensor",
+ "neighbors": [1]
+ }
+ ],
+ "get /api/v1/service/usb/port": [
+ {
+ "comName": "/dev/tty.usbmodem145301",
+ "serialNumber": "f75ab720-bbb3-4a1c-8729-84aa02ebdca0",
+ "locationId": "14530000",
+ "vendorId": "0658",
+ "productId": "0200"
+ }
+ ],
+ "get /api/v1/area": [
+ {
+ "id": "20b4f1f0-989b-4a94-b0d4-c042137da6b5",
+ "name": "My house",
+ "radius": 1000,
+ "color": "#3498db",
+ "latitude": 41.89154462447053,
+ "longitude": 12.49828345229836
+ },
+ {
+ "id": "f7312c0d-2eac-4e89-9c78-0428e06a39f4",
+ "name": "My work",
+ "radius": 2000,
+ "color": "#f1c40f",
+ "latitude": 41.93425385676557,
+ "longitude": 12.402756238310928
+ }
+ ],
+ "get /api/v1/house": [
+ {
+ "id": "23c40ffe-e1b5-4130-b8df-c56ff92ceee5",
+ "name": "My House",
+ "selector": "my-house",
+ "latitude": 41.89154462447053,
+ "longitude": 12.49828345229836,
+ "rooms": [
+ {
+ "id": "cecc52c7-3e67-4b75-9b13-9a8867b0443d",
+ "name": "Living Room",
+ "selector": "living-room"
+ },
+ {
+ "id": "f99ab22a-e6a8-4756-b1fe-4d19dc8c8620",
+ "name": "Kitchen",
+ "selector": "kitchen"
+ },
+ {
+ "id": "01ad196a-020d-4828-a7b6-41bde8496823",
+ "name": "Garden",
+ "selector": "garden"
+ }
+ ]
+ }
+ ],
+ "get /api/v1/service/zwave/device": [
+ {
+ "id": "fbedb47f-4d25-4381-8923-2633b23192a0",
+ "service_id": "a810b8db-6d04-4697-bed3-c4b72c996279",
+ "room_id": "cecc52c7-3e67-4b75-9b13-9a8867b0443d",
+ "name": "Fibaro Motion Sensor",
+ "selector": "zwave:1234",
+ "external_id": "test-sensor-external",
+ "should_poll": false,
+ "poll_frequency": null,
+ "created_at": "2019-02-12T07:49:07.556Z",
+ "updated_at": "2019-02-12T07:49:07.556Z",
+ "features": [
+ {
+ "name": "Temperature",
+ "selector": "test-temperature",
+ "category": "temperature-sensor",
+ "type": "decimal"
+ },
+ {
+ "name": "Motion",
+ "selector": "test-motion",
+ "category": "motion-sensor",
+ "type": "binary"
+ },
+ {
+ "name": "Battery",
+ "selector": "test-battery",
+ "category": "battery",
+ "type": "integer",
+ "last_value": "92"
+ },
+ {
+ "name": "Lux",
+ "selector": "test-light",
+ "category": "light-sensor",
+ "type": "integer"
+ }
+ ],
+ "room": {
+ "id": "cecc52c7-3e67-4b75-9b13-9a8867b0443d",
+ "name": "Living Room",
+ "selector": "living-room"
+ }
+ }
+ ],
+ "get /api/v1/service/mqtt": {},
+ "get /api/v1/service/mqtt/status": {
+ "configured": true,
+ "connected": true
+ },
+ "get /api/v1/service/mqtt/config": {
+ "useEmbeddedBroker": true,
+ "dockerBased": true,
+ "networkModeValid": true,
+ "brokerContainerAvailable": false
+ },
+ "get /api/v1/service/zigbee2mqtt": {},
+ "get /api/v1/service/zigbee2mqtt/permit_join": true,
+ "get /api/v1/service/zigbee2mqtt/device": [
+ {
+ "name": "Aqara Sensor",
+ "external_id": "zigbee2mqtt:0x00158d0005828ece",
+ "selector": "zigbee2mqtt-0x00158d0005828ece",
+ "room_id": "cecc52c7-3e67-4b75-9b13-9a8867b0443d",
+ "model": "WSDCGQ11LM",
+ "params": [
+ {
+ "name": "model",
+ "value": "WSDCGQ11LM"
+ }
+ ],
+ "features": [
+ {
+ "category": "pressure-sensor",
+ "external_id": "zigbee2mqtt:0x00158d0005828ece:pressure-sensor:decimal:pressure",
+ "name": "Pressure Sensor",
+ "read_only": true,
+ "selector": "zigbee2mqtt:0x00158d0005828ece:pressure-sensor:decimal:pressure",
+ "type": "decimal"
+ }
+ ]
+ }
+ ],
+ "get /api/v1/service/zigbee2mqtt/discovered": [
+ {
+ "name": "Aqara Sensor",
+ "external_id": "zigbee2mqtt:0x00158d0005828ece",
+ "selector": "zigbee2mqtt-0x00158d0005828ece",
+ "room_id": "cecc52c7-3e67-4b75-9b13-9a8867b0443d",
+ "model": "WSDCGQ11LM",
+ "supported": true,
+ "created_at": "2019-02-12T07:49:07.556Z",
+ "params": [
+ {
+ "name": "model",
+ "value": "WSDCGQ11LM"
+ }
+ ],
+ "features": [
+ {
+ "category": "pressure-sensor",
+ "external_id": "zigbee2mqtt:0x00158d0005828ece:pressure-sensor:decimal:pressure",
+ "name": "Pressure Sensor",
+ "read_only": true,
+ "selector": "zigbee2mqtt:0x00158d0005828ece:pressure-sensor:decimal:pressure",
+ "type": "decimal"
+ }
+ ]
+ },
+ {
+ "model": "WXKG01LM",
+ "name": "0x00158d00033e88d5",
+ "service_id": "f87b7af2-ca8e-44fc-b754-444354b42fee",
+ "should_poll": false,
+ "supported": true,
+ "external_id": "zigbee2mqtt:0x00158d00033e88d5",
+ "features": [
+ {
+ "category": "battery",
+ "external_id": "zigbee2mqtt:0x00158d00033e88d5:battery:integer:battery",
+ "has_feedback": false,
+ "max": 100,
+ "min": 0,
+ "name": "Battery",
+ "read_only": true,
+ "selector": "zigbee2mqtt-0x00158d00033e88d5-battery-integer-battery",
+ "type": "integer",
+ "unit": "percent"
+ },
+ {
+ "category": "button",
+ "external_id": "zigbee2mqtt:0x00158d00033e88d5:button:click:action",
+ "has_feedback": false,
+ "max": 7,
+ "min": 0,
+ "name": "Action",
+ "read_only": true,
+ "selector": "zigbee2mqtt-0x00158d00033e88d5-button-click-action",
+ "type": "click",
+ "unit": null
+ },
+ {
+ "category": "switch",
+ "external_id": "zigbee2mqtt:0x00158d00033e88d5:switch:voltage:voltage",
+ "has_feedback": false,
+ "max": 10000,
+ "min": 0,
+ "name": "Voltage",
+ "read_only": true,
+ "selector": "zigbee2mqtt-0x00158d00033e88d5-switch-voltage-voltage",
+ "type": "voltage",
+ "unit": "millivolt"
+ }
+ ]
+ },
+ {
+ "name": "Unsupported device",
+ "external_id": "zigbee2mqtt:0x00158d0005828ece",
+ "selector": "zigbee2mqtt-0x00158d0005828ece",
+ "room_id": "cecc52c7-3e67-4b75-9b13-9a8867b0443d",
+ "supported": false,
+ "features": [
+ {
+ "category": "battery",
+ "name": "Pressure Sensor",
+ "read_only": true,
+ "type": "decimal"
+ }
+ ]
+ }
+ ],
+ "get /api/v1/service/zigbee2mqtt/variable/ZIGBEE2MQTT_DRIVER_PATH": {},
+ "get /api/v1/service/zigbee2mqtt/status": {
+ "usbConfigured": true,
+ "mqttExist": true,
+ "mqttRunning": true,
+ "zigbee2mqttExist": true,
+ "zigbee2mqttRunning": true,
+ "gladysConnected": true,
+ "zigbee2mqttConnected": true,
+ "z2mEnabled": true,
+ "dockerBased": true,
+ "networkModeValid": true
+ },
+ "get /api/v1/service/tasmota": {},
+ "get /api/v1/service/tasmota/device": [
+ {
+ "name": "Switch",
+ "external_id": "tasmota:sonoff-basic",
+ "selector": "tasmota-sonoff-basic",
+ "room_id": "cecc52c7-3e67-4b75-9b13-9a8867b0443d",
+ "model": "sonoff-basic",
+ "features": [
+ {
+ "category": "switch",
+ "type": "binary"
+ }
+ ]
+ },
+ {
+ "name": "Switch",
+ "external_id": "tasmota:192.168.1.1",
+ "selector": "tasmota-192-168-1-1",
+ "room_id": "cecc52c7-3e67-4b75-9b13-9a8867b0443e",
+ "features": [
+ {
+ "category": "switch",
+ "type": "binary"
+ }
+ ],
+ "params": [
+ {
+ "name": "protocol",
+ "value": "http"
+ }
+ ]
+ }
+ ],
+ "get /api/v1/device/tasmota-sonoff-basic": {
+ "name": "Switch",
+ "external_id": "tasmota:sonoff-basic",
+ "selector": "sonoff-basic",
+ "room_id": "cecc52c7-3e67-4b75-9b13-9a8867b0443d",
+ "model": "sonoff-basic",
+ "features": [
+ {
+ "category": "switch",
+ "type": "binary",
+ "name": "Switch"
+ }
+ ]
+ },
+ "get /api/v1/device/tasmota-192-168-1-1": {
+ "name": "Switch",
+ "external_id": "tasmota:sonoff-basic",
+ "selector": "sonoff-basic",
+ "room_id": "cecc52c7-3e67-4b75-9b13-9a8867b0443d",
+ "model": "sonoff-basic",
+ "features": [
+ {
+ "category": "switch",
+ "type": "binary",
+ "name": "Switch"
+ }
+ ]
+ },
+ "get /api/v1/service/tasmota/discover/mqtt": [
+ {
+ "name": "Sonoff Basic Kitchen",
+ "external_id": "tasmota:sonoff-basic",
+ "created_at": "2019-02-12T07:49:07.556Z",
+ "model": "sonoff-basic",
+ "features": [
+ {
+ "category": "switch",
+ "type": "binary"
+ }
+ ]
+ },
+ {
+ "name": "Sonoff Pow Kitchen",
+ "external_id": "tasmota:sonoff-pow",
+ "model": "sonoff-pow",
+ "features": [
+ {
+ "category": "switch",
+ "type": "binary"
+ }
+ ]
+ },
+ {
+ "name": "Sonoff Mini Outside",
+ "external_id": "tasmota:sonoff-mini",
+ "model": "sonoff-basic",
+ "created_at": "2019-02-12T07:49:07.556Z",
+ "updatable": true,
+ "features": [
+ {
+ "category": "switch",
+ "type": "binary"
+ }
+ ]
+ }
+ ],
+ "get /api/v1/service/tasmota/discover/http": [
+ {
+ "name": "Sonoff Basic Kitchen",
+ "external_id": "tasmota:192.168.1.1",
+ "created_at": "2019-02-12T07:49:07.556Z",
+ "model": "sonoff-basic",
+ "features": [
+ {
+ "category": "switch",
+ "type": "binary"
+ }
+ ],
+ "params": [
+ {
+ "name": "protocol",
+ "value": "http"
+ }
+ ]
+ },
+ {
+ "name": "Sonoff Pow Kitchen",
+ "external_id": "tasmota:192.168.1.2",
+ "model": "sonoff-pow",
+ "features": [
+ {
+ "category": "switch",
+ "type": "binary"
+ }
+ ],
+ "params": [
+ {
+ "name": "protocol",
+ "value": "http"
+ }
+ ]
+ },
+ {
+ "name": "Sonoff Mini Outside",
+ "external_id": "tasmota:192.168.1.3",
+ "model": "sonoff-basic",
+ "created_at": "2019-02-12T07:49:07.556Z",
+ "updatable": true,
+ "features": [
+ {
+ "category": "switch",
+ "type": "binary"
+ }
+ ],
+ "params": [
+ {
+ "name": "protocol",
+ "value": "http"
+ }
+ ]
+ },
+ {
+ "name": "192.168.1.3",
+ "external_id": "tasmota:192.168.1.3",
+ "created_at": "2019-02-12T07:49:07.556Z",
+ "needAuthentication": true,
+ "features": [
+ {
+ "category": "switch",
+ "type": "binary"
+ }
+ ],
+ "params": [
+ {
+ "name": "protocol",
+ "value": "http"
+ }
+ ]
+ }
+ ],
+ "get /api/v1/service/rtsp-camera/device": [
+ {
+ "id": "c2204fdc-c22f-4fc9-b7d7-c862f3c514c7",
+ "name": "Kitchen Camera",
+ "params": [
+ {
+ "name": "CAMERA_URL",
+ "value": "http://camera-url"
+ }
+ ]
+ }
+ ],
+ "get /api/v1/service/rtsp-camera": {
+ "id": "aa7d6284-6b80-4e78-9e08-a4122207edcd"
+ },
+ "post /api/v1/service/rtsp-camera/camera/test": "data:image/jpeg;base64,/9j/4QAYRXhpZgAASUkqAAgAAAAAAAAAAAAAAP/sABFEdWNreQABAAQAAAA1AAD/4QMJaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJBZG9iZSBYTVAgQ29yZSA1LjYtYzEzOCA3OS4xNTk4MjQsIDIwMTYvMDkvMTQtMDE6MDk6MDEgICAgICAgICI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjRFMTgwODcwNzU0MjExRTk5Nzc5RkZBMTY3OTgyRDBEIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjRFMTgwODZGNzU0MjExRTk5Nzc5RkZBMTY3OTgyRDBEIiB4bXA6Q3JlYXRvclRvb2w9IlZlci4xLjAuMDAwIj4gPHhtcE1NOkRlcml2ZWRGcm9tIHN0UmVmOmluc3RhbmNlSUQ9IkYzN0JCRDNCMzkwRTdEQ0NEMkQ5ODI4MDFGNTkwMTZBIiBzdFJlZjpkb2N1bWVudElEPSJGMzdCQkQzQjM5MEU3RENDRDJEOTgyODAxRjU5MDE2QSIvPiA8L3JkZjpEZXNjcmlwdGlvbj4gPC9yZGY6UkRGPiA8L3g6eG1wbWV0YT4gPD94cGFja2V0IGVuZD0iciI/Pv/tAEhQaG90b3Nob3AgMy4wADhCSU0EBAAAAAAADxwBWgADGyVHHAIAAAIAAgA4QklNBCUAAAAAABD84R+JyLfJeC80YjQHWHfr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mUgIL2HDcptx537RXyPsbduJzXs011UM7MizJx6zmRtwWN4zqF5buI48a4bdu/nP+WppFFHhxAViViAfPc7XbcOFtNOym2l7JnwS+qGaZnjSI3VV1UjVAdTt8vPgKa6zz8nlVy+s5674k8qtY70J2gXsWsON++t9f19PKXaoMSdJXsyqrEbEY6gNb4mGpPZXXfXEZlNfp+fPneiVLynU3IO0ct2psK69W0s4Tb9XS9O6ZFgxWB3ysPPIefcOwV2kc7VlmABJ0A4mqyz8jMeV/Sgub8TUtawmxen7fNJq1JEtPy8jHxEu583JRxrSMPKz5MhuxeQFFw9ARNK9jzJVSqJAlA4LQHbVB20UttAdtAttAttQLbQHbQLbQLbRR20C20B20C20B21AttAdtAttAdtAttFHbRB20UttAdtAttAttAdtELbQHbUC20C20C20Acqi7mNgOdZ22kma1JmuK+o3xcrPMfpWaJQLptUE637eBr43b2bbbZ8PbprJMObyMibFbZFLtYteQjmp107q1JN/MTOFoT408AlVHaS/AG9ral728puNBXHaevDXnkmzMNg2R+4Utdo18ouQNfLY+81j038cLMeVKdlzGX5dP2pHALPzYDdtL2sLc666/s83lm8pB9N5hlURMhhfWQ6+Q+77q30d38nH4Z2mG/h4EGFEEj1NhvdviYjmf4V7JMOVuT5po4l3ObD761lGcWyM59qDbCDxqZXDRxcKKBL2AtqWNWapazeqfUUMF4cTzyc35DwqkjAfJlncvIxZjzNFPU1B6kiV7XmSqlEPC1Q4LRR20C20B21QttAttAdtQLbQLbQLbUB20UdtAttAdtAttAttAdtAttAdtQHbQLbVUdtQLZRB20B20C20UttEHZQLZQHbRS21ELbVC21BjfUz5sUCNj3EZO1yNtrntD8fZXl+xrvcert1WfLleodVeMOzYyDITdGZVPmsLhdOAFr614tr41+Y9Enz8OZRhkTmSclkj1Y3F72v7tK1tPWcJOUCZTpklVnMSX+NQe46DTUV0mks5T2pkmS4ILMxTduZQdu7ne9udT0/BltdMxuo5sscin08Jk2yk/mPD4f1W51x16Zc/wBWrvY6SOJIo1jTREFgCb/aa9OusnhytyrZubFji3xSclH41rKYVIcPIzJBLk3CHgndSTK24XcnJwemwb5mCgDy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",
+ "get /api/v1/gateway/status": {
+ "configured": false,
+ "connected": false
+ },
+ "get /api/v1/gateway/backup": [
+ {
+ "id": "99fac564-0844-44f6-866b-2b8dcf0d76eb",
+ "path": "https://url-backup",
+ "size": 1127680,
+ "created_at": "2019-06-25T07:01:24.846Z",
+ "updated_at": "2019-06-25T07:01:24.846Z",
+ "is_deleted": false
+ },
+ {
+ "id": "210460b2-c9a8-4891-9cca-464c3e19bfbb",
+ "path": "https://url-backup",
+ "size": 1013680,
+ "created_at": "2019-06-24T03:45:10.144Z",
+ "updated_at": "2019-06-24T03:45:10.144Z",
+ "is_deleted": false
+ }
+ ],
+ "get /api/v1/ping": {},
+ "get /api/v1/system/info": {
+ "hostname": "Raspberry Pi 4",
+ "type": "Linux",
+ "platform": "linux",
+ "arch": "x64",
+ "release": "18.5.0",
+ "uptime": 662555,
+ "loadavg": [1.908203125, 3.01513671875, 3.64013671875],
+ "totalmem": 17179869184,
+ "freemem": 492482560,
+ "cpus": [
+ {
+ "model": "Intel(R) Core(TM) i7-6567U CPU @ 3.30GHz",
+ "speed": 3300,
+ "times": {
+ "user": 34606730,
+ "nice": 0,
+ "sys": 24855850,
+ "idle": 100527470,
+ "irq": 0
+ }
+ },
+ {
+ "model": "Intel(R) Core(TM) i7-6567U CPU @ 3.30GHz",
+ "speed": 3300,
+ "times": {
+ "user": 22568450,
+ "nice": 0,
+ "sys": 10605290,
+ "idle": 126800520,
+ "irq": 0
+ }
+ },
+ {
+ "model": "Intel(R) Core(TM) i7-6567U CPU @ 3.30GHz",
+ "speed": 3300,
+ "times": {
+ "user": 34765800,
+ "nice": 0,
+ "sys": 20890230,
+ "idle": 104318270,
+ "irq": 0
+ }
+ },
+ {
+ "model": "Intel(R) Core(TM) i7-6567U CPU @ 3.30GHz",
+ "speed": 3300,
+ "times": {
+ "user": 18691910,
+ "nice": 0,
+ "sys": 8683980,
+ "idle": 132598350,
+ "irq": 0
+ }
+ }
+ ],
+ "network_interfaces": {},
+ "nodejs_version": "v10.15.2",
+ "gladys_version": "v4.0.0",
+ "is_docker": false,
+ "new_release_available": false
+ },
+ "get /api/v1/system/disk": {
+ "filesystem": "/dev/disk1s1",
+ "size": 499313172480,
+ "used": 464613756928,
+ "available": 28587036672,
+ "capacity": 0.953000005,
+ "mountpoint": "/"
+ },
+ "get /api/v1/system/container": [
+ {
+ "name": "/gladys",
+ "state": "running",
+ "id": "9e5f09775f897624deb1eb2ec8688c1b300d81bc3727fc71ae3290d3d8f71fa9",
+ "created_at": 1561506899
+ }
+ ],
+ "get /api/v1/service": [
+ {
+ "id": "27c96cfe-98ce-437b-a83f-5b13e0605203",
+ "pod_id": null,
+ "name": "example",
+ "selector": "example",
+ "version": "0.1.0",
+ "has_message_feature": false,
+ "status": "LOADING",
+ "created_at": "2020-04-11T18:41:40.051Z",
+ "updated_at": "2020-10-18T10:13:22.365Z"
+ },
+ {
+ "id": "40262062-2e71-412c-8da0-70bd03f03b90",
+ "pod_id": null,
+ "name": "philips-hue",
+ "selector": "philips-hue",
+ "version": "0.1.0",
+ "has_message_feature": false,
+ "status": "RUNNING",
+ "created_at": "2020-04-11T18:41:40.052Z",
+ "updated_at": "2020-10-30T07:44:07.731Z"
+ },
+ {
+ "id": "4cd73c14-a929-4af0-a5e2-baed35802224",
+ "pod_id": null,
+ "name": "rtsp-camera",
+ "selector": "rtsp-camera",
+ "version": "0.1.0",
+ "has_message_feature": false,
+ "status": "RUNNING",
+ "created_at": "2020-04-11T18:41:40.053Z",
+ "updated_at": "2020-10-30T07:44:07.694Z"
+ },
+ {
+ "id": "0c27de72-ced7-4f7f-8950-473b9e904e71",
+ "pod_id": null,
+ "name": "telegram",
+ "selector": "telegram",
+ "version": "0.1.0",
+ "has_message_feature": true,
+ "status": "RUNNING",
+ "created_at": "2020-04-11T18:41:40.053Z",
+ "updated_at": "2020-10-30T07:44:07.518Z"
+ },
+ {
+ "id": "09a3e250-940a-4f52-8595-e6268ffd7198",
+ "pod_id": null,
+ "name": "usb",
+ "selector": "usb",
+ "version": "0.1.0",
+ "has_message_feature": false,
+ "status": "RUNNING",
+ "created_at": "2020-04-11T18:41:40.053Z",
+ "updated_at": "2020-10-30T07:44:07.660Z"
+ },
+ {
+ "id": "366fd9d7-bfbf-4c13-bd8c-4cc777799142",
+ "pod_id": null,
+ "name": "xiaomi",
+ "selector": "xiaomi",
+ "version": "0.1.0",
+ "has_message_feature": false,
+ "status": "RUNNING",
+ "created_at": "2020-04-11T18:41:40.055Z",
+ "updated_at": "2020-10-30T07:44:07.474Z"
+ },
+ {
+ "id": "3772bbf5-b1d7-441f-9bd4-ef94920e31cd",
+ "pod_id": null,
+ "name": "zwave",
+ "selector": "zwave",
+ "version": "0.1.0",
+ "has_message_feature": false,
+ "status": "RUNNING",
+ "created_at": "2020-04-11T18:41:40.056Z",
+ "updated_at": "2020-10-30T07:44:07.594Z"
+ },
+ {
+ "id": "7355bc7f-4109-40ba-819f-fb03f91969b0",
+ "pod_id": null,
+ "name": "tasmota",
+ "selector": "tasmota",
+ "version": "0.1.0",
+ "has_message_feature": false,
+ "status": "RUNNING",
+ "created_at": "2020-04-11T18:41:40.056Z",
+ "updated_at": "2020-10-30T07:44:07.627Z"
+ },
+ {
+ "id": "2e0bc58b-11e2-4176-8ad3-9ebc8cdd2318",
+ "pod_id": null,
+ "name": "mqtt",
+ "selector": "mqtt",
+ "version": "0.1.0",
+ "has_message_feature": false,
+ "status": "ERROR",
+ "created_at": "2020-04-11T18:41:40.057Z",
+ "updated_at": "2020-10-30T07:44:07.785Z"
+ },
+ {
+ "id": "d97ba3fa-872f-4ecc-879f-46c55a2930c6",
+ "pod_id": null,
+ "name": "google-actions",
+ "selector": "google-actions",
+ "version": "0.1.0",
+ "has_message_feature": false,
+ "status": "UNKNOWN",
+ "created_at": "2020-04-11T18:41:40.111Z",
+ "updated_at": "2020-04-11T18:41:40.111Z"
+ },
+ {
+ "id": "6d3c7a63-e4b8-4650-bcd3-50cf42b2996f",
+ "pod_id": null,
+ "name": "caldav",
+ "selector": "caldav",
+ "version": "0.1.0",
+ "has_message_feature": false,
+ "status": "RUNNING",
+ "created_at": "2020-04-16T19:38:21.885Z",
+ "updated_at": "2020-10-30T07:44:07.558Z"
+ },
+ {
+ "id": "39a278e9-66da-47cb-bdaa-264ba6418091",
+ "pod_id": null,
+ "name": "openweather",
+ "selector": "openweather",
+ "version": "0.1.0",
+ "has_message_feature": false,
+ "status": "RUNNING",
+ "created_at": "2020-08-19T13:04:57.309Z",
+ "updated_at": "2020-10-30T07:44:07.814Z"
+ },
+ {
+ "id": "9682e167-e07f-4823-bd31-a60f957842e0",
+ "pod_id": null,
+ "name": "broadlink",
+ "selector": "broadlink",
+ "version": "0.1.0",
+ "has_message_feature": false,
+ "status": "UNKNOWN",
+ "created_at": "2020-08-30T15:55:19.467Z",
+ "updated_at": "2020-08-30T15:55:19.467Z"
+ },
+ {
+ "id": "d6ea610f-1e33-4c08-89a3-1c8be2cc45f9",
+ "pod_id": null,
+ "name": "bluetooth",
+ "selector": "bluetooth",
+ "version": "0.1.0",
+ "has_message_feature": false,
+ "status": "LOADING",
+ "created_at": "2020-09-02T12:35:32.763Z",
+ "updated_at": "2020-10-18T09:28:14.935Z"
+ },
+ {
+ "id": "c9fe2705-35dc-417b-b6fc-c4bbb9c69886",
+ "pod_id": null,
+ "name": "tp-link",
+ "selector": "tp-link",
+ "version": "0.1.0",
+ "has_message_feature": false,
+ "status": "RUNNING",
+ "created_at": "2020-11-11T18:41:40.052Z",
+ "updated_at": "2020-11-28T07:44:07.731Z"
+ }
+ ],
+ "get /api/v1/session": [
+ {
+ "id": "4b249694-661b-4c48-afb5-924bbedcee63",
+ "token_type": "refresh_token",
+ "scope": ["dashboard:write", "dashboard:read"],
+ "valid_until": "2019-07-26T01:00:50.137Z",
+ "last_seen": null,
+ "revoked": false,
+ "useragent": "Mozilla/5.0 (Linux; Android 6.0.1; SHIELD Tablet K1 Build/MRA58K; wv) AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/55.0.2883.91 Safari/537.36",
+ "created_at": "2019-06-26T01:00:50.138Z",
+ "updated_at": "2019-06-26T01:00:50.138Z"
+ },
+ {
+ "id": "2367a8cf-47a8-4db7-83b0-f89c2c6c34ac",
+ "token_type": "refresh_token",
+ "scope": ["dashboard:write", "dashboard:read"],
+ "valid_until": "2019-07-26T00:29:00.783Z",
+ "last_seen": null,
+ "revoked": false,
+ "useragent": "Mozilla/5.0 (iPhone; CPU iPhone OS 12_0 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/12.0 Mobile/15E148 Safari/604.1",
+ "created_at": "2019-06-26T00:29:00.783Z",
+ "updated_at": "2019-06-26T00:29:00.783Z"
+ },
+ {
+ "id": "2367a8cf-47a8-4db7-83b0-f89c2c6c34ac",
+ "token_type": "refresh_token",
+ "scope": ["dashboard:write", "dashboard:read"],
+ "valid_until": "2019-07-26T00:29:00.783Z",
+ "last_seen": null,
+ "revoked": false,
+ "useragent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.246",
+ "created_at": "2019-06-26T00:29:00.783Z",
+ "updated_at": "2019-06-26T00:29:00.783Z"
+ },
+ {
+ "id": "2367a8cf-47a8-4db7-83b0-f89c2c6c34ac",
+ "token_type": "refresh_token",
+ "scope": ["dashboard:write", "dashboard:read"],
+ "valid_until": "2019-07-26T00:29:00.783Z",
+ "last_seen": null,
+ "revoked": false,
+ "created_at": "2019-06-26T00:29:00.783Z",
+ "updated_at": "2019-06-26T00:29:00.783Z"
+ }
+ ],
+ "get /api/v1/setup": {
+ "account_configured": true
+ },
+ "get /api/v1/service/xiaomi/sensor": [
+ {
+ "name": "Xiaomi Temperature",
+ "external_id": "xiaomi:1234",
+ "selector": "xiaomi:1234",
+ "features": [
+ {
+ "name": "Temperature",
+ "selector": "xiaomi:12344:temperature",
+ "external_id": "xiaomi:12344:temperature",
+ "category": "temperature-sensor",
+ "type": "decimal",
+ "unit": "celsius",
+ "read_only": true,
+ "keep_history": true,
+ "has_feedback": true,
+ "min": -20,
+ "max": 60
+ },
+ {
+ "name": "Humidity",
+ "selector": "xiaomi:12344:humidity",
+ "external_id": "xiaomi:12344:humidity",
+ "category": "humidity-sensor",
+ "type": "decimal",
+ "unit": "percent",
+ "read_only": true,
+ "keep_history": true,
+ "has_feedback": true,
+ "min": 0,
+ "max": 100
+ },
+ {
+ "name": "Battery",
+ "selector": "xiaomi:12344:battery",
+ "external_id": "xiaomi:12344:battery",
+ "category": "battery",
+ "type": "integer",
+ "unit": "percent",
+ "read_only": true,
+ "keep_history": true,
+ "has_feedback": true,
+ "min": 0,
+ "max": 100
+ }
+ ]
+ }
+ ],
+ "get /api/v1/service/xiaomi/device": [
+ {
+ "id": "e5317b24-28e1-4839-9879-0bb7a3102e98",
+ "name": "Xiaomi Temperature",
+ "external_id": "xiaomi:1234",
+ "selector": "xiaomi:1234",
+ "room_id": "f99ab22a-e6a8-4756-b1fe-4d19dc8c8620",
+ "service_id": "70cb1e17-3b17-4886-83ab-45b00a9e03b1",
+ "features": [
+ {
+ "name": "Temperature",
+ "selector": "xiaomi:12344:temperature",
+ "external_id": "xiaomi:12344:temperature",
+ "category": "temperature-sensor",
+ "type": "decimal",
+ "unit": "celsius",
+ "read_only": true,
+ "keep_history": true,
+ "has_feedback": true,
+ "min": -20,
+ "max": 60
+ },
+ {
+ "name": "Humidity",
+ "selector": "xiaomi:12344:humidity",
+ "external_id": "xiaomi:12344:humidity",
+ "category": "humidity-sensor",
+ "type": "decimal",
+ "unit": "percent",
+ "read_only": true,
+ "keep_history": true,
+ "has_feedback": true,
+ "min": 0,
+ "max": 100
+ },
+ {
+ "name": "Battery",
+ "selector": "xiaomi:12344:battery",
+ "external_id": "xiaomi:12344:battery",
+ "category": "battery",
+ "type": "integer",
+ "unit": "percent",
+ "read_only": true,
+ "keep_history": true,
+ "has_feedback": true,
+ "min": 0,
+ "max": 100
+ }
+ ]
+ }
+ ],
+ "get /api/v1/device": [
+ {
+ "id": "06e735a3-ac62-4a05-85b6-855f2c556d7b",
+ "name": "Living room lamp",
+ "selector": "light",
+ "features": [
+ {
+ "name": "Living room lamp",
+ "type": "binary",
+ "selector": "light.binary",
+ "category": "light"
+ }
+ ]
+ }
+ ],
+ "get /api/v1/service/xiaomi": {
+ "id": "70cb1e17-3b17-4886-83ab-45b00a9e03b1",
+ "name": "Xiaomi",
+ "selector": "xiaomi"
+ },
+ "get /api/v1/device/zwave:1234": {
+ "id": "fbedb47f-4d25-4381-8923-2633b23192a0",
+ "service_id": "a810b8db-6d04-4697-bed3-c4b72c996279",
+ "room_id": "cecc52c7-3e67-4b75-9b13-9a8867b0443d",
+ "name": "Fibaro Motion Sensor",
+ "selector": "zwave:1234",
+ "external_id": "test-sensor-external",
+ "should_poll": false,
+ "poll_frequency": null,
+ "created_at": "2019-02-12T07:49:07.556Z",
+ "updated_at": "2019-02-12T07:49:07.556Z",
+ "features": [
+ {
+ "name": "Temperature",
+ "external_id": "zwave:1234:temperature",
+ "selector": "test-temperature",
+ "category": "temperature-sensor",
+ "unit": "celsius",
+ "type": "decimal"
+ },
+ {
+ "name": "Motion",
+ "selector": "test-motion",
+ "external_id": "zwave:1234:temperature",
+ "category": "motion-sensor",
+ "type": "binary"
+ },
+ {
+ "name": "Battery",
+ "selector": "test-battery",
+ "external_id": "zwave:1234:temperature",
+ "category": "battery",
+ "type": "integer",
+ "last_value": "92"
+ },
+ {
+ "name": "Lux",
+ "selector": "test-light",
+ "external_id": "zwave:1234:temperature",
+ "category": "light-sensor",
+ "type": "integer"
+ }
+ ],
+ "room": {
+ "id": "cecc52c7-3e67-4b75-9b13-9a8867b0443d",
+ "name": "Living Room",
+ "selector": "living-room"
+ }
+ },
+ "get /api/v1/service/zwave": {
+ "id": "a810b8db-6d04-4697-bed3-c4b72c996279",
+ "name": "Zwave",
+ "selector": "zwave"
+ },
+ "get /api/v1/device/xiaomi:1234": {
+ "id": "e5317b24-28e1-4839-9879-0bb7a3102e98",
+ "name": "Xiaomi Temperature",
+ "external_id": "xiaomi:1234",
+ "selector": "xiaomi:1234",
+ "room_id": "f99ab22a-e6a8-4756-b1fe-4d19dc8c8620",
+ "service_id": "70cb1e17-3b17-4886-83ab-45b00a9e03b1",
+ "features": [
+ {
+ "name": "Temperature",
+ "selector": "xiaomi:12344:temperature",
+ "external_id": "xiaomi:12344:temperature",
+ "category": "temperature-sensor",
+ "type": "decimal",
+ "unit": "celsius",
+ "read_only": true,
+ "keep_history": true,
+ "has_feedback": true,
+ "min": -20,
+ "max": 60
+ },
+ {
+ "name": "Humidity",
+ "selector": "xiaomi:12344:humidity",
+ "external_id": "xiaomi:12344:humidity",
+ "category": "humidity-sensor",
+ "type": "decimal",
+ "unit": "percent",
+ "read_only": true,
+ "keep_history": true,
+ "has_feedback": true,
+ "min": 0,
+ "max": 100
+ },
+ {
+ "name": "Battery",
+ "selector": "xiaomi:12344:battery",
+ "external_id": "xiaomi:12344:battery",
+ "category": "battery",
+ "type": "integer",
+ "unit": "percent",
+ "read_only": true,
+ "keep_history": true,
+ "has_feedback": true,
+ "min": 0,
+ "max": 100
+ }
+ ]
+ },
+ "get /api/v1/service/philips-hue": {
+ "id": "1147bdef-0c95-40f1-a7ef-922ebcad7d0e",
+ "name": "Philips Hue",
+ "selector": "philips-hue"
+ },
+ "get /api/v1/service/philips-hue/light": [
+ {
+ "id": "1",
+ "name": "New Lamp",
+ "model": "LCT007",
+ "external_id": "philips-hue:4"
+ },
+ {
+ "id": "2",
+ "name": "Living room lamp",
+ "model": "LCT007",
+ "external_id": "philips-hue:5"
+ }
+ ],
+ "get /api/v1/service/philips-hue/device": [
+ {
+ "id": "1",
+ "name": "Lounge Living Color",
+ "model": "LCT007",
+ "external_id": "philips-hue:1",
+ "features": [
+ {
+ "name": "On/Off",
+ "category": "light",
+ "type": "binary",
+ "min": 0,
+ "max": 1
+ },
+ {
+ "name": "Color",
+ "category": "light",
+ "type": "color",
+ "min": 0,
+ "max": 1
+ }
+ ]
+ },
+ {
+ "id": "2",
+ "name": "Right Bedside",
+ "type": "Extended color light",
+ "model": "LCT001",
+ "external_id": "philips-hue:2",
+ "features": [
+ {
+ "name": "On/Off",
+ "category": "light",
+ "type": "binary",
+ "min": 0,
+ "max": 1
+ },
+ {
+ "name": "Color",
+ "category": "light",
+ "type": "color",
+ "min": 0,
+ "max": 1
+ }
+ ]
+ },
+ {
+ "id": "3",
+ "name": "Left Bedside",
+ "type": "Extended color light",
+ "model": "LCT001",
+ "external_id": "philips-hue:3",
+ "features": [
+ {
+ "name": "On/Off",
+ "category": "light",
+ "type": "binary",
+ "min": 0,
+ "max": 1
+ },
+ {
+ "name": "Color",
+ "category": "light",
+ "type": "color",
+ "min": 0,
+ "max": 1
+ }
+ ]
+ }
+ ],
+ "get /api/v1/service/bluetooth": {
+ "id": "a810b8db-6d04-4697-bed3-c4b72c996279",
+ "name": "bluetooth",
+ "enabled": true
+ },
+ "get /api/v1/service/bluetooth/config": {
+ "presenceScanner": {
+ "status": "enabled",
+ "frequency": 60000
+ }
+ },
+ "get /api/v1/service/bluetooth/device": [
+ {
+ "id": "fbedb47f-4d25-4381-8923-2633b23192a0",
+ "service_id": "a810b8db-6d04-4697-bed3-c4b72c996279",
+ "room_id": "cecc52c7-3e67-4b75-9b13-9a8867b0443d",
+ "name": "Nut Smart Tracker",
+ "selector": "bluetooth-sensor",
+ "external_id": "test-sensor-external",
+ "should_poll": false,
+ "poll_frequency": null,
+ "created_at": "2019-02-12T07:49:07.556Z",
+ "updated_at": "2019-02-12T07:49:07.556Z",
+ "features": [
+ {
+ "name": "Battery",
+ "selector": "test-battery",
+ "category": "battery",
+ "type": "integer",
+ "last_value": "12"
+ }
+ ],
+ "room": {
+ "id": "cecc52c7-3e67-4b75-9b13-9a8867b0443d",
+ "name": "Living Room",
+ "selector": "living-room"
+ }
+ }
+ ],
+ "get /api/v1/device/bluetooth-sensor": {
+ "id": "fbedb47f-4d25-4381-8923-2633b23192a0",
+ "service_id": "a810b8db-6d04-4697-bed3-c4b72c996279",
+ "room_id": "cecc52c7-3e67-4b75-9b13-9a8867b0443d",
+ "name": "Nut Smart Tracker",
+ "selector": "bluetooth-sensor",
+ "external_id": "bluetooth:external",
+ "should_poll": false,
+ "poll_frequency": null,
+ "created_at": "2019-02-12T07:49:07.556Z",
+ "updated_at": "2019-02-12T07:49:07.556Z",
+ "features": [
+ {
+ "name": "Battery",
+ "selector": "test-battery",
+ "category": "battery",
+ "type": "integer",
+ "last_value": "12"
+ }
+ ],
+ "room": {
+ "id": "cecc52c7-3e67-4b75-9b13-9a8867b0443d",
+ "name": "Living Room",
+ "selector": "living-room"
+ }
+ },
+ "get /api/v1/service/bluetooth/status": {
+ "ready": true
+ },
+ "get /api/v1/service/bluetooth/peripheral": [
+ {
+ "name": "BLE Device 1",
+ "external_id": "bluetooth:0011223341",
+ "service_id": "a810b8db-6d04-4697-bed3-c4b72c996279",
+ "selector": "bluetooth-0011223341",
+ "params": [
+ {
+ "name": "loaded",
+ "value": false
+ }
+ ]
+ },
+ {
+ "name": "SML c9",
+ "model": "smlc9",
+ "external_id": "bluetooth:0011223342",
+ "selector": "bluetooth-0011223342",
+ "params": [
+ {
+ "name": "loaded",
+ "value": true
+ },
+ {
+ "name": "manufacturer",
+ "value": "AwoX"
+ }
+ ]
+ },
+ {
+ "name": "Peanut temperature",
+ "external_id": "bluetooth:0011223343",
+ "service_id": "a810b8db-6d04-4697-bed3-c4b72c996278",
+ "service": {
+ "name": "peanut"
+ },
+ "selector": "bluetooth-0011223343",
+ "params": [
+ {
+ "name": "loaded",
+ "value": true
+ },
+ {
+ "name": "manufacturer",
+ "value": "Peanut"
+ }
+ ],
+ "features": [
+ {
+ "name": "Battery",
+ "category": "battery",
+ "type": "integer",
+ "unit": "percent",
+ "read_only": true,
+ "keep_history": true,
+ "has_feedback": true,
+ "min": 0,
+ "max": 100
+ },
+ {
+ "name": "Temperature",
+ "category": "temperature-sensor",
+ "type": "decimal",
+ "read_only": true,
+ "keep_history": true,
+ "has_feedback": true,
+ "min": -100,
+ "max": 250
+ }
+ ]
+ }
+ ],
+ "get /api/v1/service/bluetooth/peripheral/bluetooth-0011223341": {
+ "name": "BLE Device 1",
+ "external_id": "bluetooth:0011223341",
+ "selector": "bluetooth-0011223341",
+ "params": [
+ {
+ "name": "loaded",
+ "value": false
+ }
+ ]
+ },
+ "get /api/v1/service/bluetooth/peripheral/bluetooth-0011223342": {
+ "name": "SML c9",
+ "model": "smlc9",
+ "external_id": "bluetooth:0011223342",
+ "selector": "bluetooth-0011223342",
+ "params": [
+ {
+ "name": "loaded",
+ "value": true
+ },
+ {
+ "name": "manufacturer",
+ "value": "AwoX"
+ }
+ ]
+ },
+ "get /api/v1/service/bluetooth/peripheral/bluetooth-0011223343": {
+ "name": "Peanut temperature",
+ "external_id": "bluetooth:0011223343",
+ "selector": "bluetooth-0011223343",
+ "params": [
+ {
+ "name": "loaded",
+ "value": true
+ },
+ {
+ "name": "manufacturer",
+ "value": "Peanut"
+ }
+ ],
+ "features": [
+ {
+ "name": "Battery",
+ "category": "battery",
+ "type": "integer",
+ "unit": "percent",
+ "read_only": true,
+ "keep_history": true,
+ "has_feedback": true,
+ "min": 0,
+ "max": 100
+ },
+ {
+ "name": "Temperature",
+ "category": "temperature-sensor",
+ "type": "decimal",
+ "read_only": true,
+ "keep_history": true,
+ "has_feedback": true,
+ "min": -100,
+ "max": 250
+ }
+ ]
+ },
+ "get /api/v1/service/ewelink": {
+ "id": "45c792a5-051b-4e6f-b746-2dd4c77d9d31",
+ "name": "ewelink",
+ "selector": "ewelink"
+ },
+ "get api/v1/service/ewelink/device": [
+ {
+ "id": "28e8ad03-70a8-431f-93cb-df916019c509",
+ "room_id": "568981d0-1a4d-40ea-af97-dd4037d2b344",
+ "name": "Switch 1",
+ "selector": "ewelink-1000768322-0",
+ "model": "MINI",
+ "external_id": "ewelink:1000768322:0",
+ "should_poll": true,
+ "poll_frequency": 60000,
+ "features": [
+ {
+ "id": "6f8172ed-37e5-4785-94ad-ec33706a31f3",
+ "device_id": "28e8ad03-70a8-431f-93cb-df916019c509",
+ "name": "Switch 1 On/Off",
+ "selector": "ewelink-1000768322-0-binary",
+ "external_id": "ewelink:1000768322:0:binary",
+ "category": "switch",
+ "type": "binary",
+ "read_only": false,
+ "has_feedback": false,
+ "min": 0,
+ "max": 1
+ }
+ ],
+ "params": [
+ {
+ "id": "5e1ef948-305b-44c5-bb78-78952b1f5cb2",
+ "device_id": "28e8ad03-70a8-431f-93cb-df916019c509",
+ "name": "IP_ADDRESS",
+ "value": "0.0.0.1"
+ },
+ {
+ "id": "f3a6f3fa-a7b0-4968-b9fd-2e492ced2274",
+ "device_id": "28e8ad03-70a8-431f-93cb-df916019c509",
+ "name": "FIRMWARE",
+ "value": "3.3.0"
+ }
+ ],
+ "room": {
+ "id": "cecc52c7-3e67-4b75-9b13-9a8867b0443d",
+ "name": "Living Room",
+ "selector": "living-room"
+ },
+ "service": {
+ "id": "45c792a5-051b-4e6f-b746-2dd4c77d9d31",
+ "name": "ewelink",
+ "selector": "ewelink"
+ }
+ }
+ ],
+ "get api/v1/service/ewelink/discover": [
+ {
+ "service_id": "45c792a5-051b-4e6f-b746-2dd4c77d9d31",
+ "name": "Switch 2",
+ "model": "Basic",
+ "external_id": "ewelink:10004636bf:0",
+ "selector": "ewelink:10004636bf:0",
+ "should_poll": true,
+ "poll_frequency": 60000,
+ "features": [
+ {
+ "name": "Switch 2 On/Off",
+ "external_id": "ewelink:10004636bf:0:binary",
+ "selector": "ewelink:10004636bf:0:binary",
+ "category": "switch",
+ "type": "binary",
+ "read_only": false,
+ "has_feedback": false,
+ "min": 0,
+ "max": 1
+ }
+ ],
+ "params": [
+ {
+ "name": "IP_ADDRESS",
+ "value": "0.0.0.2"
+ },
+ {
+ "name": "FIRMWARE",
+ "value": "3.2.1"
+ }
+ ]
+ }
+ ],
+ "get /api/v1/service/tp-link": {
+ "id": "c9fe2705-35dc-417b-b6fc-c4bbb9c69886",
+ "pod_id": null,
+ "name": "tp-link",
+ "selector": "tp-link",
+ "version": "0.1.0",
+ "has_message_feature": false,
+ "status": "RUNNING",
+ "created_at": "2020-11-11T18:41:40.052Z",
+ "updated_at": "2020-11-28T07:44:07.731Z"
+ },
+ "get /api/v1/service/tp-link/device": [
+ {
+ "id": "1",
+ "name": "Plug Coffee Machine",
+ "model": "HS100",
+ "external_id": "tp-link-1",
+ "features": [
+ {
+ "name": "On/Off",
+ "category": "switch",
+ "type": "binary",
+ "min": 0,
+ "max": 1
+ }
+ ]
+ },
+ {
+ "id": "2",
+ "name": "Light Swimming Pool",
+ "model": "LB100",
+ "external_id": "tp-link-2",
+ "features": [
+ {
+ "name": "On/Off",
+ "category": "light",
+ "type": "binary",
+ "min": 0,
+ "max": 1
+ }
+ ]
+ }
+ ],
+ "get /api/v1/service/tp-link/scan": [
+ {
+ "id": "3",
+ "name": "Plug TV Dock",
+ "model": "HS100",
+ "external_id": "tp-link-3",
+ "features": [
+ {
+ "name": "On/Off",
+ "category": "switch",
+ "type": "binary",
+ "min": 0,
+ "max": 1
+ }
+ ]
+ },
+ {
+ "id": "4",
+ "name": "Light Bedroom",
+ "model": "LB100",
+ "external_id": "tp-link-4",
+ "features": [
+ {
+ "name": "On/Off",
+ "category": "light",
+ "type": "binary",
+ "min": 0,
+ "max": 1
+ }
+ ]
+ }
+ ]
+}
diff --git a/front/src/routes/integration/all/zigbee2mqtt/discover-page/actions.js b/front/src/routes/integration/all/zigbee2mqtt/discover-page/actions.js
index 79859ca114..37ba70c890 100644
--- a/front/src/routes/integration/all/zigbee2mqtt/discover-page/actions.js
+++ b/front/src/routes/integration/all/zigbee2mqtt/discover-page/actions.js
@@ -13,7 +13,7 @@ function createActions(store) {
});
try {
- const zigbee2mqttDevices = await state.httpClient.get('/api/v1/service/zigbee2mqtt/device');
+ const zigbee2mqttDevices = await state.httpClient.get('/api/v1/service/zigbee2mqtt/discovered');
store.setState({ zigbee2mqttDevices, discoverZigbee2mqtt: false });
} catch (e) {
store.setState({
diff --git a/server/services/zigbee2mqtt/api/zigbee2mqtt.controller.js b/server/services/zigbee2mqtt/api/zigbee2mqtt.controller.js
index 31a1e85915..c14929a254 100644
--- a/server/services/zigbee2mqtt/api/zigbee2mqtt.controller.js
+++ b/server/services/zigbee2mqtt/api/zigbee2mqtt.controller.js
@@ -3,7 +3,7 @@ const logger = require('../../../utils/logger');
module.exports = function Zigbee2mqttController(gladys, zigbee2mqttManager) {
/**
- * @api {get} /api/v1/service/zigbee2mqtt/device Get discovered Zigbee2mqtt devices
+ * @api {get} /api/v1/service/zigbee2mqtt/discovered Get discovered Zigbee2mqtt devices
* @apiName getDiscoveredDevices
* @apiGroup Zigbee2mqtt
*/
@@ -101,7 +101,7 @@ module.exports = function Zigbee2mqttController(gladys, zigbee2mqttManager) {
}
return {
- 'get /api/v1/service/zigbee2mqtt/device': {
+ 'get /api/v1/service/zigbee2mqtt/discovered': {
authenticated: true,
controller: asyncMiddleware(getDiscoveredDevices),
},
diff --git a/server/test/services/zigbee2mqtt/api/zigbee2mqtt.controller.test.js b/server/test/services/zigbee2mqtt/api/zigbee2mqtt.controller.test.js
index 8397994f81..cb2de44cfa 100644
--- a/server/test/services/zigbee2mqtt/api/zigbee2mqtt.controller.test.js
+++ b/server/test/services/zigbee2mqtt/api/zigbee2mqtt.controller.test.js
@@ -29,13 +29,13 @@ describe('zigbee2mqtt API', () => {
sinon.reset();
});
- it('get /api/v1/service/zigbee2mqtt/device', async () => {
+ it('get /api/v1/service/zigbee2mqtt/discovered', async () => {
const req = {};
const res = {
json: fake.returns(null),
};
- await controller['get /api/v1/service/zigbee2mqtt/device'].controller(req, res);
+ await controller['get /api/v1/service/zigbee2mqtt/discovered'].controller(req, res);
assert.calledOnce(zigbee2mqttManager.getDiscoveredDevices);
assert.calledWith(res.json, ['device']);
From 27ca5d2878148da75ab4eafa2b1154b63034baa2 Mon Sep 17 00:00:00 2001
From: atrovato <1839717+atrovato@users.noreply.github.com>
Date: Mon, 1 Nov 2021 08:33:59 +0100
Subject: [PATCH 9/9] remove formaldehyd
---
server/services/zigbee2mqtt/exposes/numericType.js | 6 ------
1 file changed, 6 deletions(-)
diff --git a/server/services/zigbee2mqtt/exposes/numericType.js b/server/services/zigbee2mqtt/exposes/numericType.js
index ce2cd9b9bd..fef9b07957 100644
--- a/server/services/zigbee2mqtt/exposes/numericType.js
+++ b/server/services/zigbee2mqtt/exposes/numericType.js
@@ -100,12 +100,6 @@ module.exports = {
unit: DEVICE_FEATURE_UNITS.KILOWATT_HOUR,
},
},
- formaldehyd: {
- feature: {
- category: DEVICE_FEATURE_CATEGORIES.SMOKE_SENSOR,
- type: DEVICE_FEATURE_TYPES.SENSOR.DECIMAL,
- },
- },
gas: {
feature: {
category: DEVICE_FEATURE_CATEGORIES.SMOKE_SENSOR,