diff --git a/.all-contributorsrc b/.all-contributorsrc index 6478e026..133c511c 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -85,6 +85,17 @@ "contributions": [ "translation" ] + }, + { + "login": "bugsounet", + "name": "Bugsounet - Cédric", + "avatar_url": "https://avatars.githubusercontent.com/u/30669209?v=4", + "profile": "http://www.bugsounet.fr", + "contributions": [ + "code", + "bug", + "review" + ] } ], "contributorsPerLine": 7, diff --git a/.env.template b/.env.template deleted file mode 100644 index 532744e4..00000000 --- a/.env.template +++ /dev/null @@ -1,3 +0,0 @@ -CLIENT_ID="" -CLIENT_SECRET="" -REFRESH_TOKEN="" diff --git a/.github/renovate.json b/.github/renovate.json index 64ae4308..cfea8199 100644 --- a/.github/renovate.json +++ b/.github/renovate.json @@ -2,7 +2,7 @@ "$schema": "https://docs.renovatebot.com/renovate-schema.json", "extends": [ "config:base", - "schedule:automergeMonthly", + "schedule:automergeMonthly" ], "packageRules": [ { diff --git a/.github/workflows/validation.yml b/.github/workflows/validation.yml index 96a79e55..c2d27925 100644 --- a/.github/workflows/validation.yml +++ b/.github/workflows/validation.yml @@ -51,25 +51,6 @@ jobs: run: npm clean-install - name: Validate CSS Sources run: npm run validate:css - unit: - runs-on: ubuntu-latest - name: 'Unit Tests' - steps: - - name: Checkout Code - uses: actions/checkout@v4 - - name: Use Node.js ${{ env.node-version }} - uses: actions/setup-node@v4 - with: - node-version: ${{ env.node-version }} - cache: "npm" - - name: Install Dependencies - run: npm clean-install - - name: Execute Unit Tests - run: npm run test - env: - CLIENT_ID: ${{ secrets.CLIENT_ID }} - CLIENT_SECRET: ${{ secrets.CLIENT_SECRET }} - REFRESH_TOKEN: ${{ secrets.REFRESH_TOKEN }} package-lock-is-up-to-date: runs-on: ubuntu-latest steps: diff --git a/.gitignore b/.gitignore index 23ccfcc4..259ded2a 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ node_modules report .env* .DS_Store +/token.json diff --git a/README.md b/README.md index 085e10b1..925e13f7 100644 --- a/README.md +++ b/README.md @@ -29,11 +29,7 @@ cd ~/MagicMirror/modules && git clone https://github.com/CFenner/MMM-Netatmo net :warning: Note that the checkout folder is named `netatmo` and not `MMM-Netatmo` as the repository. -Navigate into the module folder and install missing dependencies: - -```shell -cd netatmo && npm ci --production --ignore-scripts -``` +Since v2.1.0: **No special dependencies and no others commands are now needed!** ### Connection to Netatmo Service API @@ -110,6 +106,7 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d Otto Lote
Otto Lote

💻 cgillinger
cgillinger

🌍 + Bugsounet - Cédric
Bugsounet - Cédric

💻 🐛 👀 diff --git a/helper.js b/helper.js index 95155370..b5dd4722 100644 --- a/helper.js +++ b/helper.js @@ -2,11 +2,12 @@ * Module: MMM-Netatmo * * By Christopher Fenner https://github.com/CFenner + * Review @bugsounet https://github.com/bugsounet * MIT Licensed. */ const fs = require('fs') const path = require('path') -const URLSearchParams = require('@ungap/url-search-params') +const moment = require('moment') module.exports = { notifications: { @@ -15,117 +16,235 @@ module.exports = { DATA: 'NETATMO_DATA', DATA_RESPONSE: 'NETATMO_DATA_RESPONSE', }, - start: function () { + + start () { console.log('Netatmo helper started ...') this.token = null }, - authenticate: async function (config) { - const self = this - self.config = config + async authenticate () { const params = new URLSearchParams() params.append('grant_type', 'refresh_token') - params.append('refresh_token', self.refresh_token || self.config.refresh_token) - params.append('client_id', self.config.clientId) - params.append('client_secret', self.config.clientSecret) + params.append('refresh_token', this.refreshToken) + params.append('client_id', this.clientId) + params.append('client_secret', this.clientSecret) try { - const result = await fetch('https://' + self.config.apiBase + self.config.authEndpoint, { + const result = await fetch(`https://${this.config.apiBase}${this.config.authEndpoint}`, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: params, - }).then(response => response.json()) + }).then((response) => response.json()) if (result.error) { - throw new Error(result.error + ': ' + result.error_description) - } + throw new Error(`${result.error} : ${result.error_description}`) + }; + + this.token = result.access_token + this.token_expires_in = result.expires_in + this.refreshToken = result.refresh_token + console.log('Netatmo: Authenticated') + + // write in token file and provides for token refresh + this.writeToken(result) + if (result.expires_in) { + const expireAt = moment(Date.now() + (result.expires_in * 1000)).format('LLLL') + console.log(`Netatmo: New Token Expire ${expireAt}`) + setTimeout(() => this.authenticateRefresh(result.refresh_token), (result.expires_in - 60) * 1000) + }; - console.log('UPDATING TOKEN ' + result.access_token) - self.token = result.access_token - self.token_expires_in = result.expires_in - self.refresh_token = result.refresh_token - // we got a new token, save it to main file to allow it to request the datas - self.sendSocketNotification(self.notifications.AUTH_RESPONSE, { + // inform module AUTH ok + this.sendSocketNotification(this.notifications.AUTH_RESPONSE, { status: 'OK', }) } catch (error) { - console.log('error:', error) - self.sendSocketNotification(self.notifications.AUTH_RESPONSE, { + console.error('Netatmo:', error) + this.sendSocketNotification(this.notifications.AUTH_RESPONSE, { payloadReturn: error, status: 'NOTOK', message: error, }) - } + }; }, - loadData: async function (config) { - const self = this - self.config = config - if (self.config.mockData === true) { - self.sendSocketNotification(self.notifications.DATA_RESPONSE, { + async loadData () { + if (this.config.mockData === true) { + this.sendSocketNotification(this.notifications.DATA_RESPONSE, { payloadReturn: this.mockData(), status: 'OK', }) return - } - if (self.token === null || self.token === undefined) { - self.sendSocketNotification(self.notifications.DATA_RESPONSE, { + }; + + if (!this.token) { + this.sendSocketNotification(this.notifications.DATA_RESPONSE, { payloadReturn: 400, status: 'INVALID_TOKEN', message: 'token not set', }) return - } + }; try { - let result = await fetch('https://' + self.config.apiBase + self.config.dataEndpoint, { + let result = await fetch(`https://${this.config.apiBase}${this.config.dataEndpoint}`, { headers: { 'Content-Type': 'application/json', - Authorization: `Bearer ${self.token}`, + Authorization: `Bearer ${this.token}`, }, }) if (result.status === 403) { - console.log('status code:', result.status, '\n', result.statusText) - self.sendSocketNotification(self.notifications.DATA_RESPONSE, { + console.warn(`Netatmo: status code: ${result.status} (${result.statusText})`) + this.sendSocketNotification(this.notifications.DATA_RESPONSE, { payloadReturn: result.statusText, status: 'INVALID_TOKEN', message: result, }) return - } + }; result = await result.json() if (result.error) { throw new Error(result.error.message) - } + }; - self.sendSocketNotification(self.notifications.DATA_RESPONSE, { + this.sendSocketNotification(this.notifications.DATA_RESPONSE, { payloadReturn: result.body.devices, status: 'OK', }) } catch (error) { - console.log('error:', error) - self.sendSocketNotification(self.notifications.DATA_RESPONSE, { + console.error('Netatmo:', error) + this.sendSocketNotification(this.notifications.DATA_RESPONSE, { payloadReturn: error, status: 'NOTOK', message: error, }) - } + }; }, - mockData: function () { + + mockData () { const sample = fs.readFileSync(path.join(__dirname, 'sample', 'sample.json'), 'utf8') return JSON.parse(sample) }, - socketNotificationReceived: function (notification, payload) { + + socketNotificationReceived (notification, payload) { switch (notification) { + case 'INIT': + this.Init(payload) + break case this.notifications.AUTH: - this.authenticate(payload) + this.authenticate() break case this.notifications.DATA: - this.loadData(payload) + this.loadData() break } }, + + Init (config) { + this.config = config + if (!this.config.clientId) { + console.error('Netatmo: clientId not set in config.') + return + } + this.clientId = this.config.clientId + + if (!this.config.clientSecret) { + console.error('Netatmo: clientSecret not set in config.') + return + } + this.clientSecret = this.config.clientSecret + + const refreshToken = this.readToken() + this.refreshToken = refreshToken || this.config.refresh_token + + if (!this.refreshToken) { + console.error('Netatmo: refresh_token not set in config.') + return + } + + console.log('Netatmo: Initialized') + this.authenticate() + }, + + /* from MMM-NetatmoThermostat + * @bugsounet + */ + readToken () { + const file = path.resolve(__dirname, './token.json') + // check presence of token.json + if (fs.existsSync(file)) { + console.log('Netatmo: using token.json file') + const tokenFile = JSON.parse(fs.readFileSync(file)) + const refreshToken = tokenFile.refresh_token + if (!refreshToken) { + console.error('Netatmo: Token not found in token.json file') + console.log('Netatmo: using refresh_token from config') + return null + } + return refreshToken + } + // Token file not used + console.log('Netatmo: using refresh_token from config') + return null + }, + + writeToken (token) { + try { + const file = path.resolve(__dirname, './token.json') + fs.writeFileSync(file, JSON.stringify(token)) + console.log('Netatmo: token.json was written successfully') + return token + } catch (error) { + ; + console.error('Netatmo: writeToken error', error.message) + return null + }; + }, + + // Refresh Token + async authenticateRefresh (refreshToken) { + console.log('Netatmo: Refresh Token') + const params = new URLSearchParams() + params.append('grant_type', 'refresh_token') + params.append('refresh_token', refreshToken) + params.append('client_id', this.clientId) + params.append('client_secret', this.clientSecret) + + try { + const result = await fetch(`https://${this.config.apiBase}${this.config.authEndpoint}`, { + method: 'POST', + headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, + body: params, + }).then((response) => response.json()) + + if (result.error) { + throw new Error(result.error) + }; + + this.writeToken(result) + this.token = result.access_token + console.log('Netatmo: TOKEN Updated') + + if (result.expires_in) { + const expireAt = moment(Date.now() + (result.expires_in * 1000)).format('LLLL') + console.log(`Netatmo: New Token Expire ${expireAt}`) + setTimeout(() => this.authenticateRefresh(result.refresh_token), (result.expires_in - 60) * 1000) + }; + + this.sendSocketNotification(this.notifications.AUTH_RESPONSE, { + status: 'OK', + }) + } catch (error) { + console.error('Netatmo:', error) + this.sendSocketNotification(this.notifications.AUTH_RESPONSE, { + payloadReturn: error, + status: 'NOTOK', + message: error, + }) + console.log('Netatmo: Retry login in 60 sec') + setTimeout(() => this.authenticate(this.config), 60 * 1000) + } + }, } diff --git a/helper.test.js b/helper.test.js deleted file mode 100644 index c0d65377..00000000 --- a/helper.test.js +++ /dev/null @@ -1,151 +0,0 @@ -require('dotenv').config() -const moduleUnderTest = require('./helper.js') - -const apiBase = 'api.netatmo.com' -const authEndpoint = '/oauth2/token' -const dataEndpoint = '/api/getstationsdata' - -describe('helper', () => { - afterEach(() => { - delete moduleUnderTest.token - delete moduleUnderTest.token_expires_in - delete moduleUnderTest.refresh_token - delete moduleUnderTest.sendSocketNotification - }) - describe('data', () => { - test('existing token', async () => { - // prepare - expect(moduleUnderTest).not.toHaveProperty('token') - moduleUnderTest.sendSocketNotification = jest.fn((type, payload) => {}) - await moduleUnderTest.authenticate({ - apiBase, - authEndpoint, - refresh_token: process.env.REFRESH_TOKEN, - clientId: process.env.CLIENT_ID, - clientSecret: process.env.CLIENT_SECRET, - }) - expect(moduleUnderTest).toHaveProperty('token') - moduleUnderTest.sendSocketNotification = jest.fn((type, payload) => { - expect(type).toBe(moduleUnderTest.notifications.DATA_RESPONSE) - expect(payload).toHaveProperty('status', 'OK') - expect(payload).toHaveProperty('payloadReturn') - expect(payload.payloadReturn).toHaveLength(2) - }) - expect(moduleUnderTest).toHaveProperty('token') - // test - await moduleUnderTest.loadData({ - apiBase, - dataEndpoint, - }) - // assert - expect(moduleUnderTest.sendSocketNotification).toHaveBeenCalled() - }) - - test('with missing token', async () => { - // moduleUnderTest.token = process.env.TOKEN - // prepare - moduleUnderTest.sendSocketNotification = jest.fn((type, payload) => { - expect(type).toBe(moduleUnderTest.notifications.DATA_RESPONSE) - expect(payload).toHaveProperty('status', 'INVALID_TOKEN') - }) - // test - await moduleUnderTest.loadData({ - apiBase, - dataEndpoint, - }) - // assert - expect(moduleUnderTest.sendSocketNotification).toHaveBeenCalled() - }) - - test('with invalid token', async () => { - moduleUnderTest.token = 'something' - // prepare - moduleUnderTest.sendSocketNotification = jest.fn((type, payload) => { - expect(type).toBe(moduleUnderTest.notifications.DATA_RESPONSE) - expect(payload).toHaveProperty('status', 'INVALID_TOKEN') - }) - // test - await moduleUnderTest.loadData({ - apiBase, - dataEndpoint, - }) - // assert - expect(moduleUnderTest.sendSocketNotification).toHaveBeenCalled() - }) - }) - - describe('authentication', () => { - test('with refresh_token from config', async () => { - // prepare - moduleUnderTest.sendSocketNotification = jest.fn((type, payload) => { - expect(type).toBe(moduleUnderTest.notifications.AUTH_RESPONSE) - expect(payload).toHaveProperty('status', 'OK') - }) - expect(moduleUnderTest).not.toHaveProperty('token') - expect(moduleUnderTest).not.toHaveProperty('token_expires_in') - expect(moduleUnderTest).not.toHaveProperty('refresh_token') - // test - await moduleUnderTest.authenticate({ - apiBase, - authEndpoint, - refresh_token: process.env.REFRESH_TOKEN, - clientId: process.env.CLIENT_ID, - clientSecret: process.env.CLIENT_SECRET, - }) - // assert - expect(moduleUnderTest).toHaveProperty('token') - expect(moduleUnderTest).toHaveProperty('token_expires_in') - expect(moduleUnderTest).toHaveProperty('refresh_token') - expect(moduleUnderTest.sendSocketNotification).toHaveBeenCalled() - }) - - test('with refresh_token from object', async () => { - // prepare - moduleUnderTest.refresh_token = process.env.REFRESH_TOKEN - moduleUnderTest.sendSocketNotification = jest.fn((type, payload) => { - expect(type).toBe(moduleUnderTest.notifications.AUTH_RESPONSE) - expect(payload).toHaveProperty('status', 'OK') - }) - expect(moduleUnderTest).not.toHaveProperty('token') - expect(moduleUnderTest).not.toHaveProperty('token_expires_in') - expect(moduleUnderTest).toHaveProperty('refresh_token') - // test - await moduleUnderTest.authenticate({ - apiBase, - authEndpoint, - refresh_token: '', - clientId: process.env.CLIENT_ID, - clientSecret: process.env.CLIENT_SECRET, - }) - // assert - expect(moduleUnderTest).toHaveProperty('token') - expect(moduleUnderTest).toHaveProperty('token_expires_in') - expect(moduleUnderTest).toHaveProperty('refresh_token') - expect(moduleUnderTest.sendSocketNotification).toHaveBeenCalled() - }) - - test('without refresh_token', async () => { - // prepare - moduleUnderTest.sendSocketNotification = jest.fn((type, payload) => { - expect(type).toBe(moduleUnderTest.notifications.AUTH_RESPONSE) - expect(payload).toHaveProperty('status', 'NOTOK') - }) - expect(moduleUnderTest).not.toHaveProperty('token') - expect(moduleUnderTest).not.toHaveProperty('token_expires_in') - expect(moduleUnderTest).not.toHaveProperty('refresh_token') - // test - await moduleUnderTest.authenticate({ - apiBase, - authEndpoint, - refresh_token: '', - clientId: process.env.CLIENT_ID, - clientSecret: process.env.CLIENT_SECRET, - }) - // assert - expect(moduleUnderTest).not.toHaveProperty('token') - expect(moduleUnderTest).not.toHaveProperty('token_expires_in') - expect(moduleUnderTest).not.toHaveProperty('refresh_token') - expect(moduleUnderTest.sendSocketNotification).toHaveBeenCalled() - }) - }) -}) diff --git a/netatmo.js b/netatmo.js index 8e336011..d8bf2898 100755 --- a/netatmo.js +++ b/netatmo.js @@ -64,24 +64,23 @@ Module.register('netatmo', { RAIN_PER_DAY: 'sum_rain_24', }, // init method - start: function () { - const self = this + start () { Log.info(`Starting module: ${this.name}`) - self.loaded = false - self.moduleList = [] + this.loaded = false + this.moduleList = [] - // get a new token at start-up. When receive, GET_CAMERA_EVENTS will be requested - setTimeout(function () { - self.sendSocketNotification(self.notifications.DATA, self.config) + // get a new token at start-up. + setTimeout(() => { + // best way is using initialize at start and if auth OK --> fetch data + this.sendSocketNotification('INIT', this.config) }, this.config.initialDelay * 1000) // set auto-update - setInterval(function () { - // request directly the data, with the previous token. When the token will become invalid (error 403), it will be requested again - self.sendSocketNotification(self.notifications.DATA, self.config) + setInterval(() => { + this.sendSocketNotification(this.notifications.DATA) }, this.config.updateInterval * 60 * 1000 + this.config.initialDelay * 1000) }, - updateModuleList: function (stationList) { + updateModuleList (stationList) { let moduleList = [] for (const station of stationList) { @@ -111,7 +110,7 @@ Module.register('netatmo', { } this.moduleList = moduleList }, - getModule: function (module, stationName) { + getModule (module, stationName) { const result = {} result.name = module.module_name @@ -132,7 +131,7 @@ Module.register('netatmo', { name: measurement, value: this.getValue(measurement, 0), unit: this.getUnit(measurement), - icon: this.getIcon(measurement, 0) + ' flash red', + icon: `${this.getIcon(measurement, 0)} flash red`, label: this.translate(measurement.toUpperCase()), }) @@ -245,11 +244,13 @@ Module.register('netatmo', { } return result }, - getMeasurement: function (module, measurement, value) { + getMeasurement (module, measurement, value) { + /* eslint-disable no-param-reassign */ value = value || module.dashboard_data[measurement] if (measurement === this.measurement.TEMPERATURE_TREND || measurement === this.measurement.PRESSURE_TREND) { value = value || 'undefined' } + /* eslint-enable no-param-reassign */ return { name: measurement, value: this.getValue(measurement, value), @@ -258,12 +259,12 @@ Module.register('netatmo', { label: this.translate(measurement.toUpperCase()), } }, - kebabCase: function (name) { + kebabCase (name) { return name.replace(/([a-z])([A-Z])/g, '$1-$2') .replace(/[\s_]+/g, '-') .toLowerCase() }, - getValue: function (measurement, value) { + getValue (measurement, value) { if (!value) { return value } switch (measurement) { case this.measurement.CO2: @@ -288,7 +289,7 @@ Module.register('netatmo', { return value.toFixed(0)// + ' km/h' case this.measurement.WIND_ANGLE: case this.measurement.GUST_ANGLE: - return this.getDirection(value) + ' | ' + value// + '°' + return `${this.getDirection(value)} | ${value}`// + '°' case this.measurement.TEMPERATURE_TREND: case this.measurement.PRESSURE_TREND: return this.translate(value.toUpperCase()) @@ -296,7 +297,7 @@ Module.register('netatmo', { return value } }, - getUnit: function (measurement) { + getUnit (measurement) { switch (measurement) { case this.measurement.CO2: return 'ppm' @@ -325,7 +326,7 @@ Module.register('netatmo', { return '' } }, - getDirection: function (value) { + getDirection (value) { if (value < 11.25) return 'N' if (value < 33.75) return 'NNE' if (value < 56.25) return 'NE' @@ -344,13 +345,13 @@ Module.register('netatmo', { if (value < 348.75) return 'NNW' return 'N' }, - getCO2Status: function (value) { + getCO2Status (value) { if (!value || value === 'undefined' || value < 0) return 'undefined' if (value >= this.config.thresholdCO2Bad) return 'bad' if (value >= this.config.thresholdCO2Average) return 'average' return 'good' }, - getIcon: function (dataType, value) { + getIcon (dataType, value) { switch (dataType) { // case this.measurement.CO2: // return 'fa-lungs' @@ -378,26 +379,26 @@ Module.register('netatmo', { return '' } }, - getTrendIcon: function (value) { + getTrendIcon (value) { if (value === 'stable') return 'fa-chevron-circle-right' if (value === 'down') return 'fa-chevron-circle-down' if (value === 'up') return 'fa-chevron-circle-up' if (value === 'undefined') return 'fa-times-circle' }, - getBatteryIcon: function (value) { + getBatteryIcon (value) { if (value > 80) return 'fa-battery-full' if (value > 60) return 'fa-battery-three-quarters' if (value > 40) return 'fa-battery-half' if (value > 20) return 'fa-battery-quarter' return 'fa-battery-empty flash red' }, - getStyles: function () { + getStyles () { return [`${this.name}.${this.config.design}.css`] }, - getTemplate: function () { + getTemplate () { return `${this.name}.${this.config.design}.njk` }, - getTemplateData: function () { + getTemplateData () { return { loaded: this.loaded, showLastMessage: this.config.showLastMessage, @@ -417,7 +418,7 @@ Module.register('netatmo', { labelLoading: this.translate('LOADING'), } }, - getTranslations: function () { + getTranslations () { return { en: 'l10n/en.json', // fallback language cs: 'l10n/cs.json', @@ -430,29 +431,31 @@ Module.register('netatmo', { sv: 'l10n/sv.json', } }, - socketNotificationReceived: function (notification, payload) { - const self = this - Log.debug('received ' + notification) + socketNotificationReceived (notification, payload) { + Log.debug(`Netatmo: received ${notification}`) switch (notification) { - case self.notifications.AUTH_RESPONSE: + case this.notifications.AUTH_RESPONSE: if (payload.status === 'OK') { - self.sendSocketNotification(self.notifications.DATA, self.config) + console.log('Netatmo: AUTH OK') + this.sendSocketNotification(this.notifications.DATA) } else { - console.log('AUTH FAILED ' + payload.message) + console.error(`Netatmo: AUTH FAILED ${payload.message}`) } break - case self.notifications.DATA_RESPONSE: + case this.notifications.DATA_RESPONSE: if (payload.status === 'OK') { console.log('Devices %o', payload.payloadReturn) const stationList = payload.payloadReturn - self.updateModuleList(stationList) - self.updateDom(self.config.animationSpeed) + this.updateModuleList(stationList) + this.updateDom(this.config.animationSpeed) } else if (payload.status === 'INVALID_TOKEN') { // node_module has no valid token, reauthenticate - console.log('DATA FAILED, refreshing token') - self.sendSocketNotification(self.notifications.AUTH, self.config) + console.error('DATA FAILED, refreshing token') + // i'm not agree with this... can have error 403 loop + // --> managed with node_helper + // this.sendSocketNotification(this.notifications.AUTH) } else { - console.log('DATA FAILED ' + payload.message) + console.error(`Netatmo: DATA FAILED ${payload.message}`) } break } diff --git a/node_helper.js b/node_helper.js index 3b9899da..3b9b38ac 100644 --- a/node_helper.js +++ b/node_helper.js @@ -5,6 +5,6 @@ * MIT Licensed. */ const NodeHelper = require('node_helper') -const helper = require('./helper') +const helper = require('./helper.js') module.exports = NodeHelper.create(helper) diff --git a/package-lock.json b/package-lock.json index df0459de..fa861ad6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,30 +1,27 @@ { "name": "netatmo", - "version": "2.0.0", + "version": "2.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "netatmo", - "version": "2.0.0", + "version": "2.1.0", "license": "MIT", - "dependencies": { - "@ungap/url-search-params": "0.2.2" - }, "devDependencies": { - "@snyk/protect": "1.1291.0", + "@snyk/protect": "1.1291.1", "dotenv": "16.3.1", "eslint": "8.57.0", "eslint-config-standard": "17.1.0", "eslint-plugin-import": "2.29.1", "eslint-plugin-n": "16.6.2", - "eslint-plugin-promise": "6.1.1", + "eslint-plugin-promise": "6.2.0", "jest": "29.7.0", "jsonlint-newline-fork": "1.6.8", "less": "4.2.0", "markdownlint": "0.32.1", - "stylelint": "16.5.0", - "stylelint-config-standard": "36.0.0" + "stylelint": "16.6.1", + "stylelint-config-standard": "36.0.1" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -681,9 +678,9 @@ "dev": true }, "node_modules/@csstools/css-parser-algorithms": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.6.1.tgz", - "integrity": "sha512-ubEkAaTfVZa+WwGhs5jbo5Xfqpeaybr/RvWzvFxRs4jfq16wH8l8Ty/QEEpINxll4xhuGfdMbipRyz5QZh9+FA==", + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-2.6.3.tgz", + "integrity": "sha512-xI/tL2zxzEbESvnSxwFgwvy5HS00oCXxL4MLs6HUiDcYfwowsoQaABKxUElp1ARITrINzBnsECOc1q0eg2GOrA==", "dev": true, "funding": [ { @@ -695,17 +692,18 @@ "url": "https://opencollective.com/csstools" } ], + "license": "MIT", "engines": { "node": "^14 || ^16 || >=18" }, "peerDependencies": { - "@csstools/css-tokenizer": "^2.2.4" + "@csstools/css-tokenizer": "^2.3.1" } }, "node_modules/@csstools/css-tokenizer": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-2.2.4.tgz", - "integrity": "sha512-PuWRAewQLbDhGeTvFuq2oClaSCKPIBmHyIobCV39JHRYN0byDcUWJl5baPeNUcqrjtdMNqFooE0FGl31I3JOqw==", + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-2.3.1.tgz", + "integrity": "sha512-iMNHTyxLbBlWIfGtabT157LH9DUx9X8+Y3oymFEuMj8HNc+rpE3dPFGFgHjpKfjeFDjLjYIAIhXPGvS2lKxL9g==", "dev": true, "funding": [ { @@ -717,14 +715,15 @@ "url": "https://opencollective.com/csstools" } ], + "license": "MIT", "engines": { "node": "^14 || ^16 || >=18" } }, "node_modules/@csstools/media-query-list-parser": { - "version": "2.1.9", - "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.9.tgz", - "integrity": "sha512-qqGuFfbn4rUmyOB0u8CVISIp5FfJ5GAR3mBrZ9/TKndHakdnm6pY0L/fbLcpPnrzwCyyTEZl1nUcXAYHEWneTA==", + "version": "2.1.11", + "resolved": "https://registry.npmjs.org/@csstools/media-query-list-parser/-/media-query-list-parser-2.1.11.tgz", + "integrity": "sha512-uox5MVhvNHqitPP+SynrB1o8oPxPMt2JLgp5ghJOWf54WGQ5OKu47efne49r1SWqs3wRP8xSWjnO9MBKxhB1dA==", "dev": true, "funding": [ { @@ -736,18 +735,19 @@ "url": "https://opencollective.com/csstools" } ], + "license": "MIT", "engines": { "node": "^14 || ^16 || >=18" }, "peerDependencies": { - "@csstools/css-parser-algorithms": "^2.6.1", - "@csstools/css-tokenizer": "^2.2.4" + "@csstools/css-parser-algorithms": "^2.6.3", + "@csstools/css-tokenizer": "^2.3.1" } }, "node_modules/@csstools/selector-specificity": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-3.0.3.tgz", - "integrity": "sha512-KEPNw4+WW5AVEIyzC80rTbWEUatTW2lXpN8+8ILC8PiPeWPjwUzrPZDIOZ2wwqDmeqOYTdSGyL3+vE5GC3FB3Q==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@csstools/selector-specificity/-/selector-specificity-3.1.1.tgz", + "integrity": "sha512-a7cxGcJ2wIlMFLlh8z2ONm+715QkPHiyJcxwQlKOz/03GPw1COpfhcmC9wm4xlZfp//jWHNNMwzjtqHXVWU9KA==", "dev": true, "funding": [ { @@ -759,6 +759,7 @@ "url": "https://opencollective.com/csstools" } ], + "license": "MIT-0", "engines": { "node": "^14 || ^16 || >=18" }, @@ -767,10 +768,11 @@ } }, "node_modules/@dual-bundle/import-meta-resolve": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@dual-bundle/import-meta-resolve/-/import-meta-resolve-4.0.0.tgz", - "integrity": "sha512-ZKXyJeFAzcpKM2kk8ipoGIPUqx9BX52omTGnfwjJvxOCaZTM2wtDK7zN0aIgPRbT9XYAlha0HtmZ+XKteuh0Gw==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@dual-bundle/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", + "integrity": "sha512-+nxncfwHM5SgAtrVzgpzJOI1ol0PkumhVo469KCf9lUi21IGcY90G98VuHm9VRrUypmAzawAHO9bs6hqeADaVg==", "dev": true, + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -1346,10 +1348,11 @@ } }, "node_modules/@snyk/protect": { - "version": "1.1291.0", - "resolved": "https://registry.npmjs.org/@snyk/protect/-/protect-1.1291.0.tgz", - "integrity": "sha512-BRbgzSOSlzIBmhdEqM0y0q8uhYd2h+tfl3OuMH62JvQ+AI9lFV5Va99gl+wqS8GBBOohQmIh4HnuD25LMCdO7Q==", + "version": "1.1291.1", + "resolved": "https://registry.npmjs.org/@snyk/protect/-/protect-1.1291.1.tgz", + "integrity": "sha512-Xb9Q4KkZTGOm5BGDBQDnPOU8YmIDUmj9Ub6O1qsCfkGm8Jk+VU6pTl5nhDYS/zmA8n5xJYEYRKUVI9mUZG8Hbg==", "dev": true, + "license": "Apache-2.0", "bin": { "snyk-protect": "bin/snyk-protect" }, @@ -1473,11 +1476,6 @@ "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", "dev": true }, - "node_modules/@ungap/url-search-params": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@ungap/url-search-params/-/url-search-params-0.2.2.tgz", - "integrity": "sha512-qQsguKXZVKdCixOHX9jqnX/K/1HekPDpGKyEcXHT+zR6EjGA7S4boSuelL4uuPv6YfhN0n8c4UxW+v/Z3gM2iw==" - }, "node_modules/acorn": { "version": "8.11.2", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.2.tgz", @@ -1847,12 +1845,13 @@ } }, "node_modules/braces": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", - "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, + "license": "MIT", "dependencies": { - "fill-range": "^7.0.1" + "fill-range": "^7.1.1" }, "engines": { "node": ">=8" @@ -2818,15 +2817,19 @@ "dev": true }, "node_modules/eslint-plugin-promise": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz", - "integrity": "sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==", + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.2.0.tgz", + "integrity": "sha512-QmAqwizauvnKOlifxyDj2ObfULpHQawlg/zQdgEixur9vl0CvZGv/LCJV2rtj3210QCoeGBzVMfMXqGAOr/4fA==", "dev": true, + "license": "ISC", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, + "funding": { + "url": "https://opencollective.com/eslint" + }, "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" + "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0" } }, "node_modules/eslint-scope": { @@ -3109,10 +3112,11 @@ } }, "node_modules/fill-range": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", - "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, + "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" }, @@ -3148,10 +3152,11 @@ } }, "node_modules/flatted": { - "version": "3.2.9", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", - "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", - "dev": true + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true, + "license": "ISC" }, "node_modules/for-each": { "version": "0.3.3", @@ -3831,6 +3836,7 @@ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.12.0" } @@ -4789,10 +4795,11 @@ } }, "node_modules/known-css-properties": { - "version": "0.30.0", - "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.30.0.tgz", - "integrity": "sha512-VSWXYUnsPu9+WYKkfmJyLKtIvaRJi1kXUqVmBACORXZQxT5oZDsoZ2vQP+bQFDnWtpI/4eq3MLoRMjI2fnLzTQ==", - "dev": true + "version": "0.31.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.31.0.tgz", + "integrity": "sha512-sBPIUGTNF0czz0mwGGUoKKJC8Q7On1GPbCSFPfyEsfHb2DyBG0Y4QtV+EVWpINSaiGKZblDNuF5AezxSgOhesQ==", + "dev": true, + "license": "MIT" }, "node_modules/less": { "version": "4.2.0", @@ -5062,12 +5069,13 @@ } }, "node_modules/micromatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", - "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", + "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", "dev": true, + "license": "MIT", "dependencies": { - "braces": "^3.0.2", + "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { @@ -5453,10 +5461,11 @@ } }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", - "dev": true + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.1.tgz", + "integrity": "sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==", + "dev": true, + "license": "ISC" }, "node_modules/picomatch": { "version": "2.3.1", @@ -5562,10 +5571,11 @@ } }, "node_modules/postcss-selector-parser": { - "version": "6.0.16", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz", - "integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==", + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.0.tgz", + "integrity": "sha512-UMz42UD0UY0EApS0ZL9o1XnLhSTtvvvLe5Dc2H2O56fvRZi+KulDyf5ctDhhtYJBGKStV2FL1fy6253cmLgqVQ==", "dev": true, + "license": "MIT", "dependencies": { "cssesc": "^3.0.0", "util-deprecate": "^1.0.2" @@ -6161,16 +6171,27 @@ } }, "node_modules/stylelint": { - "version": "16.5.0", - "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.5.0.tgz", - "integrity": "sha512-IlCBtVrG+qTy3v+tZTk50W8BIomjY/RUuzdrDqdnlCYwVuzXtPbiGfxYqtyYAyOMcb+195zRsuHn6tgfPmFfbw==", + "version": "16.6.1", + "resolved": "https://registry.npmjs.org/stylelint/-/stylelint-16.6.1.tgz", + "integrity": "sha512-yNgz2PqWLkhH2hw6X9AweV9YvoafbAD5ZsFdKN9BvSDVwGvPh+AUIrn7lYwy1S7IHmtFin75LLfX1m0D2tHu8Q==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/stylelint" + }, + { + "type": "github", + "url": "https://github.com/sponsors/stylelint" + } + ], + "license": "MIT", "dependencies": { - "@csstools/css-parser-algorithms": "^2.6.1", - "@csstools/css-tokenizer": "^2.2.4", - "@csstools/media-query-list-parser": "^2.1.9", - "@csstools/selector-specificity": "^3.0.3", - "@dual-bundle/import-meta-resolve": "^4.0.0", + "@csstools/css-parser-algorithms": "^2.6.3", + "@csstools/css-tokenizer": "^2.3.1", + "@csstools/media-query-list-parser": "^2.1.11", + "@csstools/selector-specificity": "^3.1.1", + "@dual-bundle/import-meta-resolve": "^4.1.0", "balanced-match": "^2.0.0", "colord": "^2.9.3", "cosmiconfig": "^9.0.0", @@ -6179,7 +6200,7 @@ "debug": "^4.3.4", "fast-glob": "^3.3.2", "fastest-levenshtein": "^1.0.16", - "file-entry-cache": "^8.0.0", + "file-entry-cache": "^9.0.0", "global-modules": "^2.0.0", "globby": "^11.1.0", "globjoin": "^0.1.4", @@ -6187,16 +6208,16 @@ "ignore": "^5.3.1", "imurmurhash": "^0.1.4", "is-plain-object": "^5.0.0", - "known-css-properties": "^0.30.0", + "known-css-properties": "^0.31.0", "mathml-tag-names": "^2.1.3", "meow": "^13.2.0", - "micromatch": "^4.0.5", + "micromatch": "^4.0.7", "normalize-path": "^3.0.0", - "picocolors": "^1.0.0", + "picocolors": "^1.0.1", "postcss": "^8.4.38", "postcss-resolve-nested-selector": "^0.1.1", "postcss-safe-parser": "^7.0.0", - "postcss-selector-parser": "^6.0.16", + "postcss-selector-parser": "^6.1.0", "postcss-value-parser": "^4.2.0", "resolve-from": "^5.0.0", "string-width": "^4.2.3", @@ -6211,31 +6232,49 @@ }, "engines": { "node": ">=18.12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/stylelint" } }, "node_modules/stylelint-config-recommended": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-14.0.0.tgz", - "integrity": "sha512-jSkx290CglS8StmrLp2TxAppIajzIBZKYm3IxT89Kg6fGlxbPiTiyH9PS5YUuVAFwaJLl1ikiXX0QWjI0jmgZQ==", + "version": "14.0.1", + "resolved": "https://registry.npmjs.org/stylelint-config-recommended/-/stylelint-config-recommended-14.0.1.tgz", + "integrity": "sha512-bLvc1WOz/14aPImu/cufKAZYfXs/A/owZfSMZ4N+16WGXLoX5lOir53M6odBxvhgmgdxCVnNySJmZKx73T93cg==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/stylelint" + }, + { + "type": "github", + "url": "https://github.com/sponsors/stylelint" + } + ], + "license": "MIT", "engines": { "node": ">=18.12.0" }, "peerDependencies": { - "stylelint": "^16.0.0" + "stylelint": "^16.1.0" } }, "node_modules/stylelint-config-standard": { - "version": "36.0.0", - "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-36.0.0.tgz", - "integrity": "sha512-3Kjyq4d62bYFp/Aq8PMKDwlgUyPU4nacXsjDLWJdNPRUgpuxALu1KnlAHIj36cdtxViVhXexZij65yM0uNIHug==", + "version": "36.0.1", + "resolved": "https://registry.npmjs.org/stylelint-config-standard/-/stylelint-config-standard-36.0.1.tgz", + "integrity": "sha512-8aX8mTzJ6cuO8mmD5yon61CWuIM4UD8Q5aBcWKGSf6kg+EC3uhB+iOywpTK4ca6ZL7B49en8yanOFtUW0qNzyw==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/stylelint" + }, + { + "type": "github", + "url": "https://github.com/sponsors/stylelint" + } + ], + "license": "MIT", "dependencies": { - "stylelint-config-recommended": "^14.0.0" + "stylelint-config-recommended": "^14.0.1" }, "engines": { "node": ">=18.12.0" @@ -6249,6 +6288,7 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true, + "license": "MIT", "engines": { "node": ">=12" }, @@ -6260,31 +6300,34 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-2.0.0.tgz", "integrity": "sha512-1ugUSr8BHXRnK23KfuYS+gVMC3LB8QGH9W1iGtDPsNWoQbgtXSExkBu2aDR4epiGWZOjZsj6lDl/N/AqqTC3UA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/stylelint/node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-9.0.0.tgz", + "integrity": "sha512-6MgEugi8p2tiUhqO7GnPsmbCCzj0YRCwwaTbpGRyKZesjRSzkqkAE9fPp7V2yMs5hwfgbQLgdvSSkGNg1s5Uvw==", "dev": true, + "license": "MIT", "dependencies": { - "flat-cache": "^4.0.0" + "flat-cache": "^5.0.0" }, "engines": { - "node": ">=16.0.0" + "node": ">=18" } }, "node_modules/stylelint/node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-5.0.0.tgz", + "integrity": "sha512-JrqFmyUl2PnPi1OvLyTVHnQvwQ0S+e6lGSwu8OkAZlSaNIZciTY2H/cOOROxsBA1m/LZNHDsqAgDZt6akWcjsQ==", "dev": true, + "license": "MIT", "dependencies": { - "flatted": "^3.2.9", + "flatted": "^3.3.1", "keyv": "^4.5.4" }, "engines": { - "node": ">=16" + "node": ">=18" } }, "node_modules/stylelint/node_modules/resolve-from": { @@ -6292,6 +6335,7 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" } @@ -6301,6 +6345,7 @@ "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, + "license": "ISC", "engines": { "node": ">=14" }, @@ -6313,6 +6358,7 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^6.0.1" }, @@ -6328,6 +6374,7 @@ "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-5.0.1.tgz", "integrity": "sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==", "dev": true, + "license": "ISC", "dependencies": { "imurmurhash": "^0.1.4", "signal-exit": "^4.0.1" @@ -6457,6 +6504,7 @@ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, + "license": "MIT", "dependencies": { "is-number": "^7.0.0" }, diff --git a/package.json b/package.json index 0518b17d..6cb1742c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "netatmo", - "version": "2.0.0", + "version": "2.1.0", "description": "A module for the MagicMirror² to display information about your rooms climate from your Netatmo system.", "main": "netatmo.js", "scripts": { @@ -37,22 +37,19 @@ }, "homepage": "https://github.com/CFenner/MagicMirror-Netatmo-Module#readme", "devDependencies": { - "@snyk/protect": "1.1291.0", + "@snyk/protect": "1.1291.1", "dotenv": "16.3.1", "eslint": "8.57.0", "eslint-config-standard": "17.1.0", "eslint-plugin-import": "2.29.1", "eslint-plugin-n": "16.6.2", - "eslint-plugin-promise": "6.1.1", + "eslint-plugin-promise": "6.2.0", "jest": "29.7.0", "jsonlint-newline-fork": "1.6.8", "less": "4.2.0", "markdownlint": "0.32.1", - "stylelint": "16.5.0", - "stylelint-config-standard": "36.0.0" + "stylelint": "16.6.1", + "stylelint-config-standard": "36.0.1" }, - "snyk": true, - "dependencies": { - "@ungap/url-search-params": "0.2.2" - } + "snyk": true }