homebridge-homekit-proxy
Version:
Homebridge Homekit Proxy allows you to control HomeKit-enabled Devices directly from within HomeBridege. (Based on homebridge-homekit-controller by MartinPham)
524 lines • 21.2 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.SupportedServices = exports.classFromID = exports.listKnownCharacteristics = exports.listKnownServices = void 0;
const util_1 = require("util");
const fakegato_history_1 = __importDefault(require("fakegato-history"));
function listKnownServices(api, parent) {
return [
api.hap.Service.HumiditySensor,
api.hap.Service.TemperatureSensor,
api.hap.Service.CarbonDioxideSensor,
api.hap.Service.CarbonMonoxideSensor,
api.hap.Service.AirQualitySensor,
api.hap.Service.ProtocolInformation,
api.hap.Service.AccessoryInformation,
api.hap.Service.Switch,
api.hap.Service.MotionSensor,
api.hap.Service.BatteryService,
api.hap.Service.Battery,
api.hap.Service.Lightbulb,
api.hap.Service.Outlet,
api.hap.Service.LightSensor,
api.hap.Service.IrrigationSystem,
api.hap.Service.Valve,
parent.LayoutDetectionService,
parent.AnimationService,
parent.FirmwareUpdateService,
parent.CloudSyncService,
];
}
exports.listKnownServices = listKnownServices;
function listKnownCharacteristics(api, parent) {
return [
api.hap.Characteristic.Identify,
api.hap.Characteristic.Manufacturer,
api.hap.Characteristic.Model,
api.hap.Characteristic.Name,
api.hap.Characteristic.SerialNumber,
api.hap.Characteristic.FirmwareRevision,
api.hap.Characteristic.HardwareRevision,
api.hap.Characteristic.ProductData,
api.hap.Characteristic.Version,
api.hap.Characteristic.IsConfigured,
api.hap.Characteristic.AirQuality,
api.hap.Characteristic.PM2_5Density,
api.hap.Characteristic.PM10Density,
api.hap.Characteristic.CarbonDioxideDetected,
api.hap.Characteristic.CarbonDioxideLevel,
api.hap.Characteristic.CarbonDioxidePeakLevel,
api.hap.Characteristic.CarbonMonoxideDetected,
api.hap.Characteristic.CarbonMonoxideLevel,
api.hap.Characteristic.CarbonMonoxidePeakLevel,
api.hap.Characteristic.CurrentTemperature,
api.hap.Characteristic.CurrentRelativeHumidity,
api.hap.Characteristic.On,
api.hap.Characteristic.OutletInUse,
api.hap.Characteristic.MotionDetected,
api.hap.Characteristic.StatusLowBattery,
api.hap.Characteristic.BatteryLevel,
api.hap.Characteristic.Brightness,
api.hap.Characteristic.Hue,
api.hap.Characteristic.ColorTemperature,
api.hap.Characteristic.Saturation,
api.hap.Characteristic.CurrentAmbientLightLevel,
api.hap.Characteristic.AirParticulateDensity,
api.hap.Characteristic.ChargingState,
api.hap.Characteristic.Active,
api.hap.Characteristic.ProgramMode,
api.hap.Characteristic.InUse,
api.hap.Characteristic.RemainingDuration,
api.hap.Characteristic.StatusFault,
api.hap.Characteristic.ValveType,
api.hap.Characteristic.SetDuration,
api.hap.Characteristic.ServiceLabelIndex,
parent.CloudHomeSync,
parent.CloudHomeSyncDescription,
parent.CloudProvisioningHashString,
parent.NanoleafColorTemperature,
parent.AnimationSelect,
parent.AnimationWrite,
parent.AnimationRead,
parent.AnimationList,
parent.AnimationPlayList,
parent.RythmActive,
parent.RythmConnected,
parent.RythmMode,
parent.RythmAuxAvailable,
parent.NanoleafCustomEventNotifications,
parent.LayoutDetectionButton,
parent.LayoutData,
parent.GlobalOrientation,
parent.ProductWarnings,
parent.NewFirmwareVersion,
parent.FirmwareAvailability,
parent.InstallFirmwareUpdate,
parent.SyncState,
parent.RestoreFromCloud,
];
}
exports.listKnownCharacteristics = listKnownCharacteristics;
function shortType(type) {
const parts = type.split('-');
if (parts.length > 0) {
let p = 0;
while (parts[0][p] === '0' && p < parts[0].length) {
p++;
}
return parts[0].substring(p);
}
return type;
}
function mapShort(list) {
const res = list
.map((s) => {
const item = [
{
id: s.UUID,
cls: s,
},
{
id: shortType(s.UUID),
cls: s,
},
];
return item;
})
.flat(1);
return res;
}
function classFromID(list, id) {
const result = list.find((item) => item.id === id);
if (result) {
return result.cls;
}
return undefined;
}
exports.classFromID = classFromID;
function generateCharacteristic(api, name, UUID, perms) {
const NewCharacteristic = function () {
const self = this;
api.hap.Characteristic.call(self, name, UUID, perms);
self.value = self.getDefaultValue();
};
NewCharacteristic.UUID = UUID;
NewCharacteristic.uuid = UUID;
util_1.inherits(NewCharacteristic, api.hap.Characteristic);
return NewCharacteristic;
}
function generateService(api, name, UUID, optionals) {
if (optionals === undefined) {
optionals = [];
}
const NewService = function (displayName, UUID, subtype) {
const self = this;
api.hap.Service.call(self, name, UUID, subtype);
optionals === null || optionals === void 0 ? void 0 : optionals.forEach((o) => this.addOptionalCharacteristic(o));
};
NewService.UUID = UUID;
NewService.uuid = UUID;
util_1.inherits(NewService, api.hap.Service);
return NewService;
}
//as defined here: https://github.com/simont77/fakegato-history/wiki/Services-and-characteristics-for-Elgato-Eve-devices
function _buildEveAirQuality(api) {
return generateCharacteristic(api, 'Air Quality PM25', 'E863F10B-079E-48FF-8F27-9C2605A29F52', {
format: "uint16" /* UINT16 */,
unit: 'ppm',
maxValue: 65535,
minValue: 450,
minStep: 1,
perms: ["pr" /* PAIRED_READ */, "ev" /* NOTIFY */],
});
}
function _buildCloudProvisioningHashString(api) {
return generateCharacteristic(api, 'Cloud Provisioning Hash String', 'A18E8903-CFA1-4D37-A10F-0071CEEEEEBD', {
format: "string" /* STRING */,
perms: ["pr" /* PAIRED_READ */, "hd" /* HIDDEN */],
});
}
function _buildCloudHomeSync(api) {
return generateCharacteristic(api, 'Cloud Home Sync Description', 'A18E8902-CFA1-4D37-A10F-0071CEEEEEBD', {
format: "data" /* DATA */,
perms: ["pr" /* PAIRED_READ */, "hd" /* HIDDEN */],
});
}
function _buildCloudHomeSyncDescription(api) {
return generateCharacteristic(api, 'Cloud Home Sync Description', 'A18E8902-CFA1-4D37-A10F-0071CEEEEEBD', {
format: "data" /* DATA */,
perms: ["pr" /* PAIRED_READ */, "hd" /* HIDDEN */],
});
}
function _buildNanoleafColorTemperature(api) {
return generateCharacteristic(api, 'Color Temperature', 'A18E5901-CFA1-4D37-A10F-0071CEEEEEBD', {
format: "int" /* INT */,
perms: ["pr" /* PAIRED_READ */, "hd" /* HIDDEN */, "pw" /* PAIRED_WRITE */, "ev" /* NOTIFY */],
minValue: 1200,
maxValue: 6500,
minStep: 1,
});
}
function _buildAnimationSelect(api) {
return generateCharacteristic(api, 'Animation Select', 'A18E6902-CFA1-4D37-A10F-0071CEEEEEBD', {
format: "string" /* STRING */,
perms: ["pr" /* PAIRED_READ */, "hd" /* HIDDEN */, "pw" /* PAIRED_WRITE */, "ev" /* NOTIFY */],
});
}
function _buildAnimationWrite(api) {
return generateCharacteristic(api, 'Animation Write', 'A18E6903-CFA1-4D37-A10F-0071CEEEEEBD', {
format: "data" /* DATA */,
perms: ["pw" /* PAIRED_WRITE */, "hd" /* HIDDEN */],
});
}
function _buildAnimationRead(api) {
return generateCharacteristic(api, 'Animation Read', 'A18E6904-CFA1-4D37-A10F-0071CEEEEEBD', {
format: "data" /* DATA */,
perms: ["pr" /* PAIRED_READ */, "hd" /* HIDDEN */],
});
}
function _buildAnimationList(api) {
return generateCharacteristic(api, 'Animation List', 'A18E6905-CFA1-4D37-A10F-0071CEEEEEBD', {
format: "data" /* DATA */,
perms: ["pr" /* PAIRED_READ */, "hd" /* HIDDEN */, "ev" /* NOTIFY */],
});
}
function _buildAnimationPlayList(api) {
return generateCharacteristic(api, 'Animation Playlist', 'A18E690B-CFA1-4D37-A10F-0071CEEEEEBD', {
format: "string" /* STRING */,
perms: ["pr" /* PAIRED_READ */, "hd" /* HIDDEN */, "ev" /* NOTIFY */],
});
}
function _buildRythmActive(api) {
return generateCharacteristic(api, 'Rhythm Active', 'A18E6907-CFA1-4D37-A10F-0071CEEEEEBD', {
format: "bool" /* BOOL */,
perms: ["pr" /* PAIRED_READ */, "hd" /* HIDDEN */, "ev" /* NOTIFY */],
});
}
function _buildRythmConnected(api) {
return generateCharacteristic(api, 'Rhythm Connected', 'A18E6906-CFA1-4D37-A10F-0071CEEEEEBD', {
format: "bool" /* BOOL */,
perms: ["pr" /* PAIRED_READ */, "hd" /* HIDDEN */, "ev" /* NOTIFY */],
});
}
function _buildRythmMode(api) {
return generateCharacteristic(api, 'Rhythm Mode', 'A18E6908-CFA1-4D37-A10F-0071CEEEEEBD', {
format: "int" /* INT */,
perms: ["pr" /* PAIRED_READ */, "hd" /* HIDDEN */, "ev" /* NOTIFY */, "pw" /* PAIRED_WRITE */],
maxValue: 1,
minValue: 0,
minStep: 1,
unit: 'int',
});
}
function _buildRythmAuxAvailable(api) {
return generateCharacteristic(api, 'Rhythm Aux Available', 'A18E6909-CFA1-4D37-A10F-0071CEEEEEBD', {
format: "bool" /* BOOL */,
perms: ["pr" /* PAIRED_READ */, "hd" /* HIDDEN */, "ev" /* NOTIFY */],
});
}
function _buildNanoleafCustomEventNotifications(api) {
return generateCharacteristic(api, 'Custom Event Notifications', 'A18E690A-CFA1-4D37-A10F-0071CEEEEEBD', {
format: "data" /* DATA */,
perms: ["pr" /* PAIRED_READ */, "hd" /* HIDDEN */, "ev" /* NOTIFY */],
});
}
function _buildLayoutDetectionButton(api) {
return generateCharacteristic(api, 'Layout Detection Button', 'A18E7902-CFA1-4D37-A10F-0071CEEEEEBD', {
format: "bool" /* BOOL */,
perms: ["pr" /* PAIRED_READ */, "hd" /* HIDDEN */, "pw" /* PAIRED_WRITE */],
});
}
function _buildLayoutData(api) {
return generateCharacteristic(api, 'Layout Data', 'A18E7903-CFA1-4D37-A10F-0071CEEEEEBD', {
format: "data" /* DATA */,
perms: ["pr" /* PAIRED_READ */, "hd" /* HIDDEN */, "ev" /* NOTIFY */],
});
}
function _buildGlobalOrientation(api) {
return generateCharacteristic(api, 'Global Orientation', 'A18E7904-CFA1-4D37-A10F-0071CEEEEEBD', {
format: "int" /* INT */,
perms: ["pr" /* PAIRED_READ */, "hd" /* HIDDEN */, "ev" /* NOTIFY */, "pw" /* PAIRED_WRITE */],
maxValue: 360,
minValue: 0,
minStep: 1,
});
}
function _buildProductWarning(api) {
return generateCharacteristic(api, 'Product Warnings', 'A18E7905-CFA1-4D37-A10F-0071CEEEEEBD', {
format: "data" /* DATA */,
perms: ["pr" /* PAIRED_READ */, "ev" /* NOTIFY */, "hd" /* HIDDEN */],
});
}
function _buildNewFirmwareVersion(api) {
return generateCharacteristic(api, 'New Firmware Version', 'A18E1905-CFA1-4D37-A10F-0071CEEEEEBD', {
format: "string" /* STRING */,
perms: ["pr" /* PAIRED_READ */, "ev" /* NOTIFY */],
});
}
function _buildFirmwareAvailability(api) {
return generateCharacteristic(api, 'Firmware Availability', 'A18E1904-CFA1-4D37-A10F-0071CEEEEEBD', {
format: "bool" /* BOOL */,
perms: ["pr" /* PAIRED_READ */, "ev" /* NOTIFY */, "hd" /* HIDDEN */],
});
}
function _buildInstallFirmwareUpdate(api) {
return generateCharacteristic(api, 'Install Firmware Update', 'A18E1902-CFA1-4D37-A10F-0071CEEEEEBD', {
format: "bool" /* BOOL */,
perms: ["pr" /* PAIRED_READ */, "hd" /* HIDDEN */, "pw" /* PAIRED_WRITE */],
});
}
function _buildSyncState(api) {
return generateCharacteristic(api, 'Sync State', 'A18EB902-CFA1-4D37-A10F-0071CEEEEEBD', {
format: "int" /* INT */,
perms: ["pr" /* PAIRED_READ */, "pw" /* PAIRED_WRITE */, "pw" /* PAIRED_WRITE */],
maxValue: 2,
minValue: 0,
minStep: 1,
});
}
function _buildRestoreFromCloud(api) {
return generateCharacteristic(api, 'Restore From Cloud', 'A18EB903-CFA1-4D37-A10F-0071CEEEEEBD', {
format: "bool" /* BOOL */,
perms: ["pw" /* PAIRED_WRITE */],
});
}
function _buildLayoutDetectionService(api, parent) {
return generateService(api, 'Layout Detection Service', 'A18E7901-CFA1-4D37-A10F-0071CEEEEEBD', [parent.LayoutDetectionButton, parent.LayoutData, parent.GlobalOrientation, parent.ProductWarnings]);
}
function _buildAnimationService(api, parent) {
return generateService(api, 'Animation Service', 'A18E6901-CFA1-4D37-A10F-0071CEEEEEBD', [
parent.AnimationSelect,
parent.AnimationWrite,
parent.AnimationRead,
parent.AnimationList,
parent.AnimationPlayList,
parent.RythmActive,
parent.RythmConnected,
parent.RythmMode,
parent.RythmAuxAvailable,
parent.NanoleafCustomEventNotifications,
]);
}
function _buildFirmwareUpdateService(api, parent) {
return generateService(api, 'Firmware Update Service', 'A18E1901-CFA1-4D37-A10F-0071CEEEEEBD', [parent.NewFirmwareVersion, parent.FirmwareAvailability, parent.InstallFirmwareUpdate]);
}
function _buildCloudSyncService(api, parent) {
return generateService(api, 'Cloud Sync', 'A18EB901-CFA1-4D37-A10F-0071CEEEEEBD', [parent.SyncState, parent.RestoreFromCloud]);
}
class SupportedServices {
constructor(api) {
this.api = api;
this.EveAirQuality = _buildEveAirQuality(api);
this.FakeGatoService = fakegato_history_1.default(api);
this.CloudProvisioningHashString = _buildCloudProvisioningHashString(api);
this.CloudHomeSyncDescription = _buildCloudHomeSyncDescription(api);
this.CloudHomeSync = _buildCloudHomeSync(api);
this.NanoleafColorTemperature = _buildNanoleafColorTemperature(api);
this.AnimationSelect = _buildAnimationSelect(api);
this.AnimationRead = _buildAnimationRead(api);
this.AnimationWrite = _buildAnimationWrite(api);
this.AnimationList = _buildAnimationList(api);
this.AnimationPlayList = _buildAnimationPlayList(api);
this.RythmActive = _buildRythmActive(api);
this.RythmConnected = _buildRythmConnected(api);
this.RythmMode = _buildRythmMode(api);
this.RythmAuxAvailable = _buildRythmAuxAvailable(api);
this.NanoleafCustomEventNotifications = _buildNanoleafCustomEventNotifications(api);
this.LayoutDetectionButton = _buildLayoutDetectionButton(api);
this.LayoutData = _buildLayoutData(api);
this.GlobalOrientation = _buildGlobalOrientation(api);
this.ProductWarnings = _buildProductWarning(api);
this.NewFirmwareVersion = _buildNewFirmwareVersion(api);
this.FirmwareAvailability = _buildFirmwareAvailability(api);
this.InstallFirmwareUpdate = _buildInstallFirmwareUpdate(api);
this.SyncState = _buildSyncState(api);
this.RestoreFromCloud = _buildRestoreFromCloud(api);
this.LayoutDetectionService = _buildLayoutDetectionService(api, this);
this.AnimationService = _buildAnimationService(api, this);
this.FirmwareUpdateService = _buildFirmwareUpdateService(api, this);
this.CloudSyncService = _buildCloudSyncService(api, this);
this._KnownServiceMap = mapShort(listKnownServices(api, this));
this._KnownCharMap = mapShort(listKnownCharacteristics(api, this));
// this.EveAirQuality = class EveAirQuality extends api.hap.Characteristic {
// static readonly UUID: string = 'E863F10B-079E-48FF-8F27-9C2605A29F52'
// constructor() {
// super('Air Quality PM25', EveAirQuality.UUID, {
// format: Formats.UINT16,
// perms: [Perms.NOTIFY, Perms.PAIRED_READ],
// maxValue: 65535,
// minValue: 500,
// minStep: 1,
// })
// this.value = this.getDefaultValue()
// }
// }
}
get KnownServiceMap() {
return this._KnownServiceMap;
}
get KnownCharMap() {
return this._KnownCharMap;
}
isID(needle, haystack) {
needle = needle.toLocaleUpperCase().trim();
haystack = haystack.toLocaleUpperCase().trim();
if (needle === haystack) {
return true;
}
while (needle.length < 8) {
needle = '0' + needle;
}
haystack = haystack.substring(0, 8);
return needle === haystack;
}
toPerm(inp) {
return inp.map((p) => {
if (p === 'pw') {
return "pw" /* PAIRED_WRITE */;
}
if (p === 'wr') {
return "wr" /* WRITE_RESPONSE */;
}
if (p === 'pr') {
return "pr" /* PAIRED_READ */;
}
if (p === 'ev') {
return "ev" /* EVENTS */;
}
if (p === 'aa') {
return "aa" /* ADDITIONAL_AUTHORIZATION */;
}
if (p === 'tw') {
return "tw" /* TIMED_WRITE */;
}
if (p === 'hd') {
return "hd" /* HIDDEN */;
}
return "hd" /* HIDDEN */;
});
}
classForService(type, source) {
const cl = classFromID(this._KnownServiceMap, type);
if (source === undefined) {
return cl;
}
//auto-create new service
if (cl == undefined) {
const allKeys = Object.keys(this.api.hap.Service);
const matches = allKeys
.filter((key) => this.api.hap.Service[key].UUID != undefined)
.map((key) => this.api.hap.Service[key])
.filter((service) => this.isID(type, service.UUID));
if (matches.length == 1 || matches.length == 0) {
let s;
if (matches.length == 1) {
s = matches[0];
}
else {
const characteristics = source.characteristics.map((cIn) => this.classForChar(cIn.type, cIn));
const names = source.characteristics.filter((c) => c.type === '23' || c.type === this.api.hap.Characteristic.Name.UUID);
const name = names.length > 0 ? names[0].value : undefined;
s = generateService(this.api, name == undefined ? '' : name, type, characteristics);
}
this._KnownServiceMap.push({
id: s.UUID,
cls: s,
});
this._KnownServiceMap.push({
id: shortType(s.UUID),
cls: s,
});
return s;
}
}
return cl;
}
copyCharacteristic(type, source) {
const name = source.description;
return generateCharacteristic(this.api, name === undefined ? '' : name, type, {
format: source.format,
perms: this.toPerm(source.perms),
unit: source.unit,
description: source.description,
minValue: source.minValue,
maxValue: source.maxValue,
minStep: source.minStep,
maxLen: source.maxLen,
maxDataLen: source.format === "data" /* DATA */ ? undefined : source.maxDataLen,
validValues: source.validValues,
validValueRanges: source.validValueRanges,
adminOnlyAccess: source.adminOnlyAccess,
});
}
classForChar(type, source) {
const cl = classFromID(this._KnownCharMap, type);
if (source === undefined) {
return cl;
}
//auto-create new characteristic
if (cl == undefined) {
const allKeys = Object.keys(this.api.hap.Characteristic);
const matches = allKeys
.filter((key) => this.api.hap.Characteristic[key].UUID != undefined)
.map((key) => this.api.hap.Characteristic[key])
.filter((char) => this.isID(type, char.UUID));
if (matches.length == 1 || matches.length == 0) {
const c = matches.length == 1 ? matches[0] : this.copyCharacteristic(type, source);
this._KnownCharMap.push({
id: c.UUID,
cls: c,
});
this._KnownCharMap.push({
id: shortType(c.UUID),
cls: c,
});
return c;
}
}
return cl;
}
}
exports.SupportedServices = SupportedServices;
//# sourceMappingURL=SupportedDevices.js.map