You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: 2025-09-potato-mesh.html
+29-29Lines changed: 29 additions & 29 deletions
Original file line number
Diff line number
Diff line change
@@ -2,7 +2,7 @@
2
2
<html>
3
3
<head>
4
4
<metacharset="UTF-8">
5
-
<title>2025-09 Potato-Mesh what and why</title>
5
+
<title>2025-09 PotatoMesh what and why</title>
6
6
<style>
7
7
body {
8
8
background:#fdf5e6;
@@ -67,30 +67,31 @@
67
67
</head>
68
68
<body>
69
69
<headerclass="page-top">
70
-
<imgsrc="./animated-under-construction-image-0053.gif" alt="Under Construction Sign" />
71
-
<h1>2025-09 Potato-Mesh what and why</h1>
70
+
<h1>2025-09 PotatoMesh what and why</h1>
72
71
<p><aclass="back-home" href="./index.html">← Return to the homepage</a></p>
73
72
</header>
74
73
75
74
<articleclass="post">
76
-
<p>Below is a technical sketch of <strong>Potato-Mesh</strong>: how it works, how it plugs into Meshtastic, what data flows where, and how you can run your own. Doom optional, but the mesh will outlive us if we get this right.</p>
75
+
<p>
76
+
I have been hacking on <strong>PotatoMesh</strong> for the last couple of weeks and here are some insights. I'll give you a technical sketch: how it works, how it plugs into Meshtastic, what data flows where, and how you can run your own. (Spoiler: it's white label!)
77
+
</p>
77
78
78
79
<hr/>
79
80
80
-
<h2>Why a tool like Potato-Mesh is needed</h2>
81
+
<h2>Why a tool like PotatoMesh is needed</h2>
81
82
<p>
82
-
Meshtastic gives you resilient, off-grid mesh networks using LoRa. But by itself, it’s hard to get a global view of what’s going on in a community mesh: who is alive, how many hops, where are telemetry gaps, which radios are misbehaving. During “quiet” times, we need visibility so that when crisis or scale hits, debugging, preparation, and maintenance are possible. Potato-Mesh is one of the tools built for that.
83
+
Meshtastic gives you resilient, off-grid mesh networks using LoRa. But by itself, it's hard to get a global view of what's going on in a community mesh: who is alive, how many hops, where are telemetry gaps, which radios are misbehaving. During "quiet" times, we need visibility so that when crisis or scale hits, debugging, preparation, and maintenance are possible. PotatoMesh is one of the tools I built for that.
83
84
</p>
84
85
85
86
<hr/>
86
87
87
-
<h2>Architecture of Potato-Mesh: web app + python ingestor</h2>
88
+
<h2>Architecture of PotatoMesh: Ruby web app + Python ingestor</h2>
88
89
<p>
89
-
At its core, the Potato-Mesh web app is simple: a SQLite database live on a server. It <strong>does not</strong> poll the mesh, nor listen on LoRa directly. It knows nothing until someone <strong>reports</strong> mesh data (nodes, messages) via its API endpoints. The API is the only inlet for the mesh state.
90
+
At its core, the PotatoMesh web app is simple: a SQLite database live on a server. It <strong>does not</strong> poll the mesh, nor listen on LoRa directly. It knows nothing until someone <strong>reports</strong> mesh data (nodes, messages, positions, etc.) via its API endpoints. The API is the only inlet for the mesh state of the web app.
<tr><td><code>POST /api/messages</code></td><td>Append new messages (JSON); requires same auth token</td><td></td></tr>
107
108
</tbody>
108
109
</table>
109
110
<p>
110
-
The <code>API_TOKEN</code> environment variable must be set (non-empty) on the web app to allow POSTs. GETs are open (or less restricted). (<ahref="https://github.com/l5yth/potato-mesh">GitHub</a>)
111
+
The <code>API_TOKEN</code> environment variable must be set (non-empty) on the web app to allow POSTs. GETs are open (or less restricted).
111
112
</p>
112
113
113
114
<hr/>
114
115
115
116
<h2>Inner workings: Meshtastic protocol, data ingestion</h2>
116
117
<p>
117
-
To fill those API endpoints, Potato-Mesh uses a <strong>python ingestor</strong> script (“mesh.sh” + supporting code under <code>./data/</code>) which connects to a <strong>local Meshtastic node</strong> over a serial port. Here’s outline of how data flows and is processed.
118
+
To fill those API endpoints, PotatoMesh uses a <strong>Python ingestor</strong> script ("mesh.sh" + supporting code under <code>./data/</code>) which connects to a <strong>local Meshtastic node</strong> over a serial or TCP port. Here's outline of how data flows and is processed.
118
119
</p>
119
120
120
121
<h3>Meshtastic protocol basics</h3>
121
122
<ul>
122
-
<li>Meshtastic devices communicate via <strong>Protobufs</strong>: structured message definitions in <code>.proto</code> files. These define things like <code>NodeInfo</code>, <code>MyNodeInfo</code>, <code>User</code>, messages, telemetry, etc. (<ahref="https://meshtastic.org/docs/development/reference/protobufs/?utm_source=chatgpt.com">meshtastic.org</a>)</li>
123
+
<li>Meshtastic devices communicate via encrypted <strong>protobufs</strong>: structured message definitions. These define things like <code>NodeInfo</code>, <code>MyNodeInfo</code>, <code>User</code>, messages, telemetry, positions, etc.</li>
123
124
<li>To talk to a Meshtastic node over USB/serial/TCP/BLE, there is a <strong>Client API</strong>. In that API:
124
125
<ol>
125
-
<li>When a client connects, it typically sends a <strong>startConfig</strong> (or <code>want_config_id</code>) protobuf to ask for the current NodeDB (nodes in mesh seen), the radio settings, user info, etc. (<ahref="https://meshtastic.org/docs/development/device/client-api/?utm_source=chatgpt.com">meshtastic.org</a>)</li>
126
-
<li>The node replies with a stream of <code>FromRadio</code> protobuf messages: first the configuration (radio config, user, mynode), then all known <code>NodeInfo</code> records, ending with an end-config marker. After that, mesh messages, telemetry, etc. (<ahref="https://meshtastic.org/docs/development/device/client-api/?utm_source=chatgpt.com">meshtastic.org</a>)</li>
126
+
<li>When a client connects, it typically sends a <strong>startConfig</strong> (or <code>want_config_id</code>) protobuf to ask for the current NodeDB (nodes in mesh seen), the radio settings, user info, etc.</li>
127
+
<li>The node replies with a stream of <code>FromRadio</code> protobuf messages: first the configuration (radio config, user, mynode), then the last 80 known <code>NodeInfo</code> records, ending with an end-config marker. After that, mesh messages, positions, telemetry, etc.</li>
127
128
</ol>
128
129
</li>
129
-
<li>Over serial or TCP, there is framing: i.e. Meshtastic uses a 4-byte header (START1=0x94, START2=0xc3, then two bytes length) to wrap each protobuf packet in streaming transports. If the stream is unreliable / loses bytes, there is synchronization logic. (<ahref="https://meshtastic.org/docs/development/device/client-api/?utm_source=chatgpt.com">meshtastic.org</a>)</li>
130
-
<li>Telemetry: nodes periodically report telemetry data (battery, environment, etc.) via defined protobuf messages. Also messages (text, chat), and node status / location / GPS. (<ahref="https://pole1.co.uk/blog/6/?utm_source=chatgpt.com">pole1.co.uk</a>)</li>
130
+
<li>Over serial or TCP, there is framing: i.e., Meshtastic uses a 4-byte header (START1=0x94, START2=0xc3, then two bytes length) to wrap each protobuf packet in streaming transports. If the stream is unreliable / loses bytes, there is synchronization logic.</li>
131
+
<li>Telemetry: nodes periodically report telemetry data (battery, environment, etc.) via defined protobuf messages. Also messages (text, chat), and node status / location / GPS.</li>
131
132
</ul>
132
133
133
-
<h3>Python ingestor in Potato-Mesh</h3>
134
+
<h3>Python ingestor in PotatoMesh</h3>
134
135
<p>What this script does:</p>
135
136
<ol>
136
-
<li><strong>Connect</strong> to a Meshtastic node on a serial port (e.g. <code>/dev/ttyACM0</code>), using the Meshtastic Python library. It sets things so that it receives the node database (NodeInfo etc.) and ongoing messages / telemetry as the mesh node sees them. (<ahref="https://github.com/l5yth/potato-mesh">GitHub</a>)</li>
137
+
<li><strong>Connect</strong> to a Meshtastic node on a serial port (e.g.,<code>/dev/ttyACM0</code>), using the Meshtastic Python library. It sets things so that it receives the node database (NodeInfo etc.) and ongoing messages / telemetry as the mesh node sees them.</li>
137
138
<li><strong>Parse</strong> each piece of data:
138
139
<ul>
139
-
<li>Whenever a <code>NodeInfo</code> or similar node status protobuf arrives, it constructs a “node” record (node ID, short name, etc.).</li>
140
+
<li>Whenever a <code>NodeInfo</code> or similar node status protobuf arrives, it constructs a "node" record (node ID, short name, etc.).</li>
140
141
<li>Whenever a message or telemetry arrives, collect the message: who from, to (broadcast or specific), type (text / telemetry / etc.), payload.</li>
141
142
</ul>
142
143
</li>
143
-
<li><strong>POST</strong> to the web app’s endpoints:
144
+
<li><strong>POST</strong> to the web app's endpoints:
144
145
<ul>
145
146
<li>Node updates via <code>POST /api/nodes</code></li>
146
147
<li>Message / telemetry / chat data via <code>POST /api/messages</code></li>
147
148
</ul>
148
-
<p>The tool (via environment variables) knows the instance URL and API token to use. It ensures deduplication on node IDs etc., so repeated reports of the same node do not create duplicates. (<ahref="https://github.com/l5yth/potato-mesh">GitHub</a>)</p>
149
+
<p>The tool (via environment variables) knows the instance URL and API token to use. The web app ensures deduplication on node IDs etc., so repeated reports of the same node do not create duplicates.</p>
149
150
</li>
150
-
<li><strong>Continuous listening / looping</strong>: the ingestor sits waiting for new protobuf messages via the serial stream. When new messages show up, they’re parsed & forwarded. In debug mode you can see logs like “upserted node …” or “stored message …” etc. (<ahref="https://github.com/l5yth/potato-mesh">GitHub</a>)</li>
151
+
<li><strong>Continuous listening / looping</strong>: the ingestor sits waiting for new protobuf messages via the serial stream. When new messages show up, they're parsed & forwarded. In debug mode you can see logs like "upserted node …" or "stored message …" etc. Just set "DEBUG=1".</li>
151
152
</ol>
152
153
153
154
<hr/>
@@ -161,17 +162,16 @@ <h2>Summary & running</h2>
161
162
</ul>
162
163
<p>To try it:</p>
163
164
<ul>
164
-
<li>Demo is live at <strong>potatomesh.net</strong> for Berlin #MediumFast etc. (<ahref="https://github.com/l5yth/potato-mesh">GitHub</a>)</li>
165
-
<li>Instructions in the README: using Docker / docker-compose to launch the web app; configure environment (<code>API_TOKEN</code>, etc.). Then run the python ingestor with <code>POTATOMESH_INSTANCE=<url> API_TOKEN=<token> MESH_SERIAL=<serial port> DEBUG=1 ./mesh.sh</code> etc. (<ahref="https://github.com/l5yth/potato-mesh">GitHub</a>)</li>
165
+
<li>Demo is live at <strong>potatomesh.net</strong> for Berlin #MediumFast on 868MHz.</li>
166
+
<li>Instructions in the README: using Docker / docker-compose to launch the web app; configure environment (<code>API_TOKEN</code>, etc.). Then run the python ingestor with <code>POTATOMESH_INSTANCE=<url> API_TOKEN=<token> MESH_SERIAL=<serial port> DEBUG=1 ./mesh.sh</code> etc.</li>
166
167
</ul>
167
168
168
169
<hr/>
169
170
170
171
<h2>Call to action</h2>
171
172
<p>
172
-
Run your own Potato-Mesh. Hook a Meshtastic node (or several), run the ingestor, set up the web app, and suddenly you don’t fly blind. Debug routing, telemetry, battery, nodes that drop out, hops that get too high. The mesh always wants to talk — let’s listen.
173
+
Run your own PotatoMesh. Hook a Meshtastic node (or several), run the ingestor, set up the web app, and suddenly you don't fly blind. Debug routing, telemetry, battery, nodes that drop out, hops that get too high.
173
174
</p>
174
-
<p>Doom threat: the mesh networks left unknowable will fail when they are needed most. Better to build clarity now.</p>
0 commit comments