Merge branch 'pablorevilla-meshtastic:master' into master
@@ -0,0 +1,3 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/meshtastic-python" vcs="Git" />
|
||||
<mapping directory="$PROJECT_DIR$/meshtastic-python/protobufs" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
@@ -3,7 +3,9 @@
|
||||
This project watches a MQTT topic for meshtastic messages, imports them to a
|
||||
database and has a web UI to view them.
|
||||
|
||||
Requires **`python3.12`** and **`graphviz`**.
|
||||
An example of a currently running instace for the San Francisco Bay Area mesh runs at https://meshview.bayme.sh
|
||||
|
||||
Requires **`python3.11`** or above.
|
||||
|
||||
## Preparing
|
||||
|
||||
@@ -17,6 +19,8 @@ git clone --recurse-submodules https://github.com/pablorevilla-meshtastic/meshvi
|
||||
Create a python virtual environment:
|
||||
``` bash
|
||||
cd meshview
|
||||
```
|
||||
``` bash
|
||||
python3 -m venv env
|
||||
```
|
||||
Install the environment requirements:
|
||||
@@ -30,7 +34,7 @@ sudo apt-get install graphviz
|
||||
Edit `config.ini` to change the MQTT server, username, password, and topic(s) as necessary.
|
||||
|
||||
You may also change the web server port from the ***default 8081***.
|
||||
https://github.com/madeofstown/meshview/blob/c9d65a078af5e71a6815c142dbb11e5868f8885b/config.ini#L1-L15
|
||||
https://github.com/pablorevilla-meshtastic/meshview/blob/20bc89a21feb23b0dde51e10e21638c11f4e4443/config.ini#L1-L15
|
||||
|
||||
## Running Meshview
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 32 KiB |
@@ -36,7 +36,7 @@
|
||||
<br><div style="text-align:center"><strong>Bay Area Mesh - http://bayme.sh</strong></div>
|
||||
<div style="text-align:center">Quick Links: <a href="/nodelist">Nodes</a> - <a href="/chat">Conversations</a> - <a href="/firehose">See <strong>everything</strong> </a>
|
||||
- Mesh Graph <a href="/graph/longfast">LF</a> - <a href="/graph/mediumslow">MS </a> - <a href="/stats">Stats </a>
|
||||
- <a href="/net">Weekly Net</a></div><br>
|
||||
- <a href="/net">Weekly Net</a> - <a href="/map">Map</a></div><br>
|
||||
<div id="spinner" class="spinner-border secondary-primary htmx-indicator position-absolute top-50 start-50" role="status">
|
||||
<span class="visually-hidden">Loading...</span>
|
||||
</div>
|
||||
|
||||
@@ -307,19 +307,7 @@ async def _packet_list(request, raw_packets, packet_event):
|
||||
|
||||
@routes.get("/chat_events")
|
||||
async def chat_events(request):
|
||||
"""
|
||||
Server-Sent Events (SSE) endpoint for real-time chat packet updates.
|
||||
|
||||
This endpoint listens for new chat packets related to `PortNum.TEXT_MESSAGE_APP`
|
||||
and streams them to connected clients. Messages matching the pattern `"seq \d+$"`
|
||||
are filtered out before sending.
|
||||
|
||||
Args:
|
||||
request (aiohttp.web.Request): The incoming HTTP request.
|
||||
|
||||
Returns:
|
||||
aiohttp.web.StreamResponse: SSE response streaming chat events.
|
||||
"""
|
||||
chat_packet = env.get_template("chat_packet.html")
|
||||
|
||||
# Precompile regex for filtering out unwanted messages (case insensitive)
|
||||
@@ -356,7 +344,7 @@ async def chat_events(request):
|
||||
)
|
||||
except ConnectionResetError:
|
||||
# Log when a client disconnects unexpectedly
|
||||
logging.warning("Client disconnected from SSE stream.")
|
||||
print("Client disconnected from SSE stream.")
|
||||
return # Exit the loop and close the connection
|
||||
|
||||
|
||||
@@ -451,7 +439,7 @@ async def events(request):
|
||||
)
|
||||
|
||||
except ConnectionResetError:
|
||||
logging.warning("Client disconnected from SSE stream.")
|
||||
print("Client disconnected from SSE stream.")
|
||||
return # Gracefully exit on disconnection
|
||||
|
||||
@dataclass
|
||||
@@ -1585,7 +1573,7 @@ async def net(request):
|
||||
raise # Let aiohttp handle HTTP exceptions properly
|
||||
|
||||
except Exception as e:
|
||||
logging.exception("Error processing chat request")
|
||||
print("Error processing chat request")
|
||||
return web.Response(
|
||||
text="An internal server error occurred.",
|
||||
status=500,
|
||||
@@ -1629,6 +1617,23 @@ async def net_events(request):
|
||||
return # Gracefully exit on disconnection
|
||||
|
||||
|
||||
@routes.get("/map")
|
||||
async def map(request):
|
||||
try:
|
||||
nodes= await store.get_nodes()
|
||||
template = env.get_template("map.html")
|
||||
return web.Response(
|
||||
text=template.render(nodes=nodes),
|
||||
content_type="text/html",
|
||||
)
|
||||
except Exception as e:
|
||||
|
||||
return web.Response(
|
||||
text="An error occurred while processing your request.",
|
||||
status=500,
|
||||
content_type="text/plain",
|
||||
)
|
||||
|
||||
async def run_server(bind, port, tls_cert):
|
||||
app = web.Application()
|
||||
app.add_routes(routes)
|
||||
|
||||
|
After Width: | Height: | Size: 157 KiB |
|
After Width: | Height: | Size: 80 KiB |
|
After Width: | Height: | Size: 32 KiB |
|
After Width: | Height: | Size: 586 KiB |
|
After Width: | Height: | Size: 444 KiB |
|
After Width: | Height: | Size: 171 KiB |
|
After Width: | Height: | Size: 126 KiB |