SimpleGUIChat - from Tkinter pop-out chat to mesh radio and dual PTT

A 2022 Python socket chat experiment that grew into MANET radio networking work and dual push-to-talk over IP mesh - lineage from localhost:9090 to field comms.

Before Django-Auto-Forum and before any of the Astro work on this site, there was a much smaller question: can a website spawn a pop-out chat window that feels like IRC, without living inside the browser tab?

That question became SimpleGUIChat: a Python Tkinter client and TCP socket server uploaded to GitHub on 22 July 2022, early in Zip Code Wilmington cohort 3.1. The repo description still states the original intent: Python based Tkinter chat for pop-out messaging integration into websites.

Project dossier (scope, file BOM, limits): SimpleGUIChat.

It looks humble now. It was the first time real-time messaging was treated as infrastructure instead of a tutorial exercise.

What the repo actually is

The project is a merged fork of NeuralNine's chat tutorial and The Learners of the Python Forum chat sample. The README sketches an IRC-like privilege model (Owner, Admin, Moderator, Trusted, Quiet, Silent, Banned) that never fully landed. The README itself admits it would be recompleted after recovering from the shock of deleting the only copy.

The running code is simpler:

  • server.py: binds 127.0.0.1:9090, accepts clients, collects nicknames, broadcasts every message to every connected socket
  • client.py: connects, prompts for a nickname, runs two threads (GUI loop + receive loop), renders a scrollable text area and send box in Tkinter

Comments in the client spell out the intent never finished in that repo:

# front end for chat interface
# must be built out, then built into web forum

And on the server:

# need to expand for DB lookup
# can pull from main DB for website

So even in July 2022 the architecture was pointing toward Django-Auto-Forum: browser forum as system of record, desktop pop-out as the live layer. The forum skeleton followed that fall. The chat bridge stayed a sketch.

What worked (and what did not)

What worked: proving the threading model. Tkinter on the main thread, recv() on a worker, send() from button callbacks: the minimum viable pattern for a GUI that also talks to the network. The server side showed the same shape: accept loop plus per-client handler threads.

What did not: everything that makes chat production-safe. No TLS, no auth beyond a self-chosen nickname, no persistence, no backpressure, no message framing beyond raw bytes, and a client GUI bug where self.text_area gets reassigned to a Label mid-gui_loop. The code is honest about that (# bad implementation appears more than once).

That is fine. The repo was a socket literacy milestone, not a product launch.

The line from chat sockets to radio networks

Here is the part the GitHub README does not cover, because it had not happened yet when the files went up.

SimpleGUIChat prompted thinking about who hears what, when, and over which medium. Broadcast-to-all TCP is the naïve version of a net. Real comms (at a track, on a convoy, in a paddock with spotty LTE) are not naïve:

  • Topology changes as people move (classic MANET, mobile ad-hoc network, behavior)
  • Voice beats typing when hands are full (PTT, push-to-talk)
  • One radio path is rarely enough; dual PTT matters: for example analog FM for the immediate crew plus an IP mesh backhaul for wider coordination, or two logical channels on the same mesh stack

That arc continues in field radio and mesh work:

SimpleGUIChat (2022)Field radio / mesh work (now)
TCP broadcast to all clientsMANET-style routing across moving nodes
Text in a Tkinter windowPush-to-talk voice with floor control
Single localhost serverIP mesh nodes that survive without central infra
Nickname handshakeCallsigns, groups, and dual-channel discipline

The engineering rhyme is direct: session setup, membership, floor control, fan-out. A chat server broadcasting UTF-8 strings and a mesh node forwarding voice frames are different on the wire, but the design questions overlap. Who is connected? Who is allowed to talk? What happens when a node drops? How do you avoid everyone keying at once?

Dual PTT over IP mesh (where it is heading)

"Dual PTT" in the sense that matters for field comms is not two buttons glued together for aesthetics. It is two concurrent comms planes with clear roles:

  1. Local / immediate: low-latency analog or short-range digital for the people next to you
  2. Mesh / IP: self-healing packet radio or Wi‑Fi mesh carrying voice or data when towers and venue Wi‑Fi fail

IP mesh networking (Reticulum-style logical addressing, Meshtastic-style LoRa meshes, or hybrid builds with off-the-shelf radios and custom gateways) is attractive because it treats the network as participants forwarding for each other, not a single server on :9090. That is much closer to MANET reality than the 2022 chat server ever was.

The work in progress, including event-radio buildouts documented separately, covers:

  • Node roles: fixed pit nodes vs roving spotters vs car-mounted relays
  • Channel separation: crew tactical vs logistics vs public safety awareness
  • Dual PTT ergonomics: one physical PTT for RF, one for mesh VoIP or data PTT, without cross-keying
  • Fallback: when mesh partitions, local RF still works; when RF is congested, mesh text/voice backup still routes

None of that is in the SimpleGUIChat repo. All of it traces back to the same itch: reliable group comms you control, whether the payload is {nickname}: hello or a keyed mic frame routed through six hops.

Epilogue

SimpleGUIChat will never be pinned for its UI polish. It remains on GitHub because it marks the fork in the road: from learning Python to designing networks.

The Django forum work captured async text on the web. The mesh/MANET work captures sync voice and data in places where the web does not reach. heff.world documents both threads. If you are building dual PTT over IP mesh and started life with a Tkinter chat box on localhost, you are in good company.

Repository: github.com/jjheffernan/SimpleGUIChat.

関連記事