Skip to content

Commit

Permalink
Merge branch 'main' into auth
Browse files Browse the repository at this point in the history
  • Loading branch information
CFenner committed Aug 14, 2023
2 parents 507d82b + 7250c6f commit a382dc8
Show file tree
Hide file tree
Showing 3 changed files with 176 additions and 6,984 deletions.
165 changes: 165 additions & 0 deletions node_helper_impl.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
/* Magic Mirror
* Module: MagicMirror-Netatmo-Module
*
* By Christopher Fenner https://github.com/CFenner
* MIT Licensed.
*/
const fs = require('fs')
const path = require('path')
const https = require('https')
const URLSearchParams = require('@ungap/url-search-params')

module.exports = {
notifications: {
AUTH: 'NETATMO_AUTH',
AUTH_RESPONSE: 'NETATMO_AUTH_RESPONSE',
DATA: 'NETATMO_DATA',
DATA_RESPONSE: 'NETATMO_DATA_RESPONSE',
},
start: function () {
console.log('Netatmo helper started ...')
this.token = null
this.token_time = null
},
authenticate: function (config) {
const self = this
self.config = config

// TODO: only update if token is invalid

const req = https.request({
hostname: self.config.apiBase,
path: self.config.authEndpoint,
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
}, self.callbackAuthenticate.bind(self))

req.on('error', function (e) {
console.log('There is a problem with your request:', e.message)
self.sendSocketNotification(self.notifications.AUTH_RESPONSE, {
// instanceID: self.config.instanceID,
payloadReturn: e.message,
})
})

req.write(new URLSearchParams({
scope: 'read_station',
grant_type: 'password',
username: self.config.username,
password: self.config.password,
client_id: self.config.clientId,
client_secret: self.config.clientSecret,
}).toString())

req.end()
},
loadData: function (config) {
const self = this
self.config = config
if (self.config.mockData === true) {
self.sendSocketNotification(self.notifications.DATA_RESPONSE, {
payloadReturn: this.mockData(),
status: 'OK',
})
return
}
if (self.token === null) {
self.sendSocketNotification(self.notifications.DATA_RESPONSE, {
payloadReturn: 400,
status: 'INVALID_TOKEN',
message: 'token not set',
})
return
}

const req = https.request({
hostname: self.config.apiBase,
path: self.config.dataEndpoint,
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${self.token}`,
},
}, self.callbackData.bind(self))

req.on('error', function (e) {
console.log('There is a problem with your request:', e.message)
self.sendSocketNotification(self.notifications.DATA_RESPONSE, {
payloadReturn: e.message,
status: 'NOTOK',
message: e.message,
})
})
req.end()
},
mockData: function () {
const sample = fs.readFileSync(path.join(__dirname, 'sample', 'sample.json'), 'utf8')
return JSON.parse(sample)
},
callbackAuthenticate: function (response) {
const self = this
let result = ''

response.on('error', function (e) { console.log('error', e) })
response.on('data', function (chunk) { result += chunk })
response.on('end', function () {
result = JSON.parse(result)
if (response.statusCode === 200) {
console.log('UPDATING TOKEN ' + result.access_token)
self.token = result.access_token
self.token_time = new Date()
// we got a new token, save it to main file to allow it to request the datas
self.sendSocketNotification(self.notifications.AUTH_RESPONSE, {
status: 'OK',
})
} else {
console.log('status code:', response.statusCode, '\n', result)
self.sendSocketNotification(self.notifications.AUTH_RESPONSE, {
// instanceID: self.config.instanceID,
payloadReturn: response.statusCode,
status: 'NOTOK',
message: result,
})
}
})
},
callbackData: function (response) {
const self = this
let result = ''

response.on('error', function (e) { console.log('error', e) })
response.on('data', function (chunk) { result += chunk })
response.on('end', function () {
result = JSON.parse(result)
if (response.statusCode === 200) {
self.sendSocketNotification(self.notifications.DATA_RESPONSE, {
payloadReturn: result.body.devices,
status: 'OK',
})
} else if (response.statusCode === 403) {
console.log('status code:', response.statusCode, '\n', result)
self.sendSocketNotification(self.notifications.DATA_RESPONSE, {
payloadReturn: response.statusCode,
status: 'INVALID_TOKEN',
message: result,
})
} else {
console.log('status code:', response.statusCode, '\n', result)
self.sendSocketNotification(self.notifications.DATA_RESPONSE, {
payloadReturn: response.statusCode,
status: 'NOTOK',
message: result,
})
}
})
},
socketNotificationReceived: function (notification, payload) {
switch (notification) {
case this.notifications.AUTH:
this.authenticate(payload)
break
case this.notifications.DATA:
this.loadData(payload)
break
}
},
}
11 changes: 11 additions & 0 deletions node_helper_impl.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const moduleName = 'node_helper_impl'
const moduleUnderTest = require('./' + moduleName + '.js')

describe(moduleName, () => {
test('test notifications map', () => {
expect(moduleUnderTest.notifications).toHaveProperty('AUTH', 'NETATMO_AUTH')
expect(moduleUnderTest.notifications).toHaveProperty('AUTH_RESPONSE', 'NETATMO_AUTH_RESPONSE')
expect(moduleUnderTest.notifications).toHaveProperty('DATA', 'NETATMO_DATA')
expect(moduleUnderTest.notifications).toHaveProperty('DATA_RESPONSE', 'NETATMO_DATA_RESPONSE')
})
})
Loading

0 comments on commit a382dc8

Please sign in to comment.