generated from homebridge/homebridge-plugin-template
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathaccessories.service.ts
156 lines (133 loc) · 5.15 KB
/
accessories.service.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
import path from 'path';
import fs from 'fs-extra';
import { HapClient, ServiceType } from '@oznu/hap-client';
import { BadRequestException } from '@nestjs/common';
import { Logger, API } from 'homebridge';
export class AccessoriesService {
public hapClient: HapClient = undefined;
constructor(
private readonly api: API,
private readonly logger: Logger,
) { }
async init() {
try {
const homebridgeConfig = await fs.readJson(path.resolve(this.api.user.configPath()));
this.logger.info(`Read Config and PIN is ${homebridgeConfig.bridge.pin}`);
this.hapClient = new HapClient({
pin: homebridgeConfig.bridge.pin,
logger: this.logger,
config: { debug: true },
});
this.logger.info('HAP Configured');
} catch(err) {
this.logger.error(err);
}
}
/**
* Refresh the characteristics from Homebridge
* @param services
*/
private refreshCharacteristics(services: ServiceType[]) {
services.forEach(service => service.refreshCharacteristics());
}
/**
* Load all the accessories from Homebridge
* @param refreshServices
*/
public async loadAccessories(): Promise<ServiceType[]> {
return this.hapClient.getAllServices()
.then(services => {
this.logger.info(`Got Services from loadAccesories with length ${services.length}`);
return services;
})
.catch((e) => {
if (e.response?.status === 401) {
this.logger.warn('Homebridge must be running in insecure mode to view and control accessories from this plugin.');
} else {
this.logger.error(`Failed load accessories from Homebridge: ${e.message}`);
}
return [];
});
}
/**
* Get a single accessory and refresh it's characteristics
* @param uniqueId
*/
public async getAccessory(uniqueId: string) {
const services = await this.loadAccessories();
const service = services.find(x => x.uniqueId === uniqueId);
if (!service) {
throw new BadRequestException(`Service with uniqueId of '${uniqueId}' not found.`);
}
try {
await service.refreshCharacteristics();
return service;
} catch (e) {
throw new BadRequestException(e.message);
}
}
/**
* Set a characteristics value
* @param uniqueId
* @param iid
* @param value
*/
public async setAccessoryCharacteristic(uniqueId: string, characteristicType: string, value: number | boolean | string) {
const services = await this.loadAccessories();
const service = services.find(x => x.uniqueId === uniqueId);
if (!service) {
throw new BadRequestException(`Service with uniqueId of '${uniqueId}' not found.`);
}
const characteristic = service.getCharacteristic(characteristicType);
if (!characteristic || !characteristic.canWrite) {
const types = service.serviceCharacteristics.filter(x => x.canWrite).map(x => `'${x.type}'`).join(', ');
throw new BadRequestException(`Invalid characteristicType. Valid types are: ${types}.`);
}
// integers
if (['uint8', 'uint16', 'uint32', 'uint64'].includes(characteristic.format)) {
value = parseInt(value as string, 10);
if (characteristic.minValue !== undefined && value < characteristic.minValue) {
throw new BadRequestException(`Invalid value. The value must be between ${characteristic.minValue}
and ${characteristic.maxValue}.`);
}
if (characteristic.maxValue !== undefined && value > characteristic.maxValue) {
throw new BadRequestException(`Invalid value. The value must be between ${characteristic.minValue}
and ${characteristic.maxValue}.`);
}
}
// floats
if (characteristic.format === 'float') {
value = parseFloat(value as string);
if (characteristic.minValue !== undefined && value < characteristic.minValue) {
throw new BadRequestException(`Invalid value. The value must be between ${characteristic.minValue}
and ${characteristic.maxValue}.`);
}
if (characteristic.maxValue !== undefined && value > characteristic.maxValue) {
throw new BadRequestException(`Invalid value. The value must be between ${characteristic.minValue}
and ${characteristic.maxValue}.`);
}
}
// booleans
if (characteristic.format === 'bool') {
if (typeof value === 'string') {
if (['true', '1'].includes(value.toLowerCase())) {
value = true;
} else if (['false', '0'].includes(value.toLowerCase())) {
value = false;
}
} else if (typeof value === 'number') {
value = value === 1 ? true : false;
}
if (typeof value !== 'boolean') {
throw new BadRequestException('Invalid value. The value must be a boolean (true or false).');
}
}
try {
await characteristic.setValue(value);
await service.refreshCharacteristics();
return service;
} catch (e) {
throw new BadRequestException(e.message);
}
}
}