UNPKG

iobroker.bshb

Version:

Connects Bosch Smart Home Interface-Processes to ioBroker

192 lines 10.2 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.BshbController = void 0; const bosch_smart_home_bridge_1 = require("bosch-smart-home-bridge"); const bshb_logger_1 = require("./bshb-logger"); const rxjs_1 = require("rxjs"); const utils_1 = require("./utils"); const bshb_scenario_handler_1 = require("./controller/handler/bshb-scenario-handler"); const bshb_device_handler_1 = require("./controller/handler/bshb-device-handler"); const bshb_messages_handler_1 = require("./controller/handler/bshb-messages-handler"); const bshb_open_door_window_handler_1 = require("./controller/handler/bshb-open-door-window-handler"); const bshb_intrusion_detection_handler_1 = require("./controller/handler/bshb-intrusion-detection-handler"); const bshb_general_update_handler_1 = require("./controller/handler/bshb-general-update-handler"); const bshb_air_purity_guardian_handler_1 = require("./controller/handler/bshb-air-purity-guardian-handler"); const bshb_motion_lights_handler_1 = require("./controller/handler/bshb-motion-lights-handler"); const bshb_water_alarm_handler_1 = require("./controller/handler/bshb-water-alarm-handler"); const bshb_room_handler_1 = require("./controller/handler/bshb-room-handler"); const bshb_device_status_update_handler_1 = require("./controller/handler/bshb-device-status-update-handler"); const bshb_climate_handler_1 = require("./controller/handler/bshb-climate-handler"); const bshb_user_defined_states_handler_1 = require("./controller/handler/bshb-user-defined-states-handler"); const rate_limiter_1 = require("./rate-limiter"); const bshb_automation_handler_1 = require("./controller/handler/bshb-automation-handler"); const bshb_backup_handler_1 = require("./controller/handler/bshb-backup-handler"); /** * This controller encapsulates bosch-smart-home-bridge and provides it to iobroker.bshb * * @author Christopher Holomek * @since 27.09.2019 */ class BshbController { bshb; boschSmartHomeBridge; clientName = 'ioBroker.bshb'; $rateLimit = new rxjs_1.Subject(); alive = new rxjs_1.Subject(); handlers; /** * Create a new instance of {@link BshbController} * * @param bshb * instance of {@link Bshb} * @param clientCert * client certificate * @param clientPrivateKey * client private key */ constructor(bshb, clientCert, clientPrivateKey) { this.bshb = bshb; try { this.boschSmartHomeBridge = bosch_smart_home_bridge_1.BoschSmartHomeBridgeBuilder.builder() .withHost(bshb.config.host) .withClientCert(clientCert) .withClientPrivateKey(clientPrivateKey) .withLogger(new bshb_logger_1.BshbLogger(bshb)) .withIgnoreCertificateCheck(this.bshb.config.skipServerCertificateCheck) .build(); this.handlers = []; this.handlers.push(new bshb_general_update_handler_1.BshbGeneralUpdateHandler(this.bshb, this.boschSmartHomeBridge)); this.handlers.push(new bshb_scenario_handler_1.BshbScenarioHandler(this.bshb, this.boschSmartHomeBridge)); this.handlers.push(new bshb_automation_handler_1.BshbAutomationHandler(this.bshb, this.boschSmartHomeBridge)); this.handlers.push(new bshb_user_defined_states_handler_1.BshbUserDefinedStatesHandler(this.bshb, this.boschSmartHomeBridge)); this.handlers.push(new bshb_device_status_update_handler_1.BshbDeviceStatusUpdateHandler(this.bshb, this.boschSmartHomeBridge)); this.handlers.push(new bshb_messages_handler_1.BshbMessagesHandler(this.bshb, this.boschSmartHomeBridge)); this.handlers.push(new bshb_intrusion_detection_handler_1.BshbIntrusionDetectionHandler(this.bshb, this.boschSmartHomeBridge)); this.handlers.push(new bshb_air_purity_guardian_handler_1.BshbAirPurityGuardianHandler(this.bshb, this.boschSmartHomeBridge)); this.handlers.push(new bshb_motion_lights_handler_1.BshbMotionLightsHandler(this.bshb, this.boschSmartHomeBridge)); this.handlers.push(new bshb_water_alarm_handler_1.BshbWaterAlarmHandler(this.bshb, this.boschSmartHomeBridge)); this.handlers.push(new bshb_room_handler_1.BshbRoomHandler(this.bshb, this.boschSmartHomeBridge)); this.handlers.push(new bshb_device_handler_1.BshbDeviceHandler(this.bshb, this.boschSmartHomeBridge)); this.handlers.push(new bshb_open_door_window_handler_1.BshbOpenDoorWindowHandler(this.bshb, this.boschSmartHomeBridge)); this.handlers.push(new bshb_climate_handler_1.BshbClimateHandler(this.bshb, this.boschSmartHomeBridge)); this.handlers.push(new bshb_backup_handler_1.BshbBackupHandler(this.bshb, this.boschSmartHomeBridge)); this.$rateLimit .pipe((0, rate_limiter_1.rateLimit)(this.bshb.config.rateLimit, this.bshb), (0, rxjs_1.concatMap)(data => { const observables = []; for (let i = 0; i < this.handlers.length; i++) { observables.push(this.handlers[i].sendUpdateToBshc(data.id, data.state).pipe( // Protect controller (0, rxjs_1.catchError)(err => { this.bshb.log.silly(`Handler "${this.handlers[i].constructor.name}" failed with ${err}. This might happen when the controller answers with an error.`); return (0, rxjs_1.of)(true); }), (0, rxjs_1.tap)(handled => { if (handled) { this.bshb.log.silly(`Handler "${this.handlers[i].constructor.name}" send message to controller with state id=${data.id} and value=${data.state.val}`); } }))); } return (0, rxjs_1.merge)(...observables); }), (0, rxjs_1.takeUntil)(this.alive)) .subscribe(); } catch (e) { if (e instanceof Error) { throw utils_1.Utils.createError(bshb.log, e.message); } else { throw utils_1.Utils.createError(bshb.log, e); } } } getBshcClient() { return this.boschSmartHomeBridge.getBshcClient(); } /** * Pair devices if needed * * @param systemPassword * system password of BSHC */ pairDeviceIfNeeded(systemPassword) { let pairingDelay = 5000; if (this.bshb.config.pairingDelay && this.bshb.config.pairingDelay > 5000) { pairingDelay = this.bshb.config.pairingDelay; } // Retry pairIfNeeded logic. It is a bit more complicated compared to before because pairIfNeeded completes stream after attempts. // Community wants that it reconnects all the time. But pairIfNeeded might not be suitable because client may be paired already but // connection is broken. Then pairIfNeeded never goes back to test if client is paired and is stuck. // Here we retry the pairIfNeeded without attempts configured. So we try once. If something is not ok we wait // for pairing delay before we try again. We use takeUntil to make sure that we stop streams if adapter shuts-down // takeUntil must be last in pipe to prevent issues. return new rxjs_1.Observable(subscriber => { const retry = new rxjs_1.BehaviorSubject(true); retry .pipe((0, rxjs_1.catchError)(err => err.pipe((0, rxjs_1.delay)(pairingDelay))), (0, rxjs_1.tap)(() => { this.boschSmartHomeBridge .pairIfNeeded(this.clientName, this.bshb.config.identifier, systemPassword, pairingDelay, -1) .pipe((0, rxjs_1.takeUntil)(this.bshb.alive)) .subscribe({ next: response => { // Everything is ok. We can stop all. this.bshb.log.info('Ok with pairing'); subscriber.next(response); subscriber.complete(); retry.complete(); }, error: err => { this.bshb.log.error(err); // Something went wrong. Already logged by lib. We just wait and retry. (0, rxjs_1.timer)(pairingDelay) .pipe((0, rxjs_1.takeUntil)(this.bshb.alive)) .subscribe(() => { retry.next(true); }); }, }); }), (0, rxjs_1.takeUntil)(this.bshb.alive)) .subscribe(() => { // We do not care }); }); } /** * Start overall detection * * @return observable with no content */ startDetection() { this.bshb.log.info('Start detection'); return (0, rxjs_1.concat)(...this.handlers.map(value => value.handleDetection())).pipe((0, rxjs_1.last)(undefined, void 0)); } /** * Changes on a state which results in a call to bshc controller * * @param id * id of state which changed * @param state * state itself */ setState(id, state) { this.$rateLimit.next({ id: id, state: state }); } /** * Changes from bshc controller which results in updates on ioBroker state * * @param resultEntry * entry of changes which will be mapped to a state */ setStateAck(resultEntry) { for (let i = 0; i < this.handlers.length; i++) { const handled = this.handlers[i].handleBshcUpdate(resultEntry); if (handled) { this.bshb.log.silly(`Handler "${this.handlers[i].constructor.name}" handled update form controller with result entry: ${JSON.stringify(resultEntry)} `); } } } close() { this.alive.next(true); this.alive.complete(); } } exports.BshbController = BshbController; //# sourceMappingURL=bshb-controller.js.map