homey-api
Version:
297 lines (257 loc) • 7.91 kB
JavaScript
const Util = require('../Util');
const EventEmitter = require('../EventEmitter');
/**
* An authenticated Homey API. Do not construct this class manually.
* @class
* @hideconstructor
*/
class HomeyAPI extends EventEmitter {
/**
* Platforms
* @memberof HomeyAPI
* @property {object} PLATFORMS
* @property {string} PLATFORMS.LOCAL - Homey (2016 — 2019) & Homey Pro (2019 — 2023)
* @property {string} PLATFORMS.CLOUD - Homey Cloud
* @static
*/
static PLATFORMS = {
LOCAL: 'local',
CLOUD: 'cloud',
};
/**
* Discovery Strategies
* @memberof HomeyAPI
* @property {object} DISCOVERY_STRATEGIES
* @property {string} DISCOVERY_STRATEGIES.CLOUD - Cloud HTTPS, e.g. `https://abcdef.connect.athom.com`.
* @property {string} DISCOVERY_STRATEGIES.MDNS - Local HTTP, e.g. `http://homey-abcdef.local`
* @property {string} DISCOVERY_STRATEGIES.LOCAL - Local HTTP, e.g. `http://192.168.1.100`.
* @property {string} DISCOVERY_STRATEGIES.LOCAL_SECURE - Local HTTPS, e.g. `https://192-168-1-100.homey.homeylocal.com`.
* @property {string} DISCOVERY_STRATEGIES.REMOTE_FORWARDED - Remote HTTPS, e.g. `https://12-34-56-78.homey.homeylocal.com:12345`.
* @static
*/
static DISCOVERY_STRATEGIES = {
MDNS: 'mdns',
CLOUD: 'cloud',
LOCAL: 'local',
LOCAL_SECURE: 'localSecure',
REMOTE_FORWARDED: 'remoteForwarded',
};
constructor({
api = null,
properties = {},
debug = () => { },
}) {
super();
// Set Debug Enabled
Object.defineProperty(this, '__debugFunction', {
value: debug,
enumerable: false,
writable: true,
});
// Set API
Object.defineProperty(this, '__api', {
value: api,
enumerable: false,
writable: true,
});
// Set ID
Object.defineProperty(this, 'id', {
value: properties.id ?? properties._id ?? null,
enumerable: true,
writable: true,
});
// Set Version
Object.defineProperty(this, 'version', {
value: properties.softwareVersion ?? null,
enumerable: true,
writable: true,
});
// Set Name
Object.defineProperty(this, 'name', {
value: properties.name ?? null,
enumerable: true,
writable: true,
});
// Set Language
Object.defineProperty(this, 'language', {
value: properties.language ?? null,
enumerable: true,
writable: true,
});
// Set Role
Object.defineProperty(this, 'role', {
value: properties.role ?? null,
enumerable: true,
writable: true,
});
// Set Properties
Object.defineProperty(this, '__properties', {
value: properties,
enumerable: false,
writable: false,
});
}
get _id() {
throw new Error('HomeyAPI._id is not supported, please use HomeyAPI.id');
}
__debug(...props) {
if (!this.__debugFunction) return;
this.__debugFunction(...props);
}
/*
* Storage
*/
async __getStore() {
if (!this.__api) return {};
const store = await this.__api.__getStore();
return store[`homey-${this.id}`] || {};
}
async __setStore(value) {
if (!this.__api) return;
const store = await this.__getStore();
await this.__api.__setStore({
[`homey-${this.id}`]: {
...store,
...value,
},
});
}
/*
* Internationalization
*/
/**
* Translates an i18n-object (e.g. `{ en: 'My String', nl: 'Mijn tekst' }` to a string.
* Uses the language of Homey as defined in {@link Homey}.
* @param {object} input
* @param {string} input.en - English translation
* @param {string} input.nl - Dutch translation
* @returns {string|null} - The translated string, or null
* @example
* homeyApi.__({
* en: 'Hello',
* nl: 'Hallo',
* fr: 'Bonjour',
* }); // returns "Hello" if Homey is set to English
*/
__(input) {
if (typeof input === 'object' && input !== null) {
if (typeof input[this.__properties.language] === 'string') {
return input[this.__properties.language];
}
if (typeof input['en'] === 'string') {
return input['en'];
}
}
return null;
}
/**
* Check the current role.
* @param {string} roleId - The role ID, e.g. `owner`, `manager`, `user` or `guest`.
*/
hasRole(roleId) {
return this.role === roleId;
}
/**
* Creates a {@link HomeyAPIV3Local} or {@link HomeyAPIV2} instance for use in the Apps SDK.
* @param {Object} opts
* @param {Homey} opts.homey — Homey (Apps SDK) instance.
* @param {Function|null} [opts.debug=null] — Debug function, defaults to `null`.
* @example
* const { HomeyAPI } = require('homey-api');
*
* module.exports = class MyApp extends Homey.App {
*
* async onInit() {
* // Create a HomeyAPI instance. Ensure your app has the `homey:manager:api` permission.
* this.homeyApi = await HomeyAPI.createAppAPI({
* homey: this.homey,
* });
*
* // Get all the devices, and log their names.
* const devices = await this.{@link HomeyAPIV3Local homeyApi}.{@link HomeyAPIV3Local.ManagerDevices devices}.{@link HomeyAPIV3Local.ManagerDevices#getDevices getDevices}();
* for(const device of Object.values(devices)) {
* this.log(device.name);
* }
* }
*
* }
*/
static async createAppAPI({
homey,
debug = null,
} = {}) {
if (!homey) {
throw new Error('Invalid Homey');
}
if (debug === true) {
debug = (...props) => homey.app.log('[homey-api]', ...props);
}
const props = {
debug: debug ?? function debug() { },
token: await homey.api.getOwnerApiToken(),
baseUrl: await homey.api.getLocalUrl(),
strategy: [],
properties: {
id: await homey.cloud.getHomeyId(),
softwareVersion: homey.version,
},
};
if (homey.platform === 'local' && homey.platformVersion === 1) {
const HomeyAPIV2 = require('./HomeyAPIV2');
return new HomeyAPIV2(props);
}
if (homey.platform === 'local' && homey.platformVersion === 2) {
const HomeyAPIV3Local = require('./HomeyAPIV3Local');
return new HomeyAPIV3Local(props);
}
if (homey.platform === 'cloud' && homey.platformVersion === 2) {
const HomeyAPIV3Cloud = require('./HomeyAPIV3Cloud');
return new HomeyAPIV3Cloud(props);
}
throw new Error(`Invalid Homey Platform Version: ${homey.platformVersion}`);
}
/**
* Creates a {@link HomeyAPIV3Local} instance for use in a project.
* @param {Object} opts
* @param {String} opts.address — The address of the Homey, e.g. `http://192.168.1.123:80`.
* @param {String} opts.token — A Personal Access Token created in the Homey Web App.
* @param {Function|null} opts.debug — Debug function, defaults to `null`.
* @example
* import { HomeyAPI } from 'homey-api';
* const homeyApi = await HomeyAPI.createLocalAPI({
* address: 'http://192.169.1.123',
* token: '<my_personal_access_token>',
* });
* const devices = await homeyApi.devices.getDevices();
*/
static async createLocalAPI({
address,
token,
debug = null,
}) {
if (!address) {
throw new Error('Invalid Address');
}
if (!token) {
throw new Error('Invalid Token');
}
const res = await Util.fetch(`${address}/api/manager/system/ping`);
if (!res.headers.has('X-Homey-ID')) {
throw new Error(`No Homey Found At Address: ${address}`);
}
const props = {
token,
debug: debug ?? function debug() { },
baseUrl: address,
strategy: [],
properties: {
id: res.headers.get('X-Homey-ID'),
softwareVersion: res.headers.get('X-Homey-Version'),
},
};
const HomeyAPIV3Local = require('./HomeyAPIV3Local');
return new HomeyAPIV3Local(props);
}
}
module.exports = HomeyAPI;
;