Skip to content

Commit ceba9b6

Browse files
authored
Update network.py
1 parent 213b53c commit ceba9b6

1 file changed

Lines changed: 93 additions & 86 deletions

File tree

core/network.py

Lines changed: 93 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,59 @@
11
"""
22
KingWatch Pro v17 - core/network.py
3-
4-
HYBRID BAND DETECTION MATRIX:
5-
Layer 1: TelephonyManager.getDataNetworkType() (primary, most accurate)
6-
Layer 2: NetworkCapabilities.getLinkDownstreamBandwidthKbps() (no permission)
7-
Layer 3: Heuristic from actual measured speed (always works)
8-
Layer 4: sysfs interface name fallback
9-
10-
Band is determined by best available source, updated every 5s.
11-
Returns keys: dl, ul, sig, arc
3+
Hybrid band detection + ping via background thread.
4+
Returns keys: dl, ul, sig, ping, arc
125
"""
136
import time as _time
147
import glob
158
from threading import Thread as _Thread
169

1710
_signal = "Detecting..."
11+
_ping_str = "--"
1812
_started = False
1913
_bw = {}
2014
_dl = 0.0
2115
_ul = 0.0
2216
_EMA = 0.4
2317
_band_bps = 10.0 * 125000
18+
_spdhist = [] # speed history for heuristic
19+
20+
21+
# -- Ping ------------------------------------------------------------------
22+
def _ping_once():
23+
"""TCP connect ping - all via getattr to avoid Python 3.11 cache bug."""
24+
_sk = __import__('socket')
25+
_AF_INET = getattr(_sk, 'AF_INET')
26+
_SOCK_STREAM = getattr(_sk, 'SOCK_STREAM')
27+
_SocketCls = getattr(_sk, 'socket')
28+
_now = getattr(_time, 'time')
29+
for ip, port in [("8.8.8.8", 53), ("1.1.1.1", 443)]:
30+
try:
31+
s = _SocketCls(_AF_INET, _SOCK_STREAM)
32+
_st = getattr(s, 'settimeout')
33+
_cx = getattr(s, 'connect_ex')
34+
_cl = getattr(s, 'close')
35+
_st(2.0)
36+
t0 = _now()
37+
res = _cx((ip, port))
38+
ms = round((_now() - t0) * 1000)
39+
_cl()
40+
if not res: # res == 0 means connected
41+
return str(ms) + "ms"
42+
except Exception:
43+
pass
44+
return "--"
45+
2446

25-
# Speed history for heuristic (last 10 samples in bytes/s)
26-
_speed_hist = []
47+
def _ping_loop():
48+
global _ping_str
49+
_sleep = getattr(_time, 'sleep')
50+
_sleep(3)
51+
while True:
52+
_ping_str = _ping_once()
53+
_sleep(8)
2754

2855

56+
# -- Band detection ---------------------------------------------------------
2957
def _quality(dbm):
3058
if -50 < dbm: return "Excellent"
3159
if -60 < dbm: return "Good"
@@ -34,16 +62,12 @@ def _quality(dbm):
3462
return "Poor"
3563

3664

37-
def _heuristic_band(dl_bps):
38-
"""
39-
Layer 3: Classify band from actual measured speed.
40-
Uses median of recent speed history for stability.
41-
"""
65+
def _heuristic(dl_bps):
66+
"""Layer 3: classify band from measured speed median."""
4267
global _band_bps
43-
if len(_speed_hist) < 3:
68+
if len(_spdhist) < 3:
4469
return ""
45-
samples = sorted(_speed_hist)
46-
med = samples[len(samples) // 2]
70+
med = sorted(_spdhist)[len(_spdhist) // 2]
4771
mbps = med / 125000.0
4872
if 50.0 < mbps: _band_bps = 500.0*125000; return "5G (speed)"
4973
if 10.0 < mbps: _band_bps = 50.0*125000; return "4G LTE (speed)"
@@ -52,46 +76,6 @@ def _heuristic_band(dl_bps):
5276
return ""
5377

5478

55-
def _telephony_band(ctx, Ctx):
56-
"""Layer 1: TelephonyManager - most accurate when available."""
57-
global _band_bps
58-
try:
59-
from jnius import autoclass # type: ignore
60-
TM = autoclass("android.telephony.TelephonyManager")
61-
tm = getattr(ctx, 'getSystemService')(getattr(Ctx, 'TELEPHONY_SERVICE'))
62-
nt = getattr(tm, 'getDataNetworkType')()
63-
if nt in (0,): return "" # UNKNOWN - try next layer
64-
if nt in (20,): _band_bps=500.0*125000; return "5G NR Max 500Mbps"
65-
if nt in (13,): _band_bps=50.0*125000; return "4G LTE Max 50Mbps"
66-
if nt in (19,): _band_bps=150.0*125000; return "4G LTE-CA Max 150Mbps"
67-
if nt in (15,): _band_bps=42.0*125000; return "4G HSPA+ Max 42Mbps"
68-
if nt in (8,9,10,3,5,6,12,14):
69-
_band_bps=14.0*125000; return "3G Max 14Mbps"
70-
if nt in (1,2,4,7,11,16):
71-
_band_bps=0.2*125000; return "2G Max 0.2Mbps"
72-
_band_bps=10.0*125000; return "Mobile"
73-
except Exception:
74-
pass
75-
return ""
76-
77-
78-
def _caps_band(caps):
79-
"""Layer 2: NetworkCapabilities bandwidth estimate - no permission needed."""
80-
global _band_bps
81-
try:
82-
_gDL = getattr(caps, 'getLinkDownstreamBandwidthKbps')
83-
dl = _gDL()
84-
if 0 < dl:
85-
if 50000 < dl: _band_bps=500.0*125000; return "5G ~" + str(dl//1000) + "Mbps"
86-
if 5000 < dl: _band_bps=50.0*125000; return "4G LTE ~" + str(dl//1000) + "Mbps"
87-
if 1000 < dl: _band_bps=20.0*125000; return "4G ~" + str(dl//1000) + "Mbps"
88-
if 200 < dl: _band_bps=14.0*125000; return "3G ~" + str(dl//1000) + "Mbps"
89-
_band_bps=0.2*125000; return "2G ~" + str(dl) + "Kbps"
90-
except Exception:
91-
pass
92-
return ""
93-
94-
9579
def _detect():
9680
global _band_bps
9781
try:
@@ -125,27 +109,46 @@ def _detect():
125109
except Exception:
126110
_band_bps = 100.0*125000; return "WiFi"
127111

128-
# Cellular - hybrid matrix
112+
# Cellular - Layer 1: TelephonyManager
129113
if _hT(0):
130-
# Layer 1: TelephonyManager
131-
result = _telephony_band(ctx, Ctx)
132-
if result:
133-
return result
134-
# Layer 2: NetworkCapabilities bandwidth
135-
result = _caps_band(caps)
136-
if result:
137-
return result
138-
# Layer 3: Heuristic from speed history
139-
result = _heuristic_band(_dl)
140-
if result:
141-
return result
142-
# All failed - show Mobile
143-
_band_bps = 10.0*125000
144-
return "Mobile"
114+
try:
115+
TM = autoclass("android.telephony.TelephonyManager")
116+
tm = getattr(ctx, 'getSystemService')(getattr(Ctx, 'TELEPHONY_SERVICE'))
117+
nt = getattr(tm, 'getDataNetworkType')()
118+
if nt in (20,): _band_bps=500.0*125000; return "5G NR Max 500Mbps"
119+
if nt in (13,): _band_bps=50.0*125000; return "4G LTE Max 50Mbps"
120+
if nt in (19,): _band_bps=150.0*125000; return "4G LTE-CA Max 150Mbps"
121+
if nt in (15,): _band_bps=42.0*125000; return "4G HSPA+ Max 42Mbps"
122+
if nt in (8,9,10,3,5,6,12,14):
123+
_band_bps=14.0*125000; return "3G Max 14Mbps"
124+
if nt in (1,2,4,7,11,16):
125+
_band_bps=0.2*125000; return "2G Max 0.2Mbps"
126+
# nt==0 UNKNOWN - try Layer 2
127+
except Exception:
128+
pass
129+
130+
# Layer 2: bandwidth from NetworkCapabilities
131+
try:
132+
_gDL = getattr(caps, 'getLinkDownstreamBandwidthKbps')
133+
dl = _gDL()
134+
if 0 < dl:
135+
if 50000 < dl: _band_bps=500.0*125000; return "5G ~" + str(dl//1000) + "Mbps"
136+
if 5000 < dl: _band_bps=50.0*125000; return "4G LTE ~" + str(dl//1000) + "Mbps"
137+
if 1000 < dl: _band_bps=20.0*125000; return "4G ~" + str(dl//1000) + "Mbps"
138+
if 200 < dl: _band_bps=14.0*125000; return "3G ~" + str(dl//1000) + "Mbps"
139+
_band_bps=0.2*125000; return "2G ~" + str(dl) + "Kbps"
140+
except Exception:
141+
pass
142+
143+
# Layer 3: speed heuristic
144+
h = _heuristic(_dl)
145+
if h:
146+
return h
147+
148+
_band_bps = 10.0*125000; return "Mobile"
145149

146150
if _hT(3):
147-
_band_bps = 1000.0*125000
148-
return "Ethernet Max 1000Mbps"
151+
_band_bps = 1000.0*125000; return "Ethernet Max 1000Mbps"
149152

150153
return "Connected"
151154
except Exception:
@@ -182,6 +185,7 @@ def _signal_loop():
182185
_sleep(5)
183186

184187

188+
# -- Traffic ----------------------------------------------------------------
185189
def _bytes():
186190
try:
187191
from jnius import autoclass # type: ignore
@@ -214,37 +218,46 @@ def _fmt(b):
214218
return "0 KB/s"
215219

216220

221+
# -- Public API -------------------------------------------------------------
217222
def get_network():
223+
# Returns keys: dl, ul, sig, ping, arc
218224
global _started, _dl, _ul
219225
if not _started:
220226
_started = True
221227
_t1 = _Thread(target=_signal_loop, daemon=True)
222228
getattr(_t1, 'start')()
229+
_t2 = _Thread(target=_ping_loop, daemon=True)
230+
getattr(_t2, 'start')()
223231

224232
rx, tx = _bytes()
225233
now = getattr(_time, 'time')()
226234
sig = _signal
235+
ping = _ping_str
227236

228237
if not _bw:
229238
_bw.update({"rx": rx, "tx": tx, "t": now})
230-
return {"dl": "0 KB/s", "ul": "0 KB/s", "sig": sig, "arc": 0.0}
239+
return {"dl": "0 KB/s", "ul": "0 KB/s", "sig": sig, "ping": ping, "arc": 0.0}
231240

232241
dt = now - _bw["t"]
233242
if dt < 0.3:
234243
if 0 < _band_bps:
235244
arc = min(100.0, _dl / _band_bps * 100)
236245
else:
237246
arc = 0.0
238-
return {"dl": _fmt(_dl), "ul": _fmt(_ul), "sig": sig, "arc": arc}
247+
return {"dl": _fmt(_dl), "ul": _fmt(_ul), "sig": sig, "ping": ping, "arc": arc}
239248

240249
prx = _bw["rx"]
241250
ptx = _bw["tx"]
242251
_bw.update({"rx": rx, "tx": tx, "t": now})
243252

244253
if prx < rx:
245254
dl_raw = (rx - prx) / dt
255+
_spdhist.append(dl_raw)
256+
if not (len(_spdhist) < 11):
257+
_spdhist.pop(0)
246258
else:
247259
dl_raw = 0.0
260+
248261
if ptx < tx:
249262
ul_raw = (tx - ptx) / dt
250263
else:
@@ -253,15 +266,9 @@ def get_network():
253266
_dl = _EMA * dl_raw + (1 - _EMA) * _dl
254267
_ul = _EMA * ul_raw + (1 - _EMA) * _ul
255268

256-
# Feed speed history for heuristic
257-
if 0 < dl_raw:
258-
_speed_hist.append(dl_raw)
259-
if not (len(_speed_hist) < 11):
260-
_speed_hist.pop(0)
261-
262269
if 0 < _band_bps:
263270
arc = min(100.0, _dl / _band_bps * 100)
264271
else:
265272
arc = 0.0
266273

267-
return {"dl": _fmt(_dl), "ul": _fmt(_ul), "sig": sig, "arc": arc}
274+
return {"dl": _fmt(_dl), "ul": _fmt(_ul), "sig": sig, "ping": ping, "arc": arc}

0 commit comments

Comments
 (0)