Skip to content

Commit 5faf954

Browse files
committed
Merge branch 'release/1.0.5'
2 parents a988c0e + da18097 commit 5faf954

14 files changed

+809
-736
lines changed

README.md

+6-678
Large diffs are not rendered by default.

VERSION

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
1.0.2
1+
1.0.5

bin/src/meross renamed to bin/meross

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
'use strict'
44

5-
const {version} = require('./package.json')
5+
const {version} = require('../package.json')
66
const program = require('commander')
77

88
program

bin/src/meross-info renamed to bin/meross-info

+10-4
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
'use strict'
44

5-
const {version} = require('./package.json')
5+
const {version} = require('../package.json')
66
const program = require('commander')
77
const util = require('util')
88

9-
const API = require('./api')
9+
const API = require('../lib/api')
1010

1111
const collection = (value, store = []) => {
1212
store.push(value)
@@ -20,6 +20,7 @@ program
2020
.arguments('<options>')
2121
.option('-g, --gateway <gateway>', 'Set the gateway address')
2222
.option('-k, --key <shared-key>', 'Shared key for generating signatures', '')
23+
.option('--include-wifi', 'Ask device for Nearby WIFI AP list')
2324
.option('-v, --verbose', 'Show debugging messages', '')
2425

2526
program.parse(process.argv)
@@ -33,9 +34,14 @@ if (!program.gateway) {
3334
(async () => {
3435
const gateway = program.gateway
3536
const key = program.key
37+
const includeWifiList = program.includeWifi
3638
const verbose = program.verbose
3739
const api = new API(gateway, key, null, verbose)
38-
40+
3941
console.log(`Getting info about device with IP ${gateway}`)
40-
api.deviceInformation()
42+
await api.deviceInformation()
43+
44+
if (includeWifiList) {
45+
await api.deviceWifiList()
46+
}
4147
})()

bin/src/meross-setup renamed to bin/meross-setup

+2-2
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22

33
'use strict'
44

5-
const {version} = require('./package.json')
5+
const {version} = require('../package.json')
66
const program = require('commander')
77
const util = require('util')
88

9-
const API = require('./api')
9+
const API = require('../lib/api')
1010

1111
const collection = (value, store = []) => {
1212
store.push(value)

bin/src/README.md

-8
This file was deleted.

bin/src/api.js renamed to lib/api.js

+100-39
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ const cleanServerUrl = (server) => {
2424
const serverRegex = /((([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])|(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])):(?:6553[0-5]|655[0-2][0-9]|65[0-4][0-9]{2}|6[0-4][0-9]{3}|[1-5][0-9]{4}|[1-9][0-9]{1,3}|[0-9])$/
2525

2626
const base64Encode = str => Buffer.from(str).toString('base64')
27+
const base64Decode = str => Buffer.from(str, 'base64').toString('utf8')
2728

2829
const tableOptions = {
2930
hasBorder: true,
@@ -34,11 +35,24 @@ const tableOptions = {
3435
firstColumnTextAttr: { color: 'yellow' }
3536
}
3637

38+
const percentToColor = percent => percent > .7 ? '^G' : (percent > .5 ? '^Y' : (percent > .30 ? '^y' : '^r'))
39+
40+
const bar = (percent, width) => {
41+
const partials = ['▏', '▎', '▍', '▌', '▋', '▊', '▉']
42+
let ticks = percent * width
43+
if (ticks < 0) {
44+
ticks = 0
45+
}
46+
let filled = Math.floor(ticks)
47+
let open = bar.width - filled - 1
48+
return (percentToColor(percent) + '▉').repeat(filled) + partials[Math.floor((ticks - filled) * partials.length)] + ' '.repeat(open)
49+
}
50+
3751
function logRequest(request) {
3852
let url = new URL(request.url);
3953
console.log(`> ${request.method.toUpperCase()} ${url.path}`)
4054
console.log(`> Host: ${url.host}`)
41-
55+
4256
let headers = {}
4357
headers = Object.assign(headers, request.headers.common);
4458
headers = Object.assign(headers, request.headers[request.method]);
@@ -50,9 +64,10 @@ function logRequest(request) {
5064
for (let [header, value] of Object.entries(headers)) {
5165
console.log(`> ${header}: ${value}`)
5266
}
53-
67+
5468
console.log('>')
5569
console.log(util.inspect(request.data, {showHidden: false, depth: null}))
70+
console.log('')
5671
}
5772

5873
function logResponse(response) {
@@ -62,6 +77,7 @@ function logResponse(response) {
6277
}
6378
console.log('<')
6479
console.log(util.inspect(response.data, {showHidden: false, depth: null}))
80+
console.log('')
6581
}
6682

6783
function handleRequestError(error, verbose)
@@ -84,14 +100,15 @@ module.exports = class API {
84100
this.host = host
85101
this.key = key
86102
this.userId = userId
87-
103+
this.verbose = verbose
104+
88105
axios.interceptors.request.use(request => {
89106
if (verbose) {
90107
logRequest(request)
91108
}
92109
return request
93110
})
94-
111+
95112
axios.interceptors.response.use(response => {
96113
if (verbose) {
97114
logResponse(response)
@@ -131,33 +148,33 @@ module.exports = class API {
131148
},
132149
}
133150
)
134-
151+
135152
const data = response.data;
136-
153+
137154
if ('error' in data.payload) {
138155
let {code, message} = data.payload.error;
139-
156+
140157
switch (code) {
141158
case 5001:
142159
console.error('Incorrect shared key provided.')
143160
break;
144161
}
145-
162+
146163
return
147164
}
148-
165+
149166
const system = data.payload.all.system
150167
const digest = data.payload.all.digest
151168
const hw = system.hardware
152169
const fw = system.firmware
153-
170+
154171
let rows = [
155172
['Device', `${hw.type} ${hw.subType} ${hw.chipType} (hardware:${hw.version} firmware:${fw.version})`],
156173
['UUID', hw.uuid],
157174
['Mac address', hw.macAddress],
158175
['WIFI', `${fw.innerIp} (${fw.wifiMac})`],
159176
];
160-
177+
161178
if (fw.server) {
162179
rows.push(
163180
['MQTT broker', `${fw.server}:${fw.port}`],
@@ -168,37 +185,81 @@ module.exports = class API {
168185
['Status', `^BConfiguration`]
169186
)
170187
}
171-
188+
172189
rows.push(
173190
['Credentials', `User: ^C${fw.userId}\nPassword: ^C${this.calculateDevicePassword(hw.macAddress, fw.userId)}`]
174191
)
175-
176-
if (digest.togglex) {
177-
let row = ['Switch state']
178-
let col = []
179-
for (let sw of digest.togglex) {
180-
let ch = [];
181-
if (digest.togglex.length > 1) {
182-
ch.push(`Channel ${sw.channel}:`);
183-
}
184-
ch.push(sw.onoff == 0 ? '^ROff' : '^GOn')
185-
186-
const switchUpdateDate = new Date();
187-
switchUpdateDate.setTime(sw.lmTime * 1000) // put time into ms not seconds
188-
ch.push(`(${new Intl.DateTimeFormat(process.env.LC_TIME, { dateStyle: 'full', timeStyle: 'long' }).format(switchUpdateDate)})`)
189-
190-
col.push(ch.join('^ '))
192+
193+
term.table(
194+
rows,
195+
tableOptions
196+
)
197+
} catch (error) {
198+
handleRequestError(error, this.verbose)
199+
}
200+
}
201+
202+
async deviceWifiList() {
203+
const packet = this.signPacket({
204+
'header': {
205+
'method': 'GET',
206+
'namespace': 'Appliance.Config.WifiList'
207+
},
208+
'payload': {}
209+
})
210+
211+
try {
212+
let spinner = await term.spinner({animation:'dotSpinner', rightPadding: ' '})
213+
term('Getting WIFI list…\n')
214+
215+
const response = await axios.post(
216+
`http://${this.host}/config`,
217+
packet,
218+
{
219+
headers: {
220+
'Content-Type': 'application/json'
221+
},
222+
}
223+
)
224+
225+
226+
spinner.animate(false)
227+
228+
const data = response.data;
229+
230+
if ('error' in data.payload) {
231+
let {code, message} = data.payload.error;
232+
233+
switch (code) {
234+
case 5001:
235+
console.error('Incorrect shared key provided.')
236+
break;
191237
}
192-
row.push(col.join("\n"));
193-
rows.push(row)
238+
239+
return
194240
}
195-
241+
242+
const wifiList = data.payload.wifiList
243+
244+
let rows = [
245+
['SSID', 'Signal strength'],
246+
];
247+
248+
for (const ap of wifiList) {
249+
const decodedSsid = base64Decode(ap.ssid);
250+
rows.push([decodedSsid ? decodedSsid : `<hidden ${ap.bssid}>`, bar((ap.signal / 100), 20)])
251+
}
252+
253+
let thisTableOptions = tableOptions
254+
thisTableOptions.firstColumnTextAttr = { color: 'cyan' }
255+
thisTableOptions.firstRowTextAttr = { color: 'yellow' }
256+
196257
term.table(
197258
rows,
198259
tableOptions
199260
)
200261
} catch (error) {
201-
handleRequestError(error)
262+
handleRequestError(error, this.verbose)
202263
}
203264
}
204265

@@ -212,12 +273,12 @@ module.exports = class API {
212273
port: url.port
213274
}
214275
})
215-
276+
216277
// make sure we set a failover server
217278
if (servers.length == 1) {
218279
servers.push(servers[0]);
219280
}
220-
281+
221282
term.table(
222283
[
223284
['Primary MQTT broker', `${servers[0].host}:${servers[0].port}`],
@@ -260,14 +321,14 @@ module.exports = class API {
260321
}
261322
)
262323
} catch (error) {
263-
handleRequestError(error)
324+
handleRequestError(error, this.verbose)
264325
}
265326
}
266327

267328
async configureWifiCredentials(credentials) {
268329
const ssid = base64Encode(credentials.ssid)
269330
const password = base64Encode(credentials.password)
270-
331+
271332
const packet = this.signPacket({
272333
'header': {
273334
'method': 'SET',
@@ -280,7 +341,7 @@ module.exports = class API {
280341
}
281342
}
282343
})
283-
344+
284345
term.table(
285346
[
286347
['Encoded WIFI SSID', `${ssid}`],
@@ -300,10 +361,10 @@ module.exports = class API {
300361
}
301362
)
302363
} catch (error) {
303-
handleRequestError(error)
364+
handleRequestError(error, this.verbose)
304365
}
305366
}
306-
367+
307368
calculateDevicePassword(macAddress, user = null) {
308369
return `${user}_${md5(macAddress + this.key)}`
309370
}

bin/src/package.json renamed to package.json

+11-3
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,21 @@
11
{
22
"name": "meross",
3-
"version": "1.0.4",
3+
"version": "1.0.5",
44
"description": "Utility to configure Meross devices for local MQTT",
5-
"main": "index.js",
5+
"keywords": [
6+
"smarthome",
7+
"mqtt",
8+
"meross",
9+
"cli"
10+
],
11+
"bin": {
12+
"meross": "./bin/meross"
13+
},
614
"scripts": {
715
"test": "echo \"Error: no test specified\" && exit 1"
816
},
917
"author": "Rob Griffiths <[email protected]>",
10-
"repository": "https://github.com/bytespider/Meross/tree/master/bin/src",
18+
"repository": "https://github.com/bytespider/Meross/tree/master",
1119
"license": "ISC",
1220
"dependencies": {
1321
"axios": "^0.21.1",
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)