9 function etx_color(etx
) {
10 let color
= '#bb3333';
17 } else if (etx
< 10) {
23 function snr_colors(snr
) {
24 let color
= '#bb3333';
27 } else if (snr
> 30) {
29 } else if (snr
> 20) {
38 callGetJsonStatus
: rpc
.declare({
40 method
: 'getjsondata',
41 params
: ['otable', 'v4_port', 'v6_port'],
44 callGetHosts
: rpc
.declare({
49 fetch_jsoninfo: function (otable
) {
52 var v4_port
= parseInt(uci
.get('olsrd', 'olsrd_jsoninfo', 'port') || '') || 9090;
53 var v6_port
= parseInt(uci
.get('olsrd6', 'olsrd_jsoninfo', 'port') || '') || 9090;
56 return new Promise(function (resolve
, reject
) {
57 L
.resolveDefault(self
.callGetJsonStatus(otable
, v4_port
, v6_port
), {})
58 .then(function (res
) {
61 jsonreq4
= JSON
.parse(json
.jsonreq4
);
62 jsonreq6
= json
.jsonreq6
!== '' ? JSON
.parse(json
.jsonreq6
) : [];
70 if (jsonreq4
=== '' && jsonreq6
=== '') {
71 window
.location
.href
= 'error_olsr';
72 reject([null, 0, 0, true]);
76 if (jsonreq4
!== '') {
78 jsondata4
= jsonreq4
|| {};
79 if (otable
=== 'status') {
82 data4
= jsondata4
[otable
] || [];
85 for (var i
= 0; i
< data4
.length
; i
++) {
86 data4
[i
]['proto'] = '4';
90 if (jsonreq6
!== '') {
92 jsondata6
= jsonreq6
|| {};
93 if (otable
=== 'status') {
96 data6
= jsondata6
[otable
] || [];
99 for (var j
= 0; j
< data6
.length
; j
++) {
100 data6
[j
]['proto'] = '6';
104 for (var k
= 0; k
< data6
.length
; k
++) {
105 data4
.push(data6
[k
]);
108 resolve([data4
, has_v4
, has_v6
, false]);
110 .catch(function (err
) {
112 reject([null, 0, 0, true]);
117 action_neigh
: async
function () {
119 const [data
, has_v4
, has_v6
, error
] = await
this.fetch_jsoninfo('links');
125 function compare(a
, b
) {
126 if (a
.proto
=== b
.proto
) {
127 return a
.linkCost
< b
.linkCost
;
129 return a
.proto
< b
.proto
;
134 var resolveVal
= uci
.get('luci_olsr', 'general', 'resolve');
138 devices
= await network
.getWifiDevices();
139 var rts
= await network
.getWANNetworks();
141 rts
.forEach(function (rt
) {
142 defaultgw
= rt
.getGatewayAddr() || '0.0.0.0';
145 var networkPromises
= devices
.map(async
function (dev
) {
146 var networks
= await dev
.getWifiNetworks();
148 var promiseArr
= networks
.map(async
function (net
) {
149 var radio
= await net
.getDevice();
150 var [ifname
, devnetwork
, device
, list
] = await Promise
.all([net
.getIfname(), net
.getNetworkNames(), radio
? radio
.getName() : null, net
.getAssocList()]);
154 network
: devnetwork
[0],
160 await Promise
.all(promiseArr
);
163 await Promise
.all(networkPromises
);
166 await (async
function () {
168 res
= await self
.callGetHosts();
175 function matchHostnames(ip
) {
176 var lines
= res
.hosts
.split('\n');
177 for (var i
= 0; i
< lines
.length
; i
++) {
178 var ipandhostname
= lines
[i
].trim().split(/\s+/);
179 if (ipandhostname
[0] === ip
) {
180 return ipandhostname
[1];
185 var modifiedData
= await Promise
.all(
186 data
.map(async
function (v
) {
194 if (resolveVal
=== '1') {
195 var hostname
= matchHostnames(v
.remoteIP
);
197 v
.hostname
= hostname
;
200 var hosthints
= await network
.getHostHints();
201 var networkStatus
= await network
.getStatusByAddress(v
.localIP
);
202 var lmac
= await hosthints
.getMACAddrByIPAddr(v
.localIP
);
203 var rmac
= await hosthints
.getMACAddrByIPAddr(v
.remoteIP
);
205 for (let i
= 0; i
< assoclist
.length
; i
++) {
206 var val
= assoclist
[i
];
207 if (networkStatus
!= undefined && val
.network
=== networkStatus
.interface && val
.list
) {
208 for (var assocmac
in val
.list
) {
209 var assot
= val
.list
[assocmac
];
210 if (rmac
== assot
.mac
) {
211 signal
= parseInt(assot
.signal
);
212 noise
= parseInt(assot
.noise
);
213 snr
= noise
* -1 - signal
* -1;
220 v
.interface = networkStatus
;
223 v
.signal
= signal
|| null;
224 v
.noise
= noise
|| null;
232 if (defaultgw
=== v
.remoteIP
) {
239 modifiedData
.sort(compare
);
241 var result
= { links
: modifiedData
, has_v4
: has_v4
, has_v6
: has_v6
};
251 poll
.add(function () {
254 return Promise
.all([uci
.load('olsrd'), uci
.load('luci_olsr')]);
256 render: function () {
262 return this.action_neigh()
263 .then(function (result
) {
264 neigh_res
= result
.links
;
265 has_v4
= result
.has_v4
;
266 has_v6
= result
.has_v6
;
268 var table
= E('div', { 'class': 'table cbi-section-table', 'id': 'olsr_neigh_table' }, [
269 E('div', { 'class': 'tr cbi-section-table-cell' }, [
270 E('div', { 'class': 'th cbi-section-table-cell' }, _('Neighbour IP')),
271 E('div', { 'class': 'th cbi-section-table-cell' }, _('Hostname')),
272 E('div', { 'class': 'th cbi-section-table-cell' }, _('Interface')),
273 E('div', { 'class': 'th cbi-section-table-cell' }, _('Local interface IP')),
274 E('div', { 'class': 'th cbi-section-table-cell' }, 'LQ'),
275 E('div', { 'class': 'th cbi-section-table-cell' }, 'NLQ'),
276 E('div', { 'class': 'th cbi-section-table-cell' }, 'ETX'),
277 E('div', { 'class': 'th cbi-section-table-cell' }, 'SNR'),
282 for (var k
= 0; k
< neigh_res
.length
; k
++) {
283 var link
= neigh_res
[k
];
284 link
.linkCost
= (link
.linkCost
).toFixed(3) || 0;
285 if (link
.linkCost
=== 4194304) {
288 var color
= etx_color(link
.linkCost
);
289 var snr_color
= snr_colors(link
.snr
);
290 var defaultgw_color
= '';
291 if (link
.defaultgw
=== 1) {
292 defaultgw_color
= '#ffff99';
300 lq
: link
.linkQuality
.toFixed(3),
301 nlq
: link
.neighborLinkQuality
.toFixed(3),
307 snr_color
: snr_color
,
308 dfgcolor
: defaultgw_color
,
313 var nt
= document
.getElementById('olsr_neigh_table');
316 '<div class="tr cbi-section-table-cell">' +
317 '<div class="th cbi-section-table-cell">Neighbour IP</div>' +
318 '<div class="th cbi-section-table-cell">Hostname</div>' +
319 '<div class="th cbi-section-table-cell">Interface</div>' +
320 '<div class="th cbi-section-table-cell">Local interface IP</div>' +
321 '<div class="th cbi-section-table-cell">LQ</div>' +
322 '<div class="th cbi-section-table-cell">NLQ</div>' +
323 '<div class="th cbi-section-table-cell">ETX</div>' +
324 '<div class="th cbi-section-table-cell">SNR</div>' +
327 for (var idx
= 0; idx
< rv
.length
; idx
++) {
330 if (neigh
.proto
== '6') {
332 '<div class="tr cbi-section-table-row cbi-rowstyle-' +
337 '<div class="td cbi-section-table-cell left" style="background-color:' +
339 '"><a href="http://[' +
341 ']/cgi-bin-status.html">' +
346 '<div class="tr cbi-section-table-row cbi-rowstyle-' +
351 '<div class="td cbi-section-table-cell left" style="background-color:' +
353 '"><a href="http://' +
355 '/cgi-bin-status.html">' +
360 s
+= '<div class="td cbi-section-table-cell left" style="background-color:' + neigh
.dfgcolor
+ '"><a href="http://' + neigh
.hn
+ '/cgi-bin-status.html">' + neigh
.hn
+ '</a></div>';
362 s
+= '<div class="td cbi-section-table-cell left" style="background-color:' + neigh
.dfgcolor
+ '">?</div>';
365 '<div class="td cbi-section-table-cell left" style="background-color:' +
368 (neigh
?.ifn
?.interface ?? '?') +
370 '<div class="td cbi-section-table-cell left" style="background-color:' +
375 '<div class="td cbi-section-table-cell left" style="background-color:' +
380 '<div class="td cbi-section-table-cell left" style="background-color:' +
385 '<div class="td cbi-section-table-cell left" style="background-color:' +
390 '<div class="td cbi-section-table-cell left" style="background-color:' +
392 '" title="Signal: ' +
407 for (var k
= 0; k
< neigh_res
.length
; k
++) {
408 var link
= neigh_res
[k
];
409 link
.linkCost
= Number(link
.linkCost
).toFixed(3) || 0;
410 if (link
.linkCost
=== 4194304) {
414 color
= etx_color(link
.linkCost
);
415 snr_color
= snr_colors(link
.snr
);
417 if (link
.snr
=== 0) {
421 var defaultgw_color
= '';
422 if (link
.defaultgw
=== 1) {
423 defaultgw_color
= '#ffff99';
429 'class': 'tr cbi-section-table-row cbi-rowstyle-' + i
+ ' proto-' + link
.proto
,
436 'class': 'td cbi-section-table-cell left',
437 'style': 'background-color:' + defaultgw_color
,
443 'href': 'http://[' + link
.remoteIP
+ ']/cgi-bin-status.html',
452 'class': 'td cbi-section-table-cell left',
453 'style': 'background-color:' + defaultgw_color
,
459 'href': 'http://' + link
.remoteIP
+ '/cgi-bin-status.html',
468 'class': 'td cbi-section-table-cell left',
469 'style': 'background-color:' + defaultgw_color
,
471 [E('a', { 'href': 'http://%q/cgi-bin-status.html'.format(link
.hostname
) }, '%h'.format(link
.hostname
))]
476 'class': 'td cbi-section-table-cell left',
477 'style': 'background-color:' + defaultgw_color
,
479 link
?.interface?.interface ?? '?'
484 'class': 'td cbi-section-table-cell left',
485 'style': 'background-color:' + defaultgw_color
,
492 'class': 'td cbi-section-table-cell left',
493 'style': 'background-color:' + defaultgw_color
,
495 [E('div', {}, link
.linkQuality
.toFixed(3))]
500 'class': 'td cbi-section-table-cell left',
501 'style': 'background-color:' + defaultgw_color
,
503 [E('div', {}, link
.neighborLinkQuality
.toFixed(3))]
508 'class': 'td cbi-section-table-cell left',
509 'style': 'background-color:' + color
,
511 [E('div', {}, link
.linkCost
)]
516 'class': 'td cbi-section-table-cell left',
517 'style': 'background-color:' + snr_color
,
518 'title': 'Signal: ' + link
.signal
+ ' Noise: ' + link
.noise
,
525 table
.appendChild(tr
);
529 var fieldset
= E('fieldset', { 'class': 'cbi-section' }, [E('legend', {}, _('Overview of currently established OLSR connections')), table
]);
531 var h2
= E('h2', { 'name': 'content' }, _('OLSR connections'));
532 var divToggleButtons
= E('div', { 'id': 'togglebuttons' });
533 var statusOlsrLegend
= E('div', {}, [
534 E('h3', {}, [_('Legend') + ':']),
536 E('li', {}, [E('strong', {}, [_('LQ: ')]), _('Success rate of packages received from the neighbour')]),
537 E('li', {}, [E('strong', {}, [_('NLQ: ')]), _('Success rate of packages sent to the neighbour')]),
538 E('li', {}, [E('strong', {}, [_('ETX: ')]), _('Expected retransmission count')]),
539 E('li', { 'style': 'list-style: none' }, [
541 E('li', {}, [E('strong', { 'style': 'color:#00cc00' }, [_('Green')]), ':', _('Very good (ETX < 2)')]),
542 E('li', {}, [E('strong', { 'style': 'color:#ffcb05' }, [_('Yellow')]), ':', _('Good (2 < ETX < 4)')]),
543 E('li', {}, [E('strong', { 'style': 'color:#ff6600' }, [_('Orange')]), ':', _('Still usable (4 < ETX < 10)')]),
544 E('li', {}, [E('strong', { 'style': 'color:#bb3333' }, [_('Red')]), ':', _('Bad (ETX > 10)')]),
547 E('li', {}, [E('strong', {}, [_('SNR: ')]), _('Signal Noise Ratio in dB')]),
548 E('li', { 'style': 'list-style: none' }, [
550 E('li', {}, [E('strong', { 'style': 'color:#00cc00' }, [_('Green')]), ':', _('Very good (SNR > 30)')]),
551 E('li', {}, [E('strong', { 'style': 'color:#ffcb05' }, [_('Yellow')]), ':', _('Good (30 > SNR > 20)')]),
552 E('li', {}, [E('strong', { 'style': 'color:#ff6600' }, [_('Orange')]), ':', _('Still usable (20 > SNR > 5)')]),
553 E('li', {}, [E('strong', { 'style': 'color:#bb3333' }, [_('Red')]), ':', _('Bad (SNR < 5)')]),
559 var statusOlsrCommonJs
= null;
561 if (has_v4
&& has_v6
) {
562 statusOlsrCommonJs
= E('script', {
563 type
: 'text/javascript',
564 src
: L
.resource('common/common_js.js'),
568 var result
= E([], {}, [h2
, divToggleButtons
, fieldset
, statusOlsrLegend
, statusOlsrCommonJs
]);
572 .catch(function (error
) {
573 console
.error(error
);
576 handleSaveApply
: null,