[FEAT] VirtualNode support #166

Closed
opened 2026-10-05 02:01:18 +02:00 by adam · 21 comments
Owner

I’m posting this initially as a request for feedback, since I’m not sure if it’s possible to implement this with MeshCore. The idea is to replicate what MeshMonitor currently does with virtual nodes, let me explain.

A virtual node would involve having RemoteTerm listen on a port and act as a relay to the actual MeshCore node, like this:

Mobile App  ┐
Other App   ├─ Virtual Node (5000) ─ RemoteTerm ─ MeshCore Node (5000)
Some Client ┘

This way, you could have multiple applications connected to the same node.

As I understand it, the “trick” lies in serializing the process. You support multiple connections, but instead of running them in parallel, you queue them one after another.

Obviously, this is just a suggestion, and as I mentioned at the beginning, I’m not sure if it’s possible to do with MeshCore.

I’m posting this initially as a request for feedback, since I’m not sure if it’s possible to implement this with MeshCore. The idea is to replicate what [MeshMonitor currently does with virtual nodes](https://meshmonitor.org/configuration/virtual-node.html), let me explain. A virtual node would involve having RemoteTerm listen on a port and act as a relay to the actual MeshCore node, like this: ``` Mobile App ┐ Other App ├─ Virtual Node (5000) ─ RemoteTerm ─ MeshCore Node (5000) Some Client ┘ ``` This way, you could have multiple applications connected to the same node. As I understand it, the “trick” lies in serializing the process. You support multiple connections, but instead of running them in parallel, you queue them one after another. Obviously, this is just a suggestion, and as I mentioned at the beginning, I’m not sure if it’s possible to do with MeshCore. <!-- github-sync-id:4341101446 -->
adam closed this issue 2026-10-05 02:01:18 +02:00
Author
Owner

why not use actual meshmonitor then before remoteterm?

why not use actual meshmonitor then before remoteterm? <!-- github-comment-id:4333162566 -->
Author
Owner

why not use actual meshmonitor then before remoteterm?

As far as I know, the virtual node only works with Meshtastic.

> why not use actual meshmonitor then before remoteterm? As far as I know, the virtual node only works with Meshtastic. <!-- github-comment-id:4333900773 -->
Author
Owner

@ogarcia

ah, i see, that's meshtastic, sorry. i'm using my own ai-coded simple multiplexer, not sure if it works correctly, but it works for me. i'm using it with official meshcore app to monitor live noise floor log or live discover of repeaters because remoteterm misses this)

https://gist.github.com/hackruu/03b1c5902b62a42c8af8ddef93663f16 maybe you can fit it your workflow

@ogarcia ah, i see, that's meshtastic, sorry. i'm using my own ai-coded simple multiplexer, not sure if it works correctly, but it works for me. i'm using it with official meshcore app to monitor live noise floor log or live discover of repeaters because remoteterm misses this) https://gist.github.com/hackruu/03b1c5902b62a42c8af8ddef93663f16 maybe you can fit it your workflow <!-- github-comment-id:4334039690 -->
Author
Owner

https://gist.github.com/hackruu/03b1c5902b62a42c8af8ddef93663f16 maybe you can fit it your workflow

I'll take a look, I'm sure it'll work for me 👍

> https://gist.github.com/hackruu/03b1c5902b62a42c8af8ddef93663f16 maybe you can fit it your workflow I'll take a look, I'm sure it'll work for me 👍 <!-- github-comment-id:4334902019 -->
Author
Owner

Just to toss it in the ring (I know discord folks have already seen this), I vibe coded a prototype tcp proxy as well at https://github.com/jkingsman/Remote-Terminal-for-MeshCore/tree/tcp-proxy (enable with env var MESHCORE_TCP_PROXY_ENABLED=true). If there's a consensus on superior proxy, happy to link to it in the readme.

Also

live noise floor log or live discover of repeaters

RemoteTerm exposes noise floor on the statistics page, and discovery packets are supported from the radio settings page, if those are what you mean 🙂

Just to toss it in the ring (I know discord folks have already seen this), I vibe coded a prototype tcp proxy as well at https://github.com/jkingsman/Remote-Terminal-for-MeshCore/tree/tcp-proxy (enable with env var `MESHCORE_TCP_PROXY_ENABLED=true`). If there's a consensus on superior proxy, happy to link to it in the readme. Also > live noise floor log or live discover of repeaters RemoteTerm exposes noise floor on the statistics page, and discovery packets are supported from the radio settings page, if those are what you mean 🙂 <!-- github-comment-id:4336389954 -->
Author
Owner

I vibe coded a prototype tcp proxy as well at https://github.com/jkingsman/Remote-Terminal-for-MeshCore/tree/tcp-proxy.

Yes, this is definitely a much better solution.

I was just getting started with a pure TCP approach, which does work, but of course, if one client does something, the other one doesn't know anything about it. Plus, the node doesn't really appreciate it when you reset its counters.

> I vibe coded a prototype tcp proxy as well at https://github.com/jkingsman/Remote-Terminal-for-MeshCore/tree/tcp-proxy. Yes, this is definitely a much better solution. I was just getting started with a pure TCP approach, which does work, but of course, if one client does something, the other one doesn't know anything about it. Plus, the node doesn't really appreciate it when you reset its counters. <!-- github-comment-id:4336788261 -->
Author
Owner

@jkingsman it's not as live(realtime) as in official app :)

@jkingsman it's not as live(realtime) as in official app :) <!-- github-comment-id:4337222848 -->
Author
Owner

The noise floor is sampled once per minute; is that what you mean? If not, are you meaning impulse repeater discovery or addition on advert? RemoteTerm will add new repeaters as soon as they're advertised (not trying to derail this discussion about TCP proxying; just curious)

The noise floor is sampled once per minute; is that what you mean? If not, are you meaning impulse repeater discovery or addition on advert? RemoteTerm will add new repeaters as soon as they're advertised (not trying to derail this discussion about TCP proxying; just curious) <!-- github-comment-id:4337312869 -->
Author
Owner

yes, official app shows live noise floor with 1update/s interval.

same goes for discover repeaters button, i get repeaters names as they respond, not when discover timeout is reached as in remoteterm

yes, official app shows live noise floor with 1update/s interval. same goes for discover repeaters button, i get repeaters names as they respond, not when discover timeout is reached as in remoteterm <!-- github-comment-id:4337326573 -->
Author
Owner

not the dealbreakers but it's why i'm using this tcp multiplexer

not the dealbreakers but it's why i'm using this tcp multiplexer <!-- github-comment-id:4337333460 -->
Author
Owner

I vibe coded a prototype tcp proxy as well at https://github.com/jkingsman/Remote-Terminal-for-MeshCore/tree/tcp-proxy

I'm testing it thoroughly right now. The client connects to the proxy just fine, but beyond that, it doesn't do much else (at least in the messaging part, which is what I'm testing). If the node receives a message, it reaches RemoteTerm correctly but not the proxy client, and if the proxy client sends a message, it appears to simply be rejected with this message {'error_code': 2, 'code_string': 'ERR_CODE_NOT_FOUND'}.

> I vibe coded a prototype tcp proxy as well at https://github.com/jkingsman/Remote-Terminal-for-MeshCore/tree/tcp-proxy I'm testing it thoroughly right now. The client connects to the proxy just fine, but beyond that, it doesn't do much else (at least in the messaging part, which is what I'm testing). If the node receives a message, it reaches RemoteTerm correctly but not the proxy client, and if the proxy client sends a message, it appears to simply be rejected with this message `{'error_code': 2, 'code_string': 'ERR_CODE_NOT_FOUND'}`. <!-- github-comment-id:4338064337 -->
Author
Owner

Ugh, yeah. Emulating a line level protocol is miserable. I feel like I'm growing closer and closer to just abandoning the idea; it's not a maintenance burden I really think makes sense for a project like this. I'm happy to point folks to other projects, but I don't think maintaining what is, in essence, a MeshCore radio simulator is reasonable.

Ugh, yeah. Emulating a line level protocol is miserable. I feel like I'm growing closer and closer to just abandoning the idea; it's not a maintenance burden I really think makes sense for a project like this. I'm happy to point folks to other projects, but I don't think maintaining what is, in essence, a MeshCore radio simulator is reasonable. <!-- github-comment-id:4338167103 -->
Author
Owner

Yes, I understand it’s not simple. In fact, upon closer examination, given the way communication with a Meshcore node is currently implemented, what Meshmonitor would need to implement is exactly that: an emulation.

But I've thought of something that might be simpler: a stripped-down emulation. Basically, when a client connects, it would provide the list of known nodes and the list of channels, and then send conversations in real time as they're received (no need to store history). If that client sends a message, RemoteTerm would pick it up and send it. You don’t need anything else. The whole configuration thing and so on isn’t operational; if you want to change any of that, you do it from RemoteTerm or disconnect and connect whatever you want in its place.

Yes, I understand it’s not simple. In fact, upon closer examination, given the way communication with a Meshcore node is currently implemented, what Meshmonitor would need to implement is exactly that: an emulation. But I've thought of something that might be simpler: a stripped-down emulation. Basically, when a client connects, it would provide the list of known nodes and the list of channels, and then send conversations in real time as they're received (no need to store history). If that client sends a message, RemoteTerm would pick it up and send it. You don’t need anything else. The whole configuration thing and so on isn’t operational; if you want to change any of that, you do it from RemoteTerm or disconnect and connect whatever you want in its place. <!-- github-comment-id:4346438465 -->
Author
Owner

That's already implemented in my branch. It works perfectly for me locally. The trick is figuring out all the different quirks that various clients have or engage in to get the radio to behave; as you can see on this thread, and as has been discussed on discord, there are a number of clients that still have problems with it despite it working fine for me with the official Android application.

It's not the difficulty to build; it's been built. It's the difficulty to troubleshoot and get working smoothly with all clients on all platforms, and to keep it so, but I don't particularly care for haha

That's already implemented in my branch. It works perfectly for me locally. The trick is figuring out all the different quirks that various clients have or engage in to get the radio to behave; as you can see on this thread, and as has been discussed on discord, there are a number of clients that still have problems with it despite it working fine for me with the official Android application. It's not the difficulty to build; it's been built. It's the difficulty to troubleshoot and get working smoothly with all clients on all platforms, and to keep it so, but I don't particularly care for haha <!-- github-comment-id:4346498791 -->
Author
Owner

Yes, I actually cloned the branch and set up a container with it, but it’s not quite working right. I’m connecting a client I built myself, which might not be 100% compatible with what’s already implemented.

The problem is probably with the channel mapping. I'll have to look into it more closely...

Yes, I actually cloned the branch and set up a container with it, but it’s not quite working right. I’m connecting a [client I built myself](https://github.com/ogarcia/mmrelay-meshcore-plugin), which might not be 100% compatible with what’s already implemented. The problem is probably with the channel mapping. I'll have to look into it more closely... <!-- github-comment-id:4346660399 -->
Author
Owner

Playing with the idea of creating a seperate project, that proxy between Meshcore apps and RemoteTerm, and using RemoteTerm as the source of truth.

Playing with the idea of creating a seperate project, that proxy between Meshcore apps and RemoteTerm, and using RemoteTerm as the source of truth. <!-- github-comment-id:4361274056 -->
Author
Owner

Right now, I'm testing out several modifications to the implementation I'm working on as a client. If I connect directly to the node, everything works fine. If I connect through RemoteTerm, I always get a “Channel does not exist” error:

{'error_code': 2, 'code_string': 'ERR_CODE_NOT_FOUND'}

My code is straightforward: it calls mc.commands.send_chan_msg(idx, message), where idx is the channel’s numeric ID. I’m not exactly sure why the relay that RemoteTerm uses isn’t accepting it, but that’s just how it is.

Right now, I'm testing out several modifications to the implementation I'm working on as a client. If I connect directly to the node, everything works fine. If I connect through RemoteTerm, I always get a “Channel does not exist” error: ``` {'error_code': 2, 'code_string': 'ERR_CODE_NOT_FOUND'} ``` My code is straightforward: it calls `mc.commands.send_chan_msg(idx, message)`, where idx is the channel’s numeric ID. I’m not exactly sure why the relay that RemoteTerm uses isn’t accepting it, but that’s just how it is. <!-- github-comment-id:4361409628 -->
Author
Owner

Ahh yeah I was having some difficulty keeping things straight between RemoteTerm channel I'd and the loaded slot. One of the many glitches that make me hesitant to mainline this in any way haha

Ahh yeah I was having some difficulty keeping things straight between RemoteTerm channel I'd and the loaded slot. One of the many glitches that make me hesitant to mainline this in any way haha <!-- github-comment-id:4361532478 -->
Author
Owner

Ahh yeah I was having some difficulty keeping things straight between RemoteTerm channel I'd and the loaded slot. One of the many glitches that make me hesitant to mainline this in any way haha

That's right; in fact, the log itself tells you so:

2026-05-01 20:42:10 - app.tcp_proxy.session - WARNING - [('192.168.1.123', 50966)] No channel at slot 0

It is certainly no easy task to build a virtual node that behaves just like the real one.

> Ahh yeah I was having some difficulty keeping things straight between RemoteTerm channel I'd and the loaded slot. One of the many glitches that make me hesitant to mainline this in any way haha That's right; in fact, the log itself tells you so: ``` 2026-05-01 20:42:10 - app.tcp_proxy.session - WARNING - [('192.168.1.123', 50966)] No channel at slot 0 ``` It is certainly no easy task to build a virtual node that behaves just like the real one. <!-- github-comment-id:4361568138 -->
Author
Owner

I'm gonna close this for now. I'll keep the code in the branch, but I think this is something that needs a lot more love than I'm wanting to give it right now hah.

I'm gonna close this for now. I'll keep the code in the branch, but I think this is something that needs a lot more love than I'm wanting to give it right now hah. <!-- github-comment-id:4446300196 -->
Author
Owner

In the end, I ended up making myself a little splitter. It works for me, but there might be some unchecked bugs. If you're interested, I've left it here: https://github.com/ogarcia/coresplitter

In the end, I ended up making myself a little splitter. It works for me, but there might be some unchecked bugs. If you're interested, I've left it here: https://github.com/ogarcia/coresplitter <!-- github-comment-id:4502126774 -->
Sign in to join this conversation.
No labels
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: adam/Remote-Terminal-for-MeshCore#166