mysa-js-sdk 1.0.1 → 1.1.0
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/dist/index.cjs +28 -2
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +87 -1
- package/dist/index.d.ts +87 -1
- package/dist/index.js +28 -2
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
package/dist/index.cjs
CHANGED
|
@@ -329,7 +329,33 @@ var MysaApiClient = class {
|
|
|
329
329
|
const session = await this.getFreshSession();
|
|
330
330
|
const response = await this._fetcher(`${MysaApiBaseUrl}/devices`, {
|
|
331
331
|
headers: {
|
|
332
|
-
Authorization: `${session.
|
|
332
|
+
Authorization: `${session.getIdToken().getJwtToken()}`
|
|
333
|
+
}
|
|
334
|
+
});
|
|
335
|
+
if (!response.ok) {
|
|
336
|
+
throw new MysaApiError(response);
|
|
337
|
+
}
|
|
338
|
+
return response.json();
|
|
339
|
+
}
|
|
340
|
+
async getDeviceFirmwares() {
|
|
341
|
+
this._logger.debug(`Fetching device firmwares...`);
|
|
342
|
+
const session = await this.getFreshSession();
|
|
343
|
+
const response = await this._fetcher(`${MysaApiBaseUrl}/devices/firmware`, {
|
|
344
|
+
headers: {
|
|
345
|
+
Authorization: `${session.getIdToken().getJwtToken()}`
|
|
346
|
+
}
|
|
347
|
+
});
|
|
348
|
+
if (!response.ok) {
|
|
349
|
+
throw new MysaApiError(response);
|
|
350
|
+
}
|
|
351
|
+
return response.json();
|
|
352
|
+
}
|
|
353
|
+
async getDeviceStates() {
|
|
354
|
+
this._logger.debug(`Fetching device states...`);
|
|
355
|
+
const session = await this.getFreshSession();
|
|
356
|
+
const response = await this._fetcher(`${MysaApiBaseUrl}/devices/state`, {
|
|
357
|
+
headers: {
|
|
358
|
+
Authorization: `${session.getIdToken().getJwtToken()}`
|
|
333
359
|
}
|
|
334
360
|
});
|
|
335
361
|
if (!response.ok) {
|
|
@@ -435,7 +461,7 @@ var MysaApiClient = class {
|
|
|
435
461
|
if (!this._cognitoUser || !this._cognitoUserSession) {
|
|
436
462
|
throw new UnauthenticatedError("An attempt was made to access a resource without a valid session.");
|
|
437
463
|
}
|
|
438
|
-
if (this._cognitoUserSession.isValid() && import_dayjs.default.unix(this._cognitoUserSession.
|
|
464
|
+
if (this._cognitoUserSession.isValid() && import_dayjs.default.unix(this._cognitoUserSession.getIdToken().getExpiration()).isAfter()) {
|
|
439
465
|
this._logger.info("Session is valid, no need to refresh");
|
|
440
466
|
return Promise.resolve(this._cognitoUserSession);
|
|
441
467
|
}
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/api/Errors.ts","../src/api/Logger.ts","../src/lib/EventEmitter.ts","../src/lib/PayloadParser.ts","../src/lib/PayloadTypeGuards.ts","../src/types/mqtt/in/InMessageType.ts","../src/types/mqtt/out/OutMessageType.ts","../src/api/MysaApiClient.ts"],"sourcesContent":["export * from './api';\nexport * from './types';\n","/** Error thrown when attempting to access the Mysa API without proper authentication. */\nexport class UnauthenticatedError extends Error {\n /**\n * Creates a new UnauthenticatedError instance.\n *\n * @param message - The error message\n */\n constructor(message: string) {\n super(message);\n this.name = 'UnauthenticatedError';\n }\n}\n\n/** Error thrown when a Mysa API request fails. */\nexport class MysaApiError extends Error {\n /** The HTTP status code returned by the API */\n readonly status: number;\n /** The HTTP status text returned by the API */\n readonly statusText: string;\n\n /**\n * Creates a new MysaApiError instance.\n *\n * @param apiResponse - The failed Response object from the API call\n */\n constructor(apiResponse: Response) {\n super(\n `Failed to call the '${apiResponse.url}' Mysa API endpoint. The server responded with a status of ${apiResponse.status} (${apiResponse.statusText}).`\n );\n this.name = 'MysaApiError';\n this.status = apiResponse.status;\n this.statusText = apiResponse.statusText;\n }\n}\n","/** Interface for logging operations at different severity levels */\nexport interface Logger {\n /** Logs a debug message with optional metadata */\n debug(message: string, ...meta: unknown[]): void;\n\n /** Logs an info message with optional metadata */\n info(message: string, ...meta: unknown[]): void;\n\n /** Logs a warning message with optional metadata */\n warn(message: string, ...meta: unknown[]): void;\n\n /** Logs an error message with optional metadata */\n error(message: string, ...meta: unknown[]): void;\n}\n\n/** Logger implementation that silently discards all log messages. */\n/* eslint-disable @typescript-eslint/no-unused-vars */\nexport class VoidLogger implements Logger {\n debug(message: string, ...meta: unknown[]): void {}\n info(message: string, ...meta: unknown[]): void {}\n warn(message: string, ...meta: unknown[]): void {}\n error(message: string, ...meta: unknown[]): void {}\n}\n/* eslint-enable @typescript-eslint/no-unused-vars */\n","import { EventEmitter as NodeEventEmitter } from 'node:events';\n\n/**\n * Typed wrapper around Node's `EventEmitter` class.\n *\n * @remarks\n * Source: {@link https://blog.makerx.com.au/a-type-safe-event-emitter-in-node-js}\n */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nexport class EventEmitter<TEvents extends Record<string, any>> implements NodeJS.EventEmitter {\n private _emitter = new NodeEventEmitter();\n\n emit<TEventName extends keyof TEvents & string>(eventName: TEventName, ...eventArg: TEvents[TEventName]) {\n return this._emitter.emit(eventName, ...(eventArg as []));\n }\n\n on<TEventName extends keyof TEvents & string>(\n eventName: TEventName,\n handler: (...eventArg: TEvents[TEventName]) => void\n ) {\n this._emitter.on(eventName, handler as any);\n return this;\n }\n\n once<TEventName extends keyof TEvents & string>(\n eventName: TEventName,\n handler: (...eventArg: TEvents[TEventName]) => void\n ) {\n this._emitter.once(eventName, handler as any);\n return this;\n }\n\n off<TEventName extends keyof TEvents & string>(\n eventName: TEventName,\n handler: (...eventArg: TEvents[TEventName]) => void\n ) {\n this._emitter.off(eventName, handler as any);\n return this;\n }\n\n addListener<TEventName extends keyof TEvents & string>(\n eventName: TEventName,\n listener: (...args: TEvents[TEventName]) => void\n ) {\n this._emitter.addListener(eventName, listener);\n return this;\n }\n\n removeListener<TEventName extends keyof TEvents & string>(\n eventName: TEventName,\n listener: (...args: TEvents[TEventName]) => void\n ) {\n this._emitter.removeListener(eventName, listener);\n return this;\n }\n\n removeAllListeners<TEventName extends keyof TEvents & string>(eventName?: TEventName | undefined) {\n this._emitter.removeAllListeners(eventName);\n return this;\n }\n\n setMaxListeners(n: number) {\n this._emitter.setMaxListeners(n);\n return this;\n }\n\n getMaxListeners(): number {\n return this._emitter.getMaxListeners();\n }\n\n listeners<TEventName extends keyof TEvents & string>(eventName: TEventName) {\n return this._emitter.listeners(eventName);\n }\n\n rawListeners<TEventName extends keyof TEvents & string>(eventName: TEventName) {\n return this._emitter.rawListeners(eventName);\n }\n\n listenerCount<TEventName extends keyof TEvents & string>(\n eventName: TEventName,\n listener?: (...args: TEvents[TEventName]) => void\n ) {\n return this._emitter.listenerCount(eventName, listener);\n }\n\n prependListener<TEventName extends keyof TEvents & string>(\n eventName: TEventName,\n listener: (...args: TEvents[TEventName]) => void\n ) {\n this._emitter.prependListener(eventName, listener);\n return this;\n }\n\n prependOnceListener<TEventName extends keyof TEvents & string>(\n eventName: TEventName,\n listener: (...args: TEvents[TEventName]) => void\n ) {\n this._emitter.prependOnceListener(eventName, listener);\n return this;\n }\n\n eventNames() {\n return this._emitter.eventNames();\n }\n}\n/* eslint-enable @typescript-eslint/no-explicit-any */\n","import { InPayload } from '@/types/mqtt/InPayload';\nimport { OutPayload } from '@/types/mqtt/OutPayload';\n\n/**\n * Parses an MQTT payload from binary data into a typed OutPayload object.\n *\n * Converts the raw ArrayBuffer received from MQTT messages into a structured TypeScript object representing device\n * status, state changes, or other outgoing message types from Mysa devices.\n *\n * @param payload - The raw binary MQTT message payload as ArrayBuffer\n * @returns The parsed payload as a typed OutPayload object\n * @throws Error if the payload cannot be decoded or parsed as valid JSON\n */\nexport function parseMqttPayload(payload: ArrayBuffer): OutPayload {\n try {\n const decoder = new TextDecoder('utf-8');\n const jsonString = decoder.decode(payload);\n return JSON.parse(jsonString);\n } catch (error) {\n console.error('Error parsing MQTT payload:', error);\n throw new Error('Failed to parse MQTT payload');\n }\n}\n\n/**\n * Serializes an InPayload object into binary data for MQTT transmission.\n *\n * Converts a typed TypeScript payload object into the binary ArrayBuffer format required for sending commands and\n * requests to Mysa devices via MQTT.\n *\n * @typeParam T - The specific InPayload type being serialized\n * @param payload - The typed payload object to serialize\n * @returns The serialized payload as ArrayBuffer ready for MQTT transmission\n */\nexport function serializeMqttPayload<T extends InPayload>(payload: T): ArrayBuffer {\n const jsonString = JSON.stringify(payload);\n const encoder = new TextEncoder();\n return encoder.encode(jsonString);\n}\n","import { MsgOutPayload } from '@/types/mqtt/MsgOutPayload';\nimport { MsgTypeOutPayload } from '@/types/mqtt/MsgTypeOutPayload';\nimport { OutPayload } from '@/types/mqtt/OutPayload';\n\n/**\n * Type guard function to determine if an OutPayload is a MsgType-based payload.\n *\n * Checks whether the payload uses the legacy MsgType field format for message type identification. This is used to\n * differentiate between different payload structures and ensure proper type narrowing in TypeScript.\n *\n * @param payload - The OutPayload to check\n * @returns True if the payload is a MsgTypeOutPayload, false otherwise\n */\nexport function isMsgTypeOutPayload(payload: OutPayload): payload is MsgTypeOutPayload {\n return 'MsgType' in payload;\n}\n\n/**\n * Type guard function to determine if an OutPayload is a message-based payload.\n *\n * Checks whether the payload uses the newer msg field format for message type identification. This is used to\n * differentiate between different payload structures and ensure proper type narrowing in TypeScript.\n *\n * @param payload - The OutPayload to check\n * @returns True if the payload is a MsgOutPayload, false otherwise\n */\nexport function isMsgOutPayload(payload: OutPayload): payload is MsgOutPayload {\n return 'msg' in payload;\n}\n","/**\n * Enumeration of message types for incoming MQTT messages from clients to devices.\n *\n * These message types determine how commands and requests are interpreted by Mysa devices. The enum values correspond\n * to specific numeric identifiers used in the MQTT protocol.\n */\nexport enum InMessageType {\n //\n // When the message type is reported in the `MsgType` field of the payload.\n //\n\n /** Request to check and retrieve current device settings */\n CHECK_DEVICE_SETTINGS = 6,\n\n /** Command to start publishing periodic device status updates */\n START_PUBLISHING_DEVICE_STATUS = 11,\n\n //\n // When the message type is reported in the `msg` field of the payload.\n //\n\n /** Command to change the current state of a device (temperature, mode, etc.) */\n CHANGE_DEVICE_STATE = 44\n}\n","/**\n * Enumeration of message types for outgoing MQTT messages from devices to clients.\n *\n * These message types identify different kinds of status updates, notifications, and data reports that Mysa devices can\n * send via MQTT. The enum values correspond to specific numeric identifiers used in the MQTT protocol.\n */\nexport enum OutMessageType {\n //\n // When the message type is reported in the `MsgType` field of the payload.\n //\n\n /** Version 1 device status report with basic device information */\n DEVICE_V1_STATUS = 0,\n\n /** Notification that a device's temperature setpoint has been changed */\n DEVICE_SETPOINT_CHANGE = 1,\n\n /** Device log entry or diagnostic information */\n DEVICE_LOG = 4,\n\n /** Notification sent when a device completes its boot sequence */\n DEVICE_POST_BOOT = 10,\n\n //\n // When the message type is reported in the `msg` field of the payload.\n //\n\n /** Version 2 device status report with enhanced device information */\n DEVICE_V2_STATUS = 40,\n\n /** Notification that a device's operational state has changed */\n DEVICE_STATE_CHANGE = 44\n}\n","import { MysaSession } from '@/api/MysaSession';\nimport { EventEmitter } from '@/lib/EventEmitter';\nimport { parseMqttPayload, serializeMqttPayload } from '@/lib/PayloadParser';\nimport { isMsgOutPayload, isMsgTypeOutPayload } from '@/lib/PayloadTypeGuards';\nimport { ChangeDeviceState } from '@/types/mqtt/in/ChangeDeviceState';\nimport { InMessageType } from '@/types/mqtt/in/InMessageType';\nimport { StartPublishingDeviceStatus } from '@/types/mqtt/in/StartPublishingDeviceStatus';\nimport { OutMessageType } from '@/types/mqtt/out/OutMessageType';\nimport { Devices } from '@/types/rest/Devices';\nimport { fromCognitoIdentityPool } from '@aws-sdk/credential-providers';\nimport {\n AuthenticationDetails,\n CognitoAccessToken,\n CognitoIdToken,\n CognitoRefreshToken,\n CognitoUser,\n CognitoUserPool,\n CognitoUserSession\n} from 'amazon-cognito-identity-js';\nimport { iot, mqtt } from 'aws-iot-device-sdk-v2';\nimport dayjs from 'dayjs';\nimport duration from 'dayjs/plugin/duration';\nimport { MysaApiError, UnauthenticatedError } from './Errors';\nimport { Logger, VoidLogger } from './Logger';\nimport { MysaApiClientEventTypes } from './MysaApiClientEventTypes';\nimport { MysaApiClientOptions } from './MysaApiClientOptions';\nimport { MysaDeviceMode } from './MysaDeviceMode';\n\ndayjs.extend(duration);\n\nconst AwsRegion = 'us-east-1';\nconst CognitoUserPoolId = 'us-east-1_GUFWfhI7g';\nconst CognitoClientId = '19efs8tgqe942atbqmot5m36t3';\nconst CognitoIdentityPoolId = 'us-east-1:ebd95d52-9995-45da-b059-56b865a18379';\nconst CognitoLoginKey = `cognito-idp.${AwsRegion}.amazonaws.com/${CognitoUserPoolId}`;\nconst MqttEndpoint = 'a3q27gia9qg3zy-ats.iot.us-east-1.amazonaws.com';\nconst MysaApiBaseUrl = 'https://app-prod.mysa.cloud';\nconst RealtimeKeepAliveInterval = dayjs.duration(5, 'minutes');\n\n/**\n * Main client for interacting with the Mysa API and real-time device communication.\n *\n * The MysaApiClient provides a comprehensive interface for authenticating with Mysa services, managing device data, and\n * receiving real-time updates from Mysa thermostats and heating devices. It handles both REST API calls for device\n * management and MQTT connections for live status updates and control commands.\n *\n * @example\n *\n * ```typescript\n * const client = new MysaApiClient();\n *\n * await client.login('user@example.com', 'password');\n * const devices = await client.getDevices();\n *\n * client.emitter.on('statusChanged', (status) => {\n * console.log(`Device ${status.deviceId} temperature: ${status.temperature}°C`);\n * });\n *\n * for (const device of Object.entries(devices.DevicesObj)) {\n * await client.startRealtimeUpdates(device[0]);\n * }\n * ```\n */\nexport class MysaApiClient {\n /** The current session object, if any. */\n private _cognitoUserSession?: CognitoUserSession;\n\n /** The current user object, if any. */\n private _cognitoUser?: CognitoUser;\n\n /** The logger instance used by the client. */\n private _logger: Logger;\n\n /** The fetcher function used by the client. */\n private _fetcher: typeof fetch;\n\n /** The MQTT connection used for real-time updates. */\n private _mqttConnection?: mqtt.MqttClientConnection;\n\n /** The device IDs that are currently being updated in real-time, mapped to their respective timeouts. */\n private _realtimeDeviceIds: Map<string, NodeJS.Timeout> = new Map();\n\n /** The cached devices object, if any. */\n private _cachedDevices?: Devices;\n\n /**\n * Event emitter for client events.\n *\n * @see {@link MysaApiClientEventTypes} for the possible events and their payloads.\n */\n readonly emitter = new EventEmitter<MysaApiClientEventTypes>();\n\n /**\n * Gets the persistable session object.\n *\n * @returns The current persistable session object, if any.\n */\n get session(): MysaSession | undefined {\n if (!this._cognitoUserSession || !this._cognitoUser) {\n return undefined;\n }\n\n return {\n username: this._cognitoUser.getUsername(),\n idToken: this._cognitoUserSession.getIdToken().getJwtToken(),\n accessToken: this._cognitoUserSession.getAccessToken().getJwtToken(),\n refreshToken: this._cognitoUserSession.getRefreshToken().getToken()\n };\n }\n\n /**\n * Returns whether the client currently has an active session.\n *\n * @returns True if the client has an active session, false otherwise.\n */\n get isAuthenticated(): boolean {\n return !!this.session;\n }\n\n /**\n * Constructs a new instance of the MysaApiClient.\n *\n * @param session - The persistable session object, if any.\n * @param options - The options for the client.\n */\n constructor(session?: MysaSession, options?: MysaApiClientOptions) {\n this._logger = options?.logger || new VoidLogger();\n this._fetcher = options?.fetcher || fetch;\n\n if (session) {\n this._cognitoUser = new CognitoUser({\n Username: session.username,\n Pool: new CognitoUserPool({ UserPoolId: CognitoUserPoolId, ClientId: CognitoClientId })\n });\n this._cognitoUserSession = new CognitoUserSession({\n IdToken: new CognitoIdToken({ IdToken: session.idToken }),\n AccessToken: new CognitoAccessToken({ AccessToken: session.accessToken }),\n RefreshToken: new CognitoRefreshToken({ RefreshToken: session.refreshToken })\n });\n }\n }\n\n /**\n * Logs in the user with the given email address and password.\n *\n * @param emailAddress - The email address of the user.\n * @param password - The password of the user.\n */\n async login(emailAddress: string, password: string): Promise<void> {\n this._cognitoUser = undefined;\n this._cognitoUserSession = undefined;\n this.emitter.emit('sessionChanged', this.session);\n\n return new Promise((resolve, reject) => {\n const user = new CognitoUser({\n Username: emailAddress,\n Pool: new CognitoUserPool({ UserPoolId: CognitoUserPoolId, ClientId: CognitoClientId })\n });\n\n user.authenticateUser(new AuthenticationDetails({ Username: emailAddress, Password: password }), {\n onSuccess: (session) => {\n this._cognitoUser = user;\n this._cognitoUserSession = session;\n this.emitter.emit('sessionChanged', this.session);\n\n resolve();\n },\n onFailure: (err) => {\n reject(err);\n }\n });\n });\n }\n\n /**\n * Retrieves the list of devices associated with the user.\n *\n * @returns A promise that resolves to the list of devices.\n */\n async getDevices(): Promise<Devices> {\n this._logger.debug(`Fetching devices...`);\n\n const session = await this.getFreshSession();\n\n const response = await this._fetcher(`${MysaApiBaseUrl}/devices`, {\n headers: {\n Authorization: `${session.getAccessToken().getJwtToken()}`\n }\n });\n\n if (!response.ok) {\n throw new MysaApiError(response);\n }\n\n return response.json();\n }\n\n async setDeviceState(deviceId: string, setPoint?: number, mode?: MysaDeviceMode) {\n this._logger.debug(`Setting device state for '${deviceId}'`);\n\n if (!this._cachedDevices) {\n this._cachedDevices = await this.getDevices();\n }\n\n const device = this._cachedDevices.DevicesObj[deviceId];\n\n this._logger.debug(`Initializing MQTT connection...`);\n const mqttConnection = await this.getMqttConnection();\n\n const now = dayjs();\n\n this._logger.debug(`Sending request to set device state for '${deviceId}'...`);\n const payload = serializeMqttPayload<ChangeDeviceState>({\n msg: InMessageType.CHANGE_DEVICE_STATE,\n id: now.unix(),\n time: now.unix(),\n ver: '1.0',\n src: {\n ref: this.session!.username,\n type: 100\n },\n dest: {\n ref: deviceId,\n type: 1\n },\n resp: 2,\n body: {\n ver: 1,\n type: device.Model.startsWith('BB-V1')\n ? 1\n : device.Model.startsWith('BB-V2')\n ? device.Model.endsWith('-L')\n ? 5\n : 4\n : 0,\n cmd: [\n {\n tm: -1,\n sp: setPoint,\n md: mode === 'off' ? 1 : mode === 'heat' ? 3 : undefined\n }\n ]\n }\n });\n\n await mqttConnection.publish(`/v1/dev/${deviceId}/in`, payload, mqtt.QoS.AtLeastOnce);\n }\n\n /**\n * Starts receiving real-time updates for the specified device.\n *\n * @param deviceId - The ID of the device to start receiving updates for.\n */\n async startRealtimeUpdates(deviceId: string) {\n this._logger.info(`Starting realtime updates for device '${deviceId}'`);\n\n if (this._realtimeDeviceIds.has(deviceId)) {\n this._logger.debug(`Realtime updates for device '${deviceId}' already started`);\n return;\n }\n\n this._logger.debug(`Initializing MQTT connection...`);\n const mqttConnection = await this.getMqttConnection();\n\n this._logger.debug(`Subscribing to MQTT topic '/v1/dev/${deviceId}/out'...`);\n await mqttConnection.subscribe(`/v1/dev/${deviceId}/out`, mqtt.QoS.AtLeastOnce, (_, payload) => {\n this.processMqttMessage(payload);\n });\n\n this._logger.debug(`Sending request to start publishing device status for '${deviceId}'...`);\n const payload = serializeMqttPayload<StartPublishingDeviceStatus>({\n Device: deviceId,\n MsgType: InMessageType.START_PUBLISHING_DEVICE_STATUS,\n Timestamp: dayjs().unix(),\n Timeout: RealtimeKeepAliveInterval.asSeconds()\n });\n await mqttConnection.publish(`/v1/dev/${deviceId}/in`, payload, mqtt.QoS.AtLeastOnce);\n\n const timer = setInterval(async () => {\n this._logger.debug(`Sending request to keep-alive publishing device status for '${deviceId}'...`);\n const payload = serializeMqttPayload<StartPublishingDeviceStatus>({\n Device: deviceId,\n MsgType: InMessageType.START_PUBLISHING_DEVICE_STATUS,\n Timestamp: dayjs().unix(),\n Timeout: RealtimeKeepAliveInterval.asSeconds()\n });\n await mqttConnection.publish(`/v1/dev/${deviceId}/in`, payload, mqtt.QoS.AtLeastOnce);\n }, RealtimeKeepAliveInterval.subtract(10, 'seconds').asMilliseconds());\n\n this._realtimeDeviceIds.set(deviceId, timer);\n }\n\n /**\n * Stops receiving real-time updates for the specified device.\n *\n * @param deviceId - The ID of the device to stop receiving real-time updates for.\n */\n async stopRealtimeUpdates(deviceId: string) {\n const timer = this._realtimeDeviceIds.get(deviceId);\n if (!timer) {\n this._logger.warn(`No real-time updates are running for device '${deviceId}'`);\n return;\n }\n\n this._logger.debug(`Initializing MQTT connection...`);\n const mqttConnection = await this.getMqttConnection();\n\n this._logger.debug(`Unsubscribing to MQTT topic '/v1/dev/${deviceId}/out'...`);\n await mqttConnection.unsubscribe(`/v1/dev/${deviceId}/out`);\n\n this._logger.debug(`Stopping real-time updates for device '${deviceId}'...`);\n clearInterval(timer);\n this._realtimeDeviceIds.delete(deviceId);\n }\n\n private async getFreshSession(): Promise<CognitoUserSession> {\n if (!this._cognitoUser || !this._cognitoUserSession) {\n throw new UnauthenticatedError('An attempt was made to access a resource without a valid session.');\n }\n\n if (\n this._cognitoUserSession.isValid() &&\n dayjs.unix(this._cognitoUserSession.getAccessToken().getExpiration()).isAfter()\n ) {\n this._logger.info('Session is valid, no need to refresh');\n return Promise.resolve(this._cognitoUserSession);\n }\n\n this._logger.info('Session is not valid or expired, refreshing...');\n return new Promise<CognitoUserSession>((resolve, reject) => {\n this._cognitoUser!.refreshSession(this._cognitoUserSession!.getRefreshToken(), (error, session) => {\n if (error) {\n this._logger.error('Failed to refresh session:', error);\n reject(new UnauthenticatedError('Unable to refresh the authentication session.'));\n } else {\n this._logger.info('Session refreshed successfully');\n this._cognitoUserSession = session;\n this.emitter.emit('sessionChanged', this.session);\n resolve(session);\n }\n });\n });\n }\n\n private async getMqttConnection(): Promise<mqtt.MqttClientConnection> {\n if (this._mqttConnection) {\n return this._mqttConnection;\n }\n\n const session = await this.getFreshSession();\n const credentialsProvider = fromCognitoIdentityPool({\n clientConfig: {\n region: AwsRegion\n },\n identityPoolId: CognitoIdentityPoolId,\n logins: {\n [CognitoLoginKey]: session.getIdToken().getJwtToken()\n },\n logger: this._logger\n });\n const credentials = await credentialsProvider();\n\n const builder = iot.AwsIotMqttConnectionConfigBuilder.new_with_websockets()\n .with_credentials(AwsRegion, credentials.accessKeyId, credentials.secretAccessKey, credentials.sessionToken)\n .with_endpoint(MqttEndpoint)\n .with_client_id(`mysa-js-sdk-${dayjs().unix()}`) // Unique client ID\n .with_clean_session(true)\n .with_keep_alive_seconds(30)\n .with_ping_timeout_ms(3000)\n .with_protocol_operation_timeout_ms(60000);\n\n const config = builder.build();\n const client = new mqtt.MqttClient();\n this._mqttConnection = client.new_connection(config);\n\n this._mqttConnection.on('closed', () => {\n this._logger.info('MQTT connection closed');\n this._mqttConnection = undefined;\n });\n\n await this._mqttConnection.connect();\n\n return this._mqttConnection;\n }\n\n private processMqttMessage(payload: ArrayBuffer) {\n try {\n const parsedPayload = parseMqttPayload(payload);\n\n this.emitter.emit('rawRealtimeMessageReceived', parsedPayload);\n\n if (isMsgTypeOutPayload(parsedPayload)) {\n switch (parsedPayload.MsgType) {\n case OutMessageType.DEVICE_V1_STATUS:\n this.emitter.emit('statusChanged', {\n deviceId: parsedPayload.Device,\n temperature: parsedPayload.MainTemp,\n humidity: parsedPayload.Humidity,\n setPoint: parsedPayload.SetPoint,\n current: parsedPayload.Current\n });\n break;\n\n case OutMessageType.DEVICE_SETPOINT_CHANGE:\n this.emitter.emit('setPointChanged', {\n deviceId: parsedPayload.Device,\n newSetPoint: parsedPayload.Next,\n previousSetPoint: parsedPayload.Prev\n });\n break;\n }\n } else if (isMsgOutPayload(parsedPayload)) {\n switch (parsedPayload.msg) {\n case OutMessageType.DEVICE_V2_STATUS:\n this.emitter.emit('statusChanged', {\n deviceId: parsedPayload.src.ref,\n temperature: parsedPayload.body.ambTemp,\n humidity: parsedPayload.body.hum,\n setPoint: parsedPayload.body.stpt,\n dutyCycle: parsedPayload.body.dtyCycle\n });\n break;\n\n case OutMessageType.DEVICE_STATE_CHANGE:\n this.emitter.emit('stateChanged', {\n deviceId: parsedPayload.src.ref,\n mode: parsedPayload.body.state.md === 1 ? 'off' : parsedPayload.body.state.md === 3 ? 'heat' : undefined,\n setPoint: parsedPayload.body.state.sp\n });\n break;\n }\n }\n } catch (error) {\n this._logger.error('Error handling MQTT message:', error);\n }\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;;ACCO,IAAM,uBAAN,cAAmC,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAM9C,YAAY,SAAiB;AAC3B,UAAM,OAAO;AACb,SAAK,OAAO;AAAA,EACd;AACF;AAGO,IAAM,eAAN,cAA2B,MAAM;AAAA;AAAA,EAE7B;AAAA;AAAA,EAEA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOT,YAAY,aAAuB;AACjC;AAAA,MACE,uBAAuB,YAAY,GAAG,8DAA8D,YAAY,MAAM,KAAK,YAAY,UAAU;AAAA,IACnJ;AACA,SAAK,OAAO;AACZ,SAAK,SAAS,YAAY;AAC1B,SAAK,aAAa,YAAY;AAAA,EAChC;AACF;;;AChBO,IAAM,aAAN,MAAmC;AAAA,EACxC,MAAM,YAAoB,MAAuB;AAAA,EAAC;AAAA,EAClD,KAAK,YAAoB,MAAuB;AAAA,EAAC;AAAA,EACjD,KAAK,YAAoB,MAAuB;AAAA,EAAC;AAAA,EACjD,MAAM,YAAoB,MAAuB;AAAA,EAAC;AACpD;;;ACtBA,yBAAiD;AAS1C,IAAM,eAAN,MAAuF;AAAA,EACpF,WAAW,IAAI,mBAAAA,aAAiB;AAAA,EAExC,KAAgD,cAA0B,UAA+B;AACvG,WAAO,KAAK,SAAS,KAAK,WAAW,GAAI,QAAe;AAAA,EAC1D;AAAA,EAEA,GACE,WACA,SACA;AACA,SAAK,SAAS,GAAG,WAAW,OAAc;AAC1C,WAAO;AAAA,EACT;AAAA,EAEA,KACE,WACA,SACA;AACA,SAAK,SAAS,KAAK,WAAW,OAAc;AAC5C,WAAO;AAAA,EACT;AAAA,EAEA,IACE,WACA,SACA;AACA,SAAK,SAAS,IAAI,WAAW,OAAc;AAC3C,WAAO;AAAA,EACT;AAAA,EAEA,YACE,WACA,UACA;AACA,SAAK,SAAS,YAAY,WAAW,QAAQ;AAC7C,WAAO;AAAA,EACT;AAAA,EAEA,eACE,WACA,UACA;AACA,SAAK,SAAS,eAAe,WAAW,QAAQ;AAChD,WAAO;AAAA,EACT;AAAA,EAEA,mBAA8D,WAAoC;AAChG,SAAK,SAAS,mBAAmB,SAAS;AAC1C,WAAO;AAAA,EACT;AAAA,EAEA,gBAAgB,GAAW;AACzB,SAAK,SAAS,gBAAgB,CAAC;AAC/B,WAAO;AAAA,EACT;AAAA,EAEA,kBAA0B;AACxB,WAAO,KAAK,SAAS,gBAAgB;AAAA,EACvC;AAAA,EAEA,UAAqD,WAAuB;AAC1E,WAAO,KAAK,SAAS,UAAU,SAAS;AAAA,EAC1C;AAAA,EAEA,aAAwD,WAAuB;AAC7E,WAAO,KAAK,SAAS,aAAa,SAAS;AAAA,EAC7C;AAAA,EAEA,cACE,WACA,UACA;AACA,WAAO,KAAK,SAAS,cAAc,WAAW,QAAQ;AAAA,EACxD;AAAA,EAEA,gBACE,WACA,UACA;AACA,SAAK,SAAS,gBAAgB,WAAW,QAAQ;AACjD,WAAO;AAAA,EACT;AAAA,EAEA,oBACE,WACA,UACA;AACA,SAAK,SAAS,oBAAoB,WAAW,QAAQ;AACrD,WAAO;AAAA,EACT;AAAA,EAEA,aAAa;AACX,WAAO,KAAK,SAAS,WAAW;AAAA,EAClC;AACF;;;AC3FO,SAAS,iBAAiB,SAAkC;AACjE,MAAI;AACF,UAAM,UAAU,IAAI,YAAY,OAAO;AACvC,UAAM,aAAa,QAAQ,OAAO,OAAO;AACzC,WAAO,KAAK,MAAM,UAAU;AAAA,EAC9B,SAAS,OAAO;AACd,YAAQ,MAAM,+BAA+B,KAAK;AAClD,UAAM,IAAI,MAAM,8BAA8B;AAAA,EAChD;AACF;AAYO,SAAS,qBAA0C,SAAyB;AACjF,QAAM,aAAa,KAAK,UAAU,OAAO;AACzC,QAAM,UAAU,IAAI,YAAY;AAChC,SAAO,QAAQ,OAAO,UAAU;AAClC;;;ACzBO,SAAS,oBAAoB,SAAmD;AACrF,SAAO,aAAa;AACtB;AAWO,SAAS,gBAAgB,SAA+C;AAC7E,SAAO,SAAS;AAClB;;;ACtBO,IAAK,gBAAL,kBAAKC,mBAAL;AAML,EAAAA,8BAAA,2BAAwB,KAAxB;AAGA,EAAAA,8BAAA,oCAAiC,MAAjC;AAOA,EAAAA,8BAAA,yBAAsB,MAAtB;AAhBU,SAAAA;AAAA,GAAA;;;ACAL,IAAK,iBAAL,kBAAKC,oBAAL;AAML,EAAAA,gCAAA,sBAAmB,KAAnB;AAGA,EAAAA,gCAAA,4BAAyB,KAAzB;AAGA,EAAAA,gCAAA,gBAAa,KAAb;AAGA,EAAAA,gCAAA,sBAAmB,MAAnB;AAOA,EAAAA,gCAAA,sBAAmB,MAAnB;AAGA,EAAAA,gCAAA,yBAAsB,MAAtB;AAzBU,SAAAA;AAAA,GAAA;;;ACGZ,kCAAwC;AACxC,wCAQO;AACP,mCAA0B;AAC1B,mBAAkB;AAClB,sBAAqB;AAOrB,aAAAC,QAAM,OAAO,gBAAAC,OAAQ;AAErB,IAAM,YAAY;AAClB,IAAM,oBAAoB;AAC1B,IAAM,kBAAkB;AACxB,IAAM,wBAAwB;AAC9B,IAAM,kBAAkB,eAAe,SAAS,kBAAkB,iBAAiB;AACnF,IAAM,eAAe;AACrB,IAAM,iBAAiB;AACvB,IAAM,4BAA4B,aAAAD,QAAM,SAAS,GAAG,SAAS;AA0BtD,IAAM,gBAAN,MAAoB;AAAA;AAAA,EAEjB;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA;AAAA;AAAA,EAGA,qBAAkD,oBAAI,IAAI;AAAA;AAAA,EAG1D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOC,UAAU,IAAI,aAAsC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAO7D,IAAI,UAAmC;AACrC,QAAI,CAAC,KAAK,uBAAuB,CAAC,KAAK,cAAc;AACnD,aAAO;AAAA,IACT;AAEA,WAAO;AAAA,MACL,UAAU,KAAK,aAAa,YAAY;AAAA,MACxC,SAAS,KAAK,oBAAoB,WAAW,EAAE,YAAY;AAAA,MAC3D,aAAa,KAAK,oBAAoB,eAAe,EAAE,YAAY;AAAA,MACnE,cAAc,KAAK,oBAAoB,gBAAgB,EAAE,SAAS;AAAA,IACpE;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,IAAI,kBAA2B;AAC7B,WAAO,CAAC,CAAC,KAAK;AAAA,EAChB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,YAAY,SAAuB,SAAgC;AACjE,SAAK,WAAU,mCAAS,WAAU,IAAI,WAAW;AACjD,SAAK,YAAW,mCAAS,YAAW;AAEpC,QAAI,SAAS;AACX,WAAK,eAAe,IAAI,8CAAY;AAAA,QAClC,UAAU,QAAQ;AAAA,QAClB,MAAM,IAAI,kDAAgB,EAAE,YAAY,mBAAmB,UAAU,gBAAgB,CAAC;AAAA,MACxF,CAAC;AACD,WAAK,sBAAsB,IAAI,qDAAmB;AAAA,QAChD,SAAS,IAAI,iDAAe,EAAE,SAAS,QAAQ,QAAQ,CAAC;AAAA,QACxD,aAAa,IAAI,qDAAmB,EAAE,aAAa,QAAQ,YAAY,CAAC;AAAA,QACxE,cAAc,IAAI,sDAAoB,EAAE,cAAc,QAAQ,aAAa,CAAC;AAAA,MAC9E,CAAC;AAAA,IACH;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,MAAM,MAAM,cAAsB,UAAiC;AACjE,SAAK,eAAe;AACpB,SAAK,sBAAsB;AAC3B,SAAK,QAAQ,KAAK,kBAAkB,KAAK,OAAO;AAEhD,WAAO,IAAI,QAAQ,CAAC,SAAS,WAAW;AACtC,YAAM,OAAO,IAAI,8CAAY;AAAA,QAC3B,UAAU;AAAA,QACV,MAAM,IAAI,kDAAgB,EAAE,YAAY,mBAAmB,UAAU,gBAAgB,CAAC;AAAA,MACxF,CAAC;AAED,WAAK,iBAAiB,IAAI,wDAAsB,EAAE,UAAU,cAAc,UAAU,SAAS,CAAC,GAAG;AAAA,QAC/F,WAAW,CAAC,YAAY;AACtB,eAAK,eAAe;AACpB,eAAK,sBAAsB;AAC3B,eAAK,QAAQ,KAAK,kBAAkB,KAAK,OAAO;AAEhD,kBAAQ;AAAA,QACV;AAAA,QACA,WAAW,CAAC,QAAQ;AAClB,iBAAO,GAAG;AAAA,QACZ;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,aAA+B;AACnC,SAAK,QAAQ,MAAM,qBAAqB;AAExC,UAAM,UAAU,MAAM,KAAK,gBAAgB;AAE3C,UAAM,WAAW,MAAM,KAAK,SAAS,GAAG,cAAc,YAAY;AAAA,MAChE,SAAS;AAAA,QACP,eAAe,GAAG,QAAQ,eAAe,EAAE,YAAY,CAAC;AAAA,MAC1D;AAAA,IACF,CAAC;AAED,QAAI,CAAC,SAAS,IAAI;AAChB,YAAM,IAAI,aAAa,QAAQ;AAAA,IACjC;AAEA,WAAO,SAAS,KAAK;AAAA,EACvB;AAAA,EAEA,MAAM,eAAe,UAAkB,UAAmB,MAAuB;AAC/E,SAAK,QAAQ,MAAM,6BAA6B,QAAQ,GAAG;AAE3D,QAAI,CAAC,KAAK,gBAAgB;AACxB,WAAK,iBAAiB,MAAM,KAAK,WAAW;AAAA,IAC9C;AAEA,UAAM,SAAS,KAAK,eAAe,WAAW,QAAQ;AAEtD,SAAK,QAAQ,MAAM,iCAAiC;AACpD,UAAM,iBAAiB,MAAM,KAAK,kBAAkB;AAEpD,UAAM,UAAM,aAAAA,SAAM;AAElB,SAAK,QAAQ,MAAM,4CAA4C,QAAQ,MAAM;AAC7E,UAAM,UAAU,qBAAwC;AAAA,MACtD;AAAA,MACA,IAAI,IAAI,KAAK;AAAA,MACb,MAAM,IAAI,KAAK;AAAA,MACf,KAAK;AAAA,MACL,KAAK;AAAA,QACH,KAAK,KAAK,QAAS;AAAA,QACnB,MAAM;AAAA,MACR;AAAA,MACA,MAAM;AAAA,QACJ,KAAK;AAAA,QACL,MAAM;AAAA,MACR;AAAA,MACA,MAAM;AAAA,MACN,MAAM;AAAA,QACJ,KAAK;AAAA,QACL,MAAM,OAAO,MAAM,WAAW,OAAO,IACjC,IACA,OAAO,MAAM,WAAW,OAAO,IAC7B,OAAO,MAAM,SAAS,IAAI,IACxB,IACA,IACF;AAAA,QACN,KAAK;AAAA,UACH;AAAA,YACE,IAAI;AAAA,YACJ,IAAI;AAAA,YACJ,IAAI,SAAS,QAAQ,IAAI,SAAS,SAAS,IAAI;AAAA,UACjD;AAAA,QACF;AAAA,MACF;AAAA,IACF,CAAC;AAED,UAAM,eAAe,QAAQ,WAAW,QAAQ,OAAO,SAAS,kCAAK,IAAI,WAAW;AAAA,EACtF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,qBAAqB,UAAkB;AAC3C,SAAK,QAAQ,KAAK,yCAAyC,QAAQ,GAAG;AAEtE,QAAI,KAAK,mBAAmB,IAAI,QAAQ,GAAG;AACzC,WAAK,QAAQ,MAAM,gCAAgC,QAAQ,mBAAmB;AAC9E;AAAA,IACF;AAEA,SAAK,QAAQ,MAAM,iCAAiC;AACpD,UAAM,iBAAiB,MAAM,KAAK,kBAAkB;AAEpD,SAAK,QAAQ,MAAM,sCAAsC,QAAQ,UAAU;AAC3E,UAAM,eAAe,UAAU,WAAW,QAAQ,QAAQ,kCAAK,IAAI,aAAa,CAAC,GAAGE,aAAY;AAC9F,WAAK,mBAAmBA,QAAO;AAAA,IACjC,CAAC;AAED,SAAK,QAAQ,MAAM,0DAA0D,QAAQ,MAAM;AAC3F,UAAM,UAAU,qBAAkD;AAAA,MAChE,QAAQ;AAAA,MACR;AAAA,MACA,eAAW,aAAAF,SAAM,EAAE,KAAK;AAAA,MACxB,SAAS,0BAA0B,UAAU;AAAA,IAC/C,CAAC;AACD,UAAM,eAAe,QAAQ,WAAW,QAAQ,OAAO,SAAS,kCAAK,IAAI,WAAW;AAEpF,UAAM,QAAQ,YAAY,YAAY;AACpC,WAAK,QAAQ,MAAM,+DAA+D,QAAQ,MAAM;AAChG,YAAME,WAAU,qBAAkD;AAAA,QAChE,QAAQ;AAAA,QACR;AAAA,QACA,eAAW,aAAAF,SAAM,EAAE,KAAK;AAAA,QACxB,SAAS,0BAA0B,UAAU;AAAA,MAC/C,CAAC;AACD,YAAM,eAAe,QAAQ,WAAW,QAAQ,OAAOE,UAAS,kCAAK,IAAI,WAAW;AAAA,IACtF,GAAG,0BAA0B,SAAS,IAAI,SAAS,EAAE,eAAe,CAAC;AAErE,SAAK,mBAAmB,IAAI,UAAU,KAAK;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,MAAM,oBAAoB,UAAkB;AAC1C,UAAM,QAAQ,KAAK,mBAAmB,IAAI,QAAQ;AAClD,QAAI,CAAC,OAAO;AACV,WAAK,QAAQ,KAAK,gDAAgD,QAAQ,GAAG;AAC7E;AAAA,IACF;AAEA,SAAK,QAAQ,MAAM,iCAAiC;AACpD,UAAM,iBAAiB,MAAM,KAAK,kBAAkB;AAEpD,SAAK,QAAQ,MAAM,wCAAwC,QAAQ,UAAU;AAC7E,UAAM,eAAe,YAAY,WAAW,QAAQ,MAAM;AAE1D,SAAK,QAAQ,MAAM,0CAA0C,QAAQ,MAAM;AAC3E,kBAAc,KAAK;AACnB,SAAK,mBAAmB,OAAO,QAAQ;AAAA,EACzC;AAAA,EAEA,MAAc,kBAA+C;AAC3D,QAAI,CAAC,KAAK,gBAAgB,CAAC,KAAK,qBAAqB;AACnD,YAAM,IAAI,qBAAqB,mEAAmE;AAAA,IACpG;AAEA,QACE,KAAK,oBAAoB,QAAQ,KACjC,aAAAF,QAAM,KAAK,KAAK,oBAAoB,eAAe,EAAE,cAAc,CAAC,EAAE,QAAQ,GAC9E;AACA,WAAK,QAAQ,KAAK,sCAAsC;AACxD,aAAO,QAAQ,QAAQ,KAAK,mBAAmB;AAAA,IACjD;AAEA,SAAK,QAAQ,KAAK,gDAAgD;AAClE,WAAO,IAAI,QAA4B,CAAC,SAAS,WAAW;AAC1D,WAAK,aAAc,eAAe,KAAK,oBAAqB,gBAAgB,GAAG,CAAC,OAAO,YAAY;AACjG,YAAI,OAAO;AACT,eAAK,QAAQ,MAAM,8BAA8B,KAAK;AACtD,iBAAO,IAAI,qBAAqB,+CAA+C,CAAC;AAAA,QAClF,OAAO;AACL,eAAK,QAAQ,KAAK,gCAAgC;AAClD,eAAK,sBAAsB;AAC3B,eAAK,QAAQ,KAAK,kBAAkB,KAAK,OAAO;AAChD,kBAAQ,OAAO;AAAA,QACjB;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AAAA,EAEA,MAAc,oBAAwD;AACpE,QAAI,KAAK,iBAAiB;AACxB,aAAO,KAAK;AAAA,IACd;AAEA,UAAM,UAAU,MAAM,KAAK,gBAAgB;AAC3C,UAAM,0BAAsB,qDAAwB;AAAA,MAClD,cAAc;AAAA,QACZ,QAAQ;AAAA,MACV;AAAA,MACA,gBAAgB;AAAA,MAChB,QAAQ;AAAA,QACN,CAAC,eAAe,GAAG,QAAQ,WAAW,EAAE,YAAY;AAAA,MACtD;AAAA,MACA,QAAQ,KAAK;AAAA,IACf,CAAC;AACD,UAAM,cAAc,MAAM,oBAAoB;AAE9C,UAAM,UAAU,iCAAI,kCAAkC,oBAAoB,EACvE,iBAAiB,WAAW,YAAY,aAAa,YAAY,iBAAiB,YAAY,YAAY,EAC1G,cAAc,YAAY,EAC1B,eAAe,mBAAe,aAAAA,SAAM,EAAE,KAAK,CAAC,EAAE,EAC9C,mBAAmB,IAAI,EACvB,wBAAwB,EAAE,EAC1B,qBAAqB,GAAI,EACzB,mCAAmC,GAAK;AAE3C,UAAM,SAAS,QAAQ,MAAM;AAC7B,UAAM,SAAS,IAAI,kCAAK,WAAW;AACnC,SAAK,kBAAkB,OAAO,eAAe,MAAM;AAEnD,SAAK,gBAAgB,GAAG,UAAU,MAAM;AACtC,WAAK,QAAQ,KAAK,wBAAwB;AAC1C,WAAK,kBAAkB;AAAA,IACzB,CAAC;AAED,UAAM,KAAK,gBAAgB,QAAQ;AAEnC,WAAO,KAAK;AAAA,EACd;AAAA,EAEQ,mBAAmB,SAAsB;AAC/C,QAAI;AACF,YAAM,gBAAgB,iBAAiB,OAAO;AAE9C,WAAK,QAAQ,KAAK,8BAA8B,aAAa;AAE7D,UAAI,oBAAoB,aAAa,GAAG;AACtC,gBAAQ,cAAc,SAAS;AAAA,UAC7B;AACE,iBAAK,QAAQ,KAAK,iBAAiB;AAAA,cACjC,UAAU,cAAc;AAAA,cACxB,aAAa,cAAc;AAAA,cAC3B,UAAU,cAAc;AAAA,cACxB,UAAU,cAAc;AAAA,cACxB,SAAS,cAAc;AAAA,YACzB,CAAC;AACD;AAAA,UAEF;AACE,iBAAK,QAAQ,KAAK,mBAAmB;AAAA,cACnC,UAAU,cAAc;AAAA,cACxB,aAAa,cAAc;AAAA,cAC3B,kBAAkB,cAAc;AAAA,YAClC,CAAC;AACD;AAAA,QACJ;AAAA,MACF,WAAW,gBAAgB,aAAa,GAAG;AACzC,gBAAQ,cAAc,KAAK;AAAA,UACzB;AACE,iBAAK,QAAQ,KAAK,iBAAiB;AAAA,cACjC,UAAU,cAAc,IAAI;AAAA,cAC5B,aAAa,cAAc,KAAK;AAAA,cAChC,UAAU,cAAc,KAAK;AAAA,cAC7B,UAAU,cAAc,KAAK;AAAA,cAC7B,WAAW,cAAc,KAAK;AAAA,YAChC,CAAC;AACD;AAAA,UAEF;AACE,iBAAK,QAAQ,KAAK,gBAAgB;AAAA,cAChC,UAAU,cAAc,IAAI;AAAA,cAC5B,MAAM,cAAc,KAAK,MAAM,OAAO,IAAI,QAAQ,cAAc,KAAK,MAAM,OAAO,IAAI,SAAS;AAAA,cAC/F,UAAU,cAAc,KAAK,MAAM;AAAA,YACrC,CAAC;AACD;AAAA,QACJ;AAAA,MACF;AAAA,IACF,SAAS,OAAO;AACd,WAAK,QAAQ,MAAM,gCAAgC,KAAK;AAAA,IAC1D;AAAA,EACF;AACF;","names":["NodeEventEmitter","InMessageType","OutMessageType","dayjs","duration","payload"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/api/Errors.ts","../src/api/Logger.ts","../src/lib/EventEmitter.ts","../src/lib/PayloadParser.ts","../src/lib/PayloadTypeGuards.ts","../src/types/mqtt/in/InMessageType.ts","../src/types/mqtt/out/OutMessageType.ts","../src/api/MysaApiClient.ts"],"sourcesContent":["export * from './api';\nexport * from './types';\n","/** Error thrown when attempting to access the Mysa API without proper authentication. */\nexport class UnauthenticatedError extends Error {\n /**\n * Creates a new UnauthenticatedError instance.\n *\n * @param message - The error message\n */\n constructor(message: string) {\n super(message);\n this.name = 'UnauthenticatedError';\n }\n}\n\n/** Error thrown when a Mysa API request fails. */\nexport class MysaApiError extends Error {\n /** The HTTP status code returned by the API */\n readonly status: number;\n /** The HTTP status text returned by the API */\n readonly statusText: string;\n\n /**\n * Creates a new MysaApiError instance.\n *\n * @param apiResponse - The failed Response object from the API call\n */\n constructor(apiResponse: Response) {\n super(\n `Failed to call the '${apiResponse.url}' Mysa API endpoint. The server responded with a status of ${apiResponse.status} (${apiResponse.statusText}).`\n );\n this.name = 'MysaApiError';\n this.status = apiResponse.status;\n this.statusText = apiResponse.statusText;\n }\n}\n","/** Interface for logging operations at different severity levels */\nexport interface Logger {\n /** Logs a debug message with optional metadata */\n debug(message: string, ...meta: unknown[]): void;\n\n /** Logs an info message with optional metadata */\n info(message: string, ...meta: unknown[]): void;\n\n /** Logs a warning message with optional metadata */\n warn(message: string, ...meta: unknown[]): void;\n\n /** Logs an error message with optional metadata */\n error(message: string, ...meta: unknown[]): void;\n}\n\n/** Logger implementation that silently discards all log messages. */\n/* eslint-disable @typescript-eslint/no-unused-vars */\nexport class VoidLogger implements Logger {\n debug(message: string, ...meta: unknown[]): void {}\n info(message: string, ...meta: unknown[]): void {}\n warn(message: string, ...meta: unknown[]): void {}\n error(message: string, ...meta: unknown[]): void {}\n}\n/* eslint-enable @typescript-eslint/no-unused-vars */\n","import { EventEmitter as NodeEventEmitter } from 'node:events';\n\n/**\n * Typed wrapper around Node's `EventEmitter` class.\n *\n * @remarks\n * Source: {@link https://blog.makerx.com.au/a-type-safe-event-emitter-in-node-js}\n */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nexport class EventEmitter<TEvents extends Record<string, any>> implements NodeJS.EventEmitter {\n private _emitter = new NodeEventEmitter();\n\n emit<TEventName extends keyof TEvents & string>(eventName: TEventName, ...eventArg: TEvents[TEventName]) {\n return this._emitter.emit(eventName, ...(eventArg as []));\n }\n\n on<TEventName extends keyof TEvents & string>(\n eventName: TEventName,\n handler: (...eventArg: TEvents[TEventName]) => void\n ) {\n this._emitter.on(eventName, handler as any);\n return this;\n }\n\n once<TEventName extends keyof TEvents & string>(\n eventName: TEventName,\n handler: (...eventArg: TEvents[TEventName]) => void\n ) {\n this._emitter.once(eventName, handler as any);\n return this;\n }\n\n off<TEventName extends keyof TEvents & string>(\n eventName: TEventName,\n handler: (...eventArg: TEvents[TEventName]) => void\n ) {\n this._emitter.off(eventName, handler as any);\n return this;\n }\n\n addListener<TEventName extends keyof TEvents & string>(\n eventName: TEventName,\n listener: (...args: TEvents[TEventName]) => void\n ) {\n this._emitter.addListener(eventName, listener);\n return this;\n }\n\n removeListener<TEventName extends keyof TEvents & string>(\n eventName: TEventName,\n listener: (...args: TEvents[TEventName]) => void\n ) {\n this._emitter.removeListener(eventName, listener);\n return this;\n }\n\n removeAllListeners<TEventName extends keyof TEvents & string>(eventName?: TEventName | undefined) {\n this._emitter.removeAllListeners(eventName);\n return this;\n }\n\n setMaxListeners(n: number) {\n this._emitter.setMaxListeners(n);\n return this;\n }\n\n getMaxListeners(): number {\n return this._emitter.getMaxListeners();\n }\n\n listeners<TEventName extends keyof TEvents & string>(eventName: TEventName) {\n return this._emitter.listeners(eventName);\n }\n\n rawListeners<TEventName extends keyof TEvents & string>(eventName: TEventName) {\n return this._emitter.rawListeners(eventName);\n }\n\n listenerCount<TEventName extends keyof TEvents & string>(\n eventName: TEventName,\n listener?: (...args: TEvents[TEventName]) => void\n ) {\n return this._emitter.listenerCount(eventName, listener);\n }\n\n prependListener<TEventName extends keyof TEvents & string>(\n eventName: TEventName,\n listener: (...args: TEvents[TEventName]) => void\n ) {\n this._emitter.prependListener(eventName, listener);\n return this;\n }\n\n prependOnceListener<TEventName extends keyof TEvents & string>(\n eventName: TEventName,\n listener: (...args: TEvents[TEventName]) => void\n ) {\n this._emitter.prependOnceListener(eventName, listener);\n return this;\n }\n\n eventNames() {\n return this._emitter.eventNames();\n }\n}\n/* eslint-enable @typescript-eslint/no-explicit-any */\n","import { InPayload } from '@/types/mqtt/InPayload';\nimport { OutPayload } from '@/types/mqtt/OutPayload';\n\n/**\n * Parses an MQTT payload from binary data into a typed OutPayload object.\n *\n * Converts the raw ArrayBuffer received from MQTT messages into a structured TypeScript object representing device\n * status, state changes, or other outgoing message types from Mysa devices.\n *\n * @param payload - The raw binary MQTT message payload as ArrayBuffer\n * @returns The parsed payload as a typed OutPayload object\n * @throws Error if the payload cannot be decoded or parsed as valid JSON\n */\nexport function parseMqttPayload(payload: ArrayBuffer): OutPayload {\n try {\n const decoder = new TextDecoder('utf-8');\n const jsonString = decoder.decode(payload);\n return JSON.parse(jsonString);\n } catch (error) {\n console.error('Error parsing MQTT payload:', error);\n throw new Error('Failed to parse MQTT payload');\n }\n}\n\n/**\n * Serializes an InPayload object into binary data for MQTT transmission.\n *\n * Converts a typed TypeScript payload object into the binary ArrayBuffer format required for sending commands and\n * requests to Mysa devices via MQTT.\n *\n * @typeParam T - The specific InPayload type being serialized\n * @param payload - The typed payload object to serialize\n * @returns The serialized payload as ArrayBuffer ready for MQTT transmission\n */\nexport function serializeMqttPayload<T extends InPayload>(payload: T): ArrayBuffer {\n const jsonString = JSON.stringify(payload);\n const encoder = new TextEncoder();\n return encoder.encode(jsonString);\n}\n","import { MsgOutPayload } from '@/types/mqtt/MsgOutPayload';\nimport { MsgTypeOutPayload } from '@/types/mqtt/MsgTypeOutPayload';\nimport { OutPayload } from '@/types/mqtt/OutPayload';\n\n/**\n * Type guard function to determine if an OutPayload is a MsgType-based payload.\n *\n * Checks whether the payload uses the legacy MsgType field format for message type identification. This is used to\n * differentiate between different payload structures and ensure proper type narrowing in TypeScript.\n *\n * @param payload - The OutPayload to check\n * @returns True if the payload is a MsgTypeOutPayload, false otherwise\n */\nexport function isMsgTypeOutPayload(payload: OutPayload): payload is MsgTypeOutPayload {\n return 'MsgType' in payload;\n}\n\n/**\n * Type guard function to determine if an OutPayload is a message-based payload.\n *\n * Checks whether the payload uses the newer msg field format for message type identification. This is used to\n * differentiate between different payload structures and ensure proper type narrowing in TypeScript.\n *\n * @param payload - The OutPayload to check\n * @returns True if the payload is a MsgOutPayload, false otherwise\n */\nexport function isMsgOutPayload(payload: OutPayload): payload is MsgOutPayload {\n return 'msg' in payload;\n}\n","/**\n * Enumeration of message types for incoming MQTT messages from clients to devices.\n *\n * These message types determine how commands and requests are interpreted by Mysa devices. The enum values correspond\n * to specific numeric identifiers used in the MQTT protocol.\n */\nexport enum InMessageType {\n //\n // When the message type is reported in the `MsgType` field of the payload.\n //\n\n /** Request to check and retrieve current device settings */\n CHECK_DEVICE_SETTINGS = 6,\n\n /** Command to start publishing periodic device status updates */\n START_PUBLISHING_DEVICE_STATUS = 11,\n\n //\n // When the message type is reported in the `msg` field of the payload.\n //\n\n /** Command to change the current state of a device (temperature, mode, etc.) */\n CHANGE_DEVICE_STATE = 44\n}\n","/**\n * Enumeration of message types for outgoing MQTT messages from devices to clients.\n *\n * These message types identify different kinds of status updates, notifications, and data reports that Mysa devices can\n * send via MQTT. The enum values correspond to specific numeric identifiers used in the MQTT protocol.\n */\nexport enum OutMessageType {\n //\n // When the message type is reported in the `MsgType` field of the payload.\n //\n\n /** Version 1 device status report with basic device information */\n DEVICE_V1_STATUS = 0,\n\n /** Notification that a device's temperature setpoint has been changed */\n DEVICE_SETPOINT_CHANGE = 1,\n\n /** Device log entry or diagnostic information */\n DEVICE_LOG = 4,\n\n /** Notification sent when a device completes its boot sequence */\n DEVICE_POST_BOOT = 10,\n\n //\n // When the message type is reported in the `msg` field of the payload.\n //\n\n /** Version 2 device status report with enhanced device information */\n DEVICE_V2_STATUS = 40,\n\n /** Notification that a device's operational state has changed */\n DEVICE_STATE_CHANGE = 44\n}\n","import { MysaSession } from '@/api/MysaSession';\nimport { EventEmitter } from '@/lib/EventEmitter';\nimport { parseMqttPayload, serializeMqttPayload } from '@/lib/PayloadParser';\nimport { isMsgOutPayload, isMsgTypeOutPayload } from '@/lib/PayloadTypeGuards';\nimport { ChangeDeviceState } from '@/types/mqtt/in/ChangeDeviceState';\nimport { InMessageType } from '@/types/mqtt/in/InMessageType';\nimport { StartPublishingDeviceStatus } from '@/types/mqtt/in/StartPublishingDeviceStatus';\nimport { OutMessageType } from '@/types/mqtt/out/OutMessageType';\nimport { Devices, DeviceStates, Firmwares } from '@/types/rest';\nimport { fromCognitoIdentityPool } from '@aws-sdk/credential-providers';\nimport {\n AuthenticationDetails,\n CognitoAccessToken,\n CognitoIdToken,\n CognitoRefreshToken,\n CognitoUser,\n CognitoUserPool,\n CognitoUserSession\n} from 'amazon-cognito-identity-js';\nimport { iot, mqtt } from 'aws-iot-device-sdk-v2';\nimport dayjs from 'dayjs';\nimport duration from 'dayjs/plugin/duration';\nimport { MysaApiError, UnauthenticatedError } from './Errors';\nimport { Logger, VoidLogger } from './Logger';\nimport { MysaApiClientEventTypes } from './MysaApiClientEventTypes';\nimport { MysaApiClientOptions } from './MysaApiClientOptions';\nimport { MysaDeviceMode } from './MysaDeviceMode';\n\ndayjs.extend(duration);\n\nconst AwsRegion = 'us-east-1';\nconst CognitoUserPoolId = 'us-east-1_GUFWfhI7g';\nconst CognitoClientId = '19efs8tgqe942atbqmot5m36t3';\nconst CognitoIdentityPoolId = 'us-east-1:ebd95d52-9995-45da-b059-56b865a18379';\nconst CognitoLoginKey = `cognito-idp.${AwsRegion}.amazonaws.com/${CognitoUserPoolId}`;\nconst MqttEndpoint = 'a3q27gia9qg3zy-ats.iot.us-east-1.amazonaws.com';\nconst MysaApiBaseUrl = 'https://app-prod.mysa.cloud';\nconst RealtimeKeepAliveInterval = dayjs.duration(5, 'minutes');\n\n/**\n * Main client for interacting with the Mysa API and real-time device communication.\n *\n * The MysaApiClient provides a comprehensive interface for authenticating with Mysa services, managing device data, and\n * receiving real-time updates from Mysa thermostats and heating devices. It handles both REST API calls for device\n * management and MQTT connections for live status updates and control commands.\n *\n * @example\n *\n * ```typescript\n * const client = new MysaApiClient();\n *\n * await client.login('user@example.com', 'password');\n * const devices = await client.getDevices();\n *\n * client.emitter.on('statusChanged', (status) => {\n * console.log(`Device ${status.deviceId} temperature: ${status.temperature}°C`);\n * });\n *\n * for (const device of Object.entries(devices.DevicesObj)) {\n * await client.startRealtimeUpdates(device[0]);\n * }\n * ```\n */\nexport class MysaApiClient {\n /** The current session object, if any. */\n private _cognitoUserSession?: CognitoUserSession;\n\n /** The current user object, if any. */\n private _cognitoUser?: CognitoUser;\n\n /** The logger instance used by the client. */\n private _logger: Logger;\n\n /** The fetcher function used by the client. */\n private _fetcher: typeof fetch;\n\n /** The MQTT connection used for real-time updates. */\n private _mqttConnection?: mqtt.MqttClientConnection;\n\n /** The device IDs that are currently being updated in real-time, mapped to their respective timeouts. */\n private _realtimeDeviceIds: Map<string, NodeJS.Timeout> = new Map();\n\n /** The cached devices object, if any. */\n private _cachedDevices?: Devices;\n\n /**\n * Event emitter for client events.\n *\n * @see {@link MysaApiClientEventTypes} for the possible events and their payloads.\n */\n readonly emitter = new EventEmitter<MysaApiClientEventTypes>();\n\n /**\n * Gets the persistable session object.\n *\n * @returns The current persistable session object, if any.\n */\n get session(): MysaSession | undefined {\n if (!this._cognitoUserSession || !this._cognitoUser) {\n return undefined;\n }\n\n return {\n username: this._cognitoUser.getUsername(),\n idToken: this._cognitoUserSession.getIdToken().getJwtToken(),\n accessToken: this._cognitoUserSession.getAccessToken().getJwtToken(),\n refreshToken: this._cognitoUserSession.getRefreshToken().getToken()\n };\n }\n\n /**\n * Returns whether the client currently has an active session.\n *\n * @returns True if the client has an active session, false otherwise.\n */\n get isAuthenticated(): boolean {\n return !!this.session;\n }\n\n /**\n * Constructs a new instance of the MysaApiClient.\n *\n * @param session - The persistable session object, if any.\n * @param options - The options for the client.\n */\n constructor(session?: MysaSession, options?: MysaApiClientOptions) {\n this._logger = options?.logger || new VoidLogger();\n this._fetcher = options?.fetcher || fetch;\n\n if (session) {\n this._cognitoUser = new CognitoUser({\n Username: session.username,\n Pool: new CognitoUserPool({ UserPoolId: CognitoUserPoolId, ClientId: CognitoClientId })\n });\n this._cognitoUserSession = new CognitoUserSession({\n IdToken: new CognitoIdToken({ IdToken: session.idToken }),\n AccessToken: new CognitoAccessToken({ AccessToken: session.accessToken }),\n RefreshToken: new CognitoRefreshToken({ RefreshToken: session.refreshToken })\n });\n }\n }\n\n /**\n * Logs in the user with the given email address and password.\n *\n * @param emailAddress - The email address of the user.\n * @param password - The password of the user.\n */\n async login(emailAddress: string, password: string): Promise<void> {\n this._cognitoUser = undefined;\n this._cognitoUserSession = undefined;\n this.emitter.emit('sessionChanged', this.session);\n\n return new Promise((resolve, reject) => {\n const user = new CognitoUser({\n Username: emailAddress,\n Pool: new CognitoUserPool({ UserPoolId: CognitoUserPoolId, ClientId: CognitoClientId })\n });\n\n user.authenticateUser(new AuthenticationDetails({ Username: emailAddress, Password: password }), {\n onSuccess: (session) => {\n this._cognitoUser = user;\n this._cognitoUserSession = session;\n this.emitter.emit('sessionChanged', this.session);\n\n resolve();\n },\n onFailure: (err) => {\n reject(err);\n }\n });\n });\n }\n\n /**\n * Retrieves the list of devices associated with the user.\n *\n * @returns A promise that resolves to the list of devices.\n */\n async getDevices(): Promise<Devices> {\n this._logger.debug(`Fetching devices...`);\n\n const session = await this.getFreshSession();\n\n const response = await this._fetcher(`${MysaApiBaseUrl}/devices`, {\n headers: {\n Authorization: `${session.getIdToken().getJwtToken()}`\n }\n });\n\n if (!response.ok) {\n throw new MysaApiError(response);\n }\n\n return response.json();\n }\n\n async getDeviceFirmwares(): Promise<Firmwares> {\n this._logger.debug(`Fetching device firmwares...`);\n\n const session = await this.getFreshSession();\n\n const response = await this._fetcher(`${MysaApiBaseUrl}/devices/firmware`, {\n headers: {\n Authorization: `${session.getIdToken().getJwtToken()}`\n }\n });\n\n if (!response.ok) {\n throw new MysaApiError(response);\n }\n\n return response.json();\n }\n\n async getDeviceStates(): Promise<DeviceStates> {\n this._logger.debug(`Fetching device states...`);\n\n const session = await this.getFreshSession();\n\n const response = await this._fetcher(`${MysaApiBaseUrl}/devices/state`, {\n headers: {\n Authorization: `${session.getIdToken().getJwtToken()}`\n }\n });\n\n if (!response.ok) {\n throw new MysaApiError(response);\n }\n\n return response.json();\n }\n\n async setDeviceState(deviceId: string, setPoint?: number, mode?: MysaDeviceMode) {\n this._logger.debug(`Setting device state for '${deviceId}'`);\n\n if (!this._cachedDevices) {\n this._cachedDevices = await this.getDevices();\n }\n\n const device = this._cachedDevices.DevicesObj[deviceId];\n\n this._logger.debug(`Initializing MQTT connection...`);\n const mqttConnection = await this.getMqttConnection();\n\n const now = dayjs();\n\n this._logger.debug(`Sending request to set device state for '${deviceId}'...`);\n const payload = serializeMqttPayload<ChangeDeviceState>({\n msg: InMessageType.CHANGE_DEVICE_STATE,\n id: now.unix(),\n time: now.unix(),\n ver: '1.0',\n src: {\n ref: this.session!.username,\n type: 100\n },\n dest: {\n ref: deviceId,\n type: 1\n },\n resp: 2,\n body: {\n ver: 1,\n type: device.Model.startsWith('BB-V1')\n ? 1\n : device.Model.startsWith('BB-V2')\n ? device.Model.endsWith('-L')\n ? 5\n : 4\n : 0,\n cmd: [\n {\n tm: -1,\n sp: setPoint,\n md: mode === 'off' ? 1 : mode === 'heat' ? 3 : undefined\n }\n ]\n }\n });\n\n await mqttConnection.publish(`/v1/dev/${deviceId}/in`, payload, mqtt.QoS.AtLeastOnce);\n }\n\n /**\n * Starts receiving real-time updates for the specified device.\n *\n * @param deviceId - The ID of the device to start receiving updates for.\n */\n async startRealtimeUpdates(deviceId: string) {\n this._logger.info(`Starting realtime updates for device '${deviceId}'`);\n\n if (this._realtimeDeviceIds.has(deviceId)) {\n this._logger.debug(`Realtime updates for device '${deviceId}' already started`);\n return;\n }\n\n this._logger.debug(`Initializing MQTT connection...`);\n const mqttConnection = await this.getMqttConnection();\n\n this._logger.debug(`Subscribing to MQTT topic '/v1/dev/${deviceId}/out'...`);\n await mqttConnection.subscribe(`/v1/dev/${deviceId}/out`, mqtt.QoS.AtLeastOnce, (_, payload) => {\n this.processMqttMessage(payload);\n });\n\n this._logger.debug(`Sending request to start publishing device status for '${deviceId}'...`);\n const payload = serializeMqttPayload<StartPublishingDeviceStatus>({\n Device: deviceId,\n MsgType: InMessageType.START_PUBLISHING_DEVICE_STATUS,\n Timestamp: dayjs().unix(),\n Timeout: RealtimeKeepAliveInterval.asSeconds()\n });\n await mqttConnection.publish(`/v1/dev/${deviceId}/in`, payload, mqtt.QoS.AtLeastOnce);\n\n const timer = setInterval(async () => {\n this._logger.debug(`Sending request to keep-alive publishing device status for '${deviceId}'...`);\n const payload = serializeMqttPayload<StartPublishingDeviceStatus>({\n Device: deviceId,\n MsgType: InMessageType.START_PUBLISHING_DEVICE_STATUS,\n Timestamp: dayjs().unix(),\n Timeout: RealtimeKeepAliveInterval.asSeconds()\n });\n await mqttConnection.publish(`/v1/dev/${deviceId}/in`, payload, mqtt.QoS.AtLeastOnce);\n }, RealtimeKeepAliveInterval.subtract(10, 'seconds').asMilliseconds());\n\n this._realtimeDeviceIds.set(deviceId, timer);\n }\n\n /**\n * Stops receiving real-time updates for the specified device.\n *\n * @param deviceId - The ID of the device to stop receiving real-time updates for.\n */\n async stopRealtimeUpdates(deviceId: string) {\n const timer = this._realtimeDeviceIds.get(deviceId);\n if (!timer) {\n this._logger.warn(`No real-time updates are running for device '${deviceId}'`);\n return;\n }\n\n this._logger.debug(`Initializing MQTT connection...`);\n const mqttConnection = await this.getMqttConnection();\n\n this._logger.debug(`Unsubscribing to MQTT topic '/v1/dev/${deviceId}/out'...`);\n await mqttConnection.unsubscribe(`/v1/dev/${deviceId}/out`);\n\n this._logger.debug(`Stopping real-time updates for device '${deviceId}'...`);\n clearInterval(timer);\n this._realtimeDeviceIds.delete(deviceId);\n }\n\n private async getFreshSession(): Promise<CognitoUserSession> {\n if (!this._cognitoUser || !this._cognitoUserSession) {\n throw new UnauthenticatedError('An attempt was made to access a resource without a valid session.');\n }\n\n if (\n this._cognitoUserSession.isValid() &&\n dayjs.unix(this._cognitoUserSession.getIdToken().getExpiration()).isAfter()\n ) {\n this._logger.info('Session is valid, no need to refresh');\n return Promise.resolve(this._cognitoUserSession);\n }\n\n this._logger.info('Session is not valid or expired, refreshing...');\n return new Promise<CognitoUserSession>((resolve, reject) => {\n this._cognitoUser!.refreshSession(this._cognitoUserSession!.getRefreshToken(), (error, session) => {\n if (error) {\n this._logger.error('Failed to refresh session:', error);\n reject(new UnauthenticatedError('Unable to refresh the authentication session.'));\n } else {\n this._logger.info('Session refreshed successfully');\n this._cognitoUserSession = session;\n this.emitter.emit('sessionChanged', this.session);\n resolve(session);\n }\n });\n });\n }\n\n private async getMqttConnection(): Promise<mqtt.MqttClientConnection> {\n if (this._mqttConnection) {\n return this._mqttConnection;\n }\n\n const session = await this.getFreshSession();\n const credentialsProvider = fromCognitoIdentityPool({\n clientConfig: {\n region: AwsRegion\n },\n identityPoolId: CognitoIdentityPoolId,\n logins: {\n [CognitoLoginKey]: session.getIdToken().getJwtToken()\n },\n logger: this._logger\n });\n const credentials = await credentialsProvider();\n\n const builder = iot.AwsIotMqttConnectionConfigBuilder.new_with_websockets()\n .with_credentials(AwsRegion, credentials.accessKeyId, credentials.secretAccessKey, credentials.sessionToken)\n .with_endpoint(MqttEndpoint)\n .with_client_id(`mysa-js-sdk-${dayjs().unix()}`) // Unique client ID\n .with_clean_session(true)\n .with_keep_alive_seconds(30)\n .with_ping_timeout_ms(3000)\n .with_protocol_operation_timeout_ms(60000);\n\n const config = builder.build();\n const client = new mqtt.MqttClient();\n this._mqttConnection = client.new_connection(config);\n\n this._mqttConnection.on('closed', () => {\n this._logger.info('MQTT connection closed');\n this._mqttConnection = undefined;\n });\n\n await this._mqttConnection.connect();\n\n return this._mqttConnection;\n }\n\n private processMqttMessage(payload: ArrayBuffer) {\n try {\n const parsedPayload = parseMqttPayload(payload);\n\n this.emitter.emit('rawRealtimeMessageReceived', parsedPayload);\n\n if (isMsgTypeOutPayload(parsedPayload)) {\n switch (parsedPayload.MsgType) {\n case OutMessageType.DEVICE_V1_STATUS:\n this.emitter.emit('statusChanged', {\n deviceId: parsedPayload.Device,\n temperature: parsedPayload.MainTemp,\n humidity: parsedPayload.Humidity,\n setPoint: parsedPayload.SetPoint,\n current: parsedPayload.Current\n });\n break;\n\n case OutMessageType.DEVICE_SETPOINT_CHANGE:\n this.emitter.emit('setPointChanged', {\n deviceId: parsedPayload.Device,\n newSetPoint: parsedPayload.Next,\n previousSetPoint: parsedPayload.Prev\n });\n break;\n }\n } else if (isMsgOutPayload(parsedPayload)) {\n switch (parsedPayload.msg) {\n case OutMessageType.DEVICE_V2_STATUS:\n this.emitter.emit('statusChanged', {\n deviceId: parsedPayload.src.ref,\n temperature: parsedPayload.body.ambTemp,\n humidity: parsedPayload.body.hum,\n setPoint: parsedPayload.body.stpt,\n dutyCycle: parsedPayload.body.dtyCycle\n });\n break;\n\n case OutMessageType.DEVICE_STATE_CHANGE:\n this.emitter.emit('stateChanged', {\n deviceId: parsedPayload.src.ref,\n mode: parsedPayload.body.state.md === 1 ? 'off' : parsedPayload.body.state.md === 3 ? 'heat' : undefined,\n setPoint: parsedPayload.body.state.sp\n });\n break;\n }\n }\n } catch (error) {\n this._logger.error('Error handling MQTT message:', error);\n }\n }\n}\n"],"mappings":"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","names":["NodeEventEmitter","InMessageType","OutMessageType","dayjs","duration","payload"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -289,6 +289,90 @@ interface Devices {
|
|
|
289
289
|
DevicesObj: DevicesObj;
|
|
290
290
|
}
|
|
291
291
|
|
|
292
|
+
/** Device firmware information */
|
|
293
|
+
interface FirmwareDevice {
|
|
294
|
+
/** Device ID */
|
|
295
|
+
Device: string;
|
|
296
|
+
/** Device firmware version */
|
|
297
|
+
InstalledVersion: string;
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Collection of firmware devices indexed by device ID
|
|
301
|
+
*
|
|
302
|
+
* Maps device ID strings to their corresponding firmware device objects, providing a lookup table for all devices
|
|
303
|
+
* associated with a user account.
|
|
304
|
+
*/
|
|
305
|
+
interface Firmwares {
|
|
306
|
+
Firmware: Record<string, FirmwareDevice>;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/** Represents a timestamped value with metadata */
|
|
310
|
+
interface TimestampedValue<T = number> {
|
|
311
|
+
/** Timestamp when the value was recorded */
|
|
312
|
+
t: number;
|
|
313
|
+
/** The actual value */
|
|
314
|
+
v: T;
|
|
315
|
+
}
|
|
316
|
+
/** Represents the state of a single device */
|
|
317
|
+
interface DeviceState {
|
|
318
|
+
/** Device identifier */
|
|
319
|
+
Device: string;
|
|
320
|
+
/** Overall timestamp for the device state */
|
|
321
|
+
Timestamp: number;
|
|
322
|
+
/** Time the device has been on */
|
|
323
|
+
OnTime: TimestampedValue<number>;
|
|
324
|
+
/** Temperature set point */
|
|
325
|
+
SetPoint: TimestampedValue<number>;
|
|
326
|
+
/** Display brightness level */
|
|
327
|
+
Brightness: TimestampedValue<number>;
|
|
328
|
+
/** Schedule mode setting */
|
|
329
|
+
ScheduleMode: TimestampedValue<number>;
|
|
330
|
+
/** Hold time setting */
|
|
331
|
+
HoldTime: TimestampedValue<number>;
|
|
332
|
+
/** Wi-Fi signal strength */
|
|
333
|
+
Rssi: TimestampedValue<number>;
|
|
334
|
+
/** Thermostat mode */
|
|
335
|
+
TstatMode: TimestampedValue<number>;
|
|
336
|
+
/** Available heap memory */
|
|
337
|
+
FreeHeap: TimestampedValue<number>;
|
|
338
|
+
/** Sensor temperature reading */
|
|
339
|
+
SensorTemp: TimestampedValue<number>;
|
|
340
|
+
/** Current mode */
|
|
341
|
+
Mode: TimestampedValue<number>;
|
|
342
|
+
/** Voltage measurement */
|
|
343
|
+
Voltage: TimestampedValue<number>;
|
|
344
|
+
/** Temperature corrected for calibration */
|
|
345
|
+
CorrectedTemp: TimestampedValue<number>;
|
|
346
|
+
/** Duty cycle percentage */
|
|
347
|
+
Duty: TimestampedValue<number>;
|
|
348
|
+
/** Heat sink temperature */
|
|
349
|
+
HeatSink: TimestampedValue<number>;
|
|
350
|
+
/** Time the device has been off */
|
|
351
|
+
OffTime: TimestampedValue<number>;
|
|
352
|
+
/** Connection status */
|
|
353
|
+
Connected: TimestampedValue<boolean>;
|
|
354
|
+
/** Current consumption */
|
|
355
|
+
Current: TimestampedValue<number>;
|
|
356
|
+
/** Humidity reading */
|
|
357
|
+
Humidity: TimestampedValue<number>;
|
|
358
|
+
/** Lock status */
|
|
359
|
+
Lock: TimestampedValue<number>;
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Collection of device states indexed by device ID
|
|
363
|
+
*
|
|
364
|
+
* Maps device ID strings to their corresponding device state objects, providing a lookup table for all devices
|
|
365
|
+
* associated with a user account.
|
|
366
|
+
*/
|
|
367
|
+
interface DeviceStatesObj {
|
|
368
|
+
/** Device state objects indexed by their unique device ID strings */
|
|
369
|
+
[deviceId: string]: DeviceState;
|
|
370
|
+
}
|
|
371
|
+
/** Top-level interface for the device states REST API response. */
|
|
372
|
+
interface DeviceStates {
|
|
373
|
+
DeviceStatesObj: DeviceStatesObj;
|
|
374
|
+
}
|
|
375
|
+
|
|
292
376
|
/**
|
|
293
377
|
* Base interface for all MQTT message payloads.
|
|
294
378
|
*
|
|
@@ -663,6 +747,8 @@ declare class MysaApiClient {
|
|
|
663
747
|
* @returns A promise that resolves to the list of devices.
|
|
664
748
|
*/
|
|
665
749
|
getDevices(): Promise<Devices>;
|
|
750
|
+
getDeviceFirmwares(): Promise<Firmwares>;
|
|
751
|
+
getDeviceStates(): Promise<DeviceStates>;
|
|
666
752
|
setDeviceState(deviceId: string, setPoint?: number, mode?: MysaDeviceMode): Promise<void>;
|
|
667
753
|
/**
|
|
668
754
|
* Starts receiving real-time updates for the specified device.
|
|
@@ -789,4 +875,4 @@ type MsgTypeInPayload = CheckDeviceSettings | StartPublishingDeviceStatus;
|
|
|
789
875
|
*/
|
|
790
876
|
type InPayload = MsgTypeInPayload | MsgInPayload;
|
|
791
877
|
|
|
792
|
-
export { type BrandInfo, type ChangeDeviceState, type CheckDeviceSettings, type DeviceBase, type DeviceLog, type DevicePostBoot, type DeviceSetpointChange, type DeviceStateChange, type DeviceV1Status, type DeviceV2Status, type Devices, type DevicesObj, InMessageType, type InPayload, type Logger, type ModeObj, type MsgBasePayload, type MsgInPayload, type MsgOutPayload, type MsgPayload, type MsgTypeBasePayload, type MsgTypeInPayload, type MsgTypeOutPayload, type MsgTypePayload, MysaApiClient, type MysaApiClientEventTypes, type MysaApiClientOptions, MysaApiError, type MysaDeviceMode, type MysaSession, OutMessageType, type OutPayload, type SetPointChange, type StartPublishingDeviceStatus, type StateChange, type Status, type SupportedCaps, UnauthenticatedError, VoidLogger };
|
|
878
|
+
export { type BrandInfo, type ChangeDeviceState, type CheckDeviceSettings, type DeviceBase, type DeviceLog, type DevicePostBoot, type DeviceSetpointChange, type DeviceState, type DeviceStateChange, type DeviceStates, type DeviceStatesObj, type DeviceV1Status, type DeviceV2Status, type Devices, type DevicesObj, type FirmwareDevice, type Firmwares, InMessageType, type InPayload, type Logger, type ModeObj, type MsgBasePayload, type MsgInPayload, type MsgOutPayload, type MsgPayload, type MsgTypeBasePayload, type MsgTypeInPayload, type MsgTypeOutPayload, type MsgTypePayload, MysaApiClient, type MysaApiClientEventTypes, type MysaApiClientOptions, MysaApiError, type MysaDeviceMode, type MysaSession, OutMessageType, type OutPayload, type SetPointChange, type StartPublishingDeviceStatus, type StateChange, type Status, type SupportedCaps, type TimestampedValue, UnauthenticatedError, VoidLogger };
|
package/dist/index.d.ts
CHANGED
|
@@ -289,6 +289,90 @@ interface Devices {
|
|
|
289
289
|
DevicesObj: DevicesObj;
|
|
290
290
|
}
|
|
291
291
|
|
|
292
|
+
/** Device firmware information */
|
|
293
|
+
interface FirmwareDevice {
|
|
294
|
+
/** Device ID */
|
|
295
|
+
Device: string;
|
|
296
|
+
/** Device firmware version */
|
|
297
|
+
InstalledVersion: string;
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Collection of firmware devices indexed by device ID
|
|
301
|
+
*
|
|
302
|
+
* Maps device ID strings to their corresponding firmware device objects, providing a lookup table for all devices
|
|
303
|
+
* associated with a user account.
|
|
304
|
+
*/
|
|
305
|
+
interface Firmwares {
|
|
306
|
+
Firmware: Record<string, FirmwareDevice>;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
/** Represents a timestamped value with metadata */
|
|
310
|
+
interface TimestampedValue<T = number> {
|
|
311
|
+
/** Timestamp when the value was recorded */
|
|
312
|
+
t: number;
|
|
313
|
+
/** The actual value */
|
|
314
|
+
v: T;
|
|
315
|
+
}
|
|
316
|
+
/** Represents the state of a single device */
|
|
317
|
+
interface DeviceState {
|
|
318
|
+
/** Device identifier */
|
|
319
|
+
Device: string;
|
|
320
|
+
/** Overall timestamp for the device state */
|
|
321
|
+
Timestamp: number;
|
|
322
|
+
/** Time the device has been on */
|
|
323
|
+
OnTime: TimestampedValue<number>;
|
|
324
|
+
/** Temperature set point */
|
|
325
|
+
SetPoint: TimestampedValue<number>;
|
|
326
|
+
/** Display brightness level */
|
|
327
|
+
Brightness: TimestampedValue<number>;
|
|
328
|
+
/** Schedule mode setting */
|
|
329
|
+
ScheduleMode: TimestampedValue<number>;
|
|
330
|
+
/** Hold time setting */
|
|
331
|
+
HoldTime: TimestampedValue<number>;
|
|
332
|
+
/** Wi-Fi signal strength */
|
|
333
|
+
Rssi: TimestampedValue<number>;
|
|
334
|
+
/** Thermostat mode */
|
|
335
|
+
TstatMode: TimestampedValue<number>;
|
|
336
|
+
/** Available heap memory */
|
|
337
|
+
FreeHeap: TimestampedValue<number>;
|
|
338
|
+
/** Sensor temperature reading */
|
|
339
|
+
SensorTemp: TimestampedValue<number>;
|
|
340
|
+
/** Current mode */
|
|
341
|
+
Mode: TimestampedValue<number>;
|
|
342
|
+
/** Voltage measurement */
|
|
343
|
+
Voltage: TimestampedValue<number>;
|
|
344
|
+
/** Temperature corrected for calibration */
|
|
345
|
+
CorrectedTemp: TimestampedValue<number>;
|
|
346
|
+
/** Duty cycle percentage */
|
|
347
|
+
Duty: TimestampedValue<number>;
|
|
348
|
+
/** Heat sink temperature */
|
|
349
|
+
HeatSink: TimestampedValue<number>;
|
|
350
|
+
/** Time the device has been off */
|
|
351
|
+
OffTime: TimestampedValue<number>;
|
|
352
|
+
/** Connection status */
|
|
353
|
+
Connected: TimestampedValue<boolean>;
|
|
354
|
+
/** Current consumption */
|
|
355
|
+
Current: TimestampedValue<number>;
|
|
356
|
+
/** Humidity reading */
|
|
357
|
+
Humidity: TimestampedValue<number>;
|
|
358
|
+
/** Lock status */
|
|
359
|
+
Lock: TimestampedValue<number>;
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Collection of device states indexed by device ID
|
|
363
|
+
*
|
|
364
|
+
* Maps device ID strings to their corresponding device state objects, providing a lookup table for all devices
|
|
365
|
+
* associated with a user account.
|
|
366
|
+
*/
|
|
367
|
+
interface DeviceStatesObj {
|
|
368
|
+
/** Device state objects indexed by their unique device ID strings */
|
|
369
|
+
[deviceId: string]: DeviceState;
|
|
370
|
+
}
|
|
371
|
+
/** Top-level interface for the device states REST API response. */
|
|
372
|
+
interface DeviceStates {
|
|
373
|
+
DeviceStatesObj: DeviceStatesObj;
|
|
374
|
+
}
|
|
375
|
+
|
|
292
376
|
/**
|
|
293
377
|
* Base interface for all MQTT message payloads.
|
|
294
378
|
*
|
|
@@ -663,6 +747,8 @@ declare class MysaApiClient {
|
|
|
663
747
|
* @returns A promise that resolves to the list of devices.
|
|
664
748
|
*/
|
|
665
749
|
getDevices(): Promise<Devices>;
|
|
750
|
+
getDeviceFirmwares(): Promise<Firmwares>;
|
|
751
|
+
getDeviceStates(): Promise<DeviceStates>;
|
|
666
752
|
setDeviceState(deviceId: string, setPoint?: number, mode?: MysaDeviceMode): Promise<void>;
|
|
667
753
|
/**
|
|
668
754
|
* Starts receiving real-time updates for the specified device.
|
|
@@ -789,4 +875,4 @@ type MsgTypeInPayload = CheckDeviceSettings | StartPublishingDeviceStatus;
|
|
|
789
875
|
*/
|
|
790
876
|
type InPayload = MsgTypeInPayload | MsgInPayload;
|
|
791
877
|
|
|
792
|
-
export { type BrandInfo, type ChangeDeviceState, type CheckDeviceSettings, type DeviceBase, type DeviceLog, type DevicePostBoot, type DeviceSetpointChange, type DeviceStateChange, type DeviceV1Status, type DeviceV2Status, type Devices, type DevicesObj, InMessageType, type InPayload, type Logger, type ModeObj, type MsgBasePayload, type MsgInPayload, type MsgOutPayload, type MsgPayload, type MsgTypeBasePayload, type MsgTypeInPayload, type MsgTypeOutPayload, type MsgTypePayload, MysaApiClient, type MysaApiClientEventTypes, type MysaApiClientOptions, MysaApiError, type MysaDeviceMode, type MysaSession, OutMessageType, type OutPayload, type SetPointChange, type StartPublishingDeviceStatus, type StateChange, type Status, type SupportedCaps, UnauthenticatedError, VoidLogger };
|
|
878
|
+
export { type BrandInfo, type ChangeDeviceState, type CheckDeviceSettings, type DeviceBase, type DeviceLog, type DevicePostBoot, type DeviceSetpointChange, type DeviceState, type DeviceStateChange, type DeviceStates, type DeviceStatesObj, type DeviceV1Status, type DeviceV2Status, type Devices, type DevicesObj, type FirmwareDevice, type Firmwares, InMessageType, type InPayload, type Logger, type ModeObj, type MsgBasePayload, type MsgInPayload, type MsgOutPayload, type MsgPayload, type MsgTypeBasePayload, type MsgTypeInPayload, type MsgTypeOutPayload, type MsgTypePayload, MysaApiClient, type MysaApiClientEventTypes, type MysaApiClientOptions, MysaApiError, type MysaDeviceMode, type MysaSession, OutMessageType, type OutPayload, type SetPointChange, type StartPublishingDeviceStatus, type StateChange, type Status, type SupportedCaps, type TimestampedValue, UnauthenticatedError, VoidLogger };
|
package/dist/index.js
CHANGED
|
@@ -297,7 +297,33 @@ var MysaApiClient = class {
|
|
|
297
297
|
const session = await this.getFreshSession();
|
|
298
298
|
const response = await this._fetcher(`${MysaApiBaseUrl}/devices`, {
|
|
299
299
|
headers: {
|
|
300
|
-
Authorization: `${session.
|
|
300
|
+
Authorization: `${session.getIdToken().getJwtToken()}`
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
if (!response.ok) {
|
|
304
|
+
throw new MysaApiError(response);
|
|
305
|
+
}
|
|
306
|
+
return response.json();
|
|
307
|
+
}
|
|
308
|
+
async getDeviceFirmwares() {
|
|
309
|
+
this._logger.debug(`Fetching device firmwares...`);
|
|
310
|
+
const session = await this.getFreshSession();
|
|
311
|
+
const response = await this._fetcher(`${MysaApiBaseUrl}/devices/firmware`, {
|
|
312
|
+
headers: {
|
|
313
|
+
Authorization: `${session.getIdToken().getJwtToken()}`
|
|
314
|
+
}
|
|
315
|
+
});
|
|
316
|
+
if (!response.ok) {
|
|
317
|
+
throw new MysaApiError(response);
|
|
318
|
+
}
|
|
319
|
+
return response.json();
|
|
320
|
+
}
|
|
321
|
+
async getDeviceStates() {
|
|
322
|
+
this._logger.debug(`Fetching device states...`);
|
|
323
|
+
const session = await this.getFreshSession();
|
|
324
|
+
const response = await this._fetcher(`${MysaApiBaseUrl}/devices/state`, {
|
|
325
|
+
headers: {
|
|
326
|
+
Authorization: `${session.getIdToken().getJwtToken()}`
|
|
301
327
|
}
|
|
302
328
|
});
|
|
303
329
|
if (!response.ok) {
|
|
@@ -403,7 +429,7 @@ var MysaApiClient = class {
|
|
|
403
429
|
if (!this._cognitoUser || !this._cognitoUserSession) {
|
|
404
430
|
throw new UnauthenticatedError("An attempt was made to access a resource without a valid session.");
|
|
405
431
|
}
|
|
406
|
-
if (this._cognitoUserSession.isValid() && dayjs.unix(this._cognitoUserSession.
|
|
432
|
+
if (this._cognitoUserSession.isValid() && dayjs.unix(this._cognitoUserSession.getIdToken().getExpiration()).isAfter()) {
|
|
407
433
|
this._logger.info("Session is valid, no need to refresh");
|
|
408
434
|
return Promise.resolve(this._cognitoUserSession);
|
|
409
435
|
}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/api/Errors.ts","../src/api/Logger.ts","../src/lib/EventEmitter.ts","../src/lib/PayloadParser.ts","../src/lib/PayloadTypeGuards.ts","../src/types/mqtt/in/InMessageType.ts","../src/types/mqtt/out/OutMessageType.ts","../src/api/MysaApiClient.ts"],"sourcesContent":["/** Error thrown when attempting to access the Mysa API without proper authentication. */\nexport class UnauthenticatedError extends Error {\n /**\n * Creates a new UnauthenticatedError instance.\n *\n * @param message - The error message\n */\n constructor(message: string) {\n super(message);\n this.name = 'UnauthenticatedError';\n }\n}\n\n/** Error thrown when a Mysa API request fails. */\nexport class MysaApiError extends Error {\n /** The HTTP status code returned by the API */\n readonly status: number;\n /** The HTTP status text returned by the API */\n readonly statusText: string;\n\n /**\n * Creates a new MysaApiError instance.\n *\n * @param apiResponse - The failed Response object from the API call\n */\n constructor(apiResponse: Response) {\n super(\n `Failed to call the '${apiResponse.url}' Mysa API endpoint. The server responded with a status of ${apiResponse.status} (${apiResponse.statusText}).`\n );\n this.name = 'MysaApiError';\n this.status = apiResponse.status;\n this.statusText = apiResponse.statusText;\n }\n}\n","/** Interface for logging operations at different severity levels */\nexport interface Logger {\n /** Logs a debug message with optional metadata */\n debug(message: string, ...meta: unknown[]): void;\n\n /** Logs an info message with optional metadata */\n info(message: string, ...meta: unknown[]): void;\n\n /** Logs a warning message with optional metadata */\n warn(message: string, ...meta: unknown[]): void;\n\n /** Logs an error message with optional metadata */\n error(message: string, ...meta: unknown[]): void;\n}\n\n/** Logger implementation that silently discards all log messages. */\n/* eslint-disable @typescript-eslint/no-unused-vars */\nexport class VoidLogger implements Logger {\n debug(message: string, ...meta: unknown[]): void {}\n info(message: string, ...meta: unknown[]): void {}\n warn(message: string, ...meta: unknown[]): void {}\n error(message: string, ...meta: unknown[]): void {}\n}\n/* eslint-enable @typescript-eslint/no-unused-vars */\n","import { EventEmitter as NodeEventEmitter } from 'node:events';\n\n/**\n * Typed wrapper around Node's `EventEmitter` class.\n *\n * @remarks\n * Source: {@link https://blog.makerx.com.au/a-type-safe-event-emitter-in-node-js}\n */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nexport class EventEmitter<TEvents extends Record<string, any>> implements NodeJS.EventEmitter {\n private _emitter = new NodeEventEmitter();\n\n emit<TEventName extends keyof TEvents & string>(eventName: TEventName, ...eventArg: TEvents[TEventName]) {\n return this._emitter.emit(eventName, ...(eventArg as []));\n }\n\n on<TEventName extends keyof TEvents & string>(\n eventName: TEventName,\n handler: (...eventArg: TEvents[TEventName]) => void\n ) {\n this._emitter.on(eventName, handler as any);\n return this;\n }\n\n once<TEventName extends keyof TEvents & string>(\n eventName: TEventName,\n handler: (...eventArg: TEvents[TEventName]) => void\n ) {\n this._emitter.once(eventName, handler as any);\n return this;\n }\n\n off<TEventName extends keyof TEvents & string>(\n eventName: TEventName,\n handler: (...eventArg: TEvents[TEventName]) => void\n ) {\n this._emitter.off(eventName, handler as any);\n return this;\n }\n\n addListener<TEventName extends keyof TEvents & string>(\n eventName: TEventName,\n listener: (...args: TEvents[TEventName]) => void\n ) {\n this._emitter.addListener(eventName, listener);\n return this;\n }\n\n removeListener<TEventName extends keyof TEvents & string>(\n eventName: TEventName,\n listener: (...args: TEvents[TEventName]) => void\n ) {\n this._emitter.removeListener(eventName, listener);\n return this;\n }\n\n removeAllListeners<TEventName extends keyof TEvents & string>(eventName?: TEventName | undefined) {\n this._emitter.removeAllListeners(eventName);\n return this;\n }\n\n setMaxListeners(n: number) {\n this._emitter.setMaxListeners(n);\n return this;\n }\n\n getMaxListeners(): number {\n return this._emitter.getMaxListeners();\n }\n\n listeners<TEventName extends keyof TEvents & string>(eventName: TEventName) {\n return this._emitter.listeners(eventName);\n }\n\n rawListeners<TEventName extends keyof TEvents & string>(eventName: TEventName) {\n return this._emitter.rawListeners(eventName);\n }\n\n listenerCount<TEventName extends keyof TEvents & string>(\n eventName: TEventName,\n listener?: (...args: TEvents[TEventName]) => void\n ) {\n return this._emitter.listenerCount(eventName, listener);\n }\n\n prependListener<TEventName extends keyof TEvents & string>(\n eventName: TEventName,\n listener: (...args: TEvents[TEventName]) => void\n ) {\n this._emitter.prependListener(eventName, listener);\n return this;\n }\n\n prependOnceListener<TEventName extends keyof TEvents & string>(\n eventName: TEventName,\n listener: (...args: TEvents[TEventName]) => void\n ) {\n this._emitter.prependOnceListener(eventName, listener);\n return this;\n }\n\n eventNames() {\n return this._emitter.eventNames();\n }\n}\n/* eslint-enable @typescript-eslint/no-explicit-any */\n","import { InPayload } from '@/types/mqtt/InPayload';\nimport { OutPayload } from '@/types/mqtt/OutPayload';\n\n/**\n * Parses an MQTT payload from binary data into a typed OutPayload object.\n *\n * Converts the raw ArrayBuffer received from MQTT messages into a structured TypeScript object representing device\n * status, state changes, or other outgoing message types from Mysa devices.\n *\n * @param payload - The raw binary MQTT message payload as ArrayBuffer\n * @returns The parsed payload as a typed OutPayload object\n * @throws Error if the payload cannot be decoded or parsed as valid JSON\n */\nexport function parseMqttPayload(payload: ArrayBuffer): OutPayload {\n try {\n const decoder = new TextDecoder('utf-8');\n const jsonString = decoder.decode(payload);\n return JSON.parse(jsonString);\n } catch (error) {\n console.error('Error parsing MQTT payload:', error);\n throw new Error('Failed to parse MQTT payload');\n }\n}\n\n/**\n * Serializes an InPayload object into binary data for MQTT transmission.\n *\n * Converts a typed TypeScript payload object into the binary ArrayBuffer format required for sending commands and\n * requests to Mysa devices via MQTT.\n *\n * @typeParam T - The specific InPayload type being serialized\n * @param payload - The typed payload object to serialize\n * @returns The serialized payload as ArrayBuffer ready for MQTT transmission\n */\nexport function serializeMqttPayload<T extends InPayload>(payload: T): ArrayBuffer {\n const jsonString = JSON.stringify(payload);\n const encoder = new TextEncoder();\n return encoder.encode(jsonString);\n}\n","import { MsgOutPayload } from '@/types/mqtt/MsgOutPayload';\nimport { MsgTypeOutPayload } from '@/types/mqtt/MsgTypeOutPayload';\nimport { OutPayload } from '@/types/mqtt/OutPayload';\n\n/**\n * Type guard function to determine if an OutPayload is a MsgType-based payload.\n *\n * Checks whether the payload uses the legacy MsgType field format for message type identification. This is used to\n * differentiate between different payload structures and ensure proper type narrowing in TypeScript.\n *\n * @param payload - The OutPayload to check\n * @returns True if the payload is a MsgTypeOutPayload, false otherwise\n */\nexport function isMsgTypeOutPayload(payload: OutPayload): payload is MsgTypeOutPayload {\n return 'MsgType' in payload;\n}\n\n/**\n * Type guard function to determine if an OutPayload is a message-based payload.\n *\n * Checks whether the payload uses the newer msg field format for message type identification. This is used to\n * differentiate between different payload structures and ensure proper type narrowing in TypeScript.\n *\n * @param payload - The OutPayload to check\n * @returns True if the payload is a MsgOutPayload, false otherwise\n */\nexport function isMsgOutPayload(payload: OutPayload): payload is MsgOutPayload {\n return 'msg' in payload;\n}\n","/**\n * Enumeration of message types for incoming MQTT messages from clients to devices.\n *\n * These message types determine how commands and requests are interpreted by Mysa devices. The enum values correspond\n * to specific numeric identifiers used in the MQTT protocol.\n */\nexport enum InMessageType {\n //\n // When the message type is reported in the `MsgType` field of the payload.\n //\n\n /** Request to check and retrieve current device settings */\n CHECK_DEVICE_SETTINGS = 6,\n\n /** Command to start publishing periodic device status updates */\n START_PUBLISHING_DEVICE_STATUS = 11,\n\n //\n // When the message type is reported in the `msg` field of the payload.\n //\n\n /** Command to change the current state of a device (temperature, mode, etc.) */\n CHANGE_DEVICE_STATE = 44\n}\n","/**\n * Enumeration of message types for outgoing MQTT messages from devices to clients.\n *\n * These message types identify different kinds of status updates, notifications, and data reports that Mysa devices can\n * send via MQTT. The enum values correspond to specific numeric identifiers used in the MQTT protocol.\n */\nexport enum OutMessageType {\n //\n // When the message type is reported in the `MsgType` field of the payload.\n //\n\n /** Version 1 device status report with basic device information */\n DEVICE_V1_STATUS = 0,\n\n /** Notification that a device's temperature setpoint has been changed */\n DEVICE_SETPOINT_CHANGE = 1,\n\n /** Device log entry or diagnostic information */\n DEVICE_LOG = 4,\n\n /** Notification sent when a device completes its boot sequence */\n DEVICE_POST_BOOT = 10,\n\n //\n // When the message type is reported in the `msg` field of the payload.\n //\n\n /** Version 2 device status report with enhanced device information */\n DEVICE_V2_STATUS = 40,\n\n /** Notification that a device's operational state has changed */\n DEVICE_STATE_CHANGE = 44\n}\n","import { MysaSession } from '@/api/MysaSession';\nimport { EventEmitter } from '@/lib/EventEmitter';\nimport { parseMqttPayload, serializeMqttPayload } from '@/lib/PayloadParser';\nimport { isMsgOutPayload, isMsgTypeOutPayload } from '@/lib/PayloadTypeGuards';\nimport { ChangeDeviceState } from '@/types/mqtt/in/ChangeDeviceState';\nimport { InMessageType } from '@/types/mqtt/in/InMessageType';\nimport { StartPublishingDeviceStatus } from '@/types/mqtt/in/StartPublishingDeviceStatus';\nimport { OutMessageType } from '@/types/mqtt/out/OutMessageType';\nimport { Devices } from '@/types/rest/Devices';\nimport { fromCognitoIdentityPool } from '@aws-sdk/credential-providers';\nimport {\n AuthenticationDetails,\n CognitoAccessToken,\n CognitoIdToken,\n CognitoRefreshToken,\n CognitoUser,\n CognitoUserPool,\n CognitoUserSession\n} from 'amazon-cognito-identity-js';\nimport { iot, mqtt } from 'aws-iot-device-sdk-v2';\nimport dayjs from 'dayjs';\nimport duration from 'dayjs/plugin/duration';\nimport { MysaApiError, UnauthenticatedError } from './Errors';\nimport { Logger, VoidLogger } from './Logger';\nimport { MysaApiClientEventTypes } from './MysaApiClientEventTypes';\nimport { MysaApiClientOptions } from './MysaApiClientOptions';\nimport { MysaDeviceMode } from './MysaDeviceMode';\n\ndayjs.extend(duration);\n\nconst AwsRegion = 'us-east-1';\nconst CognitoUserPoolId = 'us-east-1_GUFWfhI7g';\nconst CognitoClientId = '19efs8tgqe942atbqmot5m36t3';\nconst CognitoIdentityPoolId = 'us-east-1:ebd95d52-9995-45da-b059-56b865a18379';\nconst CognitoLoginKey = `cognito-idp.${AwsRegion}.amazonaws.com/${CognitoUserPoolId}`;\nconst MqttEndpoint = 'a3q27gia9qg3zy-ats.iot.us-east-1.amazonaws.com';\nconst MysaApiBaseUrl = 'https://app-prod.mysa.cloud';\nconst RealtimeKeepAliveInterval = dayjs.duration(5, 'minutes');\n\n/**\n * Main client for interacting with the Mysa API and real-time device communication.\n *\n * The MysaApiClient provides a comprehensive interface for authenticating with Mysa services, managing device data, and\n * receiving real-time updates from Mysa thermostats and heating devices. It handles both REST API calls for device\n * management and MQTT connections for live status updates and control commands.\n *\n * @example\n *\n * ```typescript\n * const client = new MysaApiClient();\n *\n * await client.login('user@example.com', 'password');\n * const devices = await client.getDevices();\n *\n * client.emitter.on('statusChanged', (status) => {\n * console.log(`Device ${status.deviceId} temperature: ${status.temperature}°C`);\n * });\n *\n * for (const device of Object.entries(devices.DevicesObj)) {\n * await client.startRealtimeUpdates(device[0]);\n * }\n * ```\n */\nexport class MysaApiClient {\n /** The current session object, if any. */\n private _cognitoUserSession?: CognitoUserSession;\n\n /** The current user object, if any. */\n private _cognitoUser?: CognitoUser;\n\n /** The logger instance used by the client. */\n private _logger: Logger;\n\n /** The fetcher function used by the client. */\n private _fetcher: typeof fetch;\n\n /** The MQTT connection used for real-time updates. */\n private _mqttConnection?: mqtt.MqttClientConnection;\n\n /** The device IDs that are currently being updated in real-time, mapped to their respective timeouts. */\n private _realtimeDeviceIds: Map<string, NodeJS.Timeout> = new Map();\n\n /** The cached devices object, if any. */\n private _cachedDevices?: Devices;\n\n /**\n * Event emitter for client events.\n *\n * @see {@link MysaApiClientEventTypes} for the possible events and their payloads.\n */\n readonly emitter = new EventEmitter<MysaApiClientEventTypes>();\n\n /**\n * Gets the persistable session object.\n *\n * @returns The current persistable session object, if any.\n */\n get session(): MysaSession | undefined {\n if (!this._cognitoUserSession || !this._cognitoUser) {\n return undefined;\n }\n\n return {\n username: this._cognitoUser.getUsername(),\n idToken: this._cognitoUserSession.getIdToken().getJwtToken(),\n accessToken: this._cognitoUserSession.getAccessToken().getJwtToken(),\n refreshToken: this._cognitoUserSession.getRefreshToken().getToken()\n };\n }\n\n /**\n * Returns whether the client currently has an active session.\n *\n * @returns True if the client has an active session, false otherwise.\n */\n get isAuthenticated(): boolean {\n return !!this.session;\n }\n\n /**\n * Constructs a new instance of the MysaApiClient.\n *\n * @param session - The persistable session object, if any.\n * @param options - The options for the client.\n */\n constructor(session?: MysaSession, options?: MysaApiClientOptions) {\n this._logger = options?.logger || new VoidLogger();\n this._fetcher = options?.fetcher || fetch;\n\n if (session) {\n this._cognitoUser = new CognitoUser({\n Username: session.username,\n Pool: new CognitoUserPool({ UserPoolId: CognitoUserPoolId, ClientId: CognitoClientId })\n });\n this._cognitoUserSession = new CognitoUserSession({\n IdToken: new CognitoIdToken({ IdToken: session.idToken }),\n AccessToken: new CognitoAccessToken({ AccessToken: session.accessToken }),\n RefreshToken: new CognitoRefreshToken({ RefreshToken: session.refreshToken })\n });\n }\n }\n\n /**\n * Logs in the user with the given email address and password.\n *\n * @param emailAddress - The email address of the user.\n * @param password - The password of the user.\n */\n async login(emailAddress: string, password: string): Promise<void> {\n this._cognitoUser = undefined;\n this._cognitoUserSession = undefined;\n this.emitter.emit('sessionChanged', this.session);\n\n return new Promise((resolve, reject) => {\n const user = new CognitoUser({\n Username: emailAddress,\n Pool: new CognitoUserPool({ UserPoolId: CognitoUserPoolId, ClientId: CognitoClientId })\n });\n\n user.authenticateUser(new AuthenticationDetails({ Username: emailAddress, Password: password }), {\n onSuccess: (session) => {\n this._cognitoUser = user;\n this._cognitoUserSession = session;\n this.emitter.emit('sessionChanged', this.session);\n\n resolve();\n },\n onFailure: (err) => {\n reject(err);\n }\n });\n });\n }\n\n /**\n * Retrieves the list of devices associated with the user.\n *\n * @returns A promise that resolves to the list of devices.\n */\n async getDevices(): Promise<Devices> {\n this._logger.debug(`Fetching devices...`);\n\n const session = await this.getFreshSession();\n\n const response = await this._fetcher(`${MysaApiBaseUrl}/devices`, {\n headers: {\n Authorization: `${session.getAccessToken().getJwtToken()}`\n }\n });\n\n if (!response.ok) {\n throw new MysaApiError(response);\n }\n\n return response.json();\n }\n\n async setDeviceState(deviceId: string, setPoint?: number, mode?: MysaDeviceMode) {\n this._logger.debug(`Setting device state for '${deviceId}'`);\n\n if (!this._cachedDevices) {\n this._cachedDevices = await this.getDevices();\n }\n\n const device = this._cachedDevices.DevicesObj[deviceId];\n\n this._logger.debug(`Initializing MQTT connection...`);\n const mqttConnection = await this.getMqttConnection();\n\n const now = dayjs();\n\n this._logger.debug(`Sending request to set device state for '${deviceId}'...`);\n const payload = serializeMqttPayload<ChangeDeviceState>({\n msg: InMessageType.CHANGE_DEVICE_STATE,\n id: now.unix(),\n time: now.unix(),\n ver: '1.0',\n src: {\n ref: this.session!.username,\n type: 100\n },\n dest: {\n ref: deviceId,\n type: 1\n },\n resp: 2,\n body: {\n ver: 1,\n type: device.Model.startsWith('BB-V1')\n ? 1\n : device.Model.startsWith('BB-V2')\n ? device.Model.endsWith('-L')\n ? 5\n : 4\n : 0,\n cmd: [\n {\n tm: -1,\n sp: setPoint,\n md: mode === 'off' ? 1 : mode === 'heat' ? 3 : undefined\n }\n ]\n }\n });\n\n await mqttConnection.publish(`/v1/dev/${deviceId}/in`, payload, mqtt.QoS.AtLeastOnce);\n }\n\n /**\n * Starts receiving real-time updates for the specified device.\n *\n * @param deviceId - The ID of the device to start receiving updates for.\n */\n async startRealtimeUpdates(deviceId: string) {\n this._logger.info(`Starting realtime updates for device '${deviceId}'`);\n\n if (this._realtimeDeviceIds.has(deviceId)) {\n this._logger.debug(`Realtime updates for device '${deviceId}' already started`);\n return;\n }\n\n this._logger.debug(`Initializing MQTT connection...`);\n const mqttConnection = await this.getMqttConnection();\n\n this._logger.debug(`Subscribing to MQTT topic '/v1/dev/${deviceId}/out'...`);\n await mqttConnection.subscribe(`/v1/dev/${deviceId}/out`, mqtt.QoS.AtLeastOnce, (_, payload) => {\n this.processMqttMessage(payload);\n });\n\n this._logger.debug(`Sending request to start publishing device status for '${deviceId}'...`);\n const payload = serializeMqttPayload<StartPublishingDeviceStatus>({\n Device: deviceId,\n MsgType: InMessageType.START_PUBLISHING_DEVICE_STATUS,\n Timestamp: dayjs().unix(),\n Timeout: RealtimeKeepAliveInterval.asSeconds()\n });\n await mqttConnection.publish(`/v1/dev/${deviceId}/in`, payload, mqtt.QoS.AtLeastOnce);\n\n const timer = setInterval(async () => {\n this._logger.debug(`Sending request to keep-alive publishing device status for '${deviceId}'...`);\n const payload = serializeMqttPayload<StartPublishingDeviceStatus>({\n Device: deviceId,\n MsgType: InMessageType.START_PUBLISHING_DEVICE_STATUS,\n Timestamp: dayjs().unix(),\n Timeout: RealtimeKeepAliveInterval.asSeconds()\n });\n await mqttConnection.publish(`/v1/dev/${deviceId}/in`, payload, mqtt.QoS.AtLeastOnce);\n }, RealtimeKeepAliveInterval.subtract(10, 'seconds').asMilliseconds());\n\n this._realtimeDeviceIds.set(deviceId, timer);\n }\n\n /**\n * Stops receiving real-time updates for the specified device.\n *\n * @param deviceId - The ID of the device to stop receiving real-time updates for.\n */\n async stopRealtimeUpdates(deviceId: string) {\n const timer = this._realtimeDeviceIds.get(deviceId);\n if (!timer) {\n this._logger.warn(`No real-time updates are running for device '${deviceId}'`);\n return;\n }\n\n this._logger.debug(`Initializing MQTT connection...`);\n const mqttConnection = await this.getMqttConnection();\n\n this._logger.debug(`Unsubscribing to MQTT topic '/v1/dev/${deviceId}/out'...`);\n await mqttConnection.unsubscribe(`/v1/dev/${deviceId}/out`);\n\n this._logger.debug(`Stopping real-time updates for device '${deviceId}'...`);\n clearInterval(timer);\n this._realtimeDeviceIds.delete(deviceId);\n }\n\n private async getFreshSession(): Promise<CognitoUserSession> {\n if (!this._cognitoUser || !this._cognitoUserSession) {\n throw new UnauthenticatedError('An attempt was made to access a resource without a valid session.');\n }\n\n if (\n this._cognitoUserSession.isValid() &&\n dayjs.unix(this._cognitoUserSession.getAccessToken().getExpiration()).isAfter()\n ) {\n this._logger.info('Session is valid, no need to refresh');\n return Promise.resolve(this._cognitoUserSession);\n }\n\n this._logger.info('Session is not valid or expired, refreshing...');\n return new Promise<CognitoUserSession>((resolve, reject) => {\n this._cognitoUser!.refreshSession(this._cognitoUserSession!.getRefreshToken(), (error, session) => {\n if (error) {\n this._logger.error('Failed to refresh session:', error);\n reject(new UnauthenticatedError('Unable to refresh the authentication session.'));\n } else {\n this._logger.info('Session refreshed successfully');\n this._cognitoUserSession = session;\n this.emitter.emit('sessionChanged', this.session);\n resolve(session);\n }\n });\n });\n }\n\n private async getMqttConnection(): Promise<mqtt.MqttClientConnection> {\n if (this._mqttConnection) {\n return this._mqttConnection;\n }\n\n const session = await this.getFreshSession();\n const credentialsProvider = fromCognitoIdentityPool({\n clientConfig: {\n region: AwsRegion\n },\n identityPoolId: CognitoIdentityPoolId,\n logins: {\n [CognitoLoginKey]: session.getIdToken().getJwtToken()\n },\n logger: this._logger\n });\n const credentials = await credentialsProvider();\n\n const builder = iot.AwsIotMqttConnectionConfigBuilder.new_with_websockets()\n .with_credentials(AwsRegion, credentials.accessKeyId, credentials.secretAccessKey, credentials.sessionToken)\n .with_endpoint(MqttEndpoint)\n .with_client_id(`mysa-js-sdk-${dayjs().unix()}`) // Unique client ID\n .with_clean_session(true)\n .with_keep_alive_seconds(30)\n .with_ping_timeout_ms(3000)\n .with_protocol_operation_timeout_ms(60000);\n\n const config = builder.build();\n const client = new mqtt.MqttClient();\n this._mqttConnection = client.new_connection(config);\n\n this._mqttConnection.on('closed', () => {\n this._logger.info('MQTT connection closed');\n this._mqttConnection = undefined;\n });\n\n await this._mqttConnection.connect();\n\n return this._mqttConnection;\n }\n\n private processMqttMessage(payload: ArrayBuffer) {\n try {\n const parsedPayload = parseMqttPayload(payload);\n\n this.emitter.emit('rawRealtimeMessageReceived', parsedPayload);\n\n if (isMsgTypeOutPayload(parsedPayload)) {\n switch (parsedPayload.MsgType) {\n case OutMessageType.DEVICE_V1_STATUS:\n this.emitter.emit('statusChanged', {\n deviceId: parsedPayload.Device,\n temperature: parsedPayload.MainTemp,\n humidity: parsedPayload.Humidity,\n setPoint: parsedPayload.SetPoint,\n current: parsedPayload.Current\n });\n break;\n\n case OutMessageType.DEVICE_SETPOINT_CHANGE:\n this.emitter.emit('setPointChanged', {\n deviceId: parsedPayload.Device,\n newSetPoint: parsedPayload.Next,\n previousSetPoint: parsedPayload.Prev\n });\n break;\n }\n } else if (isMsgOutPayload(parsedPayload)) {\n switch (parsedPayload.msg) {\n case OutMessageType.DEVICE_V2_STATUS:\n this.emitter.emit('statusChanged', {\n deviceId: parsedPayload.src.ref,\n temperature: parsedPayload.body.ambTemp,\n humidity: parsedPayload.body.hum,\n setPoint: parsedPayload.body.stpt,\n dutyCycle: parsedPayload.body.dtyCycle\n });\n break;\n\n case OutMessageType.DEVICE_STATE_CHANGE:\n this.emitter.emit('stateChanged', {\n deviceId: parsedPayload.src.ref,\n mode: parsedPayload.body.state.md === 1 ? 'off' : parsedPayload.body.state.md === 3 ? 'heat' : undefined,\n setPoint: parsedPayload.body.state.sp\n });\n break;\n }\n }\n } catch (error) {\n this._logger.error('Error handling MQTT message:', error);\n }\n }\n}\n"],"mappings":"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","names":["InMessageType","OutMessageType","payload"]}
|
|
1
|
+
{"version":3,"sources":["../src/api/Errors.ts","../src/api/Logger.ts","../src/lib/EventEmitter.ts","../src/lib/PayloadParser.ts","../src/lib/PayloadTypeGuards.ts","../src/types/mqtt/in/InMessageType.ts","../src/types/mqtt/out/OutMessageType.ts","../src/api/MysaApiClient.ts"],"sourcesContent":["/** Error thrown when attempting to access the Mysa API without proper authentication. */\nexport class UnauthenticatedError extends Error {\n /**\n * Creates a new UnauthenticatedError instance.\n *\n * @param message - The error message\n */\n constructor(message: string) {\n super(message);\n this.name = 'UnauthenticatedError';\n }\n}\n\n/** Error thrown when a Mysa API request fails. */\nexport class MysaApiError extends Error {\n /** The HTTP status code returned by the API */\n readonly status: number;\n /** The HTTP status text returned by the API */\n readonly statusText: string;\n\n /**\n * Creates a new MysaApiError instance.\n *\n * @param apiResponse - The failed Response object from the API call\n */\n constructor(apiResponse: Response) {\n super(\n `Failed to call the '${apiResponse.url}' Mysa API endpoint. The server responded with a status of ${apiResponse.status} (${apiResponse.statusText}).`\n );\n this.name = 'MysaApiError';\n this.status = apiResponse.status;\n this.statusText = apiResponse.statusText;\n }\n}\n","/** Interface for logging operations at different severity levels */\nexport interface Logger {\n /** Logs a debug message with optional metadata */\n debug(message: string, ...meta: unknown[]): void;\n\n /** Logs an info message with optional metadata */\n info(message: string, ...meta: unknown[]): void;\n\n /** Logs a warning message with optional metadata */\n warn(message: string, ...meta: unknown[]): void;\n\n /** Logs an error message with optional metadata */\n error(message: string, ...meta: unknown[]): void;\n}\n\n/** Logger implementation that silently discards all log messages. */\n/* eslint-disable @typescript-eslint/no-unused-vars */\nexport class VoidLogger implements Logger {\n debug(message: string, ...meta: unknown[]): void {}\n info(message: string, ...meta: unknown[]): void {}\n warn(message: string, ...meta: unknown[]): void {}\n error(message: string, ...meta: unknown[]): void {}\n}\n/* eslint-enable @typescript-eslint/no-unused-vars */\n","import { EventEmitter as NodeEventEmitter } from 'node:events';\n\n/**\n * Typed wrapper around Node's `EventEmitter` class.\n *\n * @remarks\n * Source: {@link https://blog.makerx.com.au/a-type-safe-event-emitter-in-node-js}\n */\n/* eslint-disable @typescript-eslint/no-explicit-any */\nexport class EventEmitter<TEvents extends Record<string, any>> implements NodeJS.EventEmitter {\n private _emitter = new NodeEventEmitter();\n\n emit<TEventName extends keyof TEvents & string>(eventName: TEventName, ...eventArg: TEvents[TEventName]) {\n return this._emitter.emit(eventName, ...(eventArg as []));\n }\n\n on<TEventName extends keyof TEvents & string>(\n eventName: TEventName,\n handler: (...eventArg: TEvents[TEventName]) => void\n ) {\n this._emitter.on(eventName, handler as any);\n return this;\n }\n\n once<TEventName extends keyof TEvents & string>(\n eventName: TEventName,\n handler: (...eventArg: TEvents[TEventName]) => void\n ) {\n this._emitter.once(eventName, handler as any);\n return this;\n }\n\n off<TEventName extends keyof TEvents & string>(\n eventName: TEventName,\n handler: (...eventArg: TEvents[TEventName]) => void\n ) {\n this._emitter.off(eventName, handler as any);\n return this;\n }\n\n addListener<TEventName extends keyof TEvents & string>(\n eventName: TEventName,\n listener: (...args: TEvents[TEventName]) => void\n ) {\n this._emitter.addListener(eventName, listener);\n return this;\n }\n\n removeListener<TEventName extends keyof TEvents & string>(\n eventName: TEventName,\n listener: (...args: TEvents[TEventName]) => void\n ) {\n this._emitter.removeListener(eventName, listener);\n return this;\n }\n\n removeAllListeners<TEventName extends keyof TEvents & string>(eventName?: TEventName | undefined) {\n this._emitter.removeAllListeners(eventName);\n return this;\n }\n\n setMaxListeners(n: number) {\n this._emitter.setMaxListeners(n);\n return this;\n }\n\n getMaxListeners(): number {\n return this._emitter.getMaxListeners();\n }\n\n listeners<TEventName extends keyof TEvents & string>(eventName: TEventName) {\n return this._emitter.listeners(eventName);\n }\n\n rawListeners<TEventName extends keyof TEvents & string>(eventName: TEventName) {\n return this._emitter.rawListeners(eventName);\n }\n\n listenerCount<TEventName extends keyof TEvents & string>(\n eventName: TEventName,\n listener?: (...args: TEvents[TEventName]) => void\n ) {\n return this._emitter.listenerCount(eventName, listener);\n }\n\n prependListener<TEventName extends keyof TEvents & string>(\n eventName: TEventName,\n listener: (...args: TEvents[TEventName]) => void\n ) {\n this._emitter.prependListener(eventName, listener);\n return this;\n }\n\n prependOnceListener<TEventName extends keyof TEvents & string>(\n eventName: TEventName,\n listener: (...args: TEvents[TEventName]) => void\n ) {\n this._emitter.prependOnceListener(eventName, listener);\n return this;\n }\n\n eventNames() {\n return this._emitter.eventNames();\n }\n}\n/* eslint-enable @typescript-eslint/no-explicit-any */\n","import { InPayload } from '@/types/mqtt/InPayload';\nimport { OutPayload } from '@/types/mqtt/OutPayload';\n\n/**\n * Parses an MQTT payload from binary data into a typed OutPayload object.\n *\n * Converts the raw ArrayBuffer received from MQTT messages into a structured TypeScript object representing device\n * status, state changes, or other outgoing message types from Mysa devices.\n *\n * @param payload - The raw binary MQTT message payload as ArrayBuffer\n * @returns The parsed payload as a typed OutPayload object\n * @throws Error if the payload cannot be decoded or parsed as valid JSON\n */\nexport function parseMqttPayload(payload: ArrayBuffer): OutPayload {\n try {\n const decoder = new TextDecoder('utf-8');\n const jsonString = decoder.decode(payload);\n return JSON.parse(jsonString);\n } catch (error) {\n console.error('Error parsing MQTT payload:', error);\n throw new Error('Failed to parse MQTT payload');\n }\n}\n\n/**\n * Serializes an InPayload object into binary data for MQTT transmission.\n *\n * Converts a typed TypeScript payload object into the binary ArrayBuffer format required for sending commands and\n * requests to Mysa devices via MQTT.\n *\n * @typeParam T - The specific InPayload type being serialized\n * @param payload - The typed payload object to serialize\n * @returns The serialized payload as ArrayBuffer ready for MQTT transmission\n */\nexport function serializeMqttPayload<T extends InPayload>(payload: T): ArrayBuffer {\n const jsonString = JSON.stringify(payload);\n const encoder = new TextEncoder();\n return encoder.encode(jsonString);\n}\n","import { MsgOutPayload } from '@/types/mqtt/MsgOutPayload';\nimport { MsgTypeOutPayload } from '@/types/mqtt/MsgTypeOutPayload';\nimport { OutPayload } from '@/types/mqtt/OutPayload';\n\n/**\n * Type guard function to determine if an OutPayload is a MsgType-based payload.\n *\n * Checks whether the payload uses the legacy MsgType field format for message type identification. This is used to\n * differentiate between different payload structures and ensure proper type narrowing in TypeScript.\n *\n * @param payload - The OutPayload to check\n * @returns True if the payload is a MsgTypeOutPayload, false otherwise\n */\nexport function isMsgTypeOutPayload(payload: OutPayload): payload is MsgTypeOutPayload {\n return 'MsgType' in payload;\n}\n\n/**\n * Type guard function to determine if an OutPayload is a message-based payload.\n *\n * Checks whether the payload uses the newer msg field format for message type identification. This is used to\n * differentiate between different payload structures and ensure proper type narrowing in TypeScript.\n *\n * @param payload - The OutPayload to check\n * @returns True if the payload is a MsgOutPayload, false otherwise\n */\nexport function isMsgOutPayload(payload: OutPayload): payload is MsgOutPayload {\n return 'msg' in payload;\n}\n","/**\n * Enumeration of message types for incoming MQTT messages from clients to devices.\n *\n * These message types determine how commands and requests are interpreted by Mysa devices. The enum values correspond\n * to specific numeric identifiers used in the MQTT protocol.\n */\nexport enum InMessageType {\n //\n // When the message type is reported in the `MsgType` field of the payload.\n //\n\n /** Request to check and retrieve current device settings */\n CHECK_DEVICE_SETTINGS = 6,\n\n /** Command to start publishing periodic device status updates */\n START_PUBLISHING_DEVICE_STATUS = 11,\n\n //\n // When the message type is reported in the `msg` field of the payload.\n //\n\n /** Command to change the current state of a device (temperature, mode, etc.) */\n CHANGE_DEVICE_STATE = 44\n}\n","/**\n * Enumeration of message types for outgoing MQTT messages from devices to clients.\n *\n * These message types identify different kinds of status updates, notifications, and data reports that Mysa devices can\n * send via MQTT. The enum values correspond to specific numeric identifiers used in the MQTT protocol.\n */\nexport enum OutMessageType {\n //\n // When the message type is reported in the `MsgType` field of the payload.\n //\n\n /** Version 1 device status report with basic device information */\n DEVICE_V1_STATUS = 0,\n\n /** Notification that a device's temperature setpoint has been changed */\n DEVICE_SETPOINT_CHANGE = 1,\n\n /** Device log entry or diagnostic information */\n DEVICE_LOG = 4,\n\n /** Notification sent when a device completes its boot sequence */\n DEVICE_POST_BOOT = 10,\n\n //\n // When the message type is reported in the `msg` field of the payload.\n //\n\n /** Version 2 device status report with enhanced device information */\n DEVICE_V2_STATUS = 40,\n\n /** Notification that a device's operational state has changed */\n DEVICE_STATE_CHANGE = 44\n}\n","import { MysaSession } from '@/api/MysaSession';\nimport { EventEmitter } from '@/lib/EventEmitter';\nimport { parseMqttPayload, serializeMqttPayload } from '@/lib/PayloadParser';\nimport { isMsgOutPayload, isMsgTypeOutPayload } from '@/lib/PayloadTypeGuards';\nimport { ChangeDeviceState } from '@/types/mqtt/in/ChangeDeviceState';\nimport { InMessageType } from '@/types/mqtt/in/InMessageType';\nimport { StartPublishingDeviceStatus } from '@/types/mqtt/in/StartPublishingDeviceStatus';\nimport { OutMessageType } from '@/types/mqtt/out/OutMessageType';\nimport { Devices, DeviceStates, Firmwares } from '@/types/rest';\nimport { fromCognitoIdentityPool } from '@aws-sdk/credential-providers';\nimport {\n AuthenticationDetails,\n CognitoAccessToken,\n CognitoIdToken,\n CognitoRefreshToken,\n CognitoUser,\n CognitoUserPool,\n CognitoUserSession\n} from 'amazon-cognito-identity-js';\nimport { iot, mqtt } from 'aws-iot-device-sdk-v2';\nimport dayjs from 'dayjs';\nimport duration from 'dayjs/plugin/duration';\nimport { MysaApiError, UnauthenticatedError } from './Errors';\nimport { Logger, VoidLogger } from './Logger';\nimport { MysaApiClientEventTypes } from './MysaApiClientEventTypes';\nimport { MysaApiClientOptions } from './MysaApiClientOptions';\nimport { MysaDeviceMode } from './MysaDeviceMode';\n\ndayjs.extend(duration);\n\nconst AwsRegion = 'us-east-1';\nconst CognitoUserPoolId = 'us-east-1_GUFWfhI7g';\nconst CognitoClientId = '19efs8tgqe942atbqmot5m36t3';\nconst CognitoIdentityPoolId = 'us-east-1:ebd95d52-9995-45da-b059-56b865a18379';\nconst CognitoLoginKey = `cognito-idp.${AwsRegion}.amazonaws.com/${CognitoUserPoolId}`;\nconst MqttEndpoint = 'a3q27gia9qg3zy-ats.iot.us-east-1.amazonaws.com';\nconst MysaApiBaseUrl = 'https://app-prod.mysa.cloud';\nconst RealtimeKeepAliveInterval = dayjs.duration(5, 'minutes');\n\n/**\n * Main client for interacting with the Mysa API and real-time device communication.\n *\n * The MysaApiClient provides a comprehensive interface for authenticating with Mysa services, managing device data, and\n * receiving real-time updates from Mysa thermostats and heating devices. It handles both REST API calls for device\n * management and MQTT connections for live status updates and control commands.\n *\n * @example\n *\n * ```typescript\n * const client = new MysaApiClient();\n *\n * await client.login('user@example.com', 'password');\n * const devices = await client.getDevices();\n *\n * client.emitter.on('statusChanged', (status) => {\n * console.log(`Device ${status.deviceId} temperature: ${status.temperature}°C`);\n * });\n *\n * for (const device of Object.entries(devices.DevicesObj)) {\n * await client.startRealtimeUpdates(device[0]);\n * }\n * ```\n */\nexport class MysaApiClient {\n /** The current session object, if any. */\n private _cognitoUserSession?: CognitoUserSession;\n\n /** The current user object, if any. */\n private _cognitoUser?: CognitoUser;\n\n /** The logger instance used by the client. */\n private _logger: Logger;\n\n /** The fetcher function used by the client. */\n private _fetcher: typeof fetch;\n\n /** The MQTT connection used for real-time updates. */\n private _mqttConnection?: mqtt.MqttClientConnection;\n\n /** The device IDs that are currently being updated in real-time, mapped to their respective timeouts. */\n private _realtimeDeviceIds: Map<string, NodeJS.Timeout> = new Map();\n\n /** The cached devices object, if any. */\n private _cachedDevices?: Devices;\n\n /**\n * Event emitter for client events.\n *\n * @see {@link MysaApiClientEventTypes} for the possible events and their payloads.\n */\n readonly emitter = new EventEmitter<MysaApiClientEventTypes>();\n\n /**\n * Gets the persistable session object.\n *\n * @returns The current persistable session object, if any.\n */\n get session(): MysaSession | undefined {\n if (!this._cognitoUserSession || !this._cognitoUser) {\n return undefined;\n }\n\n return {\n username: this._cognitoUser.getUsername(),\n idToken: this._cognitoUserSession.getIdToken().getJwtToken(),\n accessToken: this._cognitoUserSession.getAccessToken().getJwtToken(),\n refreshToken: this._cognitoUserSession.getRefreshToken().getToken()\n };\n }\n\n /**\n * Returns whether the client currently has an active session.\n *\n * @returns True if the client has an active session, false otherwise.\n */\n get isAuthenticated(): boolean {\n return !!this.session;\n }\n\n /**\n * Constructs a new instance of the MysaApiClient.\n *\n * @param session - The persistable session object, if any.\n * @param options - The options for the client.\n */\n constructor(session?: MysaSession, options?: MysaApiClientOptions) {\n this._logger = options?.logger || new VoidLogger();\n this._fetcher = options?.fetcher || fetch;\n\n if (session) {\n this._cognitoUser = new CognitoUser({\n Username: session.username,\n Pool: new CognitoUserPool({ UserPoolId: CognitoUserPoolId, ClientId: CognitoClientId })\n });\n this._cognitoUserSession = new CognitoUserSession({\n IdToken: new CognitoIdToken({ IdToken: session.idToken }),\n AccessToken: new CognitoAccessToken({ AccessToken: session.accessToken }),\n RefreshToken: new CognitoRefreshToken({ RefreshToken: session.refreshToken })\n });\n }\n }\n\n /**\n * Logs in the user with the given email address and password.\n *\n * @param emailAddress - The email address of the user.\n * @param password - The password of the user.\n */\n async login(emailAddress: string, password: string): Promise<void> {\n this._cognitoUser = undefined;\n this._cognitoUserSession = undefined;\n this.emitter.emit('sessionChanged', this.session);\n\n return new Promise((resolve, reject) => {\n const user = new CognitoUser({\n Username: emailAddress,\n Pool: new CognitoUserPool({ UserPoolId: CognitoUserPoolId, ClientId: CognitoClientId })\n });\n\n user.authenticateUser(new AuthenticationDetails({ Username: emailAddress, Password: password }), {\n onSuccess: (session) => {\n this._cognitoUser = user;\n this._cognitoUserSession = session;\n this.emitter.emit('sessionChanged', this.session);\n\n resolve();\n },\n onFailure: (err) => {\n reject(err);\n }\n });\n });\n }\n\n /**\n * Retrieves the list of devices associated with the user.\n *\n * @returns A promise that resolves to the list of devices.\n */\n async getDevices(): Promise<Devices> {\n this._logger.debug(`Fetching devices...`);\n\n const session = await this.getFreshSession();\n\n const response = await this._fetcher(`${MysaApiBaseUrl}/devices`, {\n headers: {\n Authorization: `${session.getIdToken().getJwtToken()}`\n }\n });\n\n if (!response.ok) {\n throw new MysaApiError(response);\n }\n\n return response.json();\n }\n\n async getDeviceFirmwares(): Promise<Firmwares> {\n this._logger.debug(`Fetching device firmwares...`);\n\n const session = await this.getFreshSession();\n\n const response = await this._fetcher(`${MysaApiBaseUrl}/devices/firmware`, {\n headers: {\n Authorization: `${session.getIdToken().getJwtToken()}`\n }\n });\n\n if (!response.ok) {\n throw new MysaApiError(response);\n }\n\n return response.json();\n }\n\n async getDeviceStates(): Promise<DeviceStates> {\n this._logger.debug(`Fetching device states...`);\n\n const session = await this.getFreshSession();\n\n const response = await this._fetcher(`${MysaApiBaseUrl}/devices/state`, {\n headers: {\n Authorization: `${session.getIdToken().getJwtToken()}`\n }\n });\n\n if (!response.ok) {\n throw new MysaApiError(response);\n }\n\n return response.json();\n }\n\n async setDeviceState(deviceId: string, setPoint?: number, mode?: MysaDeviceMode) {\n this._logger.debug(`Setting device state for '${deviceId}'`);\n\n if (!this._cachedDevices) {\n this._cachedDevices = await this.getDevices();\n }\n\n const device = this._cachedDevices.DevicesObj[deviceId];\n\n this._logger.debug(`Initializing MQTT connection...`);\n const mqttConnection = await this.getMqttConnection();\n\n const now = dayjs();\n\n this._logger.debug(`Sending request to set device state for '${deviceId}'...`);\n const payload = serializeMqttPayload<ChangeDeviceState>({\n msg: InMessageType.CHANGE_DEVICE_STATE,\n id: now.unix(),\n time: now.unix(),\n ver: '1.0',\n src: {\n ref: this.session!.username,\n type: 100\n },\n dest: {\n ref: deviceId,\n type: 1\n },\n resp: 2,\n body: {\n ver: 1,\n type: device.Model.startsWith('BB-V1')\n ? 1\n : device.Model.startsWith('BB-V2')\n ? device.Model.endsWith('-L')\n ? 5\n : 4\n : 0,\n cmd: [\n {\n tm: -1,\n sp: setPoint,\n md: mode === 'off' ? 1 : mode === 'heat' ? 3 : undefined\n }\n ]\n }\n });\n\n await mqttConnection.publish(`/v1/dev/${deviceId}/in`, payload, mqtt.QoS.AtLeastOnce);\n }\n\n /**\n * Starts receiving real-time updates for the specified device.\n *\n * @param deviceId - The ID of the device to start receiving updates for.\n */\n async startRealtimeUpdates(deviceId: string) {\n this._logger.info(`Starting realtime updates for device '${deviceId}'`);\n\n if (this._realtimeDeviceIds.has(deviceId)) {\n this._logger.debug(`Realtime updates for device '${deviceId}' already started`);\n return;\n }\n\n this._logger.debug(`Initializing MQTT connection...`);\n const mqttConnection = await this.getMqttConnection();\n\n this._logger.debug(`Subscribing to MQTT topic '/v1/dev/${deviceId}/out'...`);\n await mqttConnection.subscribe(`/v1/dev/${deviceId}/out`, mqtt.QoS.AtLeastOnce, (_, payload) => {\n this.processMqttMessage(payload);\n });\n\n this._logger.debug(`Sending request to start publishing device status for '${deviceId}'...`);\n const payload = serializeMqttPayload<StartPublishingDeviceStatus>({\n Device: deviceId,\n MsgType: InMessageType.START_PUBLISHING_DEVICE_STATUS,\n Timestamp: dayjs().unix(),\n Timeout: RealtimeKeepAliveInterval.asSeconds()\n });\n await mqttConnection.publish(`/v1/dev/${deviceId}/in`, payload, mqtt.QoS.AtLeastOnce);\n\n const timer = setInterval(async () => {\n this._logger.debug(`Sending request to keep-alive publishing device status for '${deviceId}'...`);\n const payload = serializeMqttPayload<StartPublishingDeviceStatus>({\n Device: deviceId,\n MsgType: InMessageType.START_PUBLISHING_DEVICE_STATUS,\n Timestamp: dayjs().unix(),\n Timeout: RealtimeKeepAliveInterval.asSeconds()\n });\n await mqttConnection.publish(`/v1/dev/${deviceId}/in`, payload, mqtt.QoS.AtLeastOnce);\n }, RealtimeKeepAliveInterval.subtract(10, 'seconds').asMilliseconds());\n\n this._realtimeDeviceIds.set(deviceId, timer);\n }\n\n /**\n * Stops receiving real-time updates for the specified device.\n *\n * @param deviceId - The ID of the device to stop receiving real-time updates for.\n */\n async stopRealtimeUpdates(deviceId: string) {\n const timer = this._realtimeDeviceIds.get(deviceId);\n if (!timer) {\n this._logger.warn(`No real-time updates are running for device '${deviceId}'`);\n return;\n }\n\n this._logger.debug(`Initializing MQTT connection...`);\n const mqttConnection = await this.getMqttConnection();\n\n this._logger.debug(`Unsubscribing to MQTT topic '/v1/dev/${deviceId}/out'...`);\n await mqttConnection.unsubscribe(`/v1/dev/${deviceId}/out`);\n\n this._logger.debug(`Stopping real-time updates for device '${deviceId}'...`);\n clearInterval(timer);\n this._realtimeDeviceIds.delete(deviceId);\n }\n\n private async getFreshSession(): Promise<CognitoUserSession> {\n if (!this._cognitoUser || !this._cognitoUserSession) {\n throw new UnauthenticatedError('An attempt was made to access a resource without a valid session.');\n }\n\n if (\n this._cognitoUserSession.isValid() &&\n dayjs.unix(this._cognitoUserSession.getIdToken().getExpiration()).isAfter()\n ) {\n this._logger.info('Session is valid, no need to refresh');\n return Promise.resolve(this._cognitoUserSession);\n }\n\n this._logger.info('Session is not valid or expired, refreshing...');\n return new Promise<CognitoUserSession>((resolve, reject) => {\n this._cognitoUser!.refreshSession(this._cognitoUserSession!.getRefreshToken(), (error, session) => {\n if (error) {\n this._logger.error('Failed to refresh session:', error);\n reject(new UnauthenticatedError('Unable to refresh the authentication session.'));\n } else {\n this._logger.info('Session refreshed successfully');\n this._cognitoUserSession = session;\n this.emitter.emit('sessionChanged', this.session);\n resolve(session);\n }\n });\n });\n }\n\n private async getMqttConnection(): Promise<mqtt.MqttClientConnection> {\n if (this._mqttConnection) {\n return this._mqttConnection;\n }\n\n const session = await this.getFreshSession();\n const credentialsProvider = fromCognitoIdentityPool({\n clientConfig: {\n region: AwsRegion\n },\n identityPoolId: CognitoIdentityPoolId,\n logins: {\n [CognitoLoginKey]: session.getIdToken().getJwtToken()\n },\n logger: this._logger\n });\n const credentials = await credentialsProvider();\n\n const builder = iot.AwsIotMqttConnectionConfigBuilder.new_with_websockets()\n .with_credentials(AwsRegion, credentials.accessKeyId, credentials.secretAccessKey, credentials.sessionToken)\n .with_endpoint(MqttEndpoint)\n .with_client_id(`mysa-js-sdk-${dayjs().unix()}`) // Unique client ID\n .with_clean_session(true)\n .with_keep_alive_seconds(30)\n .with_ping_timeout_ms(3000)\n .with_protocol_operation_timeout_ms(60000);\n\n const config = builder.build();\n const client = new mqtt.MqttClient();\n this._mqttConnection = client.new_connection(config);\n\n this._mqttConnection.on('closed', () => {\n this._logger.info('MQTT connection closed');\n this._mqttConnection = undefined;\n });\n\n await this._mqttConnection.connect();\n\n return this._mqttConnection;\n }\n\n private processMqttMessage(payload: ArrayBuffer) {\n try {\n const parsedPayload = parseMqttPayload(payload);\n\n this.emitter.emit('rawRealtimeMessageReceived', parsedPayload);\n\n if (isMsgTypeOutPayload(parsedPayload)) {\n switch (parsedPayload.MsgType) {\n case OutMessageType.DEVICE_V1_STATUS:\n this.emitter.emit('statusChanged', {\n deviceId: parsedPayload.Device,\n temperature: parsedPayload.MainTemp,\n humidity: parsedPayload.Humidity,\n setPoint: parsedPayload.SetPoint,\n current: parsedPayload.Current\n });\n break;\n\n case OutMessageType.DEVICE_SETPOINT_CHANGE:\n this.emitter.emit('setPointChanged', {\n deviceId: parsedPayload.Device,\n newSetPoint: parsedPayload.Next,\n previousSetPoint: parsedPayload.Prev\n });\n break;\n }\n } else if (isMsgOutPayload(parsedPayload)) {\n switch (parsedPayload.msg) {\n case OutMessageType.DEVICE_V2_STATUS:\n this.emitter.emit('statusChanged', {\n deviceId: parsedPayload.src.ref,\n temperature: parsedPayload.body.ambTemp,\n humidity: parsedPayload.body.hum,\n setPoint: parsedPayload.body.stpt,\n dutyCycle: parsedPayload.body.dtyCycle\n });\n break;\n\n case OutMessageType.DEVICE_STATE_CHANGE:\n this.emitter.emit('stateChanged', {\n deviceId: parsedPayload.src.ref,\n mode: parsedPayload.body.state.md === 1 ? 'off' : parsedPayload.body.state.md === 3 ? 'heat' : undefined,\n setPoint: parsedPayload.body.state.sp\n });\n break;\n }\n }\n } catch (error) {\n this._logger.error('Error handling MQTT message:', error);\n }\n }\n}\n"],"mappings":"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","names":["InMessageType","OutMessageType","payload"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "mysa-js-sdk",
|
|
3
|
-
"version": "1.0
|
|
3
|
+
"version": "1.1.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"private": false,
|
|
6
6
|
"description": "A JavaScript SDK for accessing Mysa smart thermostats.",
|
|
@@ -46,21 +46,21 @@
|
|
|
46
46
|
"build:docs": "typedoc"
|
|
47
47
|
},
|
|
48
48
|
"dependencies": {
|
|
49
|
-
"@aws-sdk/credential-providers": "3.
|
|
49
|
+
"@aws-sdk/credential-providers": "3.821.0",
|
|
50
50
|
"amazon-cognito-identity-js": "6.3.15",
|
|
51
51
|
"aws-iot-device-sdk-v2": "1.21.4",
|
|
52
52
|
"dayjs": "1.11.13",
|
|
53
53
|
"lodash": "4.17.21"
|
|
54
54
|
},
|
|
55
55
|
"devDependencies": {
|
|
56
|
-
"@eslint/js": "9.
|
|
56
|
+
"@eslint/js": "9.28.0",
|
|
57
57
|
"@semantic-release/npm": "12.0.1",
|
|
58
58
|
"@types/lodash": "4.17.17",
|
|
59
|
-
"@types/node": "22.15.
|
|
59
|
+
"@types/node": "22.15.29",
|
|
60
60
|
"conventional-changelog-conventionalcommits": "9.0.0",
|
|
61
61
|
"dotenv": "16.5.0",
|
|
62
|
-
"eslint": "9.
|
|
63
|
-
"eslint-plugin-jsdoc": "50.
|
|
62
|
+
"eslint": "9.28.0",
|
|
63
|
+
"eslint-plugin-jsdoc": "50.7.1",
|
|
64
64
|
"eslint-plugin-tsdoc": "0.4.0",
|
|
65
65
|
"pino": "9.7.0",
|
|
66
66
|
"pino-pretty": "13.0.0",
|
|
@@ -70,9 +70,9 @@
|
|
|
70
70
|
"semantic-release": "24.2.5",
|
|
71
71
|
"tsup": "8.5.0",
|
|
72
72
|
"tsx": "4.19.4",
|
|
73
|
-
"typedoc": "0.28.
|
|
73
|
+
"typedoc": "0.28.5",
|
|
74
74
|
"typedoc-material-theme": "1.4.0",
|
|
75
75
|
"typescript": "5.8.3",
|
|
76
|
-
"typescript-eslint": "8.
|
|
76
|
+
"typescript-eslint": "8.33.0"
|
|
77
77
|
}
|
|
78
78
|
}
|