Api.js
4.96 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
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
'use strict';
const Capabilities = require('./Capabilities')
, Lights = require('./Lights')
, Groups = require('./Groups')
, Configuration = require('./Configuration')
, Users = require('./Users')
, Sensors = require('./Sensors')
, Schedules = require('./Schedules')
, Scenes = require('./Scenes')
, Remote = require('./Remote')
, Rules = require('./Rules')
, ResourceLinks = require('./ResourceLinks')
, Cache = require('./Cache')
// , EntertainmentApi = require('./entertainment/EntertainmentApi')
, HueApiConfig = require('./HueApiConfig')
;
/**
* @typedef {import('@peter-murray/hue-bridge-model').model.Light} Light
* @typedef {import('./Cache')} Cache
*
* @type {Api}
*/
module.exports = class Api {
constructor(config, transport, remote) {
const self = this;
self._config = new HueApiConfig(config, transport, remote);
self._api = {
capabilities: new Capabilities(self),
configuration: new Configuration(self),
lights: new Lights(self),
groups: new Groups(self),
sensors: new Sensors(self),
schedules: new Schedules(self),
scenes: new Scenes(self),
users: new Users(self),
rules: new Rules(self),
resourceLinks: new ResourceLinks(self)
};
// Add the remote API if this is a remote instance of the API
if (self._config.isRemote) {
self._api.remote = new Remote(self);
}
//TODO initial investigation in to the Streaming API for Entertainment
// if (config.clientkey) {
// self.entertainment = new EntertainmentApi(self);
// }
// Load the initial state upon first connection
self._lastSyncTime = -1;
self._state = null;
self.syncWithBridge();
}
/** @returns {Capabilities} */
get capabilities() {
return this._api.capabilities;
}
/** @returns {Configuration} */
get configuration() {
return this._api.configuration;
}
/** @returns {Lights} */
get lights() {
return this._api.lights;
}
/** @returns {Groups} */
get groups() {
return this._api.groups;
}
/** @returns {Sensors} */
get sensors() {
return this._api.sensors;
}
/** @returns {Schedules} */
get schedules() {
return this._api.schedules;
}
/** @returns {Scenes} */
get scenes() {
return this._api.scenes;
}
/** @returns {Users} */
get users() {
return this._api.users;
}
/** @returns {Rules} */
get rules() {
return this._api.rules;
}
/** @returns {ResourceLinks} */
get resourceLinks() {
return this._api.resourceLinks;
}
/**
* Obtains the remote API endpoints, this will only be present if you have a remote connection established.
* @returns {Remote|null|undefined}
*/
get remote() {
return this._api.remote;
}
/**
* Obtains the previously cached state that was obtained from the bridge.
* @returns {Promise<Cache>}
*/
getCachedState() {
const self = this;
if (self.isSyncing()) {
return self._syncPromise.then(() => {
return self._state;
});
} else {
return Promise.resolve(self._state);
}
}
/**
* Checks to see if the API is still syncing with the Hue bridge.
* @returns {boolean}
*/
isSyncing() {
return this._syncPromise != null;
}
/**
* The timestamp of the last sync for the cached state.
* @returns {number}
*/
getLastSyncTime() {
return this._lastSyncTime;
}
/**
* Performs an async synchronization activity with the hue bridge to cache the state of things like lights, etc...
*/
syncWithBridge() {
const self = this;
if (!self.isSyncing()) {
if (self._config.username) {
// We can only sync if there is a username passed to us, which will not be the case if we are creating the user
// first.
self._syncPromise = self.configuration.getAll();
} else {
// We can only obtain the open config when no user is passed in
self._syncPromise = self.configuration.getUnauthenticatedConfig();
}
self._syncPromise = self._syncPromise.then(data => {
self._state = new Cache(data);
self._lastSyncTime = new Date().getTime();
self._syncPromise = null;
})
.catch(err => {
// This is an informational message for now as we do not yet want to blow up as it is difficult to see the
// context of this reported error from users so far.
console.error(`Failed to async load the bridge configuration data; ${err}`);
self._syncPromise = null;
});
}
}
/**
* Fetches the light for the specified id from the cached state.
* @param {number|string} id The id of the light to fetch from the cached state.
* @returns {Promise<Light>}
*/
getLightDefinition(id) {
return this.getCachedState()
.then(() => {
return this._state.getLight(id);
});
}
_getConfig() {
return this._config;
}
_getTransport() {
return this._config.transport;
}
_getRemote() {
return this._config.remote;
}
};