homebridge-yoto 0.0.5 → 0.0.7
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/lib/auth.js +35 -18
- package/lib/constants.js +19 -17
- package/lib/platform.js +98 -27
- package/lib/playerAccessory.js +26 -2
- package/lib/yotoApi.js +2 -1
- package/lib/yotoMqtt.js +15 -6
- package/package.json +1 -1
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,40 +12,42 @@ 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
23
|
export const YOTO_MQTT_BROKER_URL = 'wss://aqrphjqbp3u2z-ats.iot.eu-west-2.amazonaws.com'
|
|
24
|
+
export const YOTO_MQTT_AUTH_NAME = 'PublicJWTAuthorizer'
|
|
23
25
|
export const MQTT_RECONNECT_PERIOD = 5000 // milliseconds
|
|
24
26
|
export const MQTT_CONNECT_TIMEOUT = 30000 // milliseconds
|
|
25
27
|
|
|
26
28
|
/**
|
|
27
29
|
* MQTT topic templates
|
|
28
30
|
*/
|
|
29
|
-
export const MQTT_TOPIC_DATA_STATUS = '
|
|
30
|
-
export const MQTT_TOPIC_DATA_EVENTS = '
|
|
31
|
-
export const MQTT_TOPIC_RESPONSE = '
|
|
32
|
-
export const MQTT_TOPIC_COMMAND_STATUS_REQUEST = '
|
|
33
|
-
export const MQTT_TOPIC_COMMAND_EVENTS_REQUEST = '
|
|
34
|
-
export const MQTT_TOPIC_COMMAND_VOLUME_SET = '
|
|
35
|
-
export const MQTT_TOPIC_COMMAND_CARD_START = '
|
|
36
|
-
export const MQTT_TOPIC_COMMAND_CARD_STOP = '
|
|
37
|
-
export const MQTT_TOPIC_COMMAND_CARD_PAUSE = '
|
|
38
|
-
export const MQTT_TOPIC_COMMAND_CARD_RESUME = '
|
|
39
|
-
export const MQTT_TOPIC_COMMAND_SLEEP_TIMER = '
|
|
40
|
-
export const MQTT_TOPIC_COMMAND_AMBIENTS_SET = '
|
|
41
|
-
export const MQTT_TOPIC_COMMAND_REBOOT = '
|
|
31
|
+
export const MQTT_TOPIC_DATA_STATUS = 'device/{deviceId}/status'
|
|
32
|
+
export const MQTT_TOPIC_DATA_EVENTS = 'device/{deviceId}/events'
|
|
33
|
+
export const MQTT_TOPIC_RESPONSE = 'device/{deviceId}/response'
|
|
34
|
+
export const MQTT_TOPIC_COMMAND_STATUS_REQUEST = 'device/{deviceId}/command/status/request'
|
|
35
|
+
export const MQTT_TOPIC_COMMAND_EVENTS_REQUEST = 'device/{deviceId}/command/events/request'
|
|
36
|
+
export const MQTT_TOPIC_COMMAND_VOLUME_SET = 'device/{deviceId}/command/volume/set'
|
|
37
|
+
export const MQTT_TOPIC_COMMAND_CARD_START = 'device/{deviceId}/command/card/start'
|
|
38
|
+
export const MQTT_TOPIC_COMMAND_CARD_STOP = 'device/{deviceId}/command/card/stop'
|
|
39
|
+
export const MQTT_TOPIC_COMMAND_CARD_PAUSE = 'device/{deviceId}/command/card/pause'
|
|
40
|
+
export const MQTT_TOPIC_COMMAND_CARD_RESUME = 'device/{deviceId}/command/card/resume'
|
|
41
|
+
export const MQTT_TOPIC_COMMAND_SLEEP_TIMER = 'device/{deviceId}/command/sleep-timer/set'
|
|
42
|
+
export const MQTT_TOPIC_COMMAND_AMBIENTS_SET = 'device/{deviceId}/command/ambients/set'
|
|
43
|
+
export const MQTT_TOPIC_COMMAND_REBOOT = 'device/{deviceId}/command/reboot'
|
|
42
44
|
|
|
43
45
|
/**
|
|
44
46
|
* OAuth configuration
|
|
45
47
|
*/
|
|
46
48
|
export const OAUTH_CLIENT_ID = 'Y4HJ8BFqRQ24GQoLzgOzZ2KSqWmFG8LI'
|
|
47
49
|
export const OAUTH_AUDIENCE = 'https://api.yotoplay.com'
|
|
48
|
-
export const OAUTH_SCOPE = 'profile offline_access
|
|
50
|
+
export const OAUTH_SCOPE = 'openid profile offline_access'
|
|
49
51
|
export const OAUTH_POLLING_INTERVAL = 5000 // milliseconds
|
|
50
52
|
export const OAUTH_DEVICE_CODE_TIMEOUT = 300000 // 5 minutes
|
|
51
53
|
|
package/lib/platform.js
CHANGED
|
@@ -71,23 +71,7 @@ export class YotoPlatform {
|
|
|
71
71
|
try {
|
|
72
72
|
// Check if we have stored credentials
|
|
73
73
|
if (!this.config.accessToken || !this.config.refreshToken) {
|
|
74
|
-
this.
|
|
75
|
-
this.log.info(LOG_PREFIX.PLATFORM, 'Starting OAuth flow...')
|
|
76
|
-
|
|
77
|
-
const tokenResponse = await this.auth.authorize()
|
|
78
|
-
|
|
79
|
-
// Store tokens in config
|
|
80
|
-
this.config.accessToken = tokenResponse.access_token
|
|
81
|
-
this.config.refreshToken = tokenResponse.refresh_token || ''
|
|
82
|
-
this.config.tokenExpiresAt = this.auth.calculateExpiresAt(tokenResponse.expires_in)
|
|
83
|
-
|
|
84
|
-
this.log.info(LOG_PREFIX.PLATFORM, '✓ Authentication successful!')
|
|
85
|
-
this.log.warn(LOG_PREFIX.PLATFORM, 'IMPORTANT: Please update your Homebridge config with the following:')
|
|
86
|
-
this.log.warn(LOG_PREFIX.PLATFORM, JSON.stringify({
|
|
87
|
-
accessToken: this.config.accessToken,
|
|
88
|
-
refreshToken: this.config.refreshToken,
|
|
89
|
-
tokenExpiresAt: this.config.tokenExpiresAt
|
|
90
|
-
}, null, 2))
|
|
74
|
+
await this.performDeviceFlow()
|
|
91
75
|
}
|
|
92
76
|
|
|
93
77
|
// Set tokens in API client
|
|
@@ -97,16 +81,70 @@ export class YotoPlatform {
|
|
|
97
81
|
this.config.tokenExpiresAt || 0
|
|
98
82
|
)
|
|
99
83
|
|
|
100
|
-
// Connect to MQTT
|
|
101
|
-
await this.yotoMqtt.connect(this.config.accessToken)
|
|
102
|
-
|
|
103
84
|
// Discover and register devices
|
|
104
|
-
|
|
85
|
+
try {
|
|
86
|
+
await this.discoverDevices()
|
|
87
|
+
} catch (error) {
|
|
88
|
+
// Check if this is an auth error that requires re-authentication
|
|
89
|
+
if (error instanceof Error && error.message.includes('TOKEN_REFRESH_FAILED')) {
|
|
90
|
+
this.log.warn(LOG_PREFIX.PLATFORM, 'Token refresh failed, clearing tokens and restarting auth flow...')
|
|
91
|
+
await this.clearTokensAndReauth()
|
|
92
|
+
return
|
|
93
|
+
}
|
|
94
|
+
throw error
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Connect to MQTT with first device ID
|
|
98
|
+
if (this.accessories.size > 0) {
|
|
99
|
+
const firstAccessory = Array.from(this.accessories.values())[0]
|
|
100
|
+
if (firstAccessory) {
|
|
101
|
+
const firstDeviceId = firstAccessory.context.device.deviceId
|
|
102
|
+
await this.yotoMqtt.connect(this.config.accessToken || '', firstDeviceId)
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
105
|
} catch (error) {
|
|
106
106
|
this.log.error(LOG_PREFIX.PLATFORM, 'Initialization failed:', error)
|
|
107
107
|
}
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
+
/**
|
|
111
|
+
* Perform device authorization flow
|
|
112
|
+
* @returns {Promise<void>}
|
|
113
|
+
*/
|
|
114
|
+
async performDeviceFlow () {
|
|
115
|
+
this.log.warn(LOG_PREFIX.PLATFORM, ERROR_MESSAGES.NO_AUTH)
|
|
116
|
+
this.log.info(LOG_PREFIX.PLATFORM, 'Starting OAuth flow...')
|
|
117
|
+
|
|
118
|
+
const tokenResponse = await this.auth.authorize()
|
|
119
|
+
|
|
120
|
+
// Store tokens in config
|
|
121
|
+
this.config.accessToken = tokenResponse.access_token
|
|
122
|
+
this.config.refreshToken = tokenResponse.refresh_token || ''
|
|
123
|
+
this.config.tokenExpiresAt = this.auth.calculateExpiresAt(tokenResponse.expires_in)
|
|
124
|
+
|
|
125
|
+
// Save tokens to config file
|
|
126
|
+
await this.saveConfig()
|
|
127
|
+
|
|
128
|
+
this.log.info(LOG_PREFIX.PLATFORM, '✓ Authentication successful and saved to config!')
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Clear invalid tokens and restart authentication
|
|
133
|
+
* @returns {Promise<void>}
|
|
134
|
+
*/
|
|
135
|
+
async clearTokensAndReauth () {
|
|
136
|
+
// Clear tokens from config
|
|
137
|
+
this.config.accessToken = ''
|
|
138
|
+
this.config.refreshToken = ''
|
|
139
|
+
this.config.tokenExpiresAt = 0
|
|
140
|
+
|
|
141
|
+
// Save cleared config
|
|
142
|
+
await this.saveConfig()
|
|
143
|
+
|
|
144
|
+
// Restart initialization
|
|
145
|
+
await this.initialize()
|
|
146
|
+
}
|
|
147
|
+
|
|
110
148
|
/**
|
|
111
149
|
* Handle token refresh - update config
|
|
112
150
|
* @param {string} accessToken - New access token
|
|
@@ -114,17 +152,50 @@ export class YotoPlatform {
|
|
|
114
152
|
* @param {number} expiresAt - New expiration timestamp
|
|
115
153
|
*/
|
|
116
154
|
handleTokenRefresh (accessToken, refreshToken, expiresAt) {
|
|
117
|
-
this.log.info(LOG_PREFIX.PLATFORM, 'Token refreshed
|
|
155
|
+
this.log.info(LOG_PREFIX.PLATFORM, 'Token refreshed')
|
|
118
156
|
this.config.accessToken = accessToken
|
|
119
157
|
this.config.refreshToken = refreshToken
|
|
120
158
|
this.config.tokenExpiresAt = expiresAt
|
|
121
159
|
|
|
122
|
-
//
|
|
123
|
-
this.
|
|
124
|
-
|
|
125
|
-
}).catch(error => {
|
|
126
|
-
this.log.error(LOG_PREFIX.PLATFORM, 'Failed to reconnect MQTT after token refresh:', error)
|
|
160
|
+
// Save updated tokens to config file
|
|
161
|
+
this.saveConfig().catch(error => {
|
|
162
|
+
this.log.error(LOG_PREFIX.PLATFORM, 'Failed to save refreshed tokens:', error)
|
|
127
163
|
})
|
|
164
|
+
|
|
165
|
+
// Reconnect MQTT with new token
|
|
166
|
+
if (this.accessories.size > 0) {
|
|
167
|
+
const firstAccessory = Array.from(this.accessories.values())[0]
|
|
168
|
+
if (firstAccessory) {
|
|
169
|
+
const firstDeviceId = firstAccessory.context.device.deviceId
|
|
170
|
+
this.yotoMqtt.disconnect().then(() => {
|
|
171
|
+
return this.yotoMqtt.connect(accessToken, firstDeviceId)
|
|
172
|
+
}).catch(error => {
|
|
173
|
+
this.log.error(LOG_PREFIX.PLATFORM, 'Failed to reconnect MQTT after token refresh:', error)
|
|
174
|
+
})
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/**
|
|
180
|
+
* Save config to disk using Homebridge API
|
|
181
|
+
* @returns {Promise<void>}
|
|
182
|
+
*/
|
|
183
|
+
async saveConfig () {
|
|
184
|
+
try {
|
|
185
|
+
// Check if updatePlatformConfig is available (Homebridge 1.3.0+)
|
|
186
|
+
// @ts-expect-error - updatePlatformConfig may not exist in older Homebridge versions
|
|
187
|
+
if (typeof this.api.updatePlatformConfig === 'function') {
|
|
188
|
+
// @ts-expect-error - updatePlatformConfig may not exist in older Homebridge versions
|
|
189
|
+
await this.api.updatePlatformConfig([this.config])
|
|
190
|
+
this.log.debug(LOG_PREFIX.PLATFORM, 'Config saved to disk')
|
|
191
|
+
} else {
|
|
192
|
+
// Fallback for older Homebridge versions
|
|
193
|
+
this.log.debug(LOG_PREFIX.PLATFORM, 'Config updated in memory (restart Homebridge to persist)')
|
|
194
|
+
}
|
|
195
|
+
} catch (error) {
|
|
196
|
+
this.log.error(LOG_PREFIX.PLATFORM, 'Failed to save config:', error)
|
|
197
|
+
throw error
|
|
198
|
+
}
|
|
128
199
|
}
|
|
129
200
|
|
|
130
201
|
/**
|
package/lib/playerAccessory.js
CHANGED
|
@@ -93,8 +93,8 @@ export class YotoPlayerAccessory {
|
|
|
93
93
|
this.activeContentInfo = null
|
|
94
94
|
}
|
|
95
95
|
|
|
96
|
-
//
|
|
97
|
-
this.
|
|
96
|
+
// Connect MQTT for this device
|
|
97
|
+
this.connectMqtt()
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
/**
|
|
@@ -385,6 +385,30 @@ export class YotoPlayerAccessory {
|
|
|
385
385
|
.onSet(this.setAmbientLightBrightness.bind(this))
|
|
386
386
|
}
|
|
387
387
|
|
|
388
|
+
/**
|
|
389
|
+
* Connect MQTT for this device
|
|
390
|
+
*/
|
|
391
|
+
async connectMqtt () {
|
|
392
|
+
try {
|
|
393
|
+
// Ensure we have an access token
|
|
394
|
+
if (!this.platform.config.accessToken) {
|
|
395
|
+
this.log.warn(LOG_PREFIX.ACCESSORY, `[${this.device.name}] No access token available for MQTT connection`)
|
|
396
|
+
return
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
// Connect MQTT with device ID and access token
|
|
400
|
+
await this.platform.yotoMqtt.connect(
|
|
401
|
+
this.platform.config.accessToken,
|
|
402
|
+
this.device.deviceId
|
|
403
|
+
)
|
|
404
|
+
|
|
405
|
+
// Subscribe to device topics
|
|
406
|
+
await this.subscribeMqtt()
|
|
407
|
+
} catch (error) {
|
|
408
|
+
this.log.error(LOG_PREFIX.ACCESSORY, `[${this.device.name}] Failed to connect MQTT:`, error)
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
388
412
|
/**
|
|
389
413
|
* Subscribe to MQTT updates for this device
|
|
390
414
|
*/
|
package/lib/yotoApi.js
CHANGED
|
@@ -81,7 +81,8 @@ export class YotoApi {
|
|
|
81
81
|
}
|
|
82
82
|
} catch (error) {
|
|
83
83
|
this.log.error(LOG_PREFIX.API, 'Token refresh failed:', error)
|
|
84
|
-
|
|
84
|
+
// Throw specific error so platform can detect and restart auth flow
|
|
85
|
+
throw new Error('TOKEN_REFRESH_FAILED')
|
|
85
86
|
}
|
|
86
87
|
}
|
|
87
88
|
}
|
package/lib/yotoMqtt.js
CHANGED
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
import mqtt from 'mqtt'
|
|
9
9
|
import {
|
|
10
10
|
YOTO_MQTT_BROKER_URL,
|
|
11
|
+
YOTO_MQTT_AUTH_NAME,
|
|
11
12
|
MQTT_RECONNECT_PERIOD,
|
|
12
13
|
MQTT_CONNECT_TIMEOUT,
|
|
13
14
|
MQTT_TOPIC_DATA_STATUS,
|
|
@@ -51,9 +52,10 @@ export class YotoMqtt {
|
|
|
51
52
|
/**
|
|
52
53
|
* Connect to MQTT broker
|
|
53
54
|
* @param {string} accessToken - Yoto access token for authentication
|
|
55
|
+
* @param {string} deviceId - Device ID for MQTT client identification
|
|
54
56
|
* @returns {Promise<void>}
|
|
55
57
|
*/
|
|
56
|
-
async connect (accessToken) {
|
|
58
|
+
async connect (accessToken, deviceId) {
|
|
57
59
|
if (this.client) {
|
|
58
60
|
this.log.warn(LOG_PREFIX.MQTT, 'Already connected, disconnecting first...')
|
|
59
61
|
await this.disconnect()
|
|
@@ -62,12 +64,19 @@ export class YotoMqtt {
|
|
|
62
64
|
return new Promise((resolve, reject) => {
|
|
63
65
|
this.log.info(LOG_PREFIX.MQTT, `Connecting to ${this.brokerUrl}...`)
|
|
64
66
|
|
|
67
|
+
const clientId = `homebridge-yoto-${deviceId}-${Date.now()}`
|
|
68
|
+
|
|
65
69
|
this.client = mqtt.connect(this.brokerUrl, {
|
|
66
|
-
|
|
67
|
-
|
|
70
|
+
keepalive: 300,
|
|
71
|
+
port: 443,
|
|
72
|
+
protocol: 'wss',
|
|
73
|
+
username: `${deviceId}?x-amz-customauthorizer-name=${YOTO_MQTT_AUTH_NAME}`,
|
|
74
|
+
password: accessToken,
|
|
68
75
|
reconnectPeriod: MQTT_RECONNECT_PERIOD,
|
|
69
76
|
connectTimeout: MQTT_CONNECT_TIMEOUT,
|
|
70
|
-
|
|
77
|
+
clientId,
|
|
78
|
+
clean: true,
|
|
79
|
+
ALPNProtocols: ['x-amzn-mqtt-ca']
|
|
71
80
|
})
|
|
72
81
|
|
|
73
82
|
this.client.on('connect', () => {
|
|
@@ -319,10 +328,10 @@ export class YotoMqtt {
|
|
|
319
328
|
return
|
|
320
329
|
}
|
|
321
330
|
|
|
322
|
-
if (topic.includes('/
|
|
331
|
+
if (topic.includes('/status')) {
|
|
323
332
|
this.log.debug(LOG_PREFIX.MQTT, `Status update for ${deviceId}`)
|
|
324
333
|
callbacks.onStatus?.(payload)
|
|
325
|
-
} else if (topic.includes('/
|
|
334
|
+
} else if (topic.includes('/events')) {
|
|
326
335
|
this.log.debug(LOG_PREFIX.MQTT, `Events update for ${deviceId}`)
|
|
327
336
|
callbacks.onEvents?.(payload)
|
|
328
337
|
} else if (topic.includes('/response')) {
|
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.7",
|
|
5
5
|
"author": "Bret Comnes <bcomnes@gmail.com> (https://bret.io)",
|
|
6
6
|
"bugs": {
|
|
7
7
|
"url": "https://github.com/bcomnes/homebridge-yoto/issues"
|