1<%- 2 local ubus = require "ubus" 3 local sys = require "luci.sys" 4 local utl = require "luci.util" 5 6 function connect_ubus(methods) 7 local result 8 local conn = ubus.connect() 9 10 if not conn then 11 error("Failed to connect to ubusd") 12 end 13 14 result = conn:call("otbr", methods, {}) 15 16 return result 17 end 18 19 function threadget(action) 20 local result = connect_ubus(action) 21 22 return result 23 end 24-%> 25<%+header%> 26 27<h2><%:Thread Overview%></h2> 28<br /> 29 30<div class="cbi-section-node"> 31 <div class="table"> 32 <!-- physical device --> 33 <div class="tr cbi-rowstyle-2"> 34 <div class="td col-1 center middle"> 35 <span class="ifacebadge"><img src="<%=resource .. "/icons/wifi.png"%>" id="wpan0" /> <%=threadget("interfacename").InterfaceName%></span> 36 </div> 37 <div class="td col-7 left middle"> 38 <big><strong><%:Generic MAC 802.15.4 Thread%></strong></big><br /> 39 </div> 40 <div class="td middle cbi-section-actions"> 41 <div> 42 <div></div> 43 <form action="<%=url('admin/network/thread_scan')%>" method="post"> 44 <input type="hidden" name="token" value="<%=token%>" /> 45 <input type="submit" class="cbi-button cbi-button-action important" title="<%:Scan and join network%>" value="<%:Scan%>"/> 46 </form> 47 <form action="<%=url('admin/network/thread_create')%>" method="post"> 48 <input type="hidden" name="token" value="<%=token%>" /> 49 <input type="submit" class="cbi-button cbi-button-add" title="<%:Create new network%>" value="<%:Create%>"/> 50 </form> 51 </div> 52 </div> 53 </div> 54 <!-- /physical device --> 55 56 <!-- network list --> 57 <div class="tr cbi-rowstyle-1"> 58 <div class="td col-1 center middle"> 59 </div> 60 <div class="td col-7 left middle" id="status"> 61 <em><%: Collecting data... %></em> 62 </div> 63 <div class="td middle cbi-section-actions"> 64 <div id="action"> 65 </div> 66 </div> 67 </div> 68 <!-- /network list --> 69 </div> 70</div> 71 72<br /> 73<h2><%:Neighbors%></h2> 74<br /> 75 76<div class="table" id="neighbors"> 77 <div class="tr table-titles"> 78 <div class="th col-2 center"><%:Signal%></div> 79 <div class="th col-1 center"><%:Role%></div> 80 <div class="th col-4 center"><%:RLOC16%></div> 81 <div class="th col-2 center"><%:Age%></div> 82 <div class="th col-2 center"><%:Avg RSSI%></div> 83 <div class="th col-2 center"><%:Last RSSI%></div> 84 </div> 85 <div class="tr placeholder"> 86 <div class="td"><em><%:Collecting data...%></em></div> 87 </div> 88</div> 89 90<div class="table" id="parent" style="display:none;"> 91 <div class="tr table-titles"> 92 <div class="th col-2 center"><%:Signal%></div> 93 <div class="th col-1 center"><%:Role%></div> 94 <div class="th col-4 center"><%:RLOC16%></div> 95 <div class="th col-2 center"><%:Age%></div> 96 <div class="th col-2 center"><%:LinkQualityIn%></div> 97 <div class="th col-2 center"><%:ExtAddress%></div> 98 </div> 99 <div class="tr placeholder"> 100 <div class="td"><em><%:Collecting data...%></em></div> 101 </div> 102</div> 103<%+footer%> 104 105<script type="text/javascript" src="/luci-static/resources/handle_error.js"></script> 106<script type="text/javascript">//<![CDATA[ 107 handle_error(GetURLParameter('error')); 108 109 XHR.poll(2, '<%=url('admin/network/thread_state')%>', null, 110 function(x, st) 111 { 112 var sheet = document.getElementById('status'); 113 var action = document.getElementById('action'); 114 if (st && sheet && action) 115 { 116 if(st.state != "disabled") 117 { 118 sheet.innerHTML = String.format( 119 '<strong><%:Network Name: %></strong> %s<%: | %>' + 120 '<strong><%:State: %></strong>%s<br />' + 121 '<strong><%:PAN ID: %></strong>%s<%: | %>' + 122 '<strong><%:Channel: %></strong>%d<br />', 123 st.networkname, st.state, st.panid, st.channel 124 ); 125 action.innerHTML = String.format( 126 '<form class="inline" action="<%=url('admin/network/thread_stop')%>" method="post">' + 127 '<input type="hidden" name="token" value="<%=token%>" />' + 128 '<input type="submit" class="cbi-button cbi-button-neutral" title="<%:Disable this network%>" value="<%:Disable%>" />' + 129 '</form>' + 130 '<form class="inline" action="<%=url('admin/network/thread_setting')%>" method="post">' + 131 '<input type="hidden" name="token" value="<%=token%>" />' + 132 '<input type="submit" class="cbi-button cbi-button-action important" title="<%:Edit this network%>" value="<%:Edit%>"/>' + 133 '</form>' + 134 '<form class="inline" action="<%=url('admin/network/thread_view')%>" method="post">' + 135 '<input type="hidden" name="token" value="<%=token%>" />' + 136 '<input type="submit" class="cbi-button cbi-button-add" title="<%:View this network%>" value="<%:View%>"/>' + 137 '</form>' 138 ); 139 } 140 else 141 { 142 sheet.innerHTML = String.format( 143 '<strong><%:Not connect to any Thread network%></strong><br />' + 144 '<%: Please Join or Create a Thread network.%>' 145 ); 146 } 147 } 148 }); 149 function percent_thread_signal(info){ 150 var linkquality = Number(info.LinkQualityIn); 151 152 if (linkquality == 0) 153 return 0; 154 else if (linkquality == 1) 155 return 30; 156 else if(linkquality == 2) 157 return 60; 158 else 159 return 100; 160 } 161 162 function guess_thread_signal(info) { 163 var icon; 164 var scale = percent_thread_signal(info); 165 166 if (scale == 0) 167 icon = "<%=resource%>/icons/signal-0.png"; 168 else if (scale == 30) 169 icon = "<%=resource%>/icons/signal-25-50.png"; 170 else if (scale == 50) 171 icon = "<%=resource%>/icons/signal-50-75.png"; 172 else 173 icon = "<%=resource%>/icons/signal-75-100.png"; 174 175 return icon; 176 } 177 178 XHR.poll(2, '<%=url('admin/network/thread_neighbors')%>', null, 179 function(x, st) 180 { 181 if(st && st.state == 'child') 182 { 183 var tb = document.getElementById('parent'); 184 document.getElementById('neighbors').style.display = "none"; 185 if (tb) 186 { 187 var rows = []; 188 st.neighbor.forEach(function(bss) { 189 var icon = guess_thread_signal(bss); 190 var signal = percent_thread_signal(bss); 191 rows.push([ 192 '<abbr title="LinkQualityIn: %s"><img src="%s" /><br /><small> %s%</small></abbr>'.format(bss.LinkQualityIn, icon, signal), 193 '<div class="col-1 center"> %s </div>'.format(bss.Role), 194 '<div class="col-4 center"> %s </div>'.format(bss.Rloc16), 195 '<div class="col-2 center"> %s </div>'.format(bss.Age), 196 '<div class="col-2 center"> %s </div>'.format(bss.LinkQualityIn), 197 '<div class="col-2 center"> %s </div>'.format(bss.ExtAddress), 198 ]); 199 }); 200 cbi_update_table(tb, rows, '<center><em><%:No information available%></em></center>'); 201 tb.style.display = "table"; 202 } 203 } 204 else if(st) 205 { 206 var tb = document.getElementById('neighbors'); 207 document.getElementById('parent').style.display = "none"; 208 if (tb) 209 { 210 var rows = []; 211 st.neighbor.forEach(function(bss) { 212 var icon = guess_thread_signal(bss); 213 var signal = percent_thread_signal(bss); 214 rows.push([ 215 '<abbr title="LinkQualityIn: %s"><img src="%s" /><br /><small> %s%</small></abbr>'.format(bss.LinkQualityIn, icon, signal), 216 '<div class="col-1 center"> %s </div>'.format(bss.Role), 217 '<div class="col-4 center"> %s </div>'.format(bss.Rloc16), 218 '<div class="col-2 center"> %s </div>'.format(bss.Age), 219 '<div class="col-2 center"> %s </div>'.format(bss.AvgRssi), 220 '<div class="col-2 center"> %s </div>'.format(bss.LastRssi), 221 ]); 222 }); 223 cbi_update_table(tb, rows, '<center><em><%:No information available%></em></center>'); 224 tb.style.display = "table"; 225 } 226 } 227 }); 228//]]></script> 229