diff --git a/README.md b/README.md index f9b040f..c800731 100644 --- a/README.md +++ b/README.md @@ -7,16 +7,26 @@ Доступна бета-версия на ветке `beta`. Для установки выполнить команду `git clone -b beta https://github.com/lasthead0/yandex2mqtt.git`. Подробности изменений и документация в `README` ветки `beta`. ## Важно -Те, кто пользуется оригинальным проектом (или его форками), обратите внимание на то, что немного изменились настройки устройств (блок **devices** в файле конфигурации). +Те, кто пользуется оригинальным проектом (или его форками), обратите внимание на то, что немного изменились настройки устройств (блок `devices` в файле конфигурации). На данный момент проверено получение температуры и влажности с датчиков (датчики дверей и движения пока в бета-тесте), и включение/выключение света (вкл./выкл. других устройств по аналогии тоже должно работать). Прочий функционал (изменение громкости, каналов, отключение звука), поидее, так же должны работать. ## ChangeLog +###### 16.05.2021 +Добавлено логирование некоторых событий. + +###### 13.05.2021 +Добавлена поддержка API уведомлений об изменении состояний устройств. + +###### 31.03.2021 +Добавлена поддрежка разделения доступа пользователей к устройствам. + +###### Release Проведён рефакторинг кода и, местами, внесены значительные правки. -Добавлена поддержка датчиков (устройств **devices.types.sensor**) +Добавлена поддержка датчиков (устройств `devices.types.sensor`) ## Требования - **"Белый" IP адрес и домен**. Если нет своего домена и белого IP адреса можно воспользоваться Dynamic DNS сервисами (например, noip.com). @@ -55,14 +65,20 @@ npm start ``` ## Настройка yandex2mqtt -Все основные настройки моста прописываются в файл config.js. Перед запуском обязательно отредактируйте его. +Все основные настройки моста прописываются в файл `config.js`. Перед запуском обязательно отредактируйте его. ``` mv config.orig.js config.js ``` -**Файл конфигурации** +#### Файл конфигурации ``` module.exports = { + notification: [ + { + ... + }, + ... + ] mqtt: { ... }, @@ -75,34 +91,37 @@ module.exports = { { ... }, + ... ], users: [ { ... }, + ... ], devices: [ { ... }, + ... ] } ``` -**Блок настройки mqtt клиента** +###### Блок настройки mqtt клиента Указать данные Вашего MQTT сервера ``` mqtt: { - host: 'localhost', - port: 1883, - user: 'user', - password: 'password' + host: 'localhost', + port: 1883, + user: 'user', + password: 'password', }, ``` -**Блок настройки https сервера** +###### Блок настройки https сервера Указать порт, на котором будет работать мост, а так же пути к сертификату ssl. ``` https: { @@ -112,125 +131,204 @@ https: { }, ``` -**Блок настройки клиентов** +###### Блок настройки клиентов Здесь используются произвольные данные, далее они понадобятся для подключения к УД Yandex. ``` clients: [ - { - id: '1', - name: 'Yandex', - clientId: 'client', - clientSecret: 'secret', - isTrusted: false - }, + { + id: '1', + name: 'Yandex', + clientId: 'client', + clientSecret: 'secret', + isTrusted: false, + }, ], ``` -**Блок настройки пользователей** +###### Блок настройки пользователей ``` users: [ - { - id: "1", - username: "admin", - password: "admin", - name: "Administrator" - }, - { - id: "2", - username: "user1", - password: "user1", - name: "User" - }, + { + id: '1', + username: 'admin', + password: 'admin', + name: 'Administrator', + }, + { + id: '2', + username: 'user1', + password: 'user1', + name: 'User', + }, ], ``` -**Блок настройки устройств** +###### Блок настройки устройств ``` devices: [ - { - id: "lvr-003-switch", - name: "Основной свет", - room: "Гостиная", - type: "devices.types.light", - mqtt: [ - { - instance: "on", - set: "/yandex/controls/light_LvR_003/state/on", - state: "/yandex/controls/light_LvR_003/state" - }, - ], - /* mapping значений между yandex и УД */ - valueMapping: [ - { - type: "on_off", - mapping: [[false, true], [0, 1]] // [yandex, mqtt] - } - ], - capabilities: [ - { - type: "devices.capabilities.on_off", - retrievable: true, - }, - ], - }, + { + id: 'haw-002-switch', + name: 'Свет в коридоре', + room: 'Коридор', + type: 'devices.types.light', + allowedUsers: ['2'], + mqtt: [ + { + instance: 'on', + set: '/yandex/controls/light_HaW_002/on', + state: '/yandex/controls/light_HaW_002/on/state', + }, + ], + capabilities: [ + { + type: 'devices.capabilities.on_off', + retrievable: true, + }, + ], + }, - { - id: "lvr-001-weather", - name: "В гостиной", - room: "Гостиная", - type: "devices.types.sensor", - mqtt: [ - { - instance: "temperature", - state: "/yandex/sensors/LvR_001_Weather/temperature" - }, - { - instance: "humidity", - state: "/yandex/sensors/LvR_001_Weather/humidity" - } - ], - properties: [ - { - type: "devices.properties.float", - retrievable: true, - parameters: { - instance: "temperature", - unit: "unit.temperature.celsius" - }, - }, - { - type: "devices.properties.float", - retrievable: true, - parameters: { - instance: "humidity", - unit: "unit.percent" - }, - /* Блок state указывать не обязательно */ - state: { - instance: "humidity", - value: 0 - } - } - ] - }, - /* --- end */ -] + { + id: 'lvr-003-switch', + name: 'Основной свет', + room: 'Гостиная', + type: 'devices.types.light', + allowedUsers: ['2'], + mqtt: [ + { + instance: 'on', + set: '/yandex/controls/light_LvR_003/on', + state: '/yandex/controls/light_LvR_003/on/state', + }, + ], + valueMapping: [ + { + type: 'on_off', + mapping: [[false, true], [0, 1]], // [yandex, mqtt] + }, + ], + capabilities: [ + { + type: 'devices.capabilities.on_off', + retrievable: true, + }, + ], + }, + + { + id: 'lvr-001-weather', + name: 'В гостиной', + room: 'Гостиная', + type: 'devices.types.sensor', + allowedUsers: ['2'], + mqtt: [ + { + instance: 'temperature', + state: '/yandex/sensors/LvR_001_Weather/temperature', + }, + { + instance: 'humidity', + state: '/yandex/sensors/LvR_001_Weather/humidity', + }, + ], + properties: [ + { + type: 'devices.properties.float', + retrievable: true, + parameters: { + instance: 'temperature', + unit: 'unit.temperature.celsius', + }, + }, + { + type: 'devices.properties.float', + retrievable: true, + parameters: { + instance: 'humidity', + unit: 'unit.percent', + }, + }, + ], + }, + + { + id: 'plug-001-flower', + name: 'Розетка для цветка', + room: 'Гостиная', + type: 'devices.types.socket', + allowedUsers: ['2'], + mqtt: [ + { + instance: 'on', + set: '/yandex/controls/socket_LvR_002/on', + state: '/yandex/controls/socket_LvR_002/on/state', + }, + { + instance: 'power', + state: '/yandex/controls/socket_LvR_002/power', + }, + ], + capabilities: [ + { + type: 'devices.capabilities.on_off', + retrievable: true, + }, + ], + properties: [ + { + type: 'devices.properties.float', + retrievable: true, + parameters: { + instance: 'power', + unit: 'unit.watt', + }, + }, + ], + }, + /* --- end */ +], ``` -*Рекомендую указывать id в конфиге, чтобы исключить "наложение" новых устройств на "старые", которые уже добавлены в yandex.* +*Рекомендую указывать id в конфиге, чтобы исключить "наложение" новых устройств на "старые", которые уже добавлены в навык.* *В случае отсутсвия id в конфиге, он будет назначен автоматически по индексу в массиве.* -###### Mapping значений -Блок valueMapping позволяет настроить конвертацию значений между yandex api и MQTT. Это может быть актуально для умений типа **devices.capabilities.on_off** и **devices.capabilities.toggle**. +#### Уведомление об изменении состояний устройств +Платформа УД Яндекс предоставляет сервис уведомлений об изменении состояний устройств. При изменении состояния устройства (например, изменение влажности) yandex2mqtt будет отправлять запрос с новым состоянием. + +В настройках предусмотрен блок `notification`. + +``` +notification: [ + { + skill_id: '6fca0a54-a505-4420-b774-f01da95e5c31', + oauth_token: 'AQA11AAPv-V2BAT7o_ps6gEtrtNNjlE2ENYt96w', + user_id: '2' + }, +] +``` + +Если к yandex2mqtt "подключено" несколько навыков УД, то в массиве необходимо указать настройки для каждого навыка УД, который должен получать уведомления. + +`skill_id` (идентификатор вызываемого навыка, присвоенный при создании) и `oauth_token` (авторизационный токен владельца навыка) можно узнать из документации на [Уведомление об изменении состояний устройств](https://yandex.ru/dev/dialogs/smart-home/doc/reference-alerts/post-skill_id-callback-state.html), а `user_id` - id пользователя в файле конфигурации yandex2mqtt. + +*Важно. Уведомления будут отправляться при изменнии mqtt топика хранящего состояние устройства. Соответственно, если для устройства не задан топик state, то уведомление для устройтва отправляться не будет.* + + +#### Разрешенные пользователи для устройств (allowedUsers) +В блоке конфигурации можно указать пользователей (id пользователей), для которых будет доступно устройство. + +В опции `allowedUsers` указыватся массив (строковых значений) id. Если данная опция не указана, то для неё будет назначено значение ['1']; + +#### Mapping значений +Блок valueMapping позволяет настроить конвертацию значений между yandex api и MQTT. Это может быть актуально для умений типа `devices.capabilities.on_off` и `devices.capabilities.toggle`. *Например, если в УД состояние влючено/выключено соответствует значениям 1/0, то Вам понадобиться их конвертировать, т.к. в навыках Yandex значения true/false.* ``` valueMapping: [ - { - type: "on_off", - mapping: [[false, true], [0, 1]] // [yandex, mqtt] - } -] + { + type: 'on_off', + mapping: [[false, true], [0, 1]], // [yandex, mqtt] + }, +], ``` В mapping указывается миссив массивов. Первый массив - значения в yandex, второй - в MQTT. @@ -239,15 +337,19 @@ valueMapping: [ - [Типы умений устройства](https://yandex.ru/dev/dialogs/alice/doc/smart-home/concepts/capability-types.html) - [Типы встроенных датчиков](https://yandex.ru/dev/dialogs/alice/doc/smart-home/concepts/properties-types.html) +## Логирование +Добавлено две "стратегии" логирования: сообщений об ошибках в файл `log/error.log` (аргумент запуска `--log-error`) и всех сообщений в консоль (`--log-info`). +Для запуска y2m с логирование необходимо добавить аргумент запуска в команду запуска в файле настройки служба (**раздел ниже**) или запустить из консоли. + ## Создание службы -В папке /etc/systemd/system/ создать файл yandex2mqtt.service со следующим содержанем: +В папке `/etc/systemd/system/` создать файл `yandex2mqtt.service` со следующим содержанем: ``` [Unit] Description=yandex2mqtt After=network.target [Service] -ExecStart=/usr/bin/npm start +ExecStart=/usr/bin/node app.js --log-error WorkingDirectory=/opt/yandex2mqtt StandardOutput=inherit StandardError=inherit @@ -275,25 +377,24 @@ service yandex2mqtt restart ``` ## Создание навыка (в Яндекс Диалоги) - Заходим в [Яндекс Диалоги](https://dialogs.yandex.ru/developer) => Создать диалог => Умный дом -###### Основные настройки +#### Основные настройки - **Название** *Любое* - **Backend** *Endpoint URL* и указываем https://your.domain.ru:port/provider - **Тип доступа** *Приватный* -###### Публикация в каталоге +#### Публикация в каталоге - **Подзаголовок** *Любой текст* - **Имя разработчика** *Ваше имя* - **Официальный навык** *Нет* - **Описание** *Любой текст* - **Иконка** *Своя иконка* -###### Связка аккаунтов +#### Связка аккаунтов - **Авторизация** _Кнопка **"Создать"**_ -###### Создание связки аккаунтов +#### Создание связки аккаунтов - **Идентификатор приложения** *Файл конфигурации clients.clientId* - **Секрет приложения** *Файл конфигурации clients.clientSecret* - **URL авторизации** *https://your.domain.ru:port/dialog/authorize* @@ -306,7 +407,7 @@ service yandex2mqtt restart ## Известные "особенности поведения" ioBroker (iob) -###### Не изменяются и не читаются топики MQTT +#### Не изменяются и не читаются топики MQTT Если случается такое, что Алиса получает голосовую команду и не сообщает об ошибке, но при этом топик не меняет своего значения или, при изменении стейта (объекта iob) MQTT топик не публикуется (Алиса не получает нового значения, а сообщает старое) **необходимо перезапустить адаптер mqtt**. @@ -317,4 +418,3 @@ service yandex2mqtt restart "topic": "/yandex/controls/light_BdR_002/state" } ``` -**Перезапустить адаптер mqtt** \ No newline at end of file diff --git a/app.js b/app.js index e572a0e..f231134 100644 --- a/app.js +++ b/app.js @@ -2,6 +2,8 @@ const fs = require('fs'); const path = require('path'); +/* */ +const {createLogger, format, transports} = require('winston'); /* express and https */ const ejs = require('ejs'); const express = require('express'); @@ -20,6 +22,29 @@ const mqtt = require('mqtt'); const config = require('./config'); const Device = require('./device'); +/* */ +const clArgv = process.argv.slice(2); + +/* Logging */ +global.logger = createLogger({ + level: 'info', + format: format.combine( + format.errors({stack: true}), + format.timestamp(), + format.printf(({level, message, timestamp, stack}) => { + return `${timestamp} ${level}: ${stack != undefined ? stack : message}`; + }), + ), + transports: [ + new transports.Console({ + silent: clArgv.indexOf('--log-info') == -1 + }) + ], +}); + +if (clArgv.indexOf('--log-error') > -1) global.logger.add(new transports.File({filename: 'log/error.log', level: 'error'})); + +/* */ app.engine('ejs', ejs.__express); app.set('view engine', 'ejs'); app.set('views', path.join(__dirname, './views')); @@ -110,6 +135,51 @@ global.mqttClient = mqtt.connect(`mqtt://${config.mqtt.host}`, { const {deviceId, instance} = subscription; const ldevice = global.devices.find(d => d.data.id == deviceId); ldevice.updateState(`${message}`, instance); + + /* Make Request to Yandex Dialog notification API */ + Promise.all(config.notification.map(el => { + let {skill_id, oauth_token, user_id} = el; + + return new Promise((resolve, reject) => { + let req = https.request({ + hostname: 'dialogs.yandex.net', + port: 443, + path: `/api/v1/skills/${skill_id}/callback/state`, + method: 'POST', + headers: { + 'Content-Type': `application/json`, + 'Authorization': `OAuth ${oauth_token}` + } + }, res => { + res.on('data', d => { + global.logger.log('info', {message: `${d}`}); + }); + }); + + req.on('error', error => { + global.logger.log('error', {message: `${error}`}); + }); + + let {id, capabilities, properties} = ldevice.getState(); + req.write(JSON.stringify({ + "ts": Math.floor(Date.now() / 1000), + "payload": { + "user_id": `${user_id}`, + "devices": [{ + id, + capabilities: capabilities.filter(c => c.state.instance == instance), + properties: properties.filter(p => p.state.instance == instance) + }], + } + })); + + req.end(); + + resolve(true); + }); + })); + + /* */ }); module.exports = app; diff --git a/config.orig.js b/config.orig.js index 141e15c..de277f8 100644 --- a/config.orig.js +++ b/config.orig.js @@ -43,11 +43,12 @@ module.exports = { name: 'Свет в коридоре', room: 'Коридор', type: 'devices.types.light', + allowedUsers: ['2'], mqtt: [ { instance: 'on', - set: '/yandex/controls/light_HaW_002/state/on', - state: '/yandex/controls/light_HaW_002/state', + set: '/yandex/controls/light_HaW_002/on', + state: '/yandex/controls/light_HaW_002/on/state', }, ], capabilities: [ @@ -63,11 +64,12 @@ module.exports = { name: 'Основной свет', room: 'Гостиная', type: 'devices.types.light', + allowedUsers: ['2'], mqtt: [ { instance: 'on', - set: '/yandex/controls/light_LvR_003/state/on', - state: '/yandex/controls/light_LvR_003/state', + set: '/yandex/controls/light_LvR_003/on', + state: '/yandex/controls/light_LvR_003/on/state', }, ], valueMapping: [ @@ -89,6 +91,7 @@ module.exports = { name: 'В гостиной', room: 'Гостиная', type: 'devices.types.sensor', + allowedUsers: ['2'], mqtt: [ { instance: 'temperature', @@ -124,11 +127,12 @@ module.exports = { name: 'Розетка для цветка', room: 'Гостиная', type: 'devices.types.socket', + allowedUsers: ['2'], mqtt: [ { instance: 'on', - set: '/yandex/controls/socket_LvR_002/state/on', - state: '/yandex/controls/socket_LvR_002/state/on', + set: '/yandex/controls/socket_LvR_002/on', + state: '/yandex/controls/socket_LvR_002/on/state', }, { instance: 'power', diff --git a/db/access_tokens.js b/db/access_tokens.js index 0a43256..4c864a0 100644 --- a/db/access_tokens.js +++ b/db/access_tokens.js @@ -1,5 +1,6 @@ 'use strict'; +const {logger} = global; const loki = require('lokijs'); global.dbl = new loki('./loki.json', { @@ -16,36 +17,40 @@ global.dbl = new loki('./loki.json', { module.exports.find = (key, done) => { const ltoken = global.authl.findOne({'token': key}); - if (ltoken){ - console.log('Token found'); + if (ltoken) { const {userId, clientId} = ltoken; return done(null, {userId, clientId}) } else { - return done(new Error('Token Not Found')); + logger.log('error', new Error('Token Not Found')); + return done(); } }; module.exports.findByUserIdAndClientId = (userId, clientId, done) => { const ltoken = global.authl.findOne({'userId': userId}); if (ltoken){ - console.log('Load token by userId: User found'); + logger.log('info', {message: `Load token by userId (${userId}): User found`}); const {token, userId: uid, clientId: cid} = ltoken; - if (uid === userId && cid === clientId) return done(null, token); - else return done(new Error('Token Not Found')); + if (uid === userId && cid === clientId) { + return done(null, token); + } else { + logger.log('error', new Error('Token Not Found')); + return done(); + } } else { - console.log('User not found'); - return done(new Error('User Not Found')); + logger.log('error', new Error('User Not Found')); + return done(); } }; module.exports.save = (token, userId, clientId, done) => { - console.log('Start saving token'); + logger.log('info', {message: `Start saving token`}); const ltoken = global.authl.findOne({'userId': userId}); if (ltoken){ - console.log('User Updated'); + logger.log('info', {message: `User Updated`}); global.authl.update(Object.assign({}, ltoken, {token, userId, clientId})); } else { - console.log('User not Found. Create new...'); + logger.log('info', {message: `User not Found. Create new...`}); global.authl.insert({'type': 'token', token, userId, clientId}); } done(); diff --git a/db/authorization_codes.js b/db/authorization_codes.js index ae37649..c716cf2 100644 --- a/db/authorization_codes.js +++ b/db/authorization_codes.js @@ -1,10 +1,15 @@ 'use strict'; +const {logger} = global; const codes = {}; module.exports.find = (key, done) => { - if (codes[key]) return done(null, codes[key]); - return done(new Error('Code Not Found')); + if (codes[key]) { + return done(null, codes[key]); + } else { + logger.log('error', new Error('Code Not Found')); + return done(); + } }; module.exports.save = (code, clientId, redirectUri, userId, userName, done) => { diff --git a/db/clients.js b/db/clients.js index e49069f..4308a4b 100644 --- a/db/clients.js +++ b/db/clients.js @@ -1,17 +1,20 @@ 'use strict'; +const {logger} = global; const {clients} = require('../config'); module.exports.findById = (id, done) => { for (const client of clients) { if (client.id === id) return done(null, client); } - return done(new Error('Client Not Found')); + logger.log('error', new Error('Client Not Found')); + return done(); }; module.exports.findByClientId = (clientId, done) => { for (const client of clients) { if (client.clientId === clientId) return done(null, client); } - return done(new Error('Client Not Found')); + logger.log('error', new Error('Client Not Found')); + return done(); }; diff --git a/db/users.js b/db/users.js index 906954d..e2bf6a6 100644 --- a/db/users.js +++ b/db/users.js @@ -1,17 +1,20 @@ 'use strict'; +const {logger} = global; const {users} = require('../config'); module.exports.findById = (id, done) => { for (const user of users) { if (user.id === id) return done(null, user); } - return done(new Error('User Not Found')); + logger.log('error', new Error('User Not Found')); + return done(); }; module.exports.findByUsername = (username, done) => { for (const user of users) { if (user.username === username) return done(null, user); } - return done(new Error('User Not Found')); + logger.log('error', new Error('User Not Found')); + return done(); }; diff --git a/device.js b/device.js index 1bd7210..12c71e3 100644 --- a/device.js +++ b/device.js @@ -1,3 +1,5 @@ +const {logger} = global; + /* function for convert system values to Yandex (depends of capability or property type) */ function convertToYandexValue(val, actType) { switch(actType) { @@ -8,7 +10,7 @@ function convertToYandexValue(val, actType) { const value = parseFloat(val); return isNaN(value) ? 0.0 : value; } catch(e) { - console.error(`Can't parse to float: ${val}`); + logger.log('error', {message: `Can't parse to float: ${val}`}); return 0.0; } } @@ -38,11 +40,14 @@ class Device { valueMapping: options.valueMapping || [], }, capabilities: (options.capabilities || []).map(c => Object.assign({}, c, {state: (c.state == undefined) ? this.initState(c) : c.state})), - properties: (options.properties || []).map(p => Object.assign({}, p, {state: (p.state == undefined) ? this.initState(p) : p.state})) - } + properties: (options.properties || []).map(p => Object.assign({}, p, {state: (p.state == undefined) ? this.initState(p) : p.state})), + }; + this.meta = { + allowedUsers: options.allowedUsers || ['1'], + }; } - /* Create init state on device object create */ + /* Create init state (for capabilities and properties) on device object create */ initState(cp) { const {type, parameters} = cp; const actType = String(type).split('.')[2]; @@ -60,10 +65,10 @@ class Device { value: false } } - case 'toggle': { + case 'mode': { return { instance: parameters.instance, - value: false + value: parameters.modes[0].value } } case 'range': { @@ -72,20 +77,45 @@ class Device { value: parameters.range.min } } - case 'mode': { + case 'toggle': { return { instance: parameters.instance, - value: parameters.modes[0].value + value: false } } default: { - console.error(`Unsupported capability type: ${type}`) + logger.log('error', {message: `Unsupported capability type: ${type}`}); return undefined; } } } + /* Find capability by type (and instance) */ + findCapability(type, instance) { + const {capabilities} = this.data; + if (instance != undefined) { + return capabilities.find(c => c.type === type && c.state.instance === instance); + } else { + return capabilities.find(c => c.type === type); + } + } + + /* Find property by type (and instance) */ + findProperty(type, instance) { + const {properties} = this.data; + if (instance != undefined) { + return properties.find(p => p.type === type && p.state.instance === instance); + } else { + return properties.find(p => p.type === type); + } + } + + /* Find 'set' topic by instance*/ + findTopicByInstance(instance) { + return this.data.custom_data.mqtt.find(i => i.instance === instance).set; + } + /* Get mapped value (if exist) for capability type */ /** * @@ -105,21 +135,6 @@ class Device { return (mappedValue != undefined) ? mappedValue : val; } - /* Find capability by type */ - findCapability(type) { - return this.data.capabilities.find(c => c.type === type); - } - - /* Unused for now */ - findProperty(type) { - return this.data.properties.find(p => p.type === type); - } - - /* Find 'set' topic by instance*/ - findTopicByInstance(instance) { - return this.data.custom_data.mqtt.find(i => i.instance === instance).set; - } - getInfo() { const {id, name, description, room, type, capabilities, properties} = this.data; return {id, name, description, room, type, capabilities, properties}; @@ -160,7 +175,7 @@ class Device { let message; let topic; try { - const capability = this.findCapability(type); + const capability = this.findCapability(type, instance); if (capability == undefined) throw new Error(`Can't find capability '${type}' in device '${id}'`); capability.state.value = value; topic = this.findTopicByInstance(instance); @@ -168,7 +183,7 @@ class Device { message = `${value}`; } catch(e) { topic = false; - console.log(e); + logger.log('error', {message: `${e}`}); } if (topic) { @@ -198,7 +213,7 @@ class Device { const value = this.getMappedValue(val, actType, false); cp.state = {instance, value: convertToYandexValue(value, actType)}; } catch(e) { - console.error(e); + logger.log('error', {message: `${e}`}); } } } diff --git a/package.json b/package.json index a3ec69c..6150dfe 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,8 @@ "passport-http": "^0.3.0", "passport-http-bearer": "^1.0.1", "passport-local": "^1.0.0", - "passport-oauth2-client-password": "^0.1.2" + "passport-oauth2-client-password": "^0.1.2", + "winston": "^3.3.3" }, "devDependencies": { "eslint": "^7.21.0", diff --git a/routes/user.js b/routes/user.js index 16009ed..96224a1 100644 --- a/routes/user.js +++ b/routes/user.js @@ -20,20 +20,28 @@ module.exports.ping = [ module.exports.devices = [ passport.authenticate('bearer', {session: true}), (req, res) => { - const reqId = req.get('X-Request-Id'); - const r = { - request_id: reqId, - payload: { - user_id: "1", - devices: [] - } - }; + const [reqId, authToken] = [req.get('X-Request-Id'), req.get('Authorization').split(' ')[1]]; - for (const d of global.devices) { - r.payload.devices.push(d.getInfo()); - }; - - res.status(200).send(r); + try { + const {userId} = global.authl.findOne({'token': authToken}); + + const r = { + request_id: reqId, + payload: { + user_id: userId, + devices: [] + } + }; + + for (const d of global.devices.filter(d => Array.isArray(d.meta.allowedUsers) && d.meta.allowedUsers.indexOf(userId) > -1)) { + r.payload.devices.push(d.getInfo()); + }; + + res.status(200).send(r); + } catch (e) { + global.logger.log('error', {message: `${e}`}); + res.status(404).send(undefined); + } } ];