-
-
Notifications
You must be signed in to change notification settings - Fork 12
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #38 from meshtastic/wip
MQTT Client Proxy handling and v2.1.18 protos
- Loading branch information
Showing
15 changed files
with
1,406 additions
and
270 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"dotnet.defaultSolution": "Meshtastic.sln" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"dotnet.defaultSolution": "Meshtastic.Cli.sln" | ||
} |
106 changes: 106 additions & 0 deletions
106
Meshtastic.Cli/CommandHandlers/MqttProxyCommandHandler.cs
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
using Meshtastic.Data; | ||
using Meshtastic.Data.MessageFactories; | ||
using MQTTnet; | ||
using Meshtastic.Protobufs; | ||
using MQTTnet.Client; | ||
using Microsoft.Extensions.Logging; | ||
|
||
namespace Meshtastic.Cli.CommandHandlers; | ||
|
||
public class MqttProxyCommandHandler : DeviceCommandHandler | ||
{ | ||
public MqttProxyCommandHandler(DeviceConnectionContext context, CommandContext commandContext) : base(context, commandContext) { } | ||
|
||
public async Task<DeviceStateContainer> Handle() | ||
{ | ||
var wantConfig = new ToRadioMessageFactory().CreateWantConfigMessage(); | ||
var container = await Connection.WriteToRadio(wantConfig, CompleteOnConfigReceived); | ||
Connection.Disconnect(); | ||
return container; | ||
} | ||
|
||
public override async Task OnCompleted(FromRadio packet, DeviceStateContainer container) | ||
{ | ||
// connect to mqtt server with mqttnet | ||
var factory = new MqttFactory(); | ||
using var mqttClient = factory.CreateMqttClient(); | ||
MqttClientOptions options = GetMqttClientOptions(container); | ||
await mqttClient.ConnectAsync(options, CancellationToken.None); | ||
|
||
var root = String.IsNullOrWhiteSpace(container.LocalModuleConfig.Mqtt.Root) ? "msh" : container.LocalModuleConfig.Mqtt.Root; | ||
var prefix = $"{root}/{container.Metadata.FirmwareVersion.First()}"; | ||
var subscriptionTopic = $"{prefix}/#"; | ||
|
||
Logger.LogInformation($"Subscribing to topic: {subscriptionTopic}"); | ||
await mqttClient.SubscribeAsync(new MqttTopicFilterBuilder() | ||
.WithTopic(subscriptionTopic) | ||
.Build()); | ||
|
||
mqttClient.ApplicationMessageReceivedAsync += async e => | ||
{ | ||
if (e.ApplicationMessage.Topic.StartsWith($"{prefix}/stat/")) | ||
return; | ||
|
||
Logger.LogInformation($"Received MQTT from host on topic: {e.ApplicationMessage.Topic}"); | ||
|
||
// Get bytes from utf8 string | ||
var toRadio = new ToRadioMessageFactory() | ||
.CreateMqttClientProxyMessage(e.ApplicationMessage.Topic, e.ApplicationMessage.PayloadSegment.ToArray(), e.ApplicationMessage.Retain); | ||
Logger.LogDebug(toRadio.ToString()); | ||
await Connection.WriteToRadio(toRadio); | ||
}; | ||
|
||
await Connection.ReadFromRadio(async (fromRadio, container) => | ||
{ | ||
if (fromRadio?.PayloadVariantCase == FromRadio.PayloadVariantOneofCase.MqttClientProxyMessage && | ||
fromRadio.MqttClientProxyMessage is not null) | ||
{ | ||
var message = fromRadio.MqttClientProxyMessage; | ||
Logger.LogInformation($"Received MQTT message from device to proxy on topic: {message.Topic}"); | ||
if (message.PayloadVariantCase == MqttClientProxyMessage.PayloadVariantOneofCase.Data) | ||
{ | ||
Logger.LogDebug(ServiceEnvelope.Parser.ParseFrom(message.Data).ToString()); | ||
await mqttClient.PublishAsync(new MqttApplicationMessageBuilder() | ||
.WithTopic(message.Topic) | ||
.WithPayload(message.Data.ToByteArray()) | ||
.WithRetainFlag(message.Retained) | ||
.Build()); | ||
} | ||
else if (message.PayloadVariantCase == MqttClientProxyMessage.PayloadVariantOneofCase.Text) | ||
{ | ||
Logger.LogDebug(message.Text); | ||
await mqttClient.PublishAsync(new MqttApplicationMessageBuilder() | ||
.WithTopic(message.Topic) | ||
.WithPayload(message.Text) | ||
.WithRetainFlag(message.Retained) | ||
.Build()); | ||
} | ||
} | ||
return false; | ||
}); | ||
} | ||
|
||
private MqttClientOptions GetMqttClientOptions(DeviceStateContainer container) | ||
{ | ||
var builder = new MqttClientOptionsBuilder() | ||
.WithClientId(container.GetDeviceNodeInfo()?.User?.Id ?? container.MyNodeInfo.MyNodeNum.ToString()); | ||
|
||
var address = container.LocalModuleConfig.Mqtt.Address; | ||
var host = address.Split(':').FirstOrDefault() ?? container.LocalModuleConfig.Mqtt.Address; | ||
var port = address.Contains(":") ? address.Split(':').LastOrDefault() : null; | ||
|
||
if (container.LocalModuleConfig.Mqtt.TlsEnabled) | ||
{ | ||
builder = builder.WithTls() | ||
.WithTcpServer(host, Int32.Parse(port ?? "8883")); | ||
} | ||
else { | ||
builder = builder.WithTcpServer(host, Int32.Parse(port ?? "1883")); | ||
} | ||
|
||
if (container.LocalModuleConfig.Mqtt.Username is not null) | ||
builder = builder.WithCredentials(container.LocalModuleConfig.Mqtt.Username, container.LocalModuleConfig.Mqtt.Password); | ||
|
||
return builder.Build(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
using Meshtastic.Cli.Binders; | ||
using Meshtastic.Cli.CommandHandlers; | ||
using Meshtastic.Cli.Enums; | ||
using Microsoft.Extensions.Logging; | ||
|
||
namespace Meshtastic.Cli.Commands; | ||
public class MqttProxyCommand : Command | ||
{ | ||
public MqttProxyCommand(string name, string description, Option<string> port, Option<string> host, | ||
Option<OutputFormat> output, Option<LogLevel> log) : base(name, description) | ||
{ | ||
this.SetHandler(async (context, commandContext) => | ||
{ | ||
var handler = new MqttProxyCommandHandler(context, commandContext); | ||
await handler.Handle(); | ||
}, | ||
new DeviceConnectionBinder(port, host), | ||
new CommandContextBinder(log, output, new Option<uint?>("dest") { }, new Option<bool>("select-dest") { })); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
|
||
Microsoft Visual Studio Solution File, Format Version 12.00 | ||
# Visual Studio Version 17 | ||
VisualStudioVersion = 17.5.001.0 | ||
MinimumVisualStudioVersion = 10.0.40219.1 | ||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Meshtastic.Cli", "Meshtastic.Cli.csproj", "{A3FB32D2-954E-4D1D-B789-1E14AA5B2CB6}" | ||
EndProject | ||
Global | ||
GlobalSection(SolutionConfigurationPlatforms) = preSolution | ||
Debug|Any CPU = Debug|Any CPU | ||
Release|Any CPU = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(ProjectConfigurationPlatforms) = postSolution | ||
{A3FB32D2-954E-4D1D-B789-1E14AA5B2CB6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU | ||
{A3FB32D2-954E-4D1D-B789-1E14AA5B2CB6}.Debug|Any CPU.Build.0 = Debug|Any CPU | ||
{A3FB32D2-954E-4D1D-B789-1E14AA5B2CB6}.Release|Any CPU.ActiveCfg = Release|Any CPU | ||
{A3FB32D2-954E-4D1D-B789-1E14AA5B2CB6}.Release|Any CPU.Build.0 = Release|Any CPU | ||
EndGlobalSection | ||
GlobalSection(SolutionProperties) = preSolution | ||
HideSolutionNode = FALSE | ||
EndGlobalSection | ||
GlobalSection(ExtensibilityGlobals) = postSolution | ||
SolutionGuid = {CF056994-0472-486E-8D07-0D470536C40D} | ||
EndGlobalSection | ||
EndGlobal |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.