homebridge-yoto 0.0.4 → 0.0.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/config.schema.json +2 -21
- package/lib/auth.js +35 -18
- package/lib/constants.js +6 -6
- package/lib/platform.js +1 -3
- package/package.json +1 -1
package/config.schema.json
CHANGED
|
@@ -7,13 +7,6 @@
|
|
|
7
7
|
"schema": {
|
|
8
8
|
"type": "object",
|
|
9
9
|
"properties": {
|
|
10
|
-
"name": {
|
|
11
|
-
"title": "Platform Name",
|
|
12
|
-
"type": "string",
|
|
13
|
-
"default": "Yoto",
|
|
14
|
-
"required": true,
|
|
15
|
-
"description": "The name of the platform as it appears in Homebridge logs"
|
|
16
|
-
},
|
|
17
10
|
"clientId": {
|
|
18
11
|
"title": "OAuth Client ID",
|
|
19
12
|
"type": "string",
|
|
@@ -39,13 +32,7 @@
|
|
|
39
32
|
"required": false,
|
|
40
33
|
"description": "Token expiration timestamp (managed automatically)"
|
|
41
34
|
},
|
|
42
|
-
|
|
43
|
-
"title": "MQTT Broker URL",
|
|
44
|
-
"type": "string",
|
|
45
|
-
"default": "mqtt://mqtt.yotoplay.com:1883",
|
|
46
|
-
"required": false,
|
|
47
|
-
"description": "MQTT broker URL for real-time device communication"
|
|
48
|
-
},
|
|
35
|
+
|
|
49
36
|
"statusTimeoutSeconds": {
|
|
50
37
|
"title": "Status Timeout (seconds)",
|
|
51
38
|
"type": "number",
|
|
@@ -163,12 +150,6 @@
|
|
|
163
150
|
}
|
|
164
151
|
},
|
|
165
152
|
"layout": [
|
|
166
|
-
{
|
|
167
|
-
"type": "section",
|
|
168
|
-
"title": "Platform Configuration",
|
|
169
|
-
"expandable": false,
|
|
170
|
-
"items": ["name"]
|
|
171
|
-
},
|
|
172
153
|
{
|
|
173
154
|
"type": "section",
|
|
174
155
|
"title": "Authentication",
|
|
@@ -190,7 +171,7 @@
|
|
|
190
171
|
"title": "MQTT Configuration",
|
|
191
172
|
"expandable": true,
|
|
192
173
|
"expanded": false,
|
|
193
|
-
"items": ["
|
|
174
|
+
"items": ["statusTimeoutSeconds"]
|
|
194
175
|
},
|
|
195
176
|
{
|
|
196
177
|
"type": "section",
|
package/lib/auth.js
CHANGED
|
@@ -36,22 +36,34 @@ export class YotoAuth {
|
|
|
36
36
|
*/
|
|
37
37
|
async initiateDeviceFlow () {
|
|
38
38
|
this.log.info(LOG_PREFIX.AUTH, 'Initiating device authorization flow...')
|
|
39
|
+
this.log.debug(LOG_PREFIX.AUTH, `Client ID: ${this.clientId}`)
|
|
40
|
+
this.log.debug(LOG_PREFIX.AUTH, `Endpoint: ${YOTO_OAUTH_DEVICE_CODE_URL}`)
|
|
41
|
+
this.log.debug(LOG_PREFIX.AUTH, `Scope: ${OAUTH_SCOPE}`)
|
|
42
|
+
this.log.debug(LOG_PREFIX.AUTH, `Audience: ${OAUTH_AUDIENCE}`)
|
|
39
43
|
|
|
40
44
|
try {
|
|
45
|
+
const params = new URLSearchParams({
|
|
46
|
+
client_id: this.clientId,
|
|
47
|
+
scope: OAUTH_SCOPE,
|
|
48
|
+
audience: OAUTH_AUDIENCE
|
|
49
|
+
})
|
|
50
|
+
this.log.debug(LOG_PREFIX.AUTH, 'Request body:', params.toString())
|
|
51
|
+
|
|
41
52
|
const response = await fetch(YOTO_OAUTH_DEVICE_CODE_URL, {
|
|
42
53
|
method: 'POST',
|
|
43
54
|
headers: {
|
|
44
|
-
'Content-Type': 'application/
|
|
55
|
+
'Content-Type': 'application/x-www-form-urlencoded'
|
|
45
56
|
},
|
|
46
|
-
body:
|
|
47
|
-
client_id: this.clientId,
|
|
48
|
-
scope: OAUTH_SCOPE,
|
|
49
|
-
audience: OAUTH_AUDIENCE
|
|
50
|
-
})
|
|
57
|
+
body: params
|
|
51
58
|
})
|
|
52
59
|
|
|
60
|
+
this.log.debug(LOG_PREFIX.AUTH, `Response status: ${response.status}`)
|
|
61
|
+
this.log.debug(LOG_PREFIX.AUTH, 'Response headers:', Object.fromEntries(response.headers.entries()))
|
|
62
|
+
|
|
53
63
|
if (!response.ok) {
|
|
54
64
|
const errorText = await response.text()
|
|
65
|
+
this.log.error(LOG_PREFIX.AUTH, `Device code request failed with status ${response.status}`)
|
|
66
|
+
this.log.error(LOG_PREFIX.AUTH, `Error response: ${errorText}`)
|
|
55
67
|
throw new Error(`Device code request failed: ${response.status} ${errorText}`)
|
|
56
68
|
}
|
|
57
69
|
|
|
@@ -89,16 +101,19 @@ export class YotoAuth {
|
|
|
89
101
|
|
|
90
102
|
while (Date.now() - startTime < timeout) {
|
|
91
103
|
try {
|
|
104
|
+
const params = new URLSearchParams({
|
|
105
|
+
grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
|
|
106
|
+
device_code: deviceCode,
|
|
107
|
+
client_id: this.clientId,
|
|
108
|
+
audience: OAUTH_AUDIENCE
|
|
109
|
+
})
|
|
110
|
+
|
|
92
111
|
const response = await fetch(YOTO_OAUTH_TOKEN_URL, {
|
|
93
112
|
method: 'POST',
|
|
94
113
|
headers: {
|
|
95
|
-
'Content-Type': 'application/
|
|
114
|
+
'Content-Type': 'application/x-www-form-urlencoded'
|
|
96
115
|
},
|
|
97
|
-
body:
|
|
98
|
-
grant_type: 'urn:ietf:params:oauth:grant-type:device_code',
|
|
99
|
-
device_code: deviceCode,
|
|
100
|
-
client_id: this.clientId
|
|
101
|
-
})
|
|
116
|
+
body: params
|
|
102
117
|
})
|
|
103
118
|
|
|
104
119
|
if (response.ok) {
|
|
@@ -153,16 +168,18 @@ export class YotoAuth {
|
|
|
153
168
|
this.log.debug(LOG_PREFIX.AUTH, 'Refreshing access token...')
|
|
154
169
|
|
|
155
170
|
try {
|
|
171
|
+
const params = new URLSearchParams({
|
|
172
|
+
grant_type: 'refresh_token',
|
|
173
|
+
refresh_token: refreshToken,
|
|
174
|
+
client_id: this.clientId
|
|
175
|
+
})
|
|
176
|
+
|
|
156
177
|
const response = await fetch(YOTO_OAUTH_TOKEN_URL, {
|
|
157
178
|
method: 'POST',
|
|
158
179
|
headers: {
|
|
159
|
-
'Content-Type': 'application/
|
|
180
|
+
'Content-Type': 'application/x-www-form-urlencoded'
|
|
160
181
|
},
|
|
161
|
-
body:
|
|
162
|
-
grant_type: 'refresh_token',
|
|
163
|
-
refresh_token: refreshToken,
|
|
164
|
-
client_id: this.clientId
|
|
165
|
-
})
|
|
182
|
+
body: params
|
|
166
183
|
})
|
|
167
184
|
|
|
168
185
|
if (!response.ok) {
|
package/lib/constants.js
CHANGED
|
@@ -12,14 +12,15 @@ export const PLUGIN_NAME = 'homebridge-yoto'
|
|
|
12
12
|
* Yoto API endpoints
|
|
13
13
|
*/
|
|
14
14
|
export const YOTO_API_BASE_URL = 'https://api.yotoplay.com'
|
|
15
|
-
export const
|
|
16
|
-
export const
|
|
17
|
-
export const
|
|
15
|
+
export const YOTO_OAUTH_BASE_URL = 'https://login.yotoplay.com'
|
|
16
|
+
export const YOTO_OAUTH_AUTHORIZE_URL = `${YOTO_OAUTH_BASE_URL}/authorize`
|
|
17
|
+
export const YOTO_OAUTH_TOKEN_URL = `${YOTO_OAUTH_BASE_URL}/oauth/token`
|
|
18
|
+
export const YOTO_OAUTH_DEVICE_CODE_URL = `${YOTO_OAUTH_BASE_URL}/oauth/device/code`
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* MQTT configuration
|
|
21
22
|
*/
|
|
22
|
-
export const YOTO_MQTT_BROKER_URL = '
|
|
23
|
+
export const YOTO_MQTT_BROKER_URL = 'wss://aqrphjqbp3u2z-ats.iot.eu-west-2.amazonaws.com'
|
|
23
24
|
export const MQTT_RECONNECT_PERIOD = 5000 // milliseconds
|
|
24
25
|
export const MQTT_CONNECT_TIMEOUT = 30000 // milliseconds
|
|
25
26
|
|
|
@@ -45,7 +46,7 @@ export const MQTT_TOPIC_COMMAND_REBOOT = '/device/{deviceId}/command/reboot'
|
|
|
45
46
|
*/
|
|
46
47
|
export const OAUTH_CLIENT_ID = 'Y4HJ8BFqRQ24GQoLzgOzZ2KSqWmFG8LI'
|
|
47
48
|
export const OAUTH_AUDIENCE = 'https://api.yotoplay.com'
|
|
48
|
-
export const OAUTH_SCOPE = 'profile offline_access
|
|
49
|
+
export const OAUTH_SCOPE = 'profile offline_access'
|
|
49
50
|
export const OAUTH_POLLING_INTERVAL = 5000 // milliseconds
|
|
50
51
|
export const OAUTH_DEVICE_CODE_TIMEOUT = 300000 // 5 minutes
|
|
51
52
|
|
|
@@ -114,7 +115,6 @@ export const DEFAULT_CONFIG = {
|
|
|
114
115
|
platform: PLATFORM_NAME,
|
|
115
116
|
name: PLATFORM_NAME,
|
|
116
117
|
clientId: OAUTH_CLIENT_ID,
|
|
117
|
-
mqttBroker: YOTO_MQTT_BROKER_URL,
|
|
118
118
|
statusTimeoutSeconds: DEFAULT_STATUS_TIMEOUT_SECONDS,
|
|
119
119
|
exposeTemperature: true,
|
|
120
120
|
exposeBattery: true,
|
package/lib/platform.js
CHANGED
|
@@ -47,9 +47,7 @@ export class YotoPlatform {
|
|
|
47
47
|
// Initialize API clients
|
|
48
48
|
this.auth = new YotoAuth(log, this.config.clientId)
|
|
49
49
|
this.yotoApi = new YotoApi(log, this.auth)
|
|
50
|
-
this.yotoMqtt = new YotoMqtt(log
|
|
51
|
-
brokerUrl: this.config.mqttBroker
|
|
52
|
-
})
|
|
50
|
+
this.yotoMqtt = new YotoMqtt(log)
|
|
53
51
|
|
|
54
52
|
// Set up token refresh callback
|
|
55
53
|
this.yotoApi.setTokenRefreshCallback(this.handleTokenRefresh.bind(this))
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "homebridge-yoto",
|
|
3
3
|
"description": "Control your Yoto players through Apple HomeKit with real-time MQTT updates",
|
|
4
|
-
"version": "0.0.
|
|
4
|
+
"version": "0.0.6",
|
|
5
5
|
"author": "Bret Comnes <bcomnes@gmail.com> (https://bret.io)",
|
|
6
6
|
"bugs": {
|
|
7
7
|
"url": "https://github.com/bcomnes/homebridge-yoto/issues"
|