homebridge-homeassistant-mbmccormick
Version:
Homebridge plugin for Home Assistant: https://home-assistant.io
226 lines (208 loc) • 8.34 kB
JavaScript
'use strict';
let Service;
let Characteristic;
let communicationError;
class HomeAssistantSensor {
constructor(log, data, client, service, characteristic, transformData, firmware) {
// device info
this.data = data;
this.entity_id = data.entity_id;
this.uuid_base = data.entity_id;
this.firmware = firmware;
if (data.attributes && data.attributes.friendly_name) {
this.name = data.attributes.friendly_name;
} else {
this.name = data.entity_id.split('.').pop().replace(/_/g, ' ');
}
if (data.attributes && data.attributes.homebridge_manufacturer) {
this.manufacturer = String(data.attributes.homebridge_manufacturer);
} else {
this.manufacturer = 'Home Assistant';
}
if (data.attributes && data.attributes.homebridge_model) {
this.model = String(data.attributes.homebridge_model);
} else {
this.model = 'Sensor';
}
if (data.attributes && data.attributes.homebridge_serial) {
this.serial = String(data.attributes.homebridge_serial);
} else {
this.serial = data.entity_id;
}
this.entity_type = data.entity_id.split('.')[0];
this.service = service;
this.characteristic = characteristic;
if (transformData) {
this.transformData = transformData;
}
this.client = client;
this.log = log;
this.batterySource = data.attributes.homebridge_battery_source;
this.chargingSource = data.attributes.homebridge_charging_source;
}
transformData(data) {
return parseFloat(data.state);
}
onEvent(oldState, newState) {
if (newState.state) {
if (this.service === Service.CarbonDioxideSensor) {
const transformed = this.transformData(newState);
this.sensorService.getCharacteristic(this.characteristic)
.setValue(transformed, null, 'internal');
const abnormal = Characteristic.CarbonDioxideDetected.CO2_LEVELS_ABNORMAL;
const normal = Characteristic.CarbonDioxideDetected.CO2_LEVELS_NORMAL;
const detected = (transformed > 1000 ? abnormal : normal);
this.sensorService.getCharacteristic(Characteristic.CarbonDioxideDetected)
.setValue(detected, null, 'internal');
} else {
this.sensorService.getCharacteristic(this.characteristic)
.setValue(this.transformData(newState), null, 'internal');
}
}
}
identify(callback) {
this.log(`identifying: ${this.name}`);
callback();
}
getState(callback) {
this.log(`fetching state for: ${this.name}`);
this.client.fetchState(this.entity_id, (data) => {
if (data) {
callback(null, this.transformData(data));
} else {
callback(communicationError);
}
});
}
getBatteryLevel(callback) {
this.client.fetchState(this.batterySource, (data) => {
if (data) {
callback(null, parseFloat(data.state));
} else {
callback(communicationError);
}
});
}
getChargingState(callback) {
if (this.batterySource && this.chargingSource) {
this.client.fetchState(this.chargingSource, (data) => {
if (data) {
callback(null, data.state.toLowerCase() === 'charging' ? 1 : 0);
} else {
callback(communicationError);
}
});
} else {
callback(null, 2);
}
}
getLowBatteryStatus(callback) {
this.client.fetchState(this.batterySource, (data) => {
if (data) {
callback(null, parseFloat(data.state) > 20 ? 0 : 1);
} else {
callback(communicationError);
}
});
}
getServices() {
this.sensorService = new this.service(); // eslint-disable-line new-cap
const informationService = new Service.AccessoryInformation();
informationService
.setCharacteristic(Characteristic.Manufacturer, this.manufacturer)
.setCharacteristic(Characteristic.Model, this.model)
.setCharacteristic(Characteristic.SerialNumber, this.serial)
.setCharacteristic(Characteristic.FirmwareRevision, this.firmware);
this.sensorService
.getCharacteristic(this.characteristic)
.setProps({ minValue: -50 })
.on('get', this.getState.bind(this));
if (this.batterySource) {
this.batteryService = new Service.BatteryService();
this.batteryService
.getCharacteristic(Characteristic.BatteryLevel)
.setProps({ maxValue: 100, minValue: 0, minStep: 1 })
.on('get', this.getBatteryLevel.bind(this));
this.batteryService
.getCharacteristic(Characteristic.ChargingState)
.setProps({ maxValue: 2 })
.on('get', this.getChargingState.bind(this));
this.batteryService
.getCharacteristic(Characteristic.StatusLowBattery)
.on('get', this.getLowBatteryStatus.bind(this));
return [informationService, this.batteryService, this.sensorService];
}
return [informationService, this.sensorService];
}
}
function HomeAssistantSensorFactory(log, data, client, firmware) {
if (!data.attributes) {
return null;
}
let service;
let characteristic;
let transformData;
if (data.attributes.unit_of_measurement === '°C'
|| data.attributes.unit_of_measurement === '℃'
|| data.attributes.unit_of_measurement === '°F'
|| data.attributes.unit_of_measurement === '℉') {
service = Service.TemperatureSensor;
characteristic = Characteristic.CurrentTemperature;
transformData = function transformData(dataToTransform) { // eslint-disable-line no-shadow
let value = parseFloat(dataToTransform.state);
// HomeKit only works with Celsius internally
if (dataToTransform.attributes.unit_of_measurement === '°F'
|| dataToTransform.attributes.unit_of_measurement === '℉') {
value = (value - 32) / 1.8;
}
return value;
};
} else if (data.attributes.unit_of_measurement === '%' && (data.entity_id.includes('humidity') || data.attributes.homebridge_sensor_type === 'humidity')) {
service = Service.HumiditySensor;
characteristic = Characteristic.CurrentRelativeHumidity;
} else if ((typeof data.attributes.unit_of_measurement === 'string' && data.attributes.unit_of_measurement.toLowerCase() === 'lux') || data.attributes.homebridge_sensor_type === 'light') {
service = Service.LightSensor;
characteristic = Characteristic.CurrentAmbientLightLevel;
transformData = function transformData(dataToTransform) { // eslint-disable-line no-shadow
return Math.max(0.0001, parseFloat(dataToTransform.state));
};
} else if (typeof data.attributes.unit_of_measurement === 'string' && data.attributes.unit_of_measurement.toLowerCase() === 'ppm' && (data.entity_id.includes('co2') || data.attributes.homebridge_sensor_type === 'co2')) {
service = Service.CarbonDioxideSensor;
characteristic = Characteristic.CarbonDioxideLevel;
} else if ((typeof data.attributes.unit_of_measurement === 'string' && data.attributes.unit_of_measurement.toLowerCase() === 'aqi') || data.attributes.homebridge_sensor_type === 'air_quality') {
service = Service.AirQualitySensor;
characteristic = Characteristic.AirQuality;
transformData = function transformData(dataToTransform) { // eslint-disable-line no-shadow
const value = parseFloat(dataToTransform.state);
if (value <= 75) {
return 1;
} else if (value >= 76 && value <= 150) {
return 2;
} else if (value >= 151 && value <= 225) {
return 3;
} else if (value >= 226 && value <= 300) {
return 4;
} else if (value >= 301) {
return 5;
}
return 0;
};
} else {
return null;
}
return new HomeAssistantSensor(
log, data, client,
service,
characteristic,
transformData,
firmware
);
}
function HomeAssistantSensorPlatform(oService, oCharacteristic, oCommunicationError) {
Service = oService;
Characteristic = oCharacteristic;
communicationError = oCommunicationError;
return HomeAssistantSensorFactory;
}
module.exports = HomeAssistantSensorPlatform;
module.exports.HomeAssistantSensorFactory = HomeAssistantSensorFactory;