diff --git a/lib/extension/networkMap.js b/lib/extension/networkMap.js index 914f6c99..3831d3b3 100644 --- a/lib/extension/networkMap.js +++ b/lib/extension/networkMap.js @@ -85,7 +85,7 @@ class NetworkMap extends Extension { let lastSeen = 'unknown'; const date = node.type === 'Coordinator' ? Date.now() : node.lastSeen; if (date) { - lastSeen = utils.formatDate(date, 'ISO_8601_local'); + lastSeen = utils.formatDate(date, 'relative'); } labels.push(lastSeen); @@ -163,7 +163,7 @@ class NetworkMap extends Extension { let lastSeen = 'unknown'; const date = node.type === 'Coordinator' ? Date.now() : node.lastSeen; if (date) { - lastSeen = utils.formatDate(date, 'ISO_8601_local'); + lastSeen = utils.formatDate(date, 'relative'); } text.push(`---`); text.push(lastSeen); diff --git a/lib/util/utils.js b/lib/util/utils.js index 59e1fce7..9324c26e 100644 --- a/lib/util/utils.js +++ b/lib/util/utils.js @@ -1,5 +1,6 @@ const zigbeeHerdsmanConverters = require('zigbee-herdsman-converters'); const equals = require('fast-deep-equal'); +const humanizeDuration = require('humanize-duration'); // Xiaomi uses 4151 and 4447 (lumi.plug) as manufacturer ID. const xiaomiManufacturerID = [4151, 4447]; @@ -91,6 +92,10 @@ function formatDate(date, type) { case 'epoch': result = date; break; + case 'relative': + // https://github.com/EvanHahn/HumanizeDuration.js#options + result = humanizeDuration(Date.now() - date, {language: 'en', largest: 2, round: true}) + ' ago'; + break; default: throw new Error(`Unsupported type '${type}'`); } diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index 547eec71..45391948 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -2704,6 +2704,11 @@ "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", "dev": true }, + "humanize-duration": { + "version": "3.23.1", + "resolved": "https://registry.npmjs.org/humanize-duration/-/humanize-duration-3.23.1.tgz", + "integrity": "sha512-aoOEkomAETmVuQyBx4E7/LfPlC9s8pAA/USl7vFRQpDjepo3aiyvFfOhtXSDqPowdBVPFUZ7onG/KyuolX0qPg==" + }, "iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", diff --git a/package.json b/package.json index 150a6bcc..25af8a5b 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,7 @@ "debounce": "*", "fast-deep-equal": "*", "git-last-commit": "*", + "humanize-duration": "*", "js-yaml": "*", "mkdir-recursive": "*", "moment": "*", diff --git a/test/networkMap.test.js b/test/networkMap.test.js index 1354b1a5..3751d9ab 100644 --- a/test/networkMap.test.js +++ b/test/networkMap.test.js @@ -127,10 +127,6 @@ describe('Networkmap', () => { }); it('Output graphviz networkmap', async () => { - const getTimezoneOffset = Date.prototype.getTimezoneOffset; - const getHours = Date.prototype.getHours; - Date.prototype.getTimezoneOffset = () => -60; - Date.prototype.getHours = () => 1; mock(); const device = zigbeeHerdsman.devices.bulb_color; device.lastSeen = null; @@ -146,16 +142,16 @@ describe('Networkmap', () => { const expected = `digraph G { node[shape=record]; - "0x00124b00120144ae" [style="bold, filled", fillcolor="#e04e5d", fontcolor="#ffffff", label="{Coordinator|0x00124b00120144ae (0)|1970-01-01T01:00:10+01:00}"]; - "0x000b57fffec6a5b2" [style="rounded, filled", fillcolor="#4ea3e0", fontcolor="#ffffff", label="{bulb|0x000b57fffec6a5b2 (40369)|IKEA TRADFRI LED bulb E26/E27 980 lumen, dimmable, white spectrum, opal white (LED1545G12)|1970-01-01T01:00:01+01:00}"]; + "0x00124b00120144ae" [style="bold, filled", fillcolor="#e04e5d", fontcolor="#ffffff", label="{Coordinator|0x00124b00120144ae (0)|0 seconds ago}"]; + "0x000b57fffec6a5b2" [style="rounded, filled", fillcolor="#4ea3e0", fontcolor="#ffffff", label="{bulb|0x000b57fffec6a5b2 (40369)|IKEA TRADFRI LED bulb E26/E27 980 lumen, dimmable, white spectrum, opal white (LED1545G12)|9 seconds ago}"]; "0x000b57fffec6a5b2" -> "0x00124b00120144ae" [penwidth=2, weight=1, color="#009900", label="92 (routes: 6540)"] "0x000b57fffec6a5b3" [style="rounded, filled", fillcolor="#4ea3e0", fontcolor="#ffffff", label="{bulb_color|0x000b57fffec6a5b3 (40399)|Philips Hue Go (7146060PH)|unknown}"]; "0x000b57fffec6a5b3" -> "0x00124b00120144ae" [penwidth=0.5, weight=0, color="#994444", label="120"] "0x000b57fffec6a5b3" -> "0x000b57fffec6a5b2" [penwidth=0.5, weight=0, color="#994444", label="110"] - "0x0017880104e45521" [style="rounded, dashed, filled", fillcolor="#fff8ce", fontcolor="#000000", label="{button_double_key|0x0017880104e45521 (6538)|Xiaomi Aqara double key wireless wall switch (WXKG02LM)|1970-01-01T01:00:01+01:00}"]; + "0x0017880104e45521" [style="rounded, dashed, filled", fillcolor="#fff8ce", fontcolor="#000000", label="{button_double_key|0x0017880104e45521 (6538)|Xiaomi Aqara double key wireless wall switch (WXKG02LM)|9 seconds ago}"]; "0x0017880104e45521" -> "0x0017880104e45559" [penwidth=1, weight=0, color="#994444", label="130"] - "0x0017880104e45525" [style="rounded, filled", fillcolor="#4ea3e0", fontcolor="#ffffff", label="{0x0017880104e45525|0x0017880104e45525 (6536)failed: lqi,routingTable|Boef notSupportedModelID|1970-01-01T01:00:01+01:00}"]; - "0x0017880104e45559" [style="rounded, filled", fillcolor="#4ea3e0", fontcolor="#ffffff", label="{cc2530_router|0x0017880104e45559 (6540)|Custom devices (DiY) [CC2530 router](http://ptvo.info/cc2530-based-zigbee-coordinator-and-router-112/) (CC2530.ROUTER)|1970-01-01T01:00:01+01:00}"]; + "0x0017880104e45525" [style="rounded, filled", fillcolor="#4ea3e0", fontcolor="#ffffff", label="{0x0017880104e45525|0x0017880104e45525 (6536)failed: lqi,routingTable|Boef notSupportedModelID|9 seconds ago}"]; + "0x0017880104e45559" [style="rounded, filled", fillcolor="#4ea3e0", fontcolor="#ffffff", label="{cc2530_router|0x0017880104e45559 (6540)|Custom devices (DiY) [CC2530 router](http://ptvo.info/cc2530-based-zigbee-coordinator-and-router-112/) (CC2530.ROUTER)|9 seconds ago}"]; "0x0017880104e45559" -> "0x000b57fffec6a5b2" [penwidth=0.5, weight=0, color="#994444", label="100"] }`; @@ -165,15 +161,9 @@ describe('Networkmap', () => { for (let i = 0; i < expectedLines.length; i++) { expect(actualLines[i].trim()).toStrictEqual(expectedLines[i].trim()); } - Date.prototype.getTimezoneOffset = getTimezoneOffset; - Date.prototype.getHours = getHours; }); it('Output plantuml networkmap', async () => { - const getTimezoneOffset = Date.prototype.getTimezoneOffset; - const getHours = Date.prototype.getHours; - Date.prototype.getTimezoneOffset = () => -60; - Date.prototype.getHours = () => 1; mock(); const device = zigbeeHerdsman.devices.bulb_color; device.lastSeen = null; @@ -197,7 +187,7 @@ describe('Networkmap', () => { --- Boef notSupportedModelID --- - 1970-01-01T01:00:01+01:00 + 9 seconds ago ] card 0x000b57fffec6a5b2 [ @@ -207,7 +197,7 @@ describe('Networkmap', () => { --- IKEA TRADFRI LED bulb E26/E27 980 lumen, dimmable, white spectrum, opal white (LED1545G12) --- - 1970-01-01T01:00:01+01:00 + 9 seconds ago ] card 0x000b57fffec6a5b3 [ @@ -227,7 +217,7 @@ describe('Networkmap', () => { --- Xiaomi Aqara double key wireless wall switch (WXKG02LM) --- - 1970-01-01T01:00:01+01:00 + 9 seconds ago ] card 0x0017880104e45559 [ @@ -237,7 +227,7 @@ describe('Networkmap', () => { --- Custom devices (DiY) [CC2530 router](http://ptvo.info/cc2530-based-zigbee-coordinator-and-router-112/) (CC2530.ROUTER) --- - 1970-01-01T01:00:01+01:00 + 9 seconds ago ] card 0x00124b00120144ae [ @@ -245,7 +235,7 @@ describe('Networkmap', () => { --- 0x00124b00120144ae (0) --- - 1970-01-01T01:00:10+01:00 + 0 seconds ago ] 0x000b57fffec6a5b3 --> 0x00124b00120144ae: 120 @@ -262,7 +252,5 @@ describe('Networkmap', () => { for (let i = 0; i < expectedLines.length; i++) { expect(actualLines[i].trim()).toStrictEqual(expectedLines[i].trim()); } - Date.prototype.getTimezoneOffset = getTimezoneOffset; - Date.prototype.getHours = getHours; }); });