UNPKG

hap-homematic

Version:

provides a homekit bridge to the ccu

386 lines (353 loc) 15 kB
/* * File: HomeMaticWeatherStationAccessory.js * Project: hap-homematic * File Created: Sunday, 5th April 2020 6:55:06 pm * Author: Thomas Kluge (th.kluge@me.com) * ----- * The MIT License (MIT) * * Copyright (c) Thomas Kluge <th.kluge@me.com> (https://github.com/thkl) * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * ========================================================================== */ const path = require('path') const EveHomeKitWeatherTypes = require(path.join(__dirname, 'EveWeather.js')) const HomeMaticAccessory = require(path.join(__dirname, 'HomeMaticAccessory.js')) class HomeMaticWeatherStationAccessory extends HomeMaticAccessory { publishServices(Service, Characteristic) { // create characteristics let self = this var weatherStation this.applHome = (this._server.getConfig('disableHistory') === true) this.eveWeatherProg = new EveHomeKitWeatherTypes(this.gatoHomeBridge.hap) // create all optinal Characteristics if (!this.applHome) { this.debugLog('Using Eve Mode') weatherStation = this.getService(this.eveWeatherProg.Service.EveWeather) this.enableLoggingService('weather', false) } else { this.debugLog('Using AppleHome Mode') weatherStation = this.getService(new Service.TemperatureSensor(this._name)) weatherStation.addOptionalCharacteristic(Characteristic.CurrentRelativeHumidity) } this.currentTemperature = -255 this.currentHumidity = -255 this.currentPressure = -255 // temperature sensor if (this.getDataPointNameFromSettings('Temperature', null)) { this.currentTemperatureCharacteristic = weatherStation.getCharacteristic(Characteristic.CurrentTemperature) .setProps({ minValue: -100 }) .on('get', async (callback) => { let value = await self.getValueForDataPointNameWithSettingsKey('Temperature', null, true) self.debugLog('getCurrentTemperature result %s', value) if (callback) callback(null, value) }) this.currentTemperatureCharacteristic.eventEnabled = true this.registerAddressWithSettingsKeyForEventProcessingAtAccessory('Temperature', null, (newValue) => { self.currentTemperature = parseFloat(newValue) self.currentTemperatureCharacteristic.updateValue(parseFloat(newValue), null) if (!self.applHome) { self.addLogginEntry() } }) } else { this.debugLog('no temp sensor %s') this.currentTemperature = 0 } // humidity sensor if (this.getDataPointNameFromSettings('Humidity', null)) { if (!this.applHome) { this.currentHumidityCharacteristic = weatherStation.getCharacteristic(Characteristic.CurrentRelativeHumidity) } else { // Create a new Sensor let humSensor = this.addService(new Service.HumiditySensor(this._name)) this.currentHumidityCharacteristic = humSensor.getCharacteristic(Characteristic.CurrentRelativeHumidity) } this.currentHumidityCharacteristic.on('get', async (callback) => { let value = await self.getValueForDataPointNameWithSettingsKey('Humidity', null, true) self.currentHumidity = parseFloat(value) self.debugLog('getCurrentRelativeHumidity result %s', value) if (callback) callback(null, value) }) this.currentHumidityCharacteristic.eventEnabled = true this.registerAddressWithSettingsKeyForEventProcessingAtAccessory('Humidity', null, (newValue) => { self.currentHumidity = parseFloat(newValue) self.currentHumidityCharacteristic.updateValue(parseFloat(newValue), null) if (!self.applHome) { self.addLogginEntry() } }) } else { this.currentHumidity = 0 } if (!this.applHome) { this.debugLog('adding Brightness sensor to eve weather station') this.addSensor('Brightness', weatherStation, 'Brightness', Characteristic.CurrentAmbientLightLevel) } else { this.debugLog('adding Brightness sensor to Home LightSensor') let lightSensor = this.addService(new Service.LightSensor(this._name)) this.addSensor('Brightness', lightSensor, 'Brightness', Characteristic.CurrentAmbientLightLevel) lightSensor.getCharacteristic(Characteristic.StatusActive).on('get', callback => { callback(null, true) }) } // use all the optional stuff if the user not wants an appl home device if (!this.applHome) { // pressure sensor if (this.getDataPointNameFromSettings('AirPressure', null)) { this.currentPressureCharacteristic = weatherStation.getCharacteristic(this.eveWeatherProg.Characteristic.AirPressure) .on('get', async (callback) => { let value = await self.getValueForDataPointNameWithSettingsKey('AirPressure', null, true) if (callback) callback(null, value) }) this.currentPressureCharacteristic.eventEnabled = true this.registerAddressWithSettingsKeyForEventProcessingAtAccessory('AirPressure', null, (newValue) => { self.currentPressure = parseFloat(newValue) self.currentPressureCharacteristic.updateValue(parseFloat(newValue), null) self.addLogginEntry() }) } else { this.currentPressure = 0 } // SunShineDuration sensor if (this.getDataPointNameFromSettings('SunShineDuration', null)) { let setg = self.deviceServiceSettings('SunShineDuration', null) this.currentSunshineCharacteristic = weatherStation.getCharacteristic(this.eveWeatherProg.Characteristic.SunShineDuration) .on('get', async (callback) => { var duration = 0 if ((setg) && (setg.type === 'Variable')) { let varName = self.getDataPointNameFromSettings('SunShineDuration', null) + self._ccuChannelId duration = await (self._ccu.getVariableValue(varName)) duration = (parseFloat(duration) / 60).toFixed(2) // calculate hours } else { let value = await self.getValueForDataPointNameWithSettingsKey('SunShineDuration', null, true) duration = parseFloat(value) duration = (duration / 60).toFixed(2) // calculate hours } if (callback) callback(null, duration) }) this.currentSunshineCharacteristic.eventEnabled = true } if (this.getDataPointNameFromSettings('Raincount', null)) { let setg = self.deviceServiceSettings('Raincount', null) this.currentRainCountCharacteristic = weatherStation.getCharacteristic(this.eveWeatherProg.Characteristic.RainDay) .on('get', async (callback) => { var rCount = 0 if ((setg) && (setg.type === 'Variable')) { let varName = self.getDataPointNameFromSettings('Raincount', null) + self._ccuChannelId rCount = await (self._ccu.getVariableValue(varName)) rCount = (parseFloat(rCount)).toFixed(2) } else { let value = await self.getValueForDataPointNameWithSettingsKey('Raincount', null, true) rCount = parseFloat(value) rCount = (parseFloat(rCount)).toFixed(2) } if (callback) callback(null, rCount) }) this.currentRainCountCharacteristic.eventEnabled = true this.registerAddressWithSettingsKeyForEventProcessingAtAccessory('Raincount', null, (newValue) => { self.updateCharacteristic(self.currentRainCountCharacteristic, parseFloat(newValue)) }) } this.addSensor('Rain', weatherStation, 'RainBool', this.eveWeatherProg.Characteristic.RainBool, null, (vl) => { return self.isTrue(vl) }) this.addSensor('Windspeed', weatherStation, '', this.eveWeatherProg.Characteristic.WindSpeed, null, (vl) => { return parseInt(vl) }) this.addSensor('Winddirection', weatherStation, 'Wind direction', this.eveWeatherProg.Characteristic.WindDirection, null, (degree) => { return self.getWindDirection(degree) }) this.addSensor('Windrange', weatherStation, 'Wind range', this.eveWeatherProg.Characteristic.Windrange, null, (vl) => { return parseInt(vl) }) } } addSensor(configName, service, ServiceName, ServiceCharacteristics, remoteValueCallBack, converter) { let self = this this.debugLog('adding %s Sensor', configName) if (this.getDataPointNameFromSettings(configName, null)) { let currentCharacteristic = service.getCharacteristic(ServiceCharacteristics) .on('get', async (callback) => { self.debugLog('homekit get %s', configName) let value = await self.getValueForDataPointNameWithSettingsKey(configName, null, true) self.debugLog('homekit get %s result is %s', configName, value) if (converter) { value = converter(value) } else { value = parseFloat(value) } self.debugLog('get %s converged value is % this will be sent to homekit', configName, value) if (callback) { callback(null, value) } }) currentCharacteristic.eventEnabled = true this.registerAddressWithSettingsKeyForEventProcessingAtAccessory(configName, null, (newValue) => { self.debugLog('homekit event for %s with value %s', configName, newValue) if (converter) { newValue = converter(newValue) } else { parseFloat(newValue) } self.debugLog('homekit event for %s converged value is %s', configName, newValue) self.updateCharacteristic(currentCharacteristic, newValue) if (remoteValueCallBack) { remoteValueCallBack(parseFloat(newValue)) } }) } } getWindDirection(degree) { this.log.debug('[WST] convert %s', degree) if (degree === undefined) { return 'Unknown' } if (typeof degree !== 'string') { degree = parseInt(degree) } let cat = Math.round(degree % 360 / 22.5) let dir // TODO multilanguage switch (cat) { case 0: dir = 'N' break case 1: dir = 'NNE' break case 2: dir = 'NE' break case 3: dir = 'ENE' break case 4: dir = 'E' break case 5: dir = 'ESE' break case 6: dir = 'SE' break case 7: dir = 'SSE' break case 8: dir = 'S' break case 9: dir = 'SSW' break case 10: dir = 'SW' break case 11: dir = 'WSW' break case 12: dir = 'W' break case 13: dir = 'WNW' break case 14: dir = 'NW' break case 15: dir = 'NNW' break case 16: dir = 'N' break default: dir = 'Variable' } return dir } addLogginEntry() { if ((this.currentTemperature > -255) && (this.currentHumidity > -255) && (this.currentPressure > -255)) { this.log.debug('[WST] write log %s %s %s', this.currentTemperature, this.currentPressure, this.currentHumidity) this.addLogEntry({ temp: this.currentTemperature, pressure: this.currentPressure, humidity: this.currentHumidity }) } else { this.log.debug('[WST] ignore log %s %s %s', this.currentTemperature, this.currentPressure, this.currentHumidity) } } static channelTypes() { return ['HB-UNI-Sen-WEA:WEATHER', 'KS550:WEATHER', 'HmIP-SWO-B:WEATHER_TRANSMIT', 'HmIP-SWO-PR:WEATHER_TRANSMIT', 'HmIP-SWO-PL:WEATHER_TRANSMIT' ] } initServiceSettings() { return { 'HB-UNI-Sen-WEA': { Temperature: { name: 'TEMPERATURE' }, Humidity: { name: 'HUMIDITY' }, AirPressure: { name: 'AIR_PRESSURE' }, Brightness: { name: 'LUX' }, Raincount: { name: 'RAIN_COUNTER' }, Windspeed: { name: 'WIND_SPEED' }, Winddirection: { name: 'WIND_DIRECTION' }, Windrange: { name: 'WIND_DIRECTION_RANGE' } }, 'KS550': { Temperature: { name: 'TEMPERATURE' }, Humidity: { name: 'HUMIDITY' }, Brightness: { name: 'BRIGHTNESS' }, Raincount: { name: 'RAIN_COUNTER' }, Rain: { name: 'RAINING' }, Windspeed: { name: 'WIND_SPEED' }, Winddirection: { name: 'WIND_DIRECTION' }, Windrange: { name: 'WIND_DIRECTION_RANGE' } }, 'HmIP-SWO-B': { Temperature: { name: 'ACTUAL_TEMPERATURE' }, Humidity: { name: 'HUMIDITY' }, Brightness: { name: 'ILLUMINATION' }, SunShineDuration: { name: 'svHmIPSunshineCounterToday_', type: 'Variable' }, Windspeed: { name: 'WIND_SPEED' } }, 'HmIP-SWO-PR': { Temperature: { name: 'ACTUAL_TEMPERATURE' }, Humidity: { name: 'HUMIDITY' }, Brightness: { name: 'ILLUMINATION' }, Raincount: { name: 'svHmIPRainCounterToday_', type: 'Variable' }, Rain: { name: 'RAINING' }, SunShineDuration: { name: 'svHmIPSunshineCounterToday_', type: 'Variable' }, Winddirection: { name: 'WIND_DIR' }, Windspeed: { name: 'WIND_SPEED' }, Windrange: { name: 'WIND_DIR_RANGE' } }, 'HmIP-SWO-PL': { Temperature: { name: 'ACTUAL_TEMPERATURE' }, Humidity: { name: 'HUMIDITY' }, Brightness: { name: 'ILLUMINATION' }, Raincount: { name: 'svHmIPRainCounterToday_', type: 'Variable' }, Rain: { name: 'RAINING' }, SunShineDuration: { name: 'svHmIPSunshineCounterToday_', type: 'Variable' }, Winddirection: { name: 'WIND_DIR' }, Windspeed: { name: 'WIND_SPEED' } } } } static serviceDescription() { return 'This service provides a weather station for HomeKit' } static validate(configurationItem) { return false } } module.exports = HomeMaticWeatherStationAccessory