diff --git a/plejd/PlejdApi.js b/plejd/PlejdApi.js index 5e2fb6a..f7f2e64 100644 --- a/plejd/PlejdApi.js +++ b/plejd/PlejdApi.js @@ -1,4 +1,5 @@ const axios = require('axios').default; +const fs = require('fs'); const Configuration = require('./Configuration'); const Logger = require('./Logger'); @@ -25,12 +26,74 @@ class PlejdApi { async init() { logger.info('init()'); - await this.login(); - await this.getSites(); - await this.getSiteDetails(); + const cache = await this.getCachedCopy(); + const cacheExists = cache && cache.siteId && cache.siteDetails && cache.sessionToken; + + logger.debug(`Prefer cache? ${this.config.preferCachedApiResponse}`); + logger.debug(`Cache exists? ${cacheExists ? `Yes, created ${cache.dtCache}` : 'No'}`); + + if (this.config.preferCachedApiResponse && cacheExists) { + logger.info( + `Cache preferred. Skipping api requests and setting api data to response from ${cache.dtCache}`, + ); + logger.silly(`Cached response: ${JSON.stringify(cache, null, 2)}`); + this.siteId = cache.siteId; + this.siteDetails = cache.siteDetails; + this.sessionToken = cache.sessionToken; + } else { + try { + await this.login(); + await this.getSites(); + await this.getSiteDetails(); + this.saveCachedCopy(); + } catch (err) { + if (cacheExists) { + logger.warn('Failed to get api response, using cached copy instead'); + this.siteId = cache.siteId; + this.siteDetails = cache.siteDetails; + this.sessionToken = cache.sessionToken; + } else { + logger.error('Api request failed, no cached fallback available', err); + throw err; + } + } + } + this.deviceRegistry.setApiSite(this.siteDetails); + this.deviceRegistry.cryptoKey = this.siteDetails.plejdMesh.cryptoKey; + this.getDevices(); } + // eslint-disable-next-line class-methods-use-this + async getCachedCopy() { + logger.info('Getting cached api response from disk'); + + try { + const rawData = await fs.promises.readFile('/data/cachedApiResponse.json'); + const cachedCopy = JSON.parse(rawData); + + return cachedCopy; + } catch (err) { + logger.warn('No cached api response could be read. This is normal on the first run', err); + return null; + } + } + + async saveCachedCopy() { + logger.info('Saving cached copy'); + try { + const rawData = JSON.stringify({ + siteId: this.siteId, + siteDetails: this.siteDetails, + sessionToken: this.sessionToken, + dtCache: new Date().toISOString(), + }); + await fs.promises.writeFile('/data/cachedApiResponse.json', rawData); + } catch (err) { + logger.error('Failed to save cache of api response', err); + } + } + async login() { logger.info('login()'); logger.info(`logging into ${this.config.site}`); @@ -115,13 +178,11 @@ class PlejdApi { } this.siteDetails = response.data.result[0]; - this.deviceRegistry.setApiSite(this.siteDetails); logger.info(`Site details for site id ${this.siteId} found`); logger.silly(JSON.stringify(this.siteDetails, null, 2)); - this.deviceRegistry.cryptoKey = this.siteDetails.plejdMesh.cryptoKey; - if (!this.deviceRegistry.cryptoKey) { + if (!this.siteDetails.plejdMesh.cryptoKey) { throw new Error('API: No crypto key set for site'); } } catch (error) { diff --git a/plejd/config.json b/plejd/config.json index aea6676..7cfccd9 100644 --- a/plejd/config.json +++ b/plejd/config.json @@ -1,6 +1,6 @@ { "name": "Plejd", - "version": "0.5.1", + "version": "0.6.0-dev", "slug": "plejd", "description": "Adds support for the Swedish home automation devices from Plejd.", "url": "https://github.com/icanos/hassio-plejd/", @@ -18,6 +18,7 @@ "mqttUsername": "", "mqttPassword": "", "includeRoomsAsLights": false, + "preferCachedApiResponse": false, "logLevel": "info", "connectionTimeout": 2, "writeQueueWaitTime": 400 @@ -30,6 +31,7 @@ "mqttUsername": "str", "mqttPassword": "str", "includeRoomsAsLights": "bool", + "preferCachedApiResponse": "bool", "logLevel": "list(error|warn|info|debug|verbose|silly)", "connectionTimeout": "int", "writeQueueWaitTime": "int"