From 5aeee362a32da6bf2067992a62a162ecba8ec340 Mon Sep 17 00:00:00 2001 From: Jan Litzenburger Date: Thu, 23 Sep 2021 15:28:53 +0200 Subject: [PATCH 1/2] ModType v2. Refactoring --- MMM-BoschSmartHome.css | 17 +++--- MMM-BoschSmartHome.js | 2 +- node_helper.js | 4 +- rollup.config.js | 10 +++- src/backend/Backend.ts | 99 ++++++-------------------------- src/backend/BshClient.ts | 91 +++++++++++++++++++++++++++++ src/frontend/Frontend.ts | 28 ++++----- src/frontend/Utils.ts | 15 +++-- src/types/Room.ts | 3 + src/types/Service.ts | 6 ++ templates/MMM-BoschSmartHome.njk | 22 ++++--- 11 files changed, 168 insertions(+), 129 deletions(-) create mode 100644 src/backend/BshClient.ts diff --git a/MMM-BoschSmartHome.css b/MMM-BoschSmartHome.css index 237efdd..efc7bd9 100644 --- a/MMM-BoschSmartHome.css +++ b/MMM-BoschSmartHome.css @@ -16,6 +16,10 @@ margin-bottom: 4px; align-items: center; } +.bsh-error { + font-size: 0.5em; + color: red; +} .bsh-title-left { flex-grow: 4; } @@ -126,7 +130,7 @@ } .gauge-semi-circle::before { - content: ""; + content: ''; position: absolute; bottom: 0; left: 13%; @@ -181,7 +185,7 @@ } .gauge-semi-circle--mask::before { - content: ""; + content: ''; position: absolute; top: 0; left: 0; @@ -215,14 +219,7 @@ } .gauge-semi-circle.humidity { - background: linear-gradient( - to right, - #c0392b 0%, - #f1c40f 15%, - #1abc9c 50%, - #f1c40f 85%, - #c0392b 100% - ); + background: linear-gradient(to right, #c0392b 0%, #f1c40f 15%, #1abc9c 50%, #f1c40f 85%, #c0392b 100%); } .gauge-semi-circle.temperature { diff --git a/MMM-BoschSmartHome.js b/MMM-BoschSmartHome.js index 7c9b44e..39414d7 100644 --- a/MMM-BoschSmartHome.js +++ b/MMM-BoschSmartHome.js @@ -11,4 +11,4 @@ This file is auto-generated. Do not edit. ***************************************************************************** */ -!function(){"use strict";class e{static getRoomIcon(e){switch(e){case"icon_room_bathroom":return"fa-bath";case"icon_room_bedroom":return"fa-bed";case"icon_room_office":return"fa-briefcase";case"icon_room_living_room":return"fa-couch";case"icon_room_dining_room":return"fa-utensils";default:return"fa-house-user"}}static getLowBatteryDevices(e){const t=[];for(const r of e){const e=r.services.find((e=>"BatteryLevel"===e.id));e&&e.faults&&t.push(r.name)}return t}static getSwitchedOnHueDevices(e){const t=e.filter((e=>"HUE_LIGHT"===e.deviceModel)),r=[];return t.forEach((e=>{e.services.find((e=>"BinarySwitch"===e.id)).state.on&&r.indexOf(e.name)<=0&&r.push(e.name)})),r}static getOpenShutters(e){const t=e.filter((e=>"SWD"===e.deviceModel)),r=[];return t.forEach((e=>{"CLOSED"!==e.services.find((e=>"ShutterContact"===e.id)).state.value&&r.indexOf(e.profile)<=0&&r.push(e.profile)})),r}static getClimateControlService(e){const t=e.find((e=>"ROOM_CLIMATE_CONTROL"===e.deviceModel));return t?t.services.find((e=>"RoomClimateControl"===e.id)):null}static getTemperatureLevelService(e){const t=e.find((e=>"ROOM_CLIMATE_CONTROL"===e.deviceModel));return t?t.services.find((e=>"TemperatureLevel"===e.id)):null}static getAirQualityService(e){const t=e.find((e=>"TWINGUARD"===e.deviceModel));return t?t.services.find((e=>"AirQualityLevel"===e.id)):null}static getThermostatServices(e){const t=e.filter((e=>"TRV"===e.deviceModel));if(!t)return null;const r=[];return t.forEach((e=>{const t=e.services.find((e=>"TemperatureLevel"===e.id)),i=e.services.find((e=>"ValveTappet"===e.id));r.push({temperatureLevelService:t,valveTappetService:i,name:e.name})})),r}static getDishWasherService(e){const t=e.find((e=>"HOMECONNECT_DISHWASHER"===e.deviceModel));if(!t)return null;const r=t.services.find((e=>"HCDishwasher"===e.id));return r.deviceName=t.name,r}static getChartHumidityPercentage(e){return e>100?100:e}static getChartPurityPercentage(e){const t=e.state.purity/e.state.comfortZone.maxPurity*50;return t>100?100:t}static getChartTemperaturePercentage(e,t){if(!t||!e)return null;const r=e/(t.maxTemperature-(t.maxTemperature-t.minTemperature))*50;return r>100?100:r}static isHidden(e,t,r){return r.hideComponents[e.name]&&r.hideComponents[e.name].indexOf(t)>=0}}Module.register("MMM-BoschSmartHome",{defaults:{mocked:!1,debug:!1,header:null,host:"192.168.0.150",name:"MMM-BoschSmartHome",identifier:"MMM-BoschSmartHome",password:"",width:"340px",refreshIntervalInSeconds:60,displayRoomIcons:!1,hideComponents:{},airquality:{purity:"bar",humidity:"bar",temperature:"bar",preferredTemperatureProvider:"Twinguard",preferredHumidityProvider:"Twinguard"},temperatureLevel:{displayCurrentTemperature:!0,displayTargetTemperature:!0,forceRowTile:!0},thermostats:{display:!0,displayName:!1}},getStyles:()=>["font-awesome.css","MMM-BoschSmartHome.css"],getTranslations:()=>({en:"translations/en.json",de:"translations/de.json"}),getTemplate:()=>"templates/MMM-BoschSmartHome.njk",getTemplateData(){return{config:this.config,rooms:this.rooms,error:this.error,utils:e}},getHeader(){return this.config.header},start(){this.rooms=[],this.error=null,this.loadData(),this.scheduleUpdate(),this.updateDom()},scheduleUpdate(){setInterval((()=>{this.loadData()}),1e3*this.config.refreshIntervalInSeconds)},loadData(){this.sendSocketNotification("GET_STATUS",this.config)},socketNotificationReceived(e,t){"STATUS_RESULT"===e?(this.error=null,this.rooms=t,this.updateDom(),console.debug("Bosch Smart Home Rooms",this.rooms)):"ERROR"===e&&(this.error=t,this.updateDom())}})}(); +!function(e){"use strict";function t(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(r){if("default"!==r){var i=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,i.get?i:{enumerable:!0,get:function(){return e[r]}})}})),t.default=e,Object.freeze(t)}var r=t(e);class i{static getRoomIcon(e){switch(e){case"icon_room_bathroom":return"fa-bath";case"icon_room_bedroom":return"fa-bed";case"icon_room_office":return"fa-briefcase";case"icon_room_living_room":return"fa-couch";case"icon_room_dining_room":return"fa-utensils";default:return"fa-house-user"}}static getLowBatteryDevices(e){const t=[];for(const r of e){const e=r.services.find((e=>"BatteryLevel"===e.id));e&&e.faults&&t.push(r.name)}return t}static getSwitchedOnHueDevices(e){const t=e.filter((e=>"HUE_LIGHT"===e.deviceModel)),r=[];return t.forEach((e=>{e.services.find((e=>"BinarySwitch"===e.id)).state.on&&r.indexOf(e.name)<=0&&r.push(e.name)})),r}static getOpenShutters(e){const t=e.filter((e=>"SWD"===e.deviceModel)),r=[];return t.forEach((e=>{"CLOSED"!==e.services.find((e=>"ShutterContact"===e.id)).state.value&&r.indexOf(e.profile)<=0&&r.push(e.profile)})),r}static getClimateControlService(e){const t=e.find((e=>"ROOM_CLIMATE_CONTROL"===e.deviceModel));return t?t.services.find((e=>"RoomClimateControl"===e.id)):null}static getTemperatureLevelService(e){const t=e.find((e=>"ROOM_CLIMATE_CONTROL"===e.deviceModel));return t?t.services.find((e=>"TemperatureLevel"===e.id)):null}static getAirQualityService(e){const t=e.find((e=>"TWINGUARD"===e.deviceModel));return t?t.services.find((e=>"AirQualityLevel"===e.id)):null}static getThermostatServices(e){const t=e.filter((e=>"TRV"===e.deviceModel));if(!t)return null;const r=[];return t.forEach((e=>{const t=e.services.find((e=>"TemperatureLevel"===e.id)),i=e.services.find((e=>"ValveTappet"===e.id));r.push({temperatureLevelService:t,valveTappetService:i,name:e.name})})),r}static getDishWasherService(e){const t=e.find((e=>"HOMECONNECT_DISHWASHER"===e.deviceModel));if(!t)return null;const r=t.services.find((e=>"HCDishwasher"===e.id));return r.deviceName=t.name,r}static getChartHumidityPercentage(e){return e>100?100:e}static getChartPurityPercentage(e){const t=e.state.purity/e.state.comfortZone.maxPurity*50;return t>100?100:t}static getChartTemperaturePercentage(e,t){if(!t||!e)return null;const r=e/(t.maxTemperature-(t.maxTemperature-t.minTemperature))*50;return r>100?100:r}static isHidden(e,t,r){return r.hideComponents[e.name]&&r.hideComponents[e.name].indexOf(t)>=0}}Module.register("MMM-BoschSmartHome",{defaults:{mocked:!1,debug:!1,header:null,host:"192.168.0.150",name:"MMM-BoschSmartHome",identifier:"MMM-BoschSmartHome",password:"",width:"340px",refreshIntervalInSeconds:60,displayRoomIcons:!1,hideComponents:{},airquality:{purity:"bar",humidity:"bar",temperature:"bar",preferredTemperatureProvider:"Twinguard",preferredHumidityProvider:"Twinguard"},temperatureLevel:{displayCurrentTemperature:!0,displayTargetTemperature:!0,forceRowTile:!0},thermostats:{display:!0,displayName:!1}},getStyles:()=>["font-awesome.css","MMM-BoschSmartHome.css"],getTranslations:()=>({en:"translations/en.json",de:"translations/de.json"}),getTemplate:()=>"templates/MMM-BoschSmartHome.njk",getTemplateData(){return{config:this.config,rooms:this.rooms,error:this.error,utils:i}},getHeader(){return this.config.header},start(){this.rooms=[],this.error=null,this.sendSocketNotification("BSH_CONFIG_REQUEST",this.config),this.updateDom()},socketNotificationReceived(e,t){"BSH_ROOMS_RESPONSE"===e?(this.error=null,this.rooms=t,this.updateDom(),r.log("BSH Rooms",this.rooms)):"BSH_ERROR_RESPONSE"===e&&(this.error=t,console.log(this.error),this.updateDom())}})}(Log); diff --git a/node_helper.js b/node_helper.js index 9fd0015..849351c 100644 --- a/node_helper.js +++ b/node_helper.js @@ -11,7 +11,7 @@ This file is auto-generated. Do not edit. ***************************************************************************** */ -"use strict";var e=require("node_helper"),t=require("fs"),i=require("bosch-smart-home-bridge");function o(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(i){if("default"!==i){var o=Object.getOwnPropertyDescriptor(e,i);Object.defineProperty(t,i,o.get?o:{enumerable:!0,get:function(){return e[i]}})}})),t.default=e,Object.freeze(t)}var n=o(e),r=o(t),s=o(i); +"use strict";var e=require("node_helper"),t=require("logger"),i=require("bosch-smart-home-bridge"),o=require("fs");function n(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(i){if("default"!==i){var o=Object.getOwnPropertyDescriptor(e,i);Object.defineProperty(t,i,o.get?o:{enumerable:!0,get:function(){return e[i]}})}})),t.default=e,Object.freeze(t)}var s=n(e),r=n(t),c=n(i),h=n(o); /*! ***************************************************************************** Copyright (c) Microsoft Corporation. @@ -26,4 +26,4 @@ LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ -function c(e,t,i,o){return new(i||(i=Promise))((function(n,r){function s(e){try{l(o.next(e))}catch(e){r(e)}}function c(e){try{l(o.throw(e))}catch(e){r(e)}}function l(e){var t;e.done?n(e.value):(t=e.value,t instanceof i?t:new i((function(e){e(t)}))).then(s,c)}l((o=o.apply(e,t||[])).next())}))}module.exports=n.create({cert:null,key:null,logger:null,client:null,rooms:null,start(){this.cert=r.readFileSync(`${__dirname}/client-cert.pem`).toString(),this.key=r.readFileSync(`${__dirname}/client-key.pem`).toString(),this.logger=new s.DefaultLogger,this.logger.fine=()=>{},this.logger.info=e=>{e.indexOf("Using existing certificate")>=0||e.indexOf("Check if client with identifier")>=0||console.info(e)},console.log(`${this.name} helper method started...`)},establishConnection(e){return c(this,void 0,void 0,(function*(){if(!this.client)try{const t=s.BoschSmartHomeBridgeBuilder.builder().withHost(e.host).withClientCert(this.cert).withClientPrivateKey(this.key).withLogger(this.logger).build();yield t.pairIfNeeded(e.name,e.identifier,e.password).toPromise(),this.client=t.getBshcClient()}catch(e){console.log(e)}}))},loadData(){return c(this,void 0,void 0,(function*(){try{if(!this.rooms){const{parsedResponse:e}=yield this.client.getRooms().toPromise();this.rooms=e}const{parsedResponse:e}=yield this.client.getDevices().toPromise(),{parsedResponse:t}=yield this.client.getDevicesServices().toPromise();for(const i of e)i.services=t.filter((e=>e.deviceId===i.id));for(const t of this.rooms)t.devices=e.filter((e=>e.roomId===t.id))}catch(e){console.error(e.message)}}))},socketNotificationReceived(e,t){return c(this,void 0,void 0,(function*(){if("GET_STATUS"===e){if(t.mocked){const e=r.readFileSync(`${__dirname}/debugResponse.json`).toString();this.rooms=JSON.parse(e)}else yield this.establishConnection(t),yield this.loadData(),t.debug&&r.writeFileSync(`${__dirname}/debugResponse.json`,JSON.stringify(this.rooms));this.sendSocketNotification("STATUS_RESULT",this.rooms)}else console.warn(`${e} is invalid notification`)}))}}); +function l(e,t,i,o){return new(i||(i=Promise))((function(n,s){function r(e){try{h(o.next(e))}catch(e){s(e)}}function c(e){try{h(o.throw(e))}catch(e){s(e)}}function h(e){var t;e.done?n(e.value):(t=e.value,t instanceof i?t:new i((function(e){e(t)}))).then(r,c)}h((o=o.apply(e,t||[])).next())}))}class a{constructor(){this.client=null,this.config=null,this.cert=null,this.key=null,this.logger=null,this.rooms=null}setConfig(e){this.config=e}establishConnection(){return l(this,void 0,void 0,(function*(){this.cert=h.readFileSync(`${__dirname}/client-cert.pem`).toString(),this.key=h.readFileSync(`${__dirname}/client-key.pem`).toString(),this.logger=new c.DefaultLogger,this.logger.fine=()=>{},this.logger.info=e=>{e.indexOf("Using existing certificate")>=0||e.indexOf("Check if client with identifier")>=0||r.info(e)};const e=c.BoschSmartHomeBridgeBuilder.builder().withHost(this.config.host).withClientCert(this.cert).withClientPrivateKey(this.key).withLogger(this.logger).build();yield e.pairIfNeeded(this.config.name,this.config.identifier,this.config.password).toPromise(),this.client=e.getBshcClient(),r.info("Established connection to BSHB")}))}getRooms(){return l(this,void 0,void 0,(function*(){try{if(!this.client)try{yield this.establishConnection()}catch(e){throw Error(`Could not establish connection to BSHB: ${e.message}`)}if(!this.rooms){const{parsedResponse:e}=yield this.client.getRooms().toPromise();this.rooms=e,r.info("Retrieved rooms from BSHB.")}const{parsedResponse:e}=yield this.client.getDevices().toPromise(),{parsedResponse:t}=yield this.client.getDevicesServices().toPromise();for(const i of e)i.services=t.filter((e=>e.deviceId===i.id));for(const t of this.rooms)t.devices=e.filter((e=>e.roomId===t.id));return Promise.resolve(this.rooms)}catch(e){return r.error(e.message),Promise.reject(e)}}))}}module.exports=s.create({start(){this.client=new a,r.log(`${this.name} helper method started...`)},socketNotificationReceived(e,t){return l(this,void 0,void 0,(function*(){if("BSH_CONFIG_REQUEST"===e){const e=t;this.client.setConfig(e),this.getClientData(),this.schedule||(this.schedule=setInterval(this.getClientData.bind(this),1e3*e.refreshIntervalInSeconds))}}))},getClientData(){return l(this,void 0,void 0,(function*(){try{const e=yield this.client.getRooms();this.sendSocketNotification("BSH_ROOMS_RESPONSE",e)}catch(e){this.sendSocketNotification("BSH_ERROR_RESPONSE",{type:"WARNING",message:e.message})}}))}}); diff --git a/rollup.config.js b/rollup.config.js index b941b49..35347a5 100644 --- a/rollup.config.js +++ b/rollup.config.js @@ -23,16 +23,20 @@ const bannerText = `/*! ******************************************************** export default [ { input: './src/frontend/Frontend.ts', + external: ['logger'], plugins: [typescript({ module: 'ESNext' }), nodeResolve(), commonjs(), terser(), banner2(() => bannerText)], output: { file: './' + pkg.main, - format: 'iife' + format: 'iife', + globals: { + logger: 'Log' + } } }, { input: './src/backend/Backend.ts', - external: ['node_helper', 'bosch-smart-home-bridge', 'fs'], - plugins: [typescript({ module: 'ESNext' }), terser(), banner2(() => bannerText)], + external: ['node_helper', 'logger', 'bosch-smart-home-bridge', 'fs'], + plugins: [typescript({ module: 'ESNext' }), nodeResolve(), terser(), banner2(() => bannerText)], output: { file: './node_helper.js', format: 'cjs' diff --git a/src/backend/Backend.ts b/src/backend/Backend.ts index 4ae09b6..42f393d 100644 --- a/src/backend/Backend.ts +++ b/src/backend/Backend.ts @@ -1,98 +1,35 @@ import * as NodeHelper from 'node_helper' -import * as fs from 'fs' -import * as BSMB from 'bosch-smart-home-bridge' +import * as Log from 'logger' +import BshbClient from './BshClient' import { Config } from '../types/Config' -import { Device } from '../types/Device' -import { Service } from '../types/Service' module.exports = NodeHelper.create({ - cert: null, - key: null, - logger: null, - client: null, - rooms: null, start() { - this.cert = fs.readFileSync(`${__dirname}/client-cert.pem`).toString() - this.key = fs.readFileSync(`${__dirname}/client-key.pem`).toString() - - // Override Logger to avoid some annoying logs - this.logger = new BSMB.DefaultLogger() - this.logger.fine = () => {} - this.logger.info = (msg: string) => { - if (msg.indexOf('Using existing certificate') >= 0 || msg.indexOf('Check if client with identifier') >= 0) { - return - } - console.info(msg) - } - - console.log(`${this.name} helper method started...`) + this.client = new BshbClient() + Log.log(`${this.name} helper method started...`) }, - async establishConnection(config: Config) { - if (!this.client) { - try { - const bshb = BSMB.BoschSmartHomeBridgeBuilder.builder() - .withHost(config.host) - .withClientCert(this.cert) - .withClientPrivateKey(this.key) - .withLogger(this.logger) - .build() + async socketNotificationReceived(notification, payload) { + if (notification === 'BSH_CONFIG_REQUEST') { + const config = payload as Config + this.client.setConfig(config) - await bshb.pairIfNeeded(config.name, config.identifier, config.password).toPromise() - this.client = bshb.getBshcClient() - } catch (err) { - console.log(err) + this.getClientData() + if (!this.schedule) { + this.schedule = setInterval(this.getClientData.bind(this), config.refreshIntervalInSeconds * 1000) } } }, - async loadData() { + async getClientData() { try { - if (!this.rooms) { - const { parsedResponse: rooms } = await this.client.getRooms().toPromise() - this.rooms = rooms - } - - const { - parsedResponse: devices - }: { - parsedResponse: Device[] - } = await this.client.getDevices().toPromise() - - const { - parsedResponse: services - }: { - parsedResponse: Service[] - } = await this.client.getDevicesServices().toPromise() - - for (const device of devices) { - device.services = services.filter((service) => service.deviceId === device.id) - } - - for (const room of this.rooms) { - room.devices = devices.filter((device) => device.roomId === room.id) - } + const rooms = await this.client.getRooms() + this.sendSocketNotification('BSH_ROOMS_RESPONSE', rooms) } catch (err) { - console.error(err.message) - } - }, - - async socketNotificationReceived(notification, config) { - if (notification === 'GET_STATUS') { - if (config.mocked) { - const data = fs.readFileSync(`${__dirname}/debugResponse.json`).toString() - this.rooms = JSON.parse(data) - } else { - await this.establishConnection(config) - await this.loadData() - - if (config.debug) { - fs.writeFileSync(`${__dirname}/debugResponse.json`, JSON.stringify(this.rooms)) - } - } - this.sendSocketNotification('STATUS_RESULT', this.rooms) - } else { - console.warn(`${notification} is invalid notification`) + this.sendSocketNotification('BSH_ERROR_RESPONSE', { + type: 'WARNING', + message: err.message + }) } } }) diff --git a/src/backend/BshClient.ts b/src/backend/BshClient.ts new file mode 100644 index 0000000..bee33fe --- /dev/null +++ b/src/backend/BshClient.ts @@ -0,0 +1,91 @@ +import * as Log from 'logger' +import * as BSHB from 'bosch-smart-home-bridge' +import * as fs from 'fs' +import { Config } from '../types/Config' +import { Device } from '../types/Device' +import { Service } from '../types/Service' +import { Room } from '../types/Room' + +export default class BshbClient { + private client: BSHB.BshcClient = null + private config: Config = null + private cert: string = null + private key: string = null + private logger: BSHB.DefaultLogger = null + private rooms: Room[] = null + + setConfig(config: Config): void { + this.config = config + } + + private async establishConnection(): Promise { + this.cert = fs.readFileSync(`${__dirname}/client-cert.pem`).toString() + this.key = fs.readFileSync(`${__dirname}/client-key.pem`).toString() + + // Override Logger to avoid some annoying logs + this.logger = new BSHB.DefaultLogger() + this.logger.fine = () => {} + this.logger.info = (msg: string) => { + if (msg.indexOf('Using existing certificate') >= 0 || msg.indexOf('Check if client with identifier') >= 0) { + return + } + Log.info(msg) + } + + const bshb = BSHB.BoschSmartHomeBridgeBuilder.builder() + .withHost(this.config.host) + .withClientCert(this.cert) + .withClientPrivateKey(this.key) + .withLogger(this.logger) + .build() + + await bshb.pairIfNeeded(this.config.name, this.config.identifier, this.config.password).toPromise() + this.client = bshb.getBshcClient() + + Log.info('Established connection to BSHB') + } + + public async getRooms(): Promise { + try { + if (!this.client) { + try { + await this.establishConnection() + } catch (err) { + throw Error(`Could not establish connection to BSHB: ${err.message}`) + } + } + + if (!this.rooms) { + const { parsedResponse: rooms } = await this.client.getRooms().toPromise() + this.rooms = rooms + Log.info('Retrieved rooms from BSHB.') + } + + const { + parsedResponse: devices + }: { + parsedResponse: Device[] + } = await this.client.getDevices().toPromise() + + const { + parsedResponse: services + }: { + parsedResponse: Service[] + } = await this.client.getDevicesServices().toPromise() + + for (const device of devices) { + device.services = services.filter((service) => service.deviceId === device.id) + } + + for (const room of this.rooms) { + room.devices = devices.filter((device) => device.roomId === room.id) + } + + return Promise.resolve(this.rooms) + } catch (err) { + Log.error(err.message) + + return Promise.reject(err) + } + } +} diff --git a/src/frontend/Frontend.ts b/src/frontend/Frontend.ts index f91b80c..0711ffc 100644 --- a/src/frontend/Frontend.ts +++ b/src/frontend/Frontend.ts @@ -1,7 +1,8 @@ +import * as Log from 'logger' import Utils from './Utils' import { Config } from '../types/Config' -Module.register('MMM-BoschSmartHome', { +Module.register('MMM-BoschSmartHome', { defaults: { mocked: false, debug: false, @@ -30,7 +31,7 @@ Module.register('MMM-BoschSmartHome', { display: true, displayName: false } - } as Config, + }, getStyles() { return ['font-awesome.css', 'MMM-BoschSmartHome.css'] @@ -63,30 +64,21 @@ Module.register('MMM-BoschSmartHome', { start() { this.rooms = [] this.error = null - this.loadData() - this.scheduleUpdate() - this.updateDom() - }, - scheduleUpdate() { - setInterval(() => { - this.loadData() - }, this.config.refreshIntervalInSeconds * 1000) - }, - - loadData() { - this.sendSocketNotification('GET_STATUS', this.config) + this.sendSocketNotification('BSH_CONFIG_REQUEST', this.config) + this.updateDom() }, - socketNotificationReceived(notificationIdentifier: string, payload: any) { - if (notificationIdentifier === 'STATUS_RESULT') { + socketNotificationReceived(notificationIdentifier: string, payload: unknown) { + if (notificationIdentifier === 'BSH_ROOMS_RESPONSE') { this.error = null this.rooms = payload this.updateDom() - console.debug('Bosch Smart Home Rooms', this.rooms) - } else if (notificationIdentifier === 'ERROR') { + Log.log('BSH Rooms', this.rooms) + } else if (notificationIdentifier === 'BSH_ERROR_RESPONSE') { this.error = payload + console.log(this.error) this.updateDom() } } diff --git a/src/frontend/Utils.ts b/src/frontend/Utils.ts index c8b5999..60347b7 100644 --- a/src/frontend/Utils.ts +++ b/src/frontend/Utils.ts @@ -10,11 +10,12 @@ import { AirQualityService, ValveTappetService, ComfortZone, - Service + Service, + ThermostatServices } from '../types/Service' export default class BSHUtils { - static getRoomIcon(iconId: string) { + static getRoomIcon(iconId: string): string { switch (iconId) { case 'icon_room_bathroom': return 'fa-bath' @@ -31,7 +32,7 @@ export default class BSHUtils { } } - static getLowBatteryDevices(devices: Device[]) { + static getLowBatteryDevices(devices: Device[]): Device[] { const response = [] for (const device of devices) { @@ -41,10 +42,11 @@ export default class BSHUtils { response.push(device.name) } } + return response } - static getSwitchedOnHueDevices(devices: Device[]) { + static getSwitchedOnHueDevices(devices: Device[]): string[] { const hueLights = devices.filter((device) => device.deviceModel === 'HUE_LIGHT') const switchedOnDevices: string[] = [] hueLights.forEach((hueLight) => { @@ -55,10 +57,11 @@ export default class BSHUtils { switchedOnDevices.push(hueLight.name) } }) + return switchedOnDevices } - static getOpenShutters(devices: Device[]) { + static getOpenShutters(devices: Device[]): string[] { const shutterContactDevices: ShutterContactDevice[] = devices.filter((device) => device.deviceModel === 'SWD') const openShutters: string[] = [] shutterContactDevices.forEach((shutterContactDevice) => { @@ -94,7 +97,7 @@ export default class BSHUtils { return twinguardDevice.services.find((service) => service.id === 'AirQualityLevel') } - static getThermostatServices(devices: Device[]) { + static getThermostatServices(devices: Device[]): ThermostatServices[] { const temperatureLevelDevices = devices.filter((device) => device.deviceModel === 'TRV') if (!temperatureLevelDevices) return null diff --git a/src/types/Room.ts b/src/types/Room.ts index e67b312..c0f4200 100644 --- a/src/types/Room.ts +++ b/src/types/Room.ts @@ -1,5 +1,8 @@ +import { Device } from './Device' + export type Room = { id: string name: string iconId: string + devices: Device[] } diff --git a/src/types/Service.ts b/src/types/Service.ts index a13ab37..80c1cb0 100644 --- a/src/types/Service.ts +++ b/src/types/Service.ts @@ -27,6 +27,12 @@ export interface AirQualityService extends Service { state?: { purity: number; comfortZone: ComfortZone } } +export type ThermostatServices = { + temperatureLevelService: TemperatureLevelService + valveTappetService: ValveTappetService + name: string +} + export type ComfortZone = { custom?: boolean maxHumidity?: number diff --git a/templates/MMM-BoschSmartHome.njk b/templates/MMM-BoschSmartHome.njk index 90d60a2..ec27bbd 100755 --- a/templates/MMM-BoschSmartHome.njk +++ b/templates/MMM-BoschSmartHome.njk @@ -1,13 +1,19 @@ {% import "templates/Room.njk" as roomTemplate with context %} -{% if rooms and rooms.length > 0%} -
- {% for room in rooms %} - {{ roomTemplate.render(room)}} - {% endfor %} -
+{% if error %} +
+ {{ error.message }} +
{% else %} -
- {{ "LOADING" | translate | safe }} + {% if rooms and rooms.length > 0%} +
+ {% for room in rooms %} + {{ roomTemplate.render(room)}} + {% endfor %}
+ {% else %} +
+ {{ "LOADING" | translate | safe }} +
+ {% endif %} {% endif %} From da45bf1e697e8e82dfddbb4eb39afb4381e67c7b Mon Sep 17 00:00:00 2001 From: Jan Litzenburger Date: Sun, 3 Oct 2021 14:49:44 +0200 Subject: [PATCH 2/2] room name filter --- MMM-BoschSmartHome.js | 2 +- node_helper.js | 2 +- package-lock.json | 4 ++-- package.json | 2 +- templates/Room.njk | 8 +++++--- 5 files changed, 10 insertions(+), 8 deletions(-) diff --git a/MMM-BoschSmartHome.js b/MMM-BoschSmartHome.js index 39414d7..b9fce6d 100644 --- a/MMM-BoschSmartHome.js +++ b/MMM-BoschSmartHome.js @@ -1,6 +1,6 @@ /*! ***************************************************************************** mmm-bosch-smart-home - Version 1.1.1 + Version 1.2.0 A client interface for the Bosch Smart Home System on the MagicMirror² platform. Please submit bugs at https://github.com/jalibu/MMM-BoschSmartHome/issues diff --git a/node_helper.js b/node_helper.js index 849351c..af1b974 100644 --- a/node_helper.js +++ b/node_helper.js @@ -1,6 +1,6 @@ /*! ***************************************************************************** mmm-bosch-smart-home - Version 1.1.1 + Version 1.2.0 A client interface for the Bosch Smart Home System on the MagicMirror² platform. Please submit bugs at https://github.com/jalibu/MMM-BoschSmartHome/issues diff --git a/package-lock.json b/package-lock.json index 49ad5a2..c9bc502 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "mmm-bosch-smart-home", - "version": "1.1.1", + "version": "1.2.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "mmm-bosch-smart-home", - "version": "1.1.1", + "version": "1.2.0", "license": "MIT", "dependencies": { "bosch-smart-home-bridge": "^1.0.0" diff --git a/package.json b/package.json index 6b80c5c..2c19fd5 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "mmm-bosch-smart-home", - "version": "1.1.1", + "version": "1.2.0", "description": "A client interface for the Bosch Smart Home System on the MagicMirror² platform.", "main": "MMM-BoschSmartHome.js", "repository": { diff --git a/templates/Room.njk b/templates/Room.njk index 0833b99..1ebbc0d 100755 --- a/templates/Room.njk +++ b/templates/Room.njk @@ -12,9 +12,11 @@ {% endif %} - - {{room.name}} - + {% if not utils.isHidden(room, "name", config) %} + + {{room.name}} + + {% endif %} {{ climateControlBadge.render(room, utils) }}