node-tado-client
Version:
A Tado client for nodejs
768 lines • 34.6 kB
JavaScript
;
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __classPrivateFieldSet = (this && this.__classPrivateFieldSet) || function (receiver, state, value, kind, f) {
if (kind === "m") throw new TypeError("Private method is not writable");
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a setter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot write private member to an object whose class did not declare it");
return (kind === "a" ? f.call(receiver, value) : f ? f.value = value : state.set(receiver, value)), value;
};
var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (receiver, state, kind, f) {
if (kind === "a" && !f) throw new TypeError("Private accessor was defined without a getter");
if (typeof state === "function" ? receiver !== state || !f : !state.has(receiver)) throw new TypeError("Cannot read private member from an object whose class did not declare it");
return kind === "m" ? f : kind === "a" ? f.call(receiver) : f ? f.value : state.get(receiver);
};
var _BaseTado_instances, _BaseTado_httpsAgent, _BaseTado_token, _BaseTado_tokenCallback, _BaseTado_semaphore, _BaseTado_ratelimit, _BaseTado_parseDeviceToken, _BaseTado_checkDevice, _BaseTado_waitForAuth, _BaseTado_getToken;
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseTado = void 0;
const https_1 = require("https");
const axios_1 = __importStar(require("axios"));
const semaphore_1 = require("./semaphore");
const types_1 = require("./types");
const tado_url = "https://my.tado.com";
const client_id = "1bb50063-6b0c-4d11-bd99-387f4a91cc46";
const scope = "offline_access";
const grant_type = "urn:ietf:params:oauth:grant-type:device_code";
class BaseTado {
constructor() {
_BaseTado_instances.add(this);
_BaseTado_httpsAgent.set(this, void 0);
_BaseTado_token.set(this, void 0);
_BaseTado_tokenCallback.set(this, void 0);
_BaseTado_semaphore.set(this, void 0);
_BaseTado_ratelimit.set(this, undefined);
__classPrivateFieldSet(this, _BaseTado_httpsAgent, new https_1.Agent({ keepAlive: true }), "f");
__classPrivateFieldSet(this, _BaseTado_semaphore, new semaphore_1.Semaphore(1), "f");
}
/**
* Get the latest Oauth Token and Refresh Token
*
* @returns The latest token
*/
get token() {
return __classPrivateFieldGet(this, _BaseTado_token, "f");
}
/**
* Set the callback function that is called when the Oauth token changes.
*
* @param cb - The callback function
*/
setTokenCallback(cb) {
__classPrivateFieldSet(this, _BaseTado_tokenCallback, cb, "f");
}
/**
* Get the Tado API rate limit information
*
* @returns `RateLimit` if an API call has occured
*/
getRatelimit() {
return __classPrivateFieldGet(this, _BaseTado_ratelimit, "f");
}
/**
* Authenticate with the Oauth server. A refresh token may be supplied to bypass the device auth
* flow if it is still valid, otherwise the device flow is initiaited.
*
* @param refreshToken - Attempt to use this refresh token to re-authenticate
* @param timeout - Ignore the Tado provided timeout for device auth and use this value
* @returns A promise that resolves to either a `DeviceVerification` object for device auth flows
* and a promise of a token, or an undefined auth flow and a promise of a token, if the refresh token
* was supplied
*/
async authenticate(refreshToken, timeout) {
if (refreshToken) {
__classPrivateFieldSet(this, _BaseTado_token, {
access_token: "",
refresh_token: refreshToken,
expiry: new Date(0),
}, "f");
try {
const token = await __classPrivateFieldGet(this, _BaseTado_instances, "m", _BaseTado_getToken).call(this);
return [undefined, new Promise((resolve) => resolve(token))];
}
catch {
// Refresh token is no good
}
}
const verify = await (0, axios_1.default)({
url: "https://login.tado.com/oauth2/device_authorize",
method: "POST",
params: {
client_id,
scope,
},
});
if (timeout !== undefined) {
timeout = Math.min(timeout, verify.data.expires_in);
}
else {
timeout = verify.data.expires_in;
}
const token = new Promise((resolve, reject) => {
__classPrivateFieldGet(this, _BaseTado_instances, "m", _BaseTado_waitForAuth).call(this, verify.data.device_code, verify.data.interval, timeout)
.then(resolve)
.catch(reject);
});
return [verify.data, token];
}
/**
* Makes an API call to the provided URL with the specified method and data.
*
* @typeParam R - The type of the response
* @typeParam T - The type of the request body
* @param url - The endpoint to which the request is sent. If the URL contains "https", it will be used as is.
* @param method - The HTTP method to use for the request (e.g., "get", "post").
* @param data - The payload to send with the request, if applicable.
* @returns A promise that resolves to the response data.
*/
async apiCall(url, method = "get", data) {
var _a, _b;
const token = await __classPrivateFieldGet(this, _BaseTado_instances, "m", _BaseTado_getToken).call(this);
let callUrl = tado_url + url;
if (url.includes("https")) {
callUrl = url;
}
const request = {
url: callUrl,
method: method,
data: data,
headers: {
Authorization: `Bearer ${token.access_token}`,
},
httpsAgent: __classPrivateFieldGet(this, _BaseTado_httpsAgent, "f"),
};
if (method !== "get" && method !== "GET") {
request.data = data;
}
const response = await (0, axios_1.default)(request);
const headers = response.headers;
if (headers instanceof axios_1.AxiosHeaders) {
const ratelimit = {
policy: {
quota: 0,
window: 0,
},
current: {
remaining: 0,
resetsIn: undefined,
},
};
(_a = headers
.get("ratelimit-policy")) === null || _a === void 0 ? void 0 : _a.toString().split(";").forEach((v) => {
if (v.includes("=")) {
const parts = v.split("=");
if (parts[0] == "q") {
ratelimit.policy.quota = Number.parseInt(parts[1]);
}
else if (parts[0] == "w") {
ratelimit.policy.window = Number.parseInt(parts[1]);
}
}
});
(_b = headers
.get("ratelimit")) === null || _b === void 0 ? void 0 : _b.toString().split(";").forEach((v) => {
if (v.includes("=")) {
const parts = v.split("=");
if (parts[0] == "r") {
ratelimit.current.remaining = Number.parseInt(parts[1]);
}
else if (parts[0] == "t") {
ratelimit.current.resetsIn = Number.parseInt(parts[1]);
}
}
});
__classPrivateFieldSet(this, _BaseTado_ratelimit, ratelimit, "f");
}
return response.data;
}
/**
* Fetches the current user data.
*
* @returns A promise that resolves to the user data.
*/
getMe() {
return this.apiCall("/api/v2/me");
}
/**
* Fetches and returns the home details for the specified home ID.
*
* @param home_id - The ID of the home to be retrieved.
* @returns A promise that resolves to the details of the home.
*/
getHome(home_id) {
return this.apiCall(`/api/v2/homes/${home_id}`);
}
/**
* Sets the away radius for a specific home.
*
* @param home_id - The ID of the home.
* @param away_radius_meters - The away radius in meters.
* @returns A promise that resolves when the away radius is successfully set.
*/
setAwayRadius(home_id, away_radius_meters) {
return this.apiCall(`/api/v2/homes/${home_id}/awayRadiusInMeters`, "PUT", {
awayRadiusInMeters: away_radius_meters,
});
}
/**
* Fetches incident detection details for the specified home.
*
* @param home_id - The unique identifier of the home.
* @returns A promise that resolves to the incident detection details of the home.
*/
getIncidentDetection(home_id) {
return this.apiCall(`/api/v2/homes/${home_id}/incidentDetection`);
}
/**
* Enables or disables incident detection for a specified home.
*
* @param home_id - The unique identifier of the home.
* @param enabled - Indicates whether incident detection should be enabled (true) or disabled (false).
* @returns A promise that resolves when the operation is complete.
*/
setIncidentDetection(home_id, enabled) {
return this.apiCall(`/api/v2/homes/${home_id}/incidentDetection`, "PUT", {
enabled: enabled,
});
}
/**
* Checks if the early start feature is enabled for a given home.
*
* @param home_id - The unique identifier of the home.
* @returns A promise that resolves to a boolean indicating whether the early start feature is enabled.
*/
async isEarlyStartEnabled(home_id) {
const { enabled } = await this.apiCall(`/api/v2/homes/${home_id}/earlyStart`);
return enabled;
}
/**
* Sets the early start feature for a specified home.
*
* @param home_id - The unique identifier of the home.
* @param enabled - A boolean indicating whether the early start feature should be enabled or disabled.
* @returns A promise that resolves when the early start setting has been successfully updated.
*/
setEarlyStart(home_id, enabled) {
return this.apiCall(`/api/v2/homes/${home_id}/earlyStart`, "PUT", {
enabled: enabled,
});
}
/**
* Fetches the weather information for a specified home.
*
* @param home_id - The unique identifier of the home for which to retrieve the weather data.
* @returns A promise that resolves to a Weather object containing the weather information for the specified home.
*/
getWeather(home_id) {
return this.apiCall(`/api/v2/homes/${home_id}/weather`);
}
/**
* Fetches the list of installations for a given home.
*
* @param home_id - The ID of the home for which to fetch installations.
* @returns A promise that resolves to an array of installations.
*/
getInstallations(home_id) {
return this.apiCall(`/api/v2/homes/${home_id}/installations`);
}
/**
* Fetches the list of invitations for a specified home.
*
* @param home_id - The ID of the home for which to retrieve invitations.
* @returns A promise that resolves to an array of Invitation objects.
*/
getInvitations(home_id) {
return this.apiCall(`/api/v2/homes/${home_id}/invitations`);
}
/**
* Retrieves an invitation based on the provided home ID and token.
*
* @param home_id - The ID of the home for which the invitation is to be retrieved.
* @param token - The unique token (invitation id) associated with the invitation.
* @returns A promise that resolves to the invitation details.
*/
getInvitation(home_id, token) {
return this.apiCall(`/api/v2/homes/${home_id}/invitations/${token}`);
}
/**
* Creates an invitation for a specified home.
*
* @param home_id - The unique identifier of the home to which the invitation will be sent.
* @param email - The email address of the invitee.
* @returns A promise that resolves to an Invitation object.
*/
createInvitation(home_id, email) {
return this.apiCall(`/api/v2/homes/${home_id}/invitations`, "POST", {
email: email,
});
}
/**
* Resends an invitation to a specific home.
*
* @param home_id - The ID of the home for which the invitation is to be resent.
* @param token - The token representing the invitation to be resent.
* @returns A promise that resolves once the invitation has been resent.
*/
resendInvitation(home_id, token) {
return this.apiCall(`/api/v2/homes/${home_id}/invitations/${token}/resend`, "POST", {});
}
/**
* Deletes an invitation associated with a home.
*
* @param home_id - The unique identifier of the home.
* @param token - The token associated with the invitation.
* @returns A promise that resolves when the invitation is successfully deleted.
*/
deleteInvitation(home_id, token) {
return this.apiCall(`/api/v2/homes/${home_id}/invitations/${token}`, "DELETE");
}
/**
* Fetches the list of users associated with a given home.
*
* @param home_id - The ID of the home for which to fetch users.
* @returns A promise that resolves to an array of User objects.
*/
getUsers(home_id) {
return this.apiCall(`/api/v2/homes/${home_id}/users`);
}
/**
* Fetches the state of a home based on the provided home ID.
*
* @param home_id - The unique identifier of the home for which the state is to be retrieved.
* @returns A promise that resolves to the state of the specified home.
*/
getState(home_id) {
return this.apiCall(`/api/v2/homes/${home_id}/state`);
}
/**
* Retrieves the heating circuits associated with a given home based on the home ID.
*
* @param home_id - The ID of the home for which to retrieve heating circuits.
* @returns A promise that resolves to a HeatingCircuit object.
*/
getHeatingCircuits(home_id) {
return this.apiCall(`/api/v2/homes/${home_id}/heatingCircuits`);
}
/**
* Retrieves a list of mobile devices associated with a given home ID.
* @param home_id - The unique identifier of the home.
* @returns A promise that resolves to an array of MobileDevice objects.
*/
getMobileDevices(home_id) {
return this.apiCall(`/api/v2/homes/${home_id}/mobileDevices`);
}
/**
* Fetches a mobile device associated with the given home ID and mobile device ID.
*
* @param home_id - The ID of the home.
* @param mobile_device_id - The ID of the mobile device.
* @returns A promise that resolves to the mobile device data.
*/
getMobileDevice(home_id, mobile_device_id) {
return this.apiCall(`/api/v2/homes/${home_id}/mobileDevices/${mobile_device_id}`);
}
/**
* Fetches the settings for a specific mobile device within a given home.
*
* @param home_id - The unique identifier of the home.
* @param mobile_device_id - The unique identifier of the mobile device.
* @returns A promise that resolves to the mobile device's settings.
*/
getMobileDeviceSettings(home_id, mobile_device_id) {
return this.apiCall(`/api/v2/homes/${home_id}/mobileDevices/${mobile_device_id}/settings`);
}
/**
* Sets the geo-tracking settings for a specified mobile device in a given home.
*
* @param home_id - The ID of the home.
* @param mobile_device_id - The ID of the mobile device.
* @param geoTrackingEnabled - A flag indicating whether geo-tracking should be enabled.
* @returns A promise that resolves to the updated mobile device settings.
*/
async setGeoTracking(home_id, mobile_device_id, geoTrackingEnabled) {
const settings = await this.getMobileDeviceSettings(home_id, mobile_device_id);
return this.apiCall(`/api/v2/homes/${home_id}/mobileDevices/${mobile_device_id}/settings`, "put", {
...settings,
geoTrackingEnabled: geoTrackingEnabled,
});
}
/**
* Creates a push notification registration for a given home and mobile device.
*
* Note: Do not use this unless you know what you are doing, you might want to consider
* registering a dummy device.
*
* @param home_id - The identifier for the home.
* @param mobile_device_id - The identifier for the mobile device.
* @param token - The push notification token for the device.
* @returns A promise that resolves to the push notification registration (AWS SNS Endpoint ARN).
*/
createPushNotificationRegistration(home_id, mobile_device_id, token) {
return this.apiCall(`/api/v2/homes/${home_id}/mobileDevices/${mobile_device_id}/pushNotificationRegistration`, "put", {
token: token,
firebaseProject: "tado-app",
provider: "FCM",
});
}
/**
* Fetches the geo-location configuration for a specific mobile device in a home.
*
* @param home_id - The unique identifier of the home.
* @param mobile_device_id - The unique identifier of the mobile device.
* @returns A promise that resolves to the mobile device's geo-location configuration.
*/
getMobileDeviceGeoLocationConfig(home_id, mobile_device_id) {
return this.apiCall(`/api/v2/homes/${home_id}/mobileDevices/${mobile_device_id}/geoLocationConfig`);
}
/**
* Fetches the running times for a given home within the specified date range.
*
* @param home_id - The ID of the home from which to retrieve running times.
* @param from - The start date of the period in the format `YYYY-MM-DD`.
* @param to - The end date of the period in the format `YYYY-MM-DD`.
* @param aggregate - The aggregation type for running times (e.g., daily, weekly, monthly).
* @param summary_only - Determines whether to fetch only a summary of running times or detailed data.
*
* @returns A promise that resolves to either detailed running times or a summary, depending on the `summary_only` parameter.
*/
getRunningTimes(home_id, from, to, aggregate, summary_only) {
return this.apiCall(`https://minder.tado.com/v1/homes/${home_id}/runningTimes?from=${from}&to=${to}&aggregate=${aggregate}&summary_only=${summary_only}`);
}
/**
* Updates the presence status for a specified home.
*
* @param home_id - The unique identifier for the home.
* @param presence - The new presence state which must be "HOME", "AWAY", or "AUTO".
* @returns Resolves when the presence status has been successfully updated.
* @throws {@link TadoError} if the supplied presence state is not "HOME", "AWAY", or "AUTO".
*/
setPresence(home_id, presence) {
const upperCasePresence = presence.toUpperCase();
if (!["HOME", "AWAY", "AUTO"].includes(upperCasePresence)) {
throw new types_1.TadoError(`Invalid presence "${upperCasePresence}" must be "HOME", "AWAY", or "AUTO"`);
}
const method = upperCasePresence == "AUTO" ? "delete" : "put";
const config = {
homePresence: upperCasePresence,
};
return this.apiCall(`/api/v2/homes/${home_id}/presenceLock`, method, config);
}
/**
* Checks if anyone is at home based on the geo-tracking data of mobile devices.
*
* @param home_id - The unique identifier of the home.
* @returns A promise that resolves to a boolean indicating if any tracked device is at home.
*/
async isAnyoneAtHome(home_id) {
const devices = await this.getMobileDevices(home_id);
for (const device of devices) {
if (device.settings.geoTrackingEnabled && device.location && device.location.atHome) {
return true;
}
}
return false;
}
/**
* Updates the presence state of the specified home.
*
* This method checks if anyone is currently at home and compares it
* with the current presence state. If there is a discrepancy, it updates
* the presence state accordingly. If the presence state is already accurate,
* it returns a message indicating no change was needed.
*
* @param home_id - The unique identifier of the home whose presence state is to be updated.
* @returns A promise that resolves when the operation is complete,
* or returns a message if the presence state was already accurate.
*/
async updatePresence(home_id) {
const [isAnyoneAtHome, presenceState] = await Promise.all([
this.isAnyoneAtHome(home_id),
this.getState(home_id),
]);
const isPresenceAtHome = presenceState.presence === "HOME";
if (isAnyoneAtHome !== isPresenceAtHome) {
return this.setPresence(home_id, isAnyoneAtHome ? "HOME" : "AWAY");
}
else {
return "already up to date";
}
}
/**
* Fetches detailed air comfort information for a specific home.
*
* @param home_id - The unique identifier of the home.
* @returns A promise that resolves to detailed air comfort data.
*/
async getAirComfortDetailed(home_id) {
const home = await this.getHome(home_id);
const location = `latitude=${home.geolocation.latitude}&longitude=${home.geolocation.longitude}`;
return this.apiCall(`https://acme.tado.com/v1/homes/${home_id}/airComfort?${location}`);
}
/**
* Retrieves energy consumption details for a specified home, month, and year.
*
* @param home_id - The unique identifier of the home.
* @param month - The specific month for which the consumption details are requested.
* @param year - The specific year for which the consumption details are requested.
* @returns A promise resolving to the energy consumption details for the specified time period.
*/
async getEnergyIQConsumptionDetails(home_id, month, year) {
const date = `${year}-${month.toString().padStart(2, "0")}`;
return this.apiCall(`https://energy-insights.tado.com/api/homes/${home_id}/consumptionDetails?month=${date}`);
}
/**
* Fetches the energy consumption overview for a specified home, month, and year.
*
* @param home_id - The unique identifier of the home.
* @param month - The month for which the energy overview is needed.
* @param year - The year for which the energy overview is needed.
* @returns A promise that resolves to an EnergyIQOverview object containing the energy consumption details.
*/
async getEnergyIQOverview(home_id, month, year) {
const date = `${year}-${month.toString().padStart(2, "0")}`;
return this.apiCall(`https://energy-insights.tado.com/api/homes/${home_id}/consumptionOverview?month=${date}`);
}
/**
* Fetches the EnergyIQ tariff for a given home.
*
* @param home_id - The unique identifier of the home.
* @returns A promise that resolves to the {@link EnergyIQTariffs} object.
*/
getEnergyIQTariff(home_id) {
return this.apiCall(`https://energy-insights.tado.com/api/homes/${home_id}/tariffs`);
}
/**
* Adds a new energy IQ tariff for a specified home.
*
* @param home_id - The identifier of the home.
* @param unit - The unit of energy measurement.
* @param startDate - The start date of the tariff in ISO format.
* @param endDate - The end date of the tariff in ISO format.
* @param tariffInCents - The tariff amount in cents.
* @returns A promise that resolves to the API response.
* @throws {@link TadoError} if the unit is not valid.
*/
addEnergyIQTariff(home_id, unit, startDate, endDate, tariffInCents) {
if (!["m3", "kWh"].includes(unit)) {
throw new types_1.TadoError(`Invalid unit "${unit}" must be "m3", or "kWh"`);
}
return this.apiCall(`https://energy-insights.tado.com/api/homes/${home_id}/tariffs`, "post", {
unit: unit,
startDate: startDate,
endDate: endDate,
tariffInCents: tariffInCents,
});
}
/**
* Updates the Energy IQ tariff for a specified home.
*
* @param home_id - The unique identifier for the home.
* @param tariff_id - The unique identifier for the tariff.
* @param unit - The unit of the tariff, either "m3" or "kWh."
* @param startDate - The start date of the tariff in the format 'YYYY-MM-DD.'
* @param endDate - The end date of the tariff in the format 'YYYY-MM-DD.'
* @param tariffInCents - The tariff rate in cents.
* @returns A promise that resolves to the response of the API call.
* @throws {@link TadoError} if the unit is not "m3" or "kWh."
*/
updateEnergyIQTariff(home_id, tariff_id, unit, startDate, endDate, tariffInCents) {
if (!["m3", "kWh"].includes(unit)) {
throw new types_1.TadoError(`Invalid unit "${unit}" must be "m3", or "kWh"`);
}
return this.apiCall(`https://energy-insights.tado.com/api/homes/${home_id}/tariffs/${tariff_id}`, "put", {
unit: unit,
startDate: startDate,
endDate: endDate,
tariffInCents: tariffInCents,
});
}
/**
* Fetches the Energy IQ meter readings for a specified home.
*
* @param home_id - The unique identifier of the home for which the meter readings are to be retrieved.
* @returns A promise that resolves to the Energy IQ meter readings for the specified home.
*/
getEnergyIQMeterReadings(home_id) {
return this.apiCall(`https://energy-insights.tado.com/api/homes/${home_id}/meterReadings`);
}
/**
* Adds an energy IQ meter reading for a given home.
*
* @param home_id - The ID of the home.
* @param date - The date of the meter reading in ISO format.
* @param reading - The meter reading value.
* @returns A promise that resolves to the response of the API call.
*/
addEnergyIQMeterReading(home_id, date, reading) {
return this.apiCall(`https://energy-insights.tado.com/api/homes/${home_id}/meterReadings`, "post", { date: date, reading: reading });
}
/**
* Deletes a specific energy meter reading for a given home.
*
* @param home_id - The unique identifier of the home.
* @param reading_id - The unique identifier of the meter reading to be deleted.
* @returns A promise that resolves when the meter reading has been successfully deleted.
*/
deleteEnergyIQMeterReading(home_id, reading_id) {
return this.apiCall(`https://energy-insights.tado.com/api/homes/${home_id}/meterReadings/${reading_id}`, "delete", {});
}
/**
* Fetches the energy savings report for a specific home and time period.
*
* @example Get the energy savings report for the current month
* ```typescript
* const today = new Date();
* const countryCode = await tado.getHome(home_id).address.country;
* const report = await this tado.getEnergySavingsReport(home_id, today.getFullYear(), today.getMonth() + 1)
* ```
*
* @param home_id - The unique identifier of the home.
* @param year - The year for the report.
* @param month - The month for the report.
* @param countryCode - The country code of the home.
* @returns A promise that resolves to the energy savings report.
*/
getEnergySavingsReport(home_id, year, month, countryCode) {
return this.apiCall(`https://energy-bob.tado.com/${home_id}/${year}-${month}?country=${countryCode}`);
}
/**
* Retrieves the heating system information for a specific home.
*
* @param home_id - The unique identifier of the home.
* @returns A promise that resolves to the heating system information of the specified home.
*/
getHomeHeatingSystem(home_id) {
return this.apiCall(`/api/v2/homes/${home_id}/heatingSystem`);
}
/**
* Retrieves information about the specified boiler system. This includes model name, image
* used by the app, and manufacturer names.
*
* @example
* ```typescript
* const heatingSystem = await tado.getHomeHeatingSystem(1907);
* const boilerInformation = await tado.getBoilerSystemInformation(heatingSystem.boiler.id);
* console.log(
* `Your boiler model is ${boilerInformation.modelName} manufactured by ${boilerInformation.manufacturers[0].name}`,
* );
* ```
*
* @param system_id - The unique identifier of the boiler system as retrieved in {@link getHomeHeatingSystem}.
* @returns A promise that resolves to an object containing the boiler system information.
*/
async getBoilerSystemInformation(system_id) {
const response = await this.apiCall(`https://ivar.tado.com/graphql`, "POST", {
query: `{ system(id: ${system_id}) { modelName shortModelName: modelName(type: SHORT) thumbnail { schematic { url } } manufacturers { name } } }`,
});
return response.data.system;
}
}
exports.BaseTado = BaseTado;
_BaseTado_httpsAgent = new WeakMap(), _BaseTado_token = new WeakMap(), _BaseTado_tokenCallback = new WeakMap(), _BaseTado_semaphore = new WeakMap(), _BaseTado_ratelimit = new WeakMap(), _BaseTado_instances = new WeakSet(), _BaseTado_parseDeviceToken = function _BaseTado_parseDeviceToken(deviceToken) {
const expiry = new Date();
expiry.setSeconds(expiry.getSeconds() + deviceToken.expires_in - 5); // Minus 5 seconds grace
return {
access_token: deviceToken.access_token,
refresh_token: deviceToken.refresh_token,
expiry,
};
}, _BaseTado_checkDevice = async function _BaseTado_checkDevice(device_code, timeout) {
return new Promise((resolve, reject) => {
setTimeout(() => {
(0, axios_1.default)({
url: "https://login.tado.com/oauth2/token",
method: "POST",
params: {
client_id,
device_code: device_code,
grant_type,
},
})
.then((resp) => {
const deviceToken = resp.data;
resolve(__classPrivateFieldGet(this, _BaseTado_instances, "m", _BaseTado_parseDeviceToken).call(this, deviceToken));
})
.catch(reject);
}, timeout);
});
}, _BaseTado_waitForAuth = async function _BaseTado_waitForAuth(device_code, interval, expires_in) {
var _a;
for (let i = 0; i < expires_in; i += interval) {
try {
const token = await __classPrivateFieldGet(this, _BaseTado_instances, "m", _BaseTado_checkDevice).call(this, device_code, interval * 1000);
__classPrivateFieldSet(this, _BaseTado_token, token, "f");
(_a = __classPrivateFieldGet(this, _BaseTado_tokenCallback, "f")) === null || _a === void 0 ? void 0 : _a.call(this, token);
return token;
}
catch {
// Keep trying, we'll throw later
}
}
throw new types_1.AuthTimeout("Timeout waiting for user input");
}, _BaseTado_getToken = async function _BaseTado_getToken() {
var _a;
try {
await __classPrivateFieldGet(this, _BaseTado_semaphore, "f").acquire();
if (!__classPrivateFieldGet(this, _BaseTado_token, "f")) {
throw new types_1.NotAuthenticated("Tado is not authenticated. Please call the authenticate method.");
}
const now = new Date();
if (__classPrivateFieldGet(this, _BaseTado_token, "f").expiry < now) {
try {
const resp = await (0, axios_1.default)({
url: "https://login.tado.com/oauth2/token",
method: "POST",
params: {
client_id,
grant_type: "refresh_token",
refresh_token: __classPrivateFieldGet(this, _BaseTado_token, "f").refresh_token,
},
});
const token = __classPrivateFieldGet(this, _BaseTado_instances, "m", _BaseTado_parseDeviceToken).call(this, resp.data);
__classPrivateFieldSet(this, _BaseTado_token, token, "f");
(_a = __classPrivateFieldGet(this, _BaseTado_tokenCallback, "f")) === null || _a === void 0 ? void 0 : _a.call(this, token);
return token;
}
catch {
throw new types_1.InvalidRefreshToken("The refresh token has expired. Please call the authenticate method.");
}
}
else {
return __classPrivateFieldGet(this, _BaseTado_token, "f");
}
}
finally {
__classPrivateFieldGet(this, _BaseTado_semaphore, "f").release();
}
};
//# sourceMappingURL=base.js.map