iobroker.sonoff 3.0.3 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/datapoints.js CHANGED
@@ -6,6 +6,7 @@ module.exports = {
6
6
  A2: {type: 'number', role: 'value', read: true, write: false},
7
7
  A3: {type: 'number', role: 'value', read: true, write: false},
8
8
  ANALOG: {type: 'object', role: 'state', read: true, write: false},
9
+ Ap: {type: 'number', role: 'value', read: true, write: false},
9
10
  APMac: {type: 'number', role: 'state', read: true, write: false},
10
11
  Action: {type: 'string', role: 'value', read: true, write: true},
11
12
  AirQuality: {type: 'number', role: 'value', read: true, write: false, unit: '%'},
@@ -53,7 +54,7 @@ module.exports = {
53
54
  Green: {type: 'number', role: 'level.color.green', read: true, write: true, min: 0, max: 100},
54
55
  HSBColor: {type: 'string', role: 'value.hsb', read: true, write: true},
55
56
  Hostname: {type: 'string', role: 'state', read: true, write: false},
56
- Hue: {type: 'number', role: 'level.color.hue', read: true, write: true, min: 0}, // max ??
57
+ Hue: {type: 'number', role: 'level.color.hue', read: true, write: true, min: 0, max: 360},
57
58
  Humidity: {type: 'number', role: 'value.humidity', read: true, write: false, unit: '%'},
58
59
  IPAddress: {type: 'string', role: 'state', read: true, write: false},
59
60
  IPaddress: {type: 'string', role: 'state', read: true, write: false},
@@ -68,12 +69,28 @@ module.exports = {
68
69
  Leistung: {type: 'number', role: 'value.power.consumption', read: true, write: false, unit: 'W'},
69
70
  Light: {type: 'number', role: 'value', read: true, write: false, unit: 'lx'},
70
71
  Longitude: {type: 'number', role: 'value.gps.longitude', read: true, write: false, unit: '°'},
71
- Mode: {type: 'number', role: 'value', read: true, write: true},
72
+ Mode: {type: 'string', role: 'state', read: true, write: true},
72
73
  Module: {type: 'string', role: 'state', read: true, write: false},
73
74
  Noise: {type: 'number', role: 'value', read: true, write: false, unit: 'dB'},
74
75
  Output: {type: 'number', role: 'value', read: true, write: true},
75
76
  Outsidetemp: {type: 'number', role: 'value.temperature', read: true, write: false, unit: '°C'},
76
77
  PM10: {type: 'number', role: 'value', read: true, write: false, unit: 'ug/m3'},
78
+ PWM1: {type: 'number', role: 'value', read: true, write: true, min: 0, max: 1023},
79
+ PWM2: {type: 'number', role: 'value', read: true, write: true, min: 0, max: 1023},
80
+ PWM3: {type: 'number', role: 'value', read: true, write: true, min: 0, max: 1023},
81
+ PWM4: {type: 'number', role: 'value', read: true, write: true, min: 0, max: 1023},
82
+ PWM5: {type: 'number', role: 'value', read: true, write: true, min: 0, max: 1023},
83
+ PWM6: {type: 'number', role: 'value', read: true, write: true, min: 0, max: 1023},
84
+ PWM7: {type: 'number', role: 'value', read: true, write: true, min: 0, max: 1023},
85
+ PWM8: {type: 'number', role: 'value', read: true, write: true, min: 0, max: 1023},
86
+ PWM9: {type: 'number', role: 'value', read: true, write: true, min: 0, max: 1023},
87
+ PWM10: {type: 'number', role: 'value', read: true, write: true, min: 0, max: 1023},
88
+ PWM11: {type: 'number', role: 'value', read: true, write: true, min: 0, max: 1023},
89
+ PWM12: {type: 'number', role: 'value', read: true, write: true, min: 0, max: 1023},
90
+ PWM13: {type: 'number', role: 'value', read: true, write: true, min: 0, max: 1023},
91
+ PWM14: {type: 'number', role: 'value', read: true, write: true, min: 0, max: 1023},
92
+ PWM15: {type: 'number', role: 'value', read: true, write: true, min: 0, max: 1023},
93
+ PWM16: {type: 'number', role: 'value', read: true, write: true, min: 0, max: 1023},
77
94
  POWER10: {type: 'boolean', role: 'switch', read: true, write: true, storeMap: true},
78
95
  POWER11: {type: 'boolean', role: 'switch', read: true, write: true, storeMap: true},
79
96
  POWER12: {type: 'boolean', role: 'switch', read: true, write: true, storeMap: true},
@@ -123,7 +140,7 @@ module.exports = {
123
140
  SHUTTER3: {type: 'number', role: 'state', read: true, write: false},
124
141
  SHUTTER4: {type: 'number', role: 'state', read: true, write: false},
125
142
  SSId: {type: 'string', role: 'state', read: true, write: false},
126
- Saturation: {type: 'number', role: 'level.color.saturation', read: true, write: true, min: 0}, // max: 100 ??
143
+ Saturation: {type: 'number', role: 'level.color.saturation', read: true, write: true, min: 0, max: 255},
127
144
  Scheme: {type: 'number', role: 'value', read: true, write: true},
128
145
  SeaPressure: {type: 'number', role: 'value.pressure', read: true, write: false, unit: 'hPa'},
129
146
  SleepMode: {type: 'string', role: 'state', read: true, write: false},
@@ -176,7 +193,6 @@ module.exports = {
176
193
  WW_POWER: {type: 'boolean', role: 'switch.light', read: true, write: true, storeMap: true},
177
194
  Wakeup: {type: 'string', role: 'state', read: true, write: true},
178
195
  Warmwater: {type: 'number', role: 'value.temperature', read: true, write: false, unit: '°C'},
179
- Wifi_SSId: {type: 'string', role: 'state', read: true, write: true},
180
196
  Window: {type: 'number', role: 'value', read: true, write: true},
181
197
  Yesterday: {type: 'number', role: 'value.power.consumption', read: true, write: false, unit: 'kWh'},
182
198
  eCO2: {type: 'number', role: 'value.eco2', read: true, write: false, unit: 'ppm'},
package/lib/server.js CHANGED
@@ -218,7 +218,7 @@ function MQTTServer(adapter) {
218
218
  }
219
219
 
220
220
  function _setState(id, val, callback) {
221
- adapter.log.debug(`Set State after task: ${id}`);
221
+ adapter.log.debug(`Set state after task: ${id}`);
222
222
  adapter.setForeignState(id, val, true, callback);
223
223
  }
224
224
 
@@ -236,7 +236,7 @@ function MQTTServer(adapter) {
236
236
  if (callback) {
237
237
  taskCallbacks.push(callback);
238
238
  }
239
- adapter.log.debug(`updateState ${task.id} - ${tasks.length}`);
239
+ adapter.log.debug(`Update state ${task.id} - ${tasks.length}`);
240
240
  if (tasks.length === 1) {
241
241
  processTasks();
242
242
  }
@@ -276,9 +276,9 @@ function MQTTServer(adapter) {
276
276
  // set white to rgb or rgbww
277
277
  adapter.getObject(id, (err, obj) => {
278
278
  if (!obj) {
279
- adapter.log.warn(`invalid rgbww obj for ${id}`);
279
+ adapter.log.warn(`Invalid rgbww obj for ${id}`);
280
280
  } else if (typeof state.val !== 'string') {
281
- adapter.log.warn(`invalid rgbww state value for ${id} : ${JSON.stringify(state.val)} needs to be a string`);
281
+ adapter.log.warn(`Invalid rgbww state value for ${id} : ${JSON.stringify(state.val)} needs to be a string`);
282
282
  } else {
283
283
  const role = obj.common.role;
284
284
  let color;
@@ -380,7 +380,7 @@ function MQTTServer(adapter) {
380
380
  const idAlive = `${deviceDesc}.Color`;
381
381
  adapter.getForeignState(idAlive, (err, state) => {
382
382
  if (!state || typeof state.val !== 'string') {
383
- adapter.log.info(`invalid state Color for ${idAlive}, correcting value to #000000`);
383
+ adapter.log.info(`Invalid state color for ${idAlive}, correcting value to #000000`);
384
384
  adapter.setState(idAlive, '#000000', false);
385
385
  return;
386
386
  }
@@ -475,7 +475,7 @@ function MQTTServer(adapter) {
475
475
  adapter.getForeignObject(idAlive, (err, obj) => {
476
476
  if (!obj) {
477
477
  // no color object
478
- adapter.log.warn(`unknown object: ${id}: ${state}`);
478
+ adapter.log.warn(`Unknown object: ${id}: ${state}`);
479
479
  } else {
480
480
  const role = obj.common.role;
481
481
  //if (role='level.color.rgb') return;
@@ -492,7 +492,7 @@ function MQTTServer(adapter) {
492
492
  const idAlive = `${deviceDesc}.Color`;
493
493
  adapter.getForeignState(idAlive, (err, state) => {
494
494
  if (!state) {
495
- adapter.log.warn('ill state Color');
495
+ adapter.log.warn('ill state color');
496
496
  return;
497
497
  }
498
498
  const color = state.val.substring(1);
@@ -527,7 +527,7 @@ function MQTTServer(adapter) {
527
527
  const idAlive = `${deviceDesc}.Color`;
528
528
  adapter.getForeignState(idAlive, (err, state) => {
529
529
  if (!state) {
530
- adapter.log.warn('ill state Color');
530
+ adapter.log.warn('ill state color');
531
531
  return;
532
532
  }
533
533
  const color = state.val.substring(1);
@@ -608,7 +608,7 @@ function MQTTServer(adapter) {
608
608
  // other objects
609
609
  adapter.getObject(id, (err, obj) => {
610
610
  if (!obj) {
611
- adapter.log.warn(`invalid obj ${id}`);
611
+ adapter.log.warn(`Invalid object ${id}`);
612
612
  } else {
613
613
  const type = obj.common.type;
614
614
  switch (type) {
@@ -675,11 +675,15 @@ function MQTTServer(adapter) {
675
675
  cacheAddedObjects[task.id] = true;
676
676
  adapter.getForeignObject(task.id, (err, obj) => {
677
677
  if (!obj || !obj.common) {
678
+ if (task.data.common.storeMap) {
679
+ task.data = JSON.parse(JSON.stringify(task.data)); // copy
680
+ delete task.data.common.storeMap;
681
+ }
678
682
  adapter.setForeignObject(task.id, task.data, (err) => {
679
683
  if (err) {
680
- adapter.log.warn(`New Object creation error: ${err.message}`)
684
+ adapter.log.warn(`New object creation error: ${err.message}`)
681
685
  } else {
682
- adapter.log.info(`new object created: ${task.id}`);
686
+ adapter.log.info(`New object created: ${task.id}`);
683
687
  }
684
688
  if (task.cb) {
685
689
  task.cb(task.id, task.cbArg, () => {
@@ -691,8 +695,12 @@ function MQTTServer(adapter) {
691
695
  setImmediate(processTasks);
692
696
  }
693
697
  });
694
- } else if (obj.common.type !== task.data.common.type) {
695
- adapter.extendObject(task.id, {common: {type: task.data.common.type}}, err => {
698
+ } else if (obj.common.type !== task.data.common.type || obj.common.storeMap !== undefined) {
699
+ obj.common.type = task.data.common.type;
700
+ if (obj.common.storeMap !== undefined) {
701
+ delete obj.common.storeMap;
702
+ }
703
+ adapter.setForeignObject(task.id, obj, err => {
696
704
  if (err) {
697
705
  adapter.log.warn(`Object update error: ${err.message}`)
698
706
  } else {
@@ -848,12 +856,12 @@ function MQTTServer(adapter) {
848
856
  try {
849
857
  messages[i].ts = Date.now();
850
858
  messages[i].count++;
851
- adapter.log.debug(`Client [${client.id}] Resend messages on connect: ${messages[i].topic} = ${messages[i].payload}`);
859
+ adapter.log.debug(`Client [${client.id}] resend messages on connect: ${messages[i].topic} = ${messages[i].payload}`);
852
860
  if (messages[i].cmd === 'publish') {
853
861
  client.publish(messages[i]);
854
862
  }
855
863
  } catch (e) {
856
- adapter.log.warn(`Client [${client.id}] Cannot resend message: ${e}`);
864
+ adapter.log.warn(`Client [${client.id}] cannot resend message: ${e}`);
857
865
  }
858
866
 
859
867
  if (adapter.config.sendInterval) {
@@ -1128,7 +1136,7 @@ function MQTTServer(adapter) {
1128
1136
  updateState(obj, val);
1129
1137
 
1130
1138
  if (powerStateFound) {
1131
- adapter.log.debug(`Got .STATE.POWER value message -> auto add .POWER object from ${obj.id}`);
1139
+ adapter.log.debug(`Got .STATE.POWER value message ==> auto add .POWER object from ${obj.id}`);
1132
1140
  let powerId = obj.id.replace('.STATE.POWER', '.POWER');
1133
1141
  let powerName = obj.data.common.name.replace(' STATE POWER', ' POWER');
1134
1142
  let powerObj = Object.assign({}, obj);
@@ -1162,7 +1170,7 @@ function MQTTServer(adapter) {
1162
1170
  }
1163
1171
 
1164
1172
  let val = packet.payload.toString('utf8');
1165
- adapter.log.debug(`[${client.id}] Received: ${packet.topic} = ${val}`);
1173
+ adapter.log.debug(`Client [${client.id}] received: ${packet.topic} = ${val}`);
1166
1174
 
1167
1175
  /*
1168
1176
  adapter.getForeignState('system.adapter.sonoff.0.memRss', (err, state) => {
@@ -1238,7 +1246,7 @@ function MQTTServer(adapter) {
1238
1246
  checkData(client, packet.topic, NO_PREFIX, JSON.parse(val));
1239
1247
  }
1240
1248
  } catch (e) {
1241
- adapter.log.warn(`Cannot parse data "${stateId}": _${val}_ - ${e}`);
1249
+ adapter.log.warn(`Client [${client.id}] cannot parse data "${stateId}": _${val}_ - ${e}`);
1242
1250
  }
1243
1251
  }
1244
1252
  return;
@@ -1265,7 +1273,7 @@ function MQTTServer(adapter) {
1265
1273
  //adapter.log.warn('log sensor parse"' + stateId + '": _' + val);
1266
1274
  }
1267
1275
  } catch (e) {
1268
- adapter.log.warn(`Cannot parse data "${stateId}": _${val}_ - ${e}`);
1276
+ adapter.log.warn(`Client [${client.id}] cannot parse data"${stateId}": _${val}_ - ${e}`);
1269
1277
  }
1270
1278
  } else if (parts[0] === 'tele' && stateId.match(/^INFO\d?$/)) {
1271
1279
  // tele/SonoffPOW/INFO1 = {"Module":"Sonoff Pow", "Version":"5.8.0", "FallbackTopic":"SonoffPOW", "GroupTopic":"sonoffs"}
@@ -1274,14 +1282,14 @@ function MQTTServer(adapter) {
1274
1282
  try {
1275
1283
  checkData(client, packet.topic, 'INFO', JSON.parse(val));
1276
1284
  } catch (e) {
1277
- adapter.log.warn(`Cannot parse data"${stateId}": _${val}_ - ${e}`);
1285
+ adapter.log.warn(`Client [${client.id}] cannot parse data"${stateId}": _${val}_ - ${e}`);
1278
1286
  }
1279
1287
  } else if (parts[0] === 'tele' && stateId.match(/^(ENERGY)\d?$/)) {
1280
1288
  // tele/sonoff_4ch/ENERGY = {"Time":"2017-10-02T19:24:32", "Total":1.753, "Yesterday":0.308, "Today":0.205, "Period":0, "Power":3, "Factor":0.12, "Voltage":221, "Current":0.097}
1281
1289
  try {
1282
1290
  checkData(client, packet.topic, 'ENERGY', JSON.parse(val));
1283
1291
  } catch (e) {
1284
- adapter.log.warn(`Cannot parse data"${stateId}": _${val}_ - ${e}`);
1292
+ adapter.log.warn(`Client [${client.id}] cannot parse data"${stateId}": _${val}_ - ${e}`);
1285
1293
  }
1286
1294
  } else if (types[stateId]) {
1287
1295
  // /ESP_BOX/BM280/Pressure = 1010.09
@@ -1372,7 +1380,7 @@ function MQTTServer(adapter) {
1372
1380
  client.destroy();
1373
1381
  }
1374
1382
  } catch (e) {
1375
- adapter.log.warn(`Client [${client.id}] Cannot close client: ${e}`);
1383
+ adapter.log.warn(`Client [${client.id}] cannot close client: ${e}`);
1376
1384
  }
1377
1385
  }
1378
1386
 
@@ -1385,7 +1393,7 @@ function MQTTServer(adapter) {
1385
1393
  const message = clients[clientId]._messages[m];
1386
1394
  if (now - message.ts >= adapter.config.retransmitInterval) {
1387
1395
  if (message.count > adapter.config.retransmitCount) {
1388
- adapter.log.warn(`Client [${clientId}] Message ${message.messageId} deleted after ${message.count} retries`);
1396
+ adapter.log.warn(`Client [${clientId}] message ${message.messageId} deleted after ${message.count} retries`);
1389
1397
  clients[clientId]._messages.splice(m, 1);
1390
1398
  continue;
1391
1399
  }
@@ -1394,12 +1402,12 @@ function MQTTServer(adapter) {
1394
1402
  message.count++;
1395
1403
  message.ts = now;
1396
1404
  try {
1397
- adapter.log.debug(`Client [${clientId}] Resend message topic: ${message.topic}, payload: ${message.payload}`);
1405
+ adapter.log.debug(`Client [${clientId}] resend message topic: ${message.topic}, payload: ${message.payload}`);
1398
1406
  if (message.cmd === 'publish') {
1399
1407
  clients[clientId].publish(message);
1400
1408
  }
1401
1409
  } catch (e) {
1402
- adapter.log.warn(`Client [${clientId}] Cannot publish message: ${e}`);
1410
+ adapter.log.warn(`Client [${clientId}] cannot publish message: ${e}`);
1403
1411
  }
1404
1412
 
1405
1413
  if (adapter.config.sendInterval) {
@@ -1470,7 +1478,7 @@ function MQTTServer(adapter) {
1470
1478
  }
1471
1479
 
1472
1480
  if (oldClient) {
1473
- adapter.log.info(`Client [${client.id}] reconnected. Old secret ${clients[client.id].__secret}. New secret ${client.__secret}`);
1481
+ adapter.log.info(`Client [${client.id}] reconnected. Old secret ${clients[client.id].__secret} ==> New secret ${client.__secret}`);
1474
1482
  // need to destroy the old client
1475
1483
 
1476
1484
  if (client.__secret !== clients[client.id].__secret) {
@@ -1556,7 +1564,7 @@ function MQTTServer(adapter) {
1556
1564
  const pack = client._messages && client._messages.find(e => e.messageId === packet.messageId);
1557
1565
  if (pack) {
1558
1566
  // duplicate message => ignore
1559
- adapter.log.warn(`Client [${client.id}] Ignored duplicate message with ID: ${packet.messageId}`);
1567
+ adapter.log.warn(`Client [${client.id}] ignored duplicate message with ID: ${packet.messageId}`);
1560
1568
  return;
1561
1569
  } else {
1562
1570
  packet.ts = Date.now();
@@ -1595,7 +1603,7 @@ function MQTTServer(adapter) {
1595
1603
  if (pos !== null) {
1596
1604
  client.pubrel({messageId: packet.messageId});
1597
1605
  } else {
1598
- adapter.log.warn(`Client [${client.id}] Received pubrec on ${client.id} for unknown messageId ${packet.messageId}`);
1606
+ adapter.log.warn(`Client [${client.id}] received pubrec on ${client.id} for unknown message ID: ${packet.messageId}`);
1599
1607
  }
1600
1608
  });
1601
1609
 
@@ -1621,7 +1629,7 @@ function MQTTServer(adapter) {
1621
1629
  if (pos !== null) {
1622
1630
  client._messages.splice(pos, 1);
1623
1631
  } else {
1624
- adapter.log.warn(`Client [${client.id}] Received pubcomp for unknown message ID: ${packet.messageId}`);
1632
+ adapter.log.warn(`Client [${client.id}] received pubcomp for unknown message ID: ${packet.messageId}`);
1625
1633
  }
1626
1634
  });
1627
1635
 
@@ -1652,8 +1660,9 @@ function MQTTServer(adapter) {
1652
1660
  client.pubcomp({messageId: packet.messageId});
1653
1661
 
1654
1662
  receivedTopic(client._messages[pos], client);
1663
+ client._messages && client._messages.splice(pos, 1);
1655
1664
  } else {
1656
- adapter.log.warn(`Client [${client.id}] Received pubrel on ${client.id} for unknown messageId ${packet.messageId}`);
1665
+ adapter.log.warn(`Client [${client.id}] received pubrel on ${client.id} for unknown messageId ${packet.messageId}`);
1657
1666
  }
1658
1667
  });
1659
1668
 
@@ -1679,10 +1688,10 @@ function MQTTServer(adapter) {
1679
1688
  });
1680
1689
 
1681
1690
  if (pos !== null) {
1682
- adapter.log.debug(`Client [${client.id}] Received puback for ${client.id} message ID: ${packet.messageId}`);
1691
+ adapter.log.debug(`Client [${client.id}] received puback for ${client.id} message ID: ${packet.messageId}`);
1683
1692
  client._messages && client._messages.splice(pos, 1);
1684
1693
  } else {
1685
- adapter.log.warn(`Client [${client.id}] Received puback for unknown message ID: ${packet.messageId}`);
1694
+ adapter.log.warn(`Client [${client.id}] received puback for unknown message ID: ${packet.messageId}`);
1686
1695
  }
1687
1696
  });
1688
1697
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "iobroker.sonoff",
3
3
  "description": "The adapter allows to send and receive MQTT messages from ioBroker and to be a broker.",
4
- "version": "3.0.3",
4
+ "version": "3.1.0",
5
5
  "author": "bluefox <dogafox@gmail.com>",
6
6
  "homepage": "https://github.com/ioBroker/ioBroker.sonoff",
7
7
  "repository": {
@@ -17,18 +17,17 @@
17
17
  ],
18
18
  "dependencies": {
19
19
  "mqtt-connection": "^4.1.0",
20
- "@iobroker/adapter-core": "^3.0.3"
20
+ "@iobroker/adapter-core": "^3.1.4"
21
21
  },
22
22
  "devDependencies": {
23
- "@alcalzone/release-script": "^3.6.0",
24
- "@alcalzone/release-script-plugin-iobroker": "^3.6.0",
25
- "@alcalzone/release-script-plugin-license": "^3.5.9",
26
- "@iobroker/legacy-testing": "^1.0.0",
27
- "axios": "^1.5.0",
28
- "mqtt": "^4.3.7",
29
- "gulp": "^4.0.2",
30
- "mocha": "^10.2.0",
31
- "chai": "^4.3.8"
23
+ "@alcalzone/release-script": "^3.7.0",
24
+ "@alcalzone/release-script-plugin-iobroker": "^3.7.0",
25
+ "@alcalzone/release-script-plugin-license": "^3.7.0",
26
+ "@iobroker/adapter-dev": "^1.3.0",
27
+ "@iobroker/legacy-testing": "^1.0.12",
28
+ "mqtt": "^4.3.8",
29
+ "mocha": "^10.4.0",
30
+ "chai": "^4.4.1"
32
31
  },
33
32
  "bugs": {
34
33
  "url": "https://github.com/ioBroker/ioBroker.sonoff/issues"
@@ -47,10 +46,11 @@
47
46
  "release-patch": "release-script patch --yes",
48
47
  "release-minor": "release-script minor --yes",
49
48
  "release-major": "release-script major --yes",
50
- "update-packages": "ncu --upgrade"
49
+ "update-packages": "ncu --upgrade",
50
+ "translate": "translate-adapter"
51
51
  },
52
52
  "engines": {
53
- "node": ">=4.0.0"
53
+ "node": ">=18.0.0"
54
54
  },
55
55
  "license": "MIT"
56
56
  }
package/lib/tools.js DELETED
@@ -1,99 +0,0 @@
1
- const axios = require('axios').default;
2
-
3
- /**
4
- * Tests whether the given variable is a real object and not an Array
5
- * @param {any} it The variable to test
6
- * @returns {it is Record<string, any>}
7
- */
8
- function isObject(it) {
9
- // This is necessary because:
10
- // typeof null === 'object'
11
- // typeof [] === 'object'
12
- // [] instanceof Object === true
13
- return Object.prototype.toString.call(it) === '[object Object]';
14
- }
15
-
16
- /**
17
- * Tests whether the given variable is really an Array
18
- * @param {any} it The variable to test
19
- * @returns {it is any[]}
20
- */
21
- function isArray(it) {
22
- if (typeof Array.isArray === 'function') return Array.isArray(it);
23
- return Object.prototype.toString.call(it) === '[object Array]';
24
- }
25
-
26
- /**
27
- * Translates text to the target language. Automatically chooses the right translation API.
28
- * @param {string} text The text to translate
29
- * @param {string} targetLang The target languate
30
- * @param {string} [yandexApiKey] The yandex API key. You can create one for free at https://translate.yandex.com/developers
31
- * @returns {Promise<string>}
32
- */
33
- async function translateText(text, targetLang, yandexApiKey) {
34
- if (targetLang === 'en') {
35
- return text;
36
- } else if (!text) {
37
- return '';
38
- }
39
- if (yandexApiKey) {
40
- return translateYandex(text, targetLang, yandexApiKey);
41
- } else {
42
- return translateGoogle(text, targetLang);
43
- }
44
- }
45
-
46
- /**
47
- * Translates text with Yandex API
48
- * @param {string} text The text to translate
49
- * @param {string} targetLang The target languate
50
- * @param {string} apiKey The yandex API key. You can create one for free at https://translate.yandex.com/developers
51
- * @returns {Promise<string>}
52
- */
53
- async function translateYandex(text, targetLang, apiKey) {
54
- if (targetLang === 'zh-cn') {
55
- targetLang = 'zh';
56
- }
57
- try {
58
- const url = `https://translate.yandex.net/api/v1.5/tr.json/translate?key=${apiKey}&text=${encodeURIComponent(text)}&lang=en-${targetLang}`;
59
- const response = await axios({url, timeout: 15000});
60
- if (response.data && response.data.text && isArray(response.data.text)) {
61
- return response.data.text[0];
62
- }
63
- throw new Error('Invalid response for translate request');
64
- } catch (e) {
65
- throw new Error(`Could not translate to "${targetLang}": ${e}`);
66
- }
67
- }
68
-
69
- /**
70
- * Translates text with Google API
71
- * @param {string} text The text to translate
72
- * @param {string} targetLang The target languate
73
- * @returns {Promise<string>}
74
- */
75
- async function translateGoogle(text, targetLang) {
76
- try {
77
- const url = `http://translate.googleapis.com/translate_a/single?client=gtx&sl=en&tl=${targetLang}&dt=t&q=${encodeURIComponent(text)}&ie=UTF-8&oe=UTF-8`;
78
- const response = await axios({url, timeout: 15000});
79
- if (isArray(response.data)) {
80
- // we got a valid response
81
- return response.data[0][0][0];
82
- }
83
- throw new Error('Invalid response for translate request');
84
- } catch (e) {
85
- if (e.response && e.response.status === 429) {
86
- throw new Error(
87
- `Could not translate to "${targetLang}": Rate-limited by Google Translate`
88
- );
89
- } else {
90
- throw new Error(`Could not translate to "${targetLang}": ${e}`);
91
- }
92
- }
93
- }
94
-
95
- module.exports = {
96
- isArray,
97
- isObject,
98
- translateText
99
- };