added channel filtering min_packets, and allowlist, fixed javascript error, new sample.config.ini sections

This commit is contained in:
Nathan
2025-10-16 01:07:49 -07:00
parent 954cd4653d
commit c5a1009877
5 changed files with 66 additions and 37 deletions

View File

@@ -1,14 +0,0 @@
2025-10-14 20:13:45,221 [INFO] Daily cleanup is disabled by configuration.
2025-10-14 20:25:47,645 [INFO] Daily cleanup is disabled by configuration.
2025-10-14 20:34:48,026 [INFO] Daily cleanup is disabled by configuration.
2025-10-14 21:11:16,069 [INFO] Daily cleanup is disabled by configuration.
2025-10-14 21:19:58,777 [INFO] Daily cleanup is disabled by configuration.
2025-10-14 21:20:29,595 [INFO] Daily cleanup is disabled by configuration.
2025-10-15 10:28:37,193 [INFO] Daily cleanup is disabled by configuration.
2025-10-15 15:54:56,829 [INFO] Daily cleanup is disabled by configuration.
2025-10-15 15:59:16,304 [INFO] Daily cleanup is disabled by configuration.
2025-10-15 16:27:05,307 [INFO] Daily cleanup is disabled by configuration.
2025-10-15 16:29:14,882 [INFO] Daily cleanup is disabled by configuration.
2025-10-15 17:04:31,298 [INFO] Daily cleanup is disabled by configuration.
2025-10-15 17:11:28,215 [INFO] Daily cleanup is disabled by configuration.
2025-10-15 18:00:31,833 [INFO] Daily cleanup is disabled by configuration.

View File

@@ -384,11 +384,15 @@ async def get_packet_stats(
}
async def get_channels_in_period(period_type: str = "hour", length: int = 24):
async def get_channels_in_period(period_type: str = "hour", length: int = 24, min_packets: int = 5, allowlist: list[str] | None = None):
"""
Returns a list of distinct channels used in packets over a given period.
Returns a list of distinct channels used in packets over a given period,
filtered to only include channels with at least min_packets packets.
period_type: "hour" or "day"
length: number of hours or days to look back
min_packets: minimum number of packets a channel must have to be included (default: 5)
allowlist: optional list of allowed channel names. If None or contains '*', all channels are allowed
"""
now = datetime.now()
@@ -400,13 +404,23 @@ async def get_channels_in_period(period_type: str = "hour", length: int = 24):
raise ValueError("period_type must be 'hour' or 'day'")
async with database.async_session() as session:
# Count packets per channel and filter by minimum packet count
q = (
select(Packet.channel)
select(Packet.channel, func.count(Packet.id).label('packet_count'))
.where(Packet.import_time >= start_time)
.distinct()
.where(Packet.channel.isnot(None))
.group_by(Packet.channel)
.having(func.count(Packet.id) >= min_packets)
.order_by(Packet.channel)
)
result = await session.execute(q)
channels = [row[0] for row in result if row[0] is not None]
channels = [row[0] for row in result]
# Apply allowlist filtering if specified
if allowlist and '*' not in allowlist:
# Filter to only include channels in the allowlist (case-insensitive)
allowlist_lower = [ch.lower() for ch in allowlist]
channels = [ch for ch in channels if ch.lower() in allowlist_lower]
return channels

View File

@@ -243,25 +243,23 @@ nodes.forEach(n=>{
}
});
const tracerouteChannelCounts = new Map();
const channelCounts = new Map();
edges.forEach(edge=>{
if(edge.type === 'traceroute'){
const weight = typeof edge.weight === 'number' ? edge.weight : 1;
const fromChannel = channelByNodeId.get(String(edge.source));
const toChannel = channelByNodeId.get(String(edge.target));
if(fromChannel){
tracerouteChannelCounts.set(fromChannel, (tracerouteChannelCounts.get(fromChannel) || 0) + weight);
}
if(toChannel){
tracerouteChannelCounts.set(toChannel, (tracerouteChannelCounts.get(toChannel) || 0) + weight);
}
const weight = typeof edge.weight === 'number' ? edge.weight : 1;
const fromChannel = channelByNodeId.get(String(edge.source));
const toChannel = channelByNodeId.get(String(edge.target));
if(fromChannel){
channelCounts.set(fromChannel, (channelCounts.get(fromChannel) || 0) + weight);
}
if(toChannel){
channelCounts.set(toChannel, (channelCounts.get(toChannel) || 0) + weight);
}
});
let channelOptions = [];
if (tracerouteChannelCounts.size) {
if (channelCounts.size) {
channelOptions = Array.from(
[...tracerouteChannelCounts.entries()]
[...channelCounts.entries()]
.filter(([_, count]) => count > 0)
.map(([channel]) => channel)
).sort();
@@ -388,10 +386,8 @@ function searchNode(){
else alert("Node not found in current channel!");
}
initializeChannelOptions().then(() => {
populateChannelDropdown();
filterByChannel(true);
});
populateChannelDropdown();
filterByChannel(true);
window.addEventListener('resize', ()=>chart.resize());
</script>
{% endblock %}

View File

@@ -1510,9 +1510,29 @@ async def get_config(request):
async def api_channels(request: web.Request):
period_type = request.query.get("period_type", "hour")
length = int(request.query.get("length", 24))
# Get min_packets from config, with fallback to query param or default
config_min_packets = CONFIG.get("site", {}).get("min_packets_for_channel", "5")
try:
default_min_packets = int(config_min_packets)
except (ValueError, TypeError):
default_min_packets = 5
min_packets = int(request.query.get("min_packets", default_min_packets))
# Get channel allowlist from config
allowlist_str = CONFIG.get("site", {}).get("channel_allowlist", "*")
if allowlist_str and allowlist_str.strip():
# Parse comma-separated list, or use '*' for all
if allowlist_str.strip() == "*":
allowlist = None # None means all channels allowed
else:
allowlist = [ch.strip() for ch in allowlist_str.split(",") if ch.strip()]
else:
allowlist = None
try:
channels = await store.get_channels_in_period(period_type, length)
channels = await store.get_channels_in_period(period_type, length, min_packets, allowlist)
return web.json_response({"channels": channels})
except Exception as e:
return web.json_response({"channels": [], "error": str(e)})

View File

@@ -1,6 +1,8 @@
# -------------------------
# Server Configuration
# -------------------------
# important: no leading spaces on configuration lines.
[server]
# The address to bind the server to. Use * to listen on all interfaces.
bind = *
@@ -59,6 +61,17 @@ firehose_interal=3
weekly_net_message = Weekly Mesh check-in. We will keep it open on every Wednesday from 5:00pm for checkins. The message format should be (LONG NAME) - (CITY YOU ARE IN) #BayMeshNet.
net_tag = #BayMeshNet
# Channel filtering configuration
# Minimum number of packets required for a channel to appear in dropdowns
min_packets_for_channel = 5
# Channel allowlist: comma-separated list of channels to display, or * for all channels
# Use * to show all channels with sufficient packets
# Or specify channels like: LongFast,MediumSlow,MediumFast,ShortTurbo,LongSlow,ShortFast,ShortSlow,VLongSlow
channel_allowlist = *
# Examples of common Meshtastic channels:
#channel_allowlist = LongFast,MediumSlow,MediumFast,ShortTurbo,LongSlow,ShortFast,ShortSlow,VLongSlow
# -------------------------
# MQTT Broker Configuration
# -------------------------