Browse Source

mqtt 断线重连

样式分支
pry 2 years ago
parent
commit
86fa450cd5
11 changed files with 548 additions and 132 deletions
  1. +1
    -2
      BPASmartClient.Business/Plugin/MQTTMgr.cs
  2. +7
    -0
      BPASmartClient.CustomResource/BPASmartClient.CustomResource.csproj
  3. BIN
     
  4. +262
    -86
      BPASmartClient.CustomResource/Pages/View/LoginView.xaml
  5. +52
    -4
      BPASmartClient.CustomResource/Pages/View/LoginView.xaml.cs
  6. +6
    -1
      BPASmartClient.CustomResource/Pages/View/MainView.xaml
  7. +1
    -0
      BPASmartClient.CustomResource/Pages/View/MainView.xaml.cs
  8. BIN
     
  9. BIN
     
  10. +1
    -3
      BPASmartClient.MQTT/BPASmartClient.MQTT.csproj
  11. +218
    -36
      BPASmartClient.MQTT/MQTTProxy.cs

+ 1
- 2
BPASmartClient.Business/Plugin/MQTTMgr.cs View File

@@ -46,12 +46,11 @@ namespace BPASmartClient.Business
mqttProxy.Connected = new Action(() =>
{
mqttProxy.Subscrib(TopicDefine.GetInstance().SubscribTopics.ToArray());
MessageLog.GetInstance.Show("MQTT 连接成功");
});
//MQTT 连接成功
mqttProxy.LostConnect = new Action(() =>
{
MqttHelper.GetInstance().MqttSubscriptionAsync(TopicDefine.GetInstance().SubscribTopics.ToArray());
mqttProxy.Subscrib(TopicDefine.GetInstance().SubscribTopics.ToArray());
});
//MQTT 数据接收
mqttProxy.MessageRecive = new Action<string>((message) =>


+ 7
- 0
BPASmartClient.CustomResource/BPASmartClient.CustomResource.csproj View File

@@ -188,6 +188,13 @@
<None Remove="Image\顶部线条.png" />
<None Remove="Image\顶部背景.png" />
<None Remove="Image\黑菠萝科技.png" />
<None Remove="Videos\Login.mp4" />
</ItemGroup>

<ItemGroup>
<Content Include="Videos\Login.mp4">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</Content>
</ItemGroup>

<ItemGroup>


BIN
View File


+ 262
- 86
BPASmartClient.CustomResource/Pages/View/LoginView.xaml View File

@@ -8,8 +8,8 @@
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:vm="clr-namespace:BPASmartClient.CustomResource.Pages.ViewModel"
Title="LoginView"
Width="500"
Height="300"
Width="1920"
Height="1080"
AllowsTransparency="True"
Background="{x:Null}"
Topmost="True"
@@ -63,9 +63,9 @@
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontFamily="../../Fonts/#iconfont"
FontSize="20"
FontSize="30"
Foreground="{TemplateBinding BorderBrush}"
Text="&#xe850;" />
Text="&#xe60c;" />

<!--<TextBlock
Name="markText"
@@ -144,7 +144,7 @@
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontFamily="../../Fonts/#iconfont"
FontSize="20"
FontSize="30"
Foreground="{TemplateBinding BorderBrush}"
Text="&#xe66d;" />

@@ -191,9 +191,157 @@
</Style>
<!--#endregion-->

<!--#region 操作按钮样式-->
<Style x:Key="ButtonStyle" TargetType="Button">
<Setter Property="Margin" Value="20,20" />
<Setter Property="Background" Value="#cc009DFF" />
<Setter Property="BorderThickness" Value="0" />
<Setter Property="FontSize" Value="30" />
<Setter Property="Foreground" Value="White" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border
Name="TitleBarBr"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="20">
<ContentPresenter
Margin="{TemplateBinding Margin}"
HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="{TemplateBinding VerticalContentAlignment}" />
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="true">
<Setter TargetName="TitleBarBr" Property="Background" Value="#009DFF" />
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!--#endregion-->

</Window.Resources>

<Border
<Grid>
<MediaElement
Name="player"
HorizontalAlignment="Center"
VerticalAlignment="Center"
LoadedBehavior="Manual" />

<!--<MediaElement
Name="player"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Source="../../Videos/Login.mp4"
LoadedBehavior="Play">
<MediaElement.Triggers>
<EventTrigger RoutedEvent="MediaElement.Loaded">
<EventTrigger.Actions>
<BeginStoryboard>
<Storyboard>
<MediaTimeline
RepeatBehavior="Forever"
Source="../../Videos/Login.mp4"
Storyboard.TargetName="player" />
</Storyboard>
</BeginStoryboard>
</EventTrigger.Actions>
</EventTrigger>
</MediaElement.Triggers>
</MediaElement>-->

<Grid x:Name="grid" Margin="400,180">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>

<TextBlock
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="40"
Foreground="#009DFF"
Text="用户登录" />

<TextBlock
Grid.Row="4"
HorizontalAlignment="Center"
VerticalAlignment="Center"
FontSize="30"
Foreground="#FFEF2020"
Text="{Binding ErrorInfo}" />

<TextBox
Grid.Row="1"
Margin="20,20"
BorderBrush="#009DFF"
BorderThickness="3"
FontSize="30"
Foreground="#009DFF"
Style="{DynamicResource UserTextBoxStyle}"
TabIndex="1"
Text="{Binding UserName}" />

<PasswordBox
Name="pb"
Grid.Row="2"
Margin="20,20"
common:PasswordHelper.Attach="True"
common:PasswordHelper.Password="{Binding Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
BorderBrush="#009DFF"
BorderThickness="3"
FontSize="30"
Foreground="#009DFF"
PasswordChanged="PasswordBox_PasswordChanged"
Style="{DynamicResource PasswordBoxStyle}"
TabIndex="2" />

<TextBlock
Name="markText"
Grid.Row="2"
Margin="70,5"
HorizontalAlignment="Left"
VerticalAlignment="Center"
FontSize="30"
Foreground="#88009dff"
IsHitTestVisible="False"
Text="请输入账号密码"
Visibility="Visible" />

<Grid Grid.Row="3">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>

<Button
Command="{Binding ExitCommand}"
Content="退 出"
Style="{StaticResource ButtonStyle}" />

<Button
Grid.Column="1"
Command="{Binding LoginCommand}"
Content="登 录"
Style="{StaticResource ButtonStyle}"
TabIndex="3" />

</Grid>

</Grid>


</Grid>


<!--<Border
x:Name="br"
BorderBrush="#009dff"
BorderThickness="2">
@@ -204,103 +352,131 @@
Color="#009DFF" />
</Border.Effect>
<Grid>
<Image Source="../../Image/登录界面背景.jpg" Stretch="Fill" />
<Image Source="../../Image/阴影边框.png" Stretch="Fill" />
-->
<!--<Image Source="../../Image/登录界面背景1.jpg" Stretch="Fill" />
<Image Source="../../Image/阴影边框.png" Stretch="Fill" />-->
<!--
<Border
Width="400"
Height="260"
Margin="0,0,0,250"
BorderBrush="#009dff"
BorderThickness="2">
<Border.Effect>
<DropShadowEffect
BlurRadius="10"
ShadowDepth="1"
Color="#009DFF" />
</Border.Effect>

<Grid Width="400" Height="260">
-->
<!--<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>-->

<Grid Margin="50,20">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>

<TextBlock
Margin="0,10,0,0"
HorizontalAlignment="Center"
FontSize="20"
Foreground="#ddd"
Text="用户登录" />

<TextBlock
Margin="20,10,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
FontSize="16"
Foreground="#FFEF2020"
Text="{Binding ErrorInfo}" />

<TextBox
Grid.Row="1"
Height="40"
Margin="20,0"
BorderBrush="#009DFF"
FontSize="16"
Foreground="#aadddddd"
Style="{DynamicResource UserTextBoxStyle}"
TabIndex="1"
Text="{Binding UserName}" />

<PasswordBox
Name="pb"
Grid.Row="2"
Height="40"
Margin="20,0"
common:PasswordHelper.Attach="True"
common:PasswordHelper.Password="{Binding Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
BorderBrush="#009DFF"
FontSize="16"
Foreground="#aadddddd"
PasswordChanged="PasswordBox_PasswordChanged"
Style="{DynamicResource PasswordBoxStyle}"
TabIndex="2" />

<TextBlock
Name="markText"
Grid.Row="2"
Margin="70,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
FontSize="20"
Foreground="#88009dff"
IsHitTestVisible="False"
Text="请输入账号密码"
Visibility="Visible" />


<Grid Grid.Row="3">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>

<Button
Margin="20,10"
Background="#009DFF"
BorderThickness="0"
Command="{Binding ExitCommand}"
Content="退 出"
<!--<TextBlock
Margin="0,10,0,0"
HorizontalAlignment="Center"
FontSize="20"
Foreground="White" />

<Button
Grid.Column="1"
Margin="20,10"
Background="#009DFF"
BorderThickness="0"
Command="{Binding LoginCommand}"
Content="登 录"
Foreground="#ddd"
Text="用户登录" />

<TextBlock
Margin="20,10,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Bottom"
FontSize="16"
Foreground="#FFEF2020"
Text="{Binding ErrorInfo}" />

<TextBox
Grid.Row="1"
Height="40"
Margin="20,0"
BorderBrush="#009DFF"
FontSize="16"
Foreground="#009DFF"
Style="{DynamicResource UserTextBoxStyle}"
TabIndex="1"
Text="{Binding UserName}" />

<PasswordBox
Name="pb"
Grid.Row="2"
Height="40"
Margin="20,0"
common:PasswordHelper.Attach="True"
common:PasswordHelper.Password="{Binding Password, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
BorderBrush="#009DFF"
FontSize="16"
Foreground="#009DFF"
PasswordChanged="PasswordBox_PasswordChanged"
Style="{DynamicResource PasswordBoxStyle}"
TabIndex="2" />

<TextBlock
Name="markText"
Grid.Row="2"
Margin="70,0"
HorizontalAlignment="Left"
VerticalAlignment="Center"
FontSize="20"
Foreground="White"
TabIndex="3" />
Foreground="#88009dff"
IsHitTestVisible="False"
Text="请输入账号密码"
Visibility="Visible" />




<Grid Grid.Row="3">
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>

<Button
Margin="20,10"
Background="#009DFF"
BorderThickness="0"
Command="{Binding ExitCommand}"
Content="退 出"
FontSize="20"
Foreground="White" />

<Button
Grid.Column="1"
Margin="20,10"
Background="#009DFF"
BorderThickness="0"
Command="{Binding LoginCommand}"
Content="登 录"
FontSize="20"
Foreground="White"
TabIndex="3" />

</Grid>-->
<!--

</Grid>

</Grid>
</Border>
</Grid>

</Border>

-->
<!--<Grid x:Name="gr">
<Grid.Background>
<ImageBrush Opacity="0.8" ImageSource="../../Image/登录界面背景.jpg" />


+ 52
- 4
BPASmartClient.CustomResource/Pages/View/LoginView.xaml.cs View File

@@ -1,8 +1,11 @@
using BPASmartClient.Helper;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
@@ -23,15 +26,60 @@ namespace BPASmartClient.CustomResource.Pages.View
public LoginView()
{
InitializeComponent();
this.br.MouseLeftButtonDown += (o, e) =>
{
if (e.LeftButton == MouseButtonState.Pressed) this.DragMove();
};
grid.Visibility = Visibility.Collapsed;
this.Loaded += LoginView_Loaded;
this.WindowState = WindowState.Maximized;
ActionManage.GetInstance.CancelRegister("LoginOk");
ActionManage.GetInstance.CancelRegister("ExitAction");
ActionManage.GetInstance.Register(new Action(() => { this.DialogResult = true; this.Close(); }), "LoginOk");
ActionManage.GetInstance.Register(new Action(() => { this.DialogResult = false; this.Close(); }), "ExitAction");
}

private void LoginView_Loaded(object sender, RoutedEventArgs e)
{
string path = @"Videos\Login.mp4";
if (File.Exists(path))
{
// 绑定视频文件
player.Source = new Uri(path);

// 交互式控制
player.LoadedBehavior = MediaState.Manual;

// 添加元素加载完成事件 -- 自动开始播放
player.Loaded += new RoutedEventHandler(media_Loaded);

// 添加媒体播放结束事件 -- 重新播放
player.MediaEnded += new RoutedEventHandler(media_MediaEnded);

// 添加元素卸载完成事件 -- 停止播放
player.Unloaded += new RoutedEventHandler(media_Unloaded);

player.MediaOpened += Player_MediaOpened;
}
}

private void Player_MediaOpened(object sender, RoutedEventArgs e)
{
grid.Visibility = Visibility.Visible;
}

private void media_Loaded(object sender, RoutedEventArgs e)
{
(sender as MediaElement).Play();
}

private void media_MediaEnded(object sender, RoutedEventArgs e)
{
// MediaElement需要先停止播放才能再开始播放,
// 否则会停在最后一帧不动
(sender as MediaElement).Stop();
(sender as MediaElement).Play();
}

private void media_Unloaded(object sender, RoutedEventArgs e)
{
(sender as MediaElement).Stop();
}

private void PasswordBox_PasswordChanged(object sender, RoutedEventArgs e)


+ 6
- 1
BPASmartClient.CustomResource/Pages/View/MainView.xaml View File

@@ -320,17 +320,22 @@
HorizontalAlignment="Right"
Columns="3">
<Button
Visibility="Hidden"
IsEnabled="False"
Name="ButMin"
Content="&#xe664;"
Style="{StaticResource TitleBarStyle}" />
<Button
Visibility="Hidden"
IsEnabled="False"
Name="ButMax"
Content="&#xe65d;"
FontSize="22"
Style="{StaticResource TitleBarStyle}" />
<Button
Name="ButClose"
Content="&#xe639;"
Content="&#xe679;"
Foreground="Red"
Style="{StaticResource TitleBarStyle}" />
</UniformGrid>
<!--#endregion-->


+ 1
- 0
BPASmartClient.CustomResource/Pages/View/MainView.xaml.cs View File

@@ -23,6 +23,7 @@ namespace BPASmartClient.CustomResource.Pages.View
public MainView()
{
InitializeComponent();
this.WindowState = WindowState.Maximized;
this.ButMin.Click += (o, e) => { this.WindowState = WindowState.Minimized; };
this.ButMax.Click += (o, e) => { this.WindowState = this.WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized; };
this.ButClose.Click += (o, e) => { this.Close(); };


BIN
View File


BIN
View File


+ 1
- 3
BPASmartClient.MQTT/BPASmartClient.MQTT.csproj View File

@@ -5,9 +5,7 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="BPA.MQTTClient" Version="1.0.11" />
<PackageReference Include="BPA.MQTTnet" Version="1.0.3" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="6.0.1" />
<PackageReference Include="MQTTnet" Version="3.1.2" />
</ItemGroup>

<ItemGroup>


+ 218
- 36
BPASmartClient.MQTT/MQTTProxy.cs View File

@@ -1,76 +1,258 @@
using BPA.MQTTClient;
using Microsoft.Extensions.Configuration;
//using BPA.MQTTClient;
//using Microsoft.Extensions.Configuration;
//using MQTTnet.Client;
//using MQTTnet.Client;
//using MQTTnet;
//using MQTTnet.Client;
//using MQTTnet.Client.Options;
//using MQTTnet.Client.Receiving;
using BPASmartClient.Helper;
using BPASmartClient.Message;
using MQTTnet;
using MQTTnet.Client;
using MQTTnet.Client.Receiving;
using MQTTnet.Client.Options;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace BPASmartClient.MQTT
{
public class MQTTProxy
{
private IMqttClient client;
IMqttClientOptions options;
public Action<string> MessageRecive { get; set; }
public Action Connected { get; set; }
public Action LostConnect { get; set; }

public bool IsConnected { get; set; }

private IMqttClient client;
Action UseDisconnectedAction;


public async void Connect(string UserName, string pass, string IP, int port, string clientID)
{
options = new MqttClientOptionsBuilder().WithTcpServer(IP, port).WithClientId(clientID).WithCredentials(UserName, pass).Build();
client = new MqttFactory().CreateMqttClient();
client.UseDisconnectedHandler(c =>
{
if (UseDisconnectedAction == null)
{
Reconnect();//注册UseDisconnectedAction委托
UseDisconnectedAction();//执行委托
}

}).UseApplicationMessageReceivedHandler(c =>
{
MessageRecive?.Invoke(Encoding.UTF8.GetString(c.ApplicationMessage.Payload));
}).UseConnectedHandler((e) =>
{
//MessageLog.GetInstance.Show($"连接成功");
});

try
{
await client.ConnectAsync(options);
}
catch (Exception ex)
{
MessageLog.GetInstance.ShowEx(ex.Message);
MessageLog.GetInstance.Show("mqtt连接失败!重连执行中");
}

if (client.IsConnected)
{
MessageLog.GetInstance.Show("MQTT连接成功!");
Connected?.Invoke();
}

public void Connect(string userName, string Password, string ip, int port, string clientId)
}

private void Reconnect()
{
IConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
configurationBuilder.AddMqttClientHostedService(p =>
UseDisconnectedAction = new Action(() =>
{
p.Server = ip;
p.Port = port;
//p.UserName = "rafiul";
//p.Password = "12345678";
p.UserName = userName;
p.Password = Password;
p.mqttClientConnectedHandlerDelegate = new MQTTnet.Client.Connecting.MqttClientConnectedHandlerDelegate(e =>
MessageLog.GetInstance.ShowEx("MQTT 断开连接");
Thread.Sleep(2000);
while (!UniversalHelper.GetInstance().GetNetworkState())
{
IsConnected = true;
Connected?.Invoke();
});
//p.mqttClientDisconnectedHandlerDelegate = new MQTTnet.Client.Disconnecting.MqttClientDisconnectedHandlerDelegate(e =>
//{
// IsConnected = false;
// LostConnect?.Invoke();
//});
p.ConnectedResult += (s, e) =>
Thread.Sleep(2000);
}
bool ErrorFlag = false;
while (!client.IsConnected)
{
client = e;
};
p.MqttApplicationMessageReceivedHandler = new MqttApplicationMessageReceivedHandlerDelegate(e =>
try
{
MessageLog.GetInstance.Show($"重连中");
client.ConnectAsync(options).Wait();
}
catch (Exception ex)
{
if (!ErrorFlag)
{
MessageLog.GetInstance.ShowEx(ex.ToString());
ErrorFlag = true;
}
}
Thread.Sleep(3000);
}

if (client.IsConnected)
{
MessageRecive?.Invoke(Encoding.Default.GetString(e.ApplicationMessage.Payload));
});
MessageLog.GetInstance.Show("MQTT重连成功!");
LostConnect?.Invoke();
}
UseDisconnectedAction = null;
});
}

public void CloseConnect()
/// <summary>
/// Mqtt 订阅
/// </summary>
/// <param name="topic">需要订阅的主题</param>
public async void MqttSubscriptionAsync(string topic)
{
client.Dispose();
if (client != null && client.IsConnected)
{
try
{
var result = await client.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic(topic).WithExactlyOnceQoS().Build());
}
catch { }
}
}

public async void Publish(string topic, string content)
/// <summary>
/// Mqtt 订阅
/// </summary>
/// <param name="topic">需要订阅的主题</param>
public async void Subscrib(params string[] topic)
{
if (client.IsConnected)
await client.PublishAsync(topic, content);
if (client != null && client.IsConnected)
{
try
{
foreach (var item in topic)
{
var result = await client.SubscribeAsync(new MqttTopicFilterBuilder().WithTopic(item).WithExactlyOnceQoS().Build());
}
}
catch { }
}
}

public async void Subscrib(params string[] topics)
/// <summary>
/// Mqtt 发布
/// </summary>
/// <param name="topic">需要发布的主题</param>
/// <param name="content">需要发布的内容</param>
public async void Publish(string topic, string content)
{
foreach (var topic in topics)
if (client != null && client.IsConnected)
{
await client.SubscribeAsync(new MqttTopicFilter() { Topic = topic, QualityOfServiceLevel = MQTTnet.Protocol.MqttQualityOfServiceLevel.AtMostOnce });
var msg = new MqttApplicationMessageBuilder().WithTopic(topic).WithPayload(content).WithExactlyOnceQoS().Build();
try
{
var result = await client.PublishAsync(msg);
}
catch { }
}
}


































//public Action<string> MessageRecive { get; set; }
//public Action Connected { get; set; }
//public Action LostConnect { get; set; }

//public bool IsConnected { get; set; }

//private IMqttClient client;

//public void Connect(string userName, string Password, string ip, int port, string clientId)
//{
// IConfigurationBuilder configurationBuilder = new ConfigurationBuilder();
// configurationBuilder.AddMqttClientHostedService(p =>
// {
// p.Server = ip;
// p.Port = port;
// //p.UserName = "rafiul";
// //p.Password = "12345678";
// p.UserName = userName;
// p.Password = Password;
// p.mqttClientConnectedHandlerDelegate = new MQTTnet.Client.Connecting.MqttClientConnectedHandlerDelegate(e =>
// {
// IsConnected = true;
// Connected?.Invoke();
// });
// //p.mqttClientDisconnectedHandlerDelegate = new MQTTnet.Client.Disconnecting.MqttClientDisconnectedHandlerDelegate(e =>
// //{
// // IsConnected = false;
// // LostConnect?.Invoke();
// //});
// p.ConnectedResult += (s, e) =>
// {
// client = e;
// };
// p.MqttApplicationMessageReceivedHandler = new MqttApplicationMessageReceivedHandlerDelegate(e =>
// {
// MessageRecive?.Invoke(Encoding.Default.GetString(e.ApplicationMessage.Payload));
// });
// });
//}

public void CloseConnect()
{
client.Dispose();
}

//public async void Publish(string topic, string content)
//{
// if (client.IsConnected)
// await client.PublishAsync(topic, content);
//}

//public async void Subscrib(params string[] topics)
//{
// foreach (var topic in topics)
// {
// await client.SubscribeAsync(new MqttTopicFilter() { Topic = topic, QualityOfServiceLevel = MQTTnet.Protocol.MqttQualityOfServiceLevel.AtMostOnce });
// }
//}
}
}

Loading…
Cancel
Save