import { Service , PlatformAccessory , CharacteristicValue } from 'homebridge' ; import { HoneywellHomePlatform } from '../platform' ; import { interval , Subject } from 'rxjs' ; import { skipWhile } from 'rxjs/operators' ; import { location , sensorAccessory , device , devicesConfig , T9groups } from '../settings' ; /**
 * Platform Accessory
 * An instance of this class is created for each accessory your platform registers
 * Each accessory may expose multiple services of different service types.
 */ export class RoomSensors { private service : Service ; temperatureService ? : Service ; occupancyService ? : Service ; humidityService ? : Service ; StatusLowBattery ! : CharacteristicValue ; OccupancyDetected ! : CharacteristicValue ; CurrentTemperature ! : CharacteristicValue ; CurrentRelativeHumidity ! : CharacteristicValue ; TemperatureDisplayUnits ! : CharacteristicValue ; accessoryId ! : number ; roomId ! : number ; action ! : string ; deviceLogging ! : string ; deviceRefreshRate ! : number ; SensorUpdateInProgress ! : boolean ; doSensorUpdate ! : Subject < void > ; constructor ( private readonly platform , private accessory , public readonly locationId , public device , public sensorAccessory , public readonly group ) { this . logs ( device ) ; this . refreshRate ( device ) ; this . config ( device ) ; this . CurrentTemperature ; this . StatusLowBattery ; this . OccupancyDetected ; this . CurrentRelativeHumidity ; this . accessoryId = sensorAccessory . accessoryId ; this . roomId = sensorAccessory . roomId ; this . doSensorUpdate = new Subject ( ) ; this . SensorUpdateInProgress = false ; accessory . getService ( this . platform . Service . AccessoryInformation ) ! . setCharacteristic ( this . platform . Characteristic . Manufacturer , 'Honeywell' ) . setCharacteristic ( this . platform . Characteristic . Model , sensorAccessory . accessoryAttribute . model ) . setCharacteristic ( this . platform . Characteristic . SerialNumber , sensorAccessory . deviceID ) . setCharacteristic ( this . platform . Characteristic . FirmwareRevision , accessory . context . firmwareRevision ) . getCharacteristic ( this . platform . Characteristic . FirmwareRevision ) . updateValue ( accessory . context . firmwareRevision ) ; ( this . service = this . accessory . getService ( this . platform . Service . Battery ) || this . accessory . addService ( this . platform . Service . Battery ) ) , `${ accessory . displayName } Battery` ; this . service . setCharacteristic ( this . platform . Characteristic . Name , accessory . displayName ) ; this . parseStatus ( ) ; this . service . setCharacteristic ( this . platform . Characteristic . ChargingState , 2 ) ; if ( device . thermostat ?. roomsensor ?. hide_temperature ) { this . debugLog ( `Room Sensor: ${ accessory . displayName } Removing Temperature Sensor Service` ) ; this . temperatureService = this . accessory . getService ( this . platform . Service . TemperatureSensor ) ; accessory . removeService ( this . temperatureService ! ) ; } else if ( ! this . temperatureService ) { this . debugLog ( `Room Sensor: ${ accessory . displayName } Add Temperature Sensor Service` ) ; ( this . temperatureService = this . accessory . getService ( this . platform . Service . TemperatureSensor ) || this . accessory . addService ( this . platform . Service . TemperatureSensor ) ) , `${ accessory . displayName } Temperature Sensor` ; this . temperatureService . setCharacteristic ( this . platform . Characteristic . Name , `${ accessory . displayName } Temperature Sensor` ) ; this . temperatureService . getCharacteristic ( this . platform . Characteristic . CurrentTemperature ) . setProps ( { minValue : - 273.15 , maxValue : 100 , minStep : 0.1 , } ) . onGet ( ( ) => { return this . CurrentTemperature ; } ) ; } else { this . debugLog ( `Room Sensor: ${ accessory . displayName } Temperature Sensor Service Not Added` ) ; } if ( device . thermostat ?. roomsensor ?. hide_occupancy ) { this . debugLog ( `Room Sensor: ${ accessory . displayName } Removing Occupancy Sensor Service` ) ; this . occupancyService = this . accessory . getService ( this . platform . Service . OccupancySensor ) ; accessory . removeService ( this . occupancyService ! ) ; } else if ( ! this . occupancyService ) { this . debugLog ( `Room Sensor: ${ accessory . displayName } Add Occupancy Sensor Service` ) ; ( this . occupancyService = this . accessory . getService ( this . platform . Service . OccupancySensor ) || this . accessory . addService ( this . platform . Service . OccupancySensor ) ) , `${ accessory . displayName } Occupancy Sensor` ; this . occupancyService . setCharacteristic ( this . platform . Characteristic . Name , `${ accessory . displayName } Occupancy Sensor` ) ; } else { this . debugLog ( `Room Sensor: ${ accessory . displayName } Occupancy Sensor Service Not Added` ) ; } if ( device . thermostat ?. roomsensor ?. hide_humidity ) { this . debugLog ( `Room Sensor: ${ accessory . displayName } Removing Humidity Sensor Service` ) ; this . humidityService = this . accessory . getService ( this . platform . Service . HumiditySensor ) ; accessory . removeService ( this . humidityService ! ) ; } else if ( ! this . humidityService ) { this . debugLog ( `Room Sensor: ${ accessory . displayName } Add Humidity Sensor Service` ) ; ( this . humidityService = this . accessory . getService ( this . platform . Service . HumiditySensor ) || this . accessory . addService ( this . platform . Service . HumiditySensor ) ) , `${ accessory . displayName } Humidity Sensor` ; this . humidityService . setCharacteristic ( this . platform . Characteristic . Name , `${ accessory . displayName } Humidity Sensor` ) ; this . humidityService . getCharacteristic ( this . platform . Characteristic . CurrentRelativeHumidity ) . setProps ( { minStep : 0.1 , } ) . onGet ( ( ) => { return this . CurrentRelativeHumidity ; } ) ; } else { this . debugLog ( `Room Sensor: ${ accessory . displayName } Humidity Sensor Service Not Added` ) ; } this . updateHomeKitCharacteristics ( ) ; interval ( this . platform . config . options ! . refreshRate ! * 1000 ) . pipe ( skipWhile ( ( ) => this . SensorUpdateInProgress ) ) . subscribe ( ( ) => { this . refreshStatus ( ) ; } ) ; } /**
     * Parse the device status from the honeywell api
     */ parseStatus ( ) { if ( this . sensorAccessory . accessoryValue . batteryStatus . startsWith ( 'Ok' ) ) { this . StatusLowBattery = this . platform . Characteristic . StatusLowBattery . BATTERY_LEVEL_NORMAL ; } else { this . StatusLowBattery = this . platform . Characteristic . StatusLowBattery . BATTERY_LEVEL_LOW ; } this . debugLog ( `Room Sensor: ${ this . accessory . displayName } StatusLowBattery: ${ this . StatusLowBattery }` ) ; if ( ! this . device . thermostat ?. roomsensor ?. hide_temperature ) { this . CurrentTemperature = this . toCelsius ( this . sensorAccessory . accessoryValue . indoorTemperature ) ; } this . debugLog ( `Room Sensor: ${ this . accessory . displayName } CurrentTemperature: ${ this . CurrentTemperature }°c` ) ; if ( ! this . device . thermostat ?. roomsensor ?. hide_occupancy ) { if ( this . sensorAccessory . accessoryValue . occupancyDet ) { this . OccupancyDetected = 1 ; } else { this . OccupancyDetected = 0 ; } } if ( ! this . device . thermostat ?. roomsensor ?. hide_humidity ) { this . CurrentRelativeHumidity = this . sensorAccessory . accessoryValue . indoorHumidity ; } this . debugLog ( `Room Sensor: ${ this . accessory . displayName } CurrentRelativeHumidity: ${ this . CurrentRelativeHumidity }%` ) ; } /**
     * Asks the Honeywell Home API for the latest device information
     */ async refreshStatus ( ) { try { const roomsensors = await this . platform . getCurrentSensorData ( this . device , this . group , this . locationId ) ; this . sensorAccessory = roomsensors [ this . roomId ] [ this . accessoryId ] ; this . parseStatus ( ) ; this . updateHomeKitCharacteristics ( ) ; } catch ( e ) { this . action = 'refreshStatus' ; this . honeywellAPIError ( e ) ; this . apiError ( e ) ; } } /**
     * Updates the status for each of the HomeKit Characteristics
     */ updateHomeKitCharacteristics ( ) { if ( this . StatusLowBattery === undefined ) { this . debugLog ( `Room Sensor: ${ this . accessory . displayName } StatusLowBattery: ${ this . StatusLowBattery }` ) ; } else { this . service . updateCharacteristic ( this . platform . Characteristic . StatusLowBattery , this . StatusLowBattery ) ; this . debugLog ( `Room Sensor: ${ this . accessory . displayName } updateCharacteristic StatusLowBattery: ${ this . StatusLowBattery }` ) ; } if ( this . device . thermostat ?. roomsensor ?. hide_temperature || this . CurrentTemperature === undefined && Number . isNaN ( this . CurrentTemperature ) ) { this . debugLog ( `Room Sensor: ${ this . accessory . displayName } CurrentTemperature: ${ this . CurrentTemperature }` ) ; } else { this . temperatureService ?. updateCharacteristic ( this . platform . Characteristic . CurrentTemperature , this . CurrentTemperature ) ; this . debugLog ( `Room Sensor: ${ this . accessory . displayName } updateCharacteristic CurrentTemperature: ${ this . CurrentTemperature }` ) ; } if ( this . device . thermostat ?. roomsensor ?. hide_occupancy || this . OccupancyDetected === undefined ) { this . debugLog ( `Room Sensor: ${ this . accessory . displayName } OccupancyDetected: ${ this . OccupancyDetected }` ) ; } else { this . occupancyService ?. updateCharacteristic ( this . platform . Characteristic . OccupancyDetected , this . OccupancyDetected ) ; this . debugLog ( `Room Sensor: ${ this . accessory . displayName } updateCharacteristic OccupancyDetected: ${ this . OccupancyDetected }` ) ; } if ( this . device . thermostat ?. roomsensor ?. hide_humidity || this . CurrentRelativeHumidity === undefined ) { this . debugLog ( `Room Sensor: ${ this . accessory . displayName } CurrentRelativeHumidity: ${ this . CurrentRelativeHumidity }` ) ; } else { this . humidityService ?. updateCharacteristic ( this . platform . Characteristic . CurrentRelativeHumidity , this . CurrentRelativeHumidity ) ; this . debugLog ( `Room Sensor: ${ this . accessory . displayName }` + ` updateCharacteristic CurrentRelativeHumidity: ${ this . CurrentRelativeHumidity }` ) ; } } public apiError ( e ) { this . service . updateCharacteristic ( this . platform . Characteristic . StatusLowBattery , e ) ; if ( ! this . device . thermostat ?. roomsensor ?. hide_temperature ) { this . temperatureService ?. updateCharacteristic ( this . platform . Characteristic . CurrentTemperature , e ) ; } } public honeywellAPIError ( e ) { if ( e . message . includes ( '400' ) ) { this . platform . log . error ( `Room Sensor: ${ this . accessory . displayName } failed to ${ this . action }, Bad Request` ) ; this . debugLog ( 'The client has issued an invalid request. This is commonly used to specify validation errors in a request payload.' ) ; } else if ( e . message . includes ( '401' ) ) { this . platform . log . error ( `Room Sensor: ${ this . accessory . displayName } failed to ${ this . action }, Unauthorized Request` ) ; this . debugLog ( 'Authorization for the API is required, but the request has not been authenticated.' ) ; } else if ( e . message . includes ( '403' ) ) { this . platform . log . error ( `Room Sensor: ${ this . accessory . displayName } failed to ${ this . action }, Forbidden Request` ) ; this . debugLog ( 'The request has been authenticated but does not have appropriate permissions, or a requested resource is not found.' ) ; } else if ( e . message . includes ( '404' ) ) { this . platform . log . error ( `Room Sensor: ${ this . accessory . displayName } failed to ${ this . action }, Requst Not Found` ) ; this . debugLog ( 'Specifies the requested path does not exist.' ) ; } else if ( e . message . includes ( '406' ) ) { this . platform . log . error ( `Room Sensor: ${ this . accessory . displayName } failed to ${ this . action }, Request Not Acceptable` ) ; this . debugLog ( 'The client has requested a MIME type via the Accept header for a value not supported by the server.' ) ; } else if ( e . message . includes ( '415' ) ) { this . platform . log . error ( `Room Sensor: ${ this . accessory . displayName } failed to ${ this . action }, Unsupported Requst Header` ) ; this . debugLog ( 'The client has defined a contentType header that is not supported by the server.' ) ; } else if ( e . message . includes ( '422' ) ) { this . platform . log . error ( `Room Sensor: ${ this . accessory . displayName } failed to ${ this . action }, Unprocessable Entity` ) ; this . debugLog ( 'The client has made a valid request, but the server cannot process it.' + ' This is often used for APIs for which certain limits have been exceeded.' ) ; } else if ( e . message . includes ( '429' ) ) { this . platform . log . error ( `Room Sensor: ${ this . accessory . displayName } failed to ${ this . action }, Too Many Requests` ) ; this . debugLog ( 'The client has exceeded the number of requests allowed for a given time window.' ) ; } else if ( e . message . includes ( '500' ) ) { this . platform . log . error ( `Room Sensor: ${ this . accessory . displayName } failed to ${ this . action }, Internal Server Error` ) ; this . debugLog ( 'An unexpected error on the SmartThings servers has occurred. These errors should be rare.' ) ; } else { this . platform . log . error ( `Room Sensor: ${ this . accessory . displayName } failed to ${ this . action },` ) ; } if ( this . deviceLogging . includes ( 'debug' ) ) { this . platform . log . error ( `Room Sensor: ${ this . accessory . displayName } failed to pushChanges, Error Message: ${ JSON . stringify ( e . message ) }` ) ; } if ( this . deviceLogging . includes ( 'debug' ) || this . platform . debugMode ) { this . platform . log . error ( `Room Sensor: ${ this . accessory . displayName } Error: ${ JSON . stringify ( e ) }` ) ; } } /**
     * Converts the value to celsius if the temperature units are in Fahrenheit
     */ toCelsius ( value ) { if ( this . TemperatureDisplayUnits === this . platform . Characteristic . TemperatureDisplayUnits . CELSIUS ) { return value ; } return Math . round ( ( 5 / 9 ) * ( value - 32 ) * 2 ) / 2 ; } config ( device ) { let config = { } ; if ( device . thermostat ?. roomsensor ) { config = device . thermostat ?. roomsensor ; } if ( device . logging !== undefined ) { config [ 'logging' ] = device . thermostat ?. roomsensor ?. logging ; } if ( device . refreshRate !== undefined ) { config [ 'refreshRate' ] = device . thermostat ?. roomsensor ?. refreshRate ; } if ( Object . entries ( config ) . length !== 0 ) { this . warnLog ( `Room Sensor: ${ this . accessory . displayName } Config: ${ JSON . stringify ( config ) }` ) ; } } refreshRate ( device ) { if ( device . thermostat ?. roomsensor ?. refreshRate ) { this . deviceRefreshRate = this . accessory . context . refreshRate = device . thermostat ?. roomsensor ?. refreshRate ; this . debugLog ( `Room Sensor: ${ this . accessory . displayName } Using Device Config refreshRate: ${ this . deviceRefreshRate }` ) ; } else if ( device . refreshRate ) { this . deviceRefreshRate = this . accessory . context . refreshRate = device . refreshRate ; this . debugLog ( `Room Sensor: ${ this . accessory . displayName } Using Thermostat Device Config refreshRate: ${ this . deviceRefreshRate }` ) ; } else if ( this . platform . config . options ! . refreshRate ) { this . deviceRefreshRate = this . accessory . context . refreshRate = this . platform . config . options ! . refreshRate ; this . debugLog ( `Room Sensor: ${ this . accessory . displayName } Using Platform Config refreshRate: ${ this . deviceRefreshRate }` ) ; } } logs ( device ) { if ( this . platform . debugMode ) { this . deviceLogging = this . accessory . context . logging = 'debugMode' ; this . debugLog ( `Room Sensor: ${ this . accessory . displayName } Using Debug Mode Logging: ${ this . deviceLogging }` ) ; } else if ( device . thermostat ?. roomsensor ?. logging ) { this . deviceLogging = this . accessory . context . logging = device . thermostat ?. roomsensor ?. logging ; this . debugLog ( `Room Sensor: ${ this . accessory . displayName } Using Device Config Logging: ${ this . deviceLogging }` ) ; } else if ( this . platform . config . options ?. logging ) { this . deviceLogging = this . accessory . context . logging = this . platform . config . options ?. logging ; this . debugLog ( `Room Sensor: ${ this . accessory . displayName } Using Platform Config Logging: ${ this . deviceLogging }` ) ; } else { this . deviceLogging = this . accessory . context . logging = 'standard' ; this . debugLog ( `Room Sensor: ${ this . accessory . displayName } Logging Not Set, Using: ${ this . deviceLogging }` ) ; } } /**
   * Logging for Device
   */ infoLog ( ... log ) { if ( this . enablingDeviceLogging ( ) ) { this . platform . log . info ( String ( ... log ) ) ; } } warnLog ( ... log ) { if ( this . enablingDeviceLogging ( ) ) { this . platform . log . warn ( String ( ... log ) ) ; } } errorLog ( ... log ) { if ( this . enablingDeviceLogging ( ) ) { this . platform . log . error ( String ( ... log ) ) ; } } debugLog ( ... log ) { if ( this . enablingDeviceLogging ( ) ) { if ( this . deviceLogging === 'debug' ) { this . platform . log . info ( '[DEBUG]' , String ( ... log ) ) ; } else { this . platform . log . debug ( String ( ... log ) ) ; } } } enablingDeviceLogging ( ) { return this . deviceLogging . includes ( 'debug' ) || this . deviceLogging === 'standard' ; } }