-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathplatform.ts
More file actions
165 lines (127 loc) · 5.36 KB
/
platform.ts
File metadata and controls
165 lines (127 loc) · 5.36 KB
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
157
158
159
160
161
162
163
164
165
import {
API,
IndependentPlatformPlugin,
Logger,
PlatformConfig,
Service,
Characteristic,
PlatformAccessory,
} from 'homebridge';
import fetch from 'node-fetch';
import { YamahaAVRAccessory } from './accessory.js';
import { YamahaVolumeAccessory } from './volumeAccessory.js';
import { PLATFORM_NAME, PLUGIN_NAME } from './settings.js';
import { AccessoryContext, DeviceInfo, Features, Zone } from './types.js';
import { YamahaPureDirectAccessory } from './pureDirectAccessory.js';
export class YamahaAVRPlatform implements IndependentPlatformPlugin {
public readonly Service: typeof Service = this.api.hap.Service;
public readonly Characteristic: typeof Characteristic = this.api.hap.Characteristic;
public readonly platformAccessories: PlatformAccessory[] = [];
public readonly externalAccessories: PlatformAccessory[] = [];
constructor(public readonly log: Logger, public readonly config: PlatformConfig, public readonly api: API) {
this.log.debug('Finished initializing platform:', this.config.name);
this.api.on('didFinishLaunching', () => {
if (!this.config.ip) {
this.log.error('IP address has not been set.');
return;
}
this.discoverAVR();
});
}
configureAccessory(accessory: PlatformAccessory) {
this.log.info('Loading accessory from cache:', accessory.displayName);
this.platformAccessories.push(accessory);
}
async discoverAVR() {
try {
const baseApiUrl = `http://${this.config.ip}/YamahaExtendedControl/v1`;
const deviceInfoResponse = await fetch(`${baseApiUrl}/system/getDeviceInfo`);
const deviceInfo = (await deviceInfoResponse.json()) as DeviceInfo;
const featuresResponse = await fetch(`${baseApiUrl}/system/getFeatures`);
const features = (await featuresResponse.json()) as Features;
if (deviceInfo.response_code !== 0) {
throw new Error();
}
const device: AccessoryContext['device'] = {
displayName: this.config.name ?? `Yamaha ${deviceInfo.model_name}`,
modelName: deviceInfo.model_name,
systemId: deviceInfo.system_id,
firmwareVersion: deviceInfo.system_version,
baseApiUrl,
};
if (this.config.enablePureDirectSwitch) {
await this.createPureDirectAccessory(device);
}
await this.createZoneAccessories(device, 'main');
features.zone.length > 1 && (await this.createZoneAccessories(device, 'zone2'));
features.zone.length > 2 && (await this.createZoneAccessories(device, 'zone3'));
features.zone.length > 3 && (await this.createZoneAccessories(device, 'zone4'));
if (this.externalAccessories.length > 0) {
this.api.publishExternalAccessories(PLUGIN_NAME, this.externalAccessories);
}
} catch {
this.log.error(`
Failed to get system config from ${this.config.name}. Please verify the AVR is connected and accessible at ${this.config.ip}
`);
}
}
async createZoneAccessories(device, zone) {
if (zone !== 'main' && !this.config[`${zone}Enabled`]) {
return;
}
const avrAccessory = await this.createAVRAccessory(device, zone);
this.externalAccessories.push(avrAccessory);
if (this.config.volumeAccessoryEnabled) {
await this.createVolumeAccessory(device, zone);
}
}
async createAVRAccessory(device: AccessoryContext['device'], zone: Zone['id']): Promise<PlatformAccessory> {
let uuid = `${device.systemId}_${this.config.ip}`;
if (zone !== 'main') {
uuid = `${uuid}_${zone}`;
}
uuid = this.api.hap.uuid.generate(uuid);
const accessory = new this.api.platformAccessory<AccessoryContext>(
`${device.displayName} ${zone}`,
uuid,
this.api.hap.Categories.AUDIO_RECEIVER,
);
accessory.context = { device };
new YamahaAVRAccessory(this, accessory, zone);
return accessory;
}
async createVolumeAccessory(device: AccessoryContext['device'], zone: Zone['id']): Promise<void> {
let uuid = `${device.systemId}_${this.config.ip}_volume`;
if (zone !== 'main') {
uuid = `${uuid}_${zone}`;
}
uuid = this.api.hap.uuid.generate(uuid);
const accessory = new this.api.platformAccessory<AccessoryContext>(
`AVR Vol. ${zone}`,
uuid,
this.api.hap.Categories.FAN,
);
accessory.context = { device };
new YamahaVolumeAccessory(this, accessory, zone);
const existingAccessory = this.platformAccessories.find((accessory) => accessory.UUID === uuid);
if (existingAccessory) {
this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [existingAccessory]);
}
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
}
async createPureDirectAccessory(device: AccessoryContext['device']): Promise<void> {
const uuid = this.api.hap.uuid.generate(`${device.systemId}_${this.config.ip}_pureDirect`);
const accessory = new this.api.platformAccessory<AccessoryContext>(
'AVR Pure Direct',
uuid,
this.api.hap.Categories.SWITCH,
);
accessory.context = { device };
new YamahaPureDirectAccessory(this, accessory);
const existingAccessory = this.platformAccessories.find((accessory) => accessory.UUID === uuid);
if (existingAccessory) {
this.api.unregisterPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [existingAccessory]);
}
this.api.registerPlatformAccessories(PLUGIN_NAME, PLATFORM_NAME, [accessory]);
}
}