fajiao
2 years ago
41 changed files with 2210 additions and 172 deletions
@ -0,0 +1,12 @@ |
|||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
namespace EC.Util.Common; |
||||
|
|
||||
|
public static class SystemUtil |
||||
|
{ |
||||
|
[DllImport("Kernel32")] |
||||
|
public static extern void AllocConsole(); |
||||
|
|
||||
|
[DllImport("Kernel32")] |
||||
|
public static extern void FreeConsole(); |
||||
|
} |
Binary file not shown.
@ -1,10 +1,18 @@ |
|||||
<Application xmlns="https://github.com/avaloniaui" |
<Application xmlns="https://github.com/avaloniaui" |
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
xmlns:icons="using:Material.Icons.Avalonia" |
||||
|
xmlns:styles="using:Material.Styles.Themes" |
||||
x:Class="JiLinApp.App" |
x:Class="JiLinApp.App" |
||||
RequestedThemeVariant="Default"> |
RequestedThemeVariant="Default"> |
||||
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. --> |
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. --> |
||||
|
|
||||
<Application.Styles> |
<Application.Styles> |
||||
<FluentTheme /> |
<icons:MaterialIconStyles /> |
||||
|
<styles:MaterialTheme BaseTheme="Light" PrimaryColor="Blue" SecondaryColor="Lime" /> |
||||
|
<Style Selector="ComboBox"> |
||||
|
<Setter Property="MaxDropDownHeight" Value="350" /> |
||||
|
</Style> |
||||
|
<Style Selector="ComboBox:disabled Border[Name=PART_Border]"> |
||||
|
<Setter Property="BorderBrush" Value="#a6a6a6" /> |
||||
|
</Style> |
||||
</Application.Styles> |
</Application.Styles> |
||||
</Application> |
</Application> |
@ -0,0 +1,156 @@ |
|||||
|
<Window xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
||||
|
xmlns:components="using:JiLinApp.Components" |
||||
|
xmlns:controls="using:Material.Styles.Controls" |
||||
|
xmlns:assists="using:Material.Styles.Assists" |
||||
|
xmlns:icons="using:Material.Icons.Avalonia" |
||||
|
x:Class="JiLinApp.Components.CameraRealPlay" |
||||
|
Icon="/Assets/avalonia-logo.ico" |
||||
|
Title="RealPlay" Width="769" Height="397"> |
||||
|
<Window.Styles> |
||||
|
<!--PtzCtrlPanel--> |
||||
|
<Style Selector="#RealPlayGrid StackPanel[Name=PtzCtrlPanel]"> |
||||
|
<Setter Property="HorizontalAlignment" Value="Center" /> |
||||
|
<Setter Property="VerticalAlignment" Value="Center" /> |
||||
|
</Style> |
||||
|
<Style Selector="#PtzCtrlPanel StackPanel"> |
||||
|
<Setter Property="HorizontalAlignment" Value="Center" /> |
||||
|
<Setter Property="VerticalAlignment" Value="Center" /> |
||||
|
</Style> |
||||
|
<Style Selector="#PtzCtrlPanel StackPanel Button"> |
||||
|
<Setter Property="Width" Value="32" /> |
||||
|
<Setter Property="Height" Value="32" /> |
||||
|
<Setter Property="Padding" Value="0" /> |
||||
|
</Style> |
||||
|
<Style Selector="#PtzCtrlPanel StackPanel[(Grid.Column)=1] TextBlock"> |
||||
|
<Setter Property="Foreground" Value="#2b1f19" /> |
||||
|
<Setter Property="FontSize" Value="13" /> |
||||
|
</Style> |
||||
|
<Style Selector="#PtzCtrlPanel StackPanel:nth-child(n+10) Button"> |
||||
|
<Setter Property="Width" Value="27" /> |
||||
|
<Setter Property="Height" Value="27" /> |
||||
|
<Setter Property="Padding" Value="0" /> |
||||
|
</Style> |
||||
|
<Style Selector="#PtzCtrlPanel ComboBox[Name=PresetIdCbx] > StackPanel"> |
||||
|
<Setter Property="Width" Value="100" /> |
||||
|
</Style> |
||||
|
<Style Selector="#PtzCtrlPanel Button[Name=GotoBtn]"> |
||||
|
<Setter Property="Width" Value="100" /> |
||||
|
<Setter Property="Height" Value="30" /> |
||||
|
</Style> |
||||
|
<Style Selector="Window Panel#PART_MinimiseButton"> |
||||
|
<Setter Property="IsVisible" Value="False" /> |
||||
|
</Style> |
||||
|
<Style Selector="Window Panel#PART_RestoreButton"> |
||||
|
<Setter Property="IsVisible" Value="False" /> |
||||
|
</Style> |
||||
|
</Window.Styles> |
||||
|
|
||||
|
<Grid Name="RealPlayGrid" ColumnDefinitions="640*,114*"> |
||||
|
<DockPanel Grid.Column="0"> |
||||
|
<components:NativeHost Name="player" /> |
||||
|
</DockPanel> |
||||
|
|
||||
|
<StackPanel Name="PtzCtrlPanel" Grid.Column="1"> |
||||
|
<Grid RowDefinitions="35,35,35,5,30,30,30,5,60,35" ColumnDefinitions="35,35,35"> |
||||
|
<StackPanel Grid.Row="0" Grid.Column="0"> |
||||
|
<Button Name="LeftTopBtn" Classes="Outline"> |
||||
|
<icons:MaterialIcon Kind="ArrowTopLeft" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="0" Grid.Column="1"> |
||||
|
<Button Name="TopBtn" Classes="Outline"> |
||||
|
<icons:MaterialIcon Kind="ArrowTop" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="0" Grid.Column="2"> |
||||
|
<Button Name="RightTopBtn" Classes="Outline"> |
||||
|
<icons:MaterialIcon Kind="ArrowTopRight" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<StackPanel Grid.Row="1" Grid.Column="0"> |
||||
|
<Button Name="LeftBtn" Classes="Outline"> |
||||
|
<icons:MaterialIcon Kind="ArrowLeft" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="1" Grid.Column="1"> |
||||
|
<Button Name="AutoMoveBtn" Classes="Outline"> |
||||
|
<icons:MaterialIcon Kind="Circle" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="1" Grid.Column="2"> |
||||
|
<Button Name="RightBtn" Classes="Outline"> |
||||
|
<icons:MaterialIcon Kind="ArrowRight" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<StackPanel Grid.Row="2" Grid.Column="0"> |
||||
|
<Button Name="LeftDownBtn" Classes="Outline"> |
||||
|
<icons:MaterialIcon Kind="ArrowBottomLeft" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="2" Grid.Column="1"> |
||||
|
<Button Name="DownBtn" Classes="Outline"> |
||||
|
<icons:MaterialIcon Kind="ArrowBottom" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="2" Grid.Column="2"> |
||||
|
<Button Name="RightDownBtn" Classes="Outline"> |
||||
|
<icons:MaterialIcon Kind="ArrowBottomRight" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<StackPanel Grid.Row="4" Grid.Column="0"> |
||||
|
<Button Name="ZoomInBtn" Classes="Outline"> |
||||
|
<icons:MaterialIcon Kind="PlusBold" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="4" Grid.Column="1"> |
||||
|
<TextBlock Text="调焦" /> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="4" Grid.Column="2"> |
||||
|
<Button Name="ZoomOutBtn" Classes="Outline"> |
||||
|
<icons:MaterialIcon Kind="MinusThick" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<StackPanel Grid.Row="5" Grid.Column="0"> |
||||
|
<Button Name="FocusNearBtn" Classes="Outline"> |
||||
|
<icons:MaterialIcon Kind="PlusThick" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="5" Grid.Column="1"> |
||||
|
<TextBlock Text="聚焦" /> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="5" Grid.Column="2"> |
||||
|
<Button Name="FocusFarBtn" Classes="Outline"> |
||||
|
<icons:MaterialIcon Kind="MinusThick" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<StackPanel Grid.Row="6" Grid.Column="0"> |
||||
|
<Button Name="IrisOpenBtn" Classes="Outline"> |
||||
|
<icons:MaterialIcon Kind="PlusThick" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="6" Grid.Column="1"> |
||||
|
<TextBlock Text="光焦" /> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="6" Grid.Column="2"> |
||||
|
<Button Name="IrisCloseBtn" Classes="Outline"> |
||||
|
<icons:MaterialIcon Kind="MinusThick" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<StackPanel Grid.Row="8" Grid.ColumnSpan="3"> |
||||
|
<ComboBox Name="PresetIdCbx" Classes="Outline" ContextFlyout="{x:Null}" assists:ComboBoxAssist.Label="预置点" /> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="9" Grid.ColumnSpan="3"> |
||||
|
<Button Name="GotoBtn" Classes="Light" Content="前往预置点" /> |
||||
|
</StackPanel> |
||||
|
</Grid> |
||||
|
</StackPanel> |
||||
|
</Grid> |
||||
|
</Window> |
@ -0,0 +1,180 @@ |
|||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Input; |
||||
|
using Avalonia.Interactivity; |
||||
|
using Avalonia.Threading; |
||||
|
using EC.Util.CameraSDK; |
||||
|
using JiLinApp.Core.Avalonia; |
||||
|
using JiLinApp.Docking.Ptz; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Runtime.InteropServices; |
||||
|
|
||||
|
namespace JiLinApp.Components; |
||||
|
|
||||
|
public partial class CameraRealPlay : Window |
||||
|
{ |
||||
|
#region
|
||||
|
|
||||
|
private ICameraSdk? CameraSdk { get; set; } |
||||
|
|
||||
|
#endregion
|
||||
|
|
||||
|
public CameraRealPlay() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
|
||||
|
//绑定云台响应事件
|
||||
|
List<Button> btnList = new(); |
||||
|
ControlsUtil.FindChild(PtzCtrlPanel, ref btnList); |
||||
|
foreach (var btn in btnList) |
||||
|
{ |
||||
|
if ((btn.Name ?? string.Empty).StartsWith("goto", StringComparison.OrdinalIgnoreCase)) btn.Click += GotoBtn_Click; |
||||
|
else |
||||
|
{ |
||||
|
btn.AddHandler(PointerPressedEvent, PtzBtn_MouseDown, RoutingStrategies.Tunnel); |
||||
|
btn.AddHandler(PointerReleasedEvent, PtzBtn_MouseUp, RoutingStrategies.Tunnel); |
||||
|
} |
||||
|
} |
||||
|
// 初始化预置点 id 下拉框
|
||||
|
for (int i = 1; i <= 10; i++) PresetIdCbx.Items.Add(new ComboBoxItem { Content = i }); |
||||
|
PresetIdCbx.SelectedIndex = 0; |
||||
|
} |
||||
|
|
||||
|
public CameraRealPlay(ICameraSdk cameraSdk) : this() |
||||
|
{ |
||||
|
SetCameraSdk(cameraSdk); |
||||
|
} |
||||
|
|
||||
|
#region Inner
|
||||
|
|
||||
|
public void SetCameraSdk(ICameraSdk cameraSdk) |
||||
|
{ |
||||
|
CameraSdk = cameraSdk; |
||||
|
} |
||||
|
|
||||
|
public IntPtr GetHwnd() |
||||
|
{ |
||||
|
return player.Handle; |
||||
|
} |
||||
|
|
||||
|
public bool IsClosed { get; private set; } |
||||
|
|
||||
|
protected override void OnClosing(WindowClosingEventArgs e) |
||||
|
{ |
||||
|
base.OnClosing(e); |
||||
|
IsClosed = true; |
||||
|
StopPlay(); |
||||
|
} |
||||
|
|
||||
|
#endregion Inner
|
||||
|
|
||||
|
#region Play
|
||||
|
|
||||
|
public void StartPlay() |
||||
|
{ |
||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) |
||||
|
{ |
||||
|
} |
||||
|
if (CameraSdk is HiKSdk hikSdk) |
||||
|
{ |
||||
|
if (RealplayPort < 0) |
||||
|
{ |
||||
|
int nPort = -1; |
||||
|
bool ret = PlayCtrlSdk.PlayM4_GetPort(ref nPort); |
||||
|
if (!ret) hikSdk.BuildPlayCtrlException(nPort); |
||||
|
RealplayPort = nPort; |
||||
|
} |
||||
|
hikSdk.RealDataCallBack = HikRealDataCallBack; |
||||
|
} |
||||
|
else if (CameraSdk is DaHuaSdk dhSdk) |
||||
|
{ |
||||
|
} |
||||
|
else if (CameraSdk is YuShiSdk ysSdk) |
||||
|
{ |
||||
|
} |
||||
|
CameraSdk?.StartPlay(player.Handle); |
||||
|
} |
||||
|
|
||||
|
public void StopPlay() |
||||
|
{ |
||||
|
Dispatcher.UIThread.InvokeAsync(() => CameraSdk?.StopPlay()); |
||||
|
if (RuntimeInformation.IsOSPlatform(OSPlatform.Linux)) |
||||
|
{ |
||||
|
} |
||||
|
if (CameraSdk is HiKSdk hikSdk) |
||||
|
{ |
||||
|
if (RealplayPort >= 0) |
||||
|
{ |
||||
|
PlayCtrlSdk.PlayM4_Stop(RealplayPort); |
||||
|
PlayCtrlSdk.PlayM4_CloseStream(RealplayPort); |
||||
|
PlayCtrlSdk.PlayM4_FreePort(RealplayPort); |
||||
|
RealplayPort = -1; |
||||
|
} |
||||
|
hikSdk.RealDataCallBack = null; |
||||
|
} |
||||
|
else if (CameraSdk is DaHuaSdk dhSdk) |
||||
|
{ |
||||
|
} |
||||
|
else if (CameraSdk is YuShiSdk ysSdk) |
||||
|
{ |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public bool IsPlaying() |
||||
|
{ |
||||
|
return CameraSdk?.IsPlaying() ?? false; |
||||
|
} |
||||
|
|
||||
|
private int RealplayPort { get; set; } = -1; |
||||
|
|
||||
|
private void HikRealDataCallBack(int lRealHandle, uint dwDataType, IntPtr pBuffer, uint dwBufSize, IntPtr pUser) |
||||
|
{ |
||||
|
if (RealplayPort < 0 || dwBufSize <= 0) return; |
||||
|
Dispatcher.UIThread.Invoke(() => |
||||
|
{ |
||||
|
switch (dwDataType) |
||||
|
{ |
||||
|
case HiKOriSdk.NET_DVR_SYSHEAD: |
||||
|
PlayCtrlSdk.PlayM4_SetStreamOpenMode(RealplayPort, 0); |
||||
|
PlayCtrlSdk.PlayM4_OpenStream(RealplayPort, pBuffer, dwBufSize, 2 * 1024 * 1024); |
||||
|
PlayCtrlSdk.PlayM4_SetDisplayBuf(RealplayPort, 5); |
||||
|
PlayCtrlSdk.PlayM4_Play(RealplayPort, GetHwnd()); |
||||
|
break; |
||||
|
|
||||
|
case HiKOriSdk.NET_DVR_STREAMDATA: |
||||
|
PlayCtrlSdk.PlayM4_InputData(RealplayPort, pBuffer, dwBufSize); |
||||
|
break; |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
|
||||
|
#endregion Play
|
||||
|
|
||||
|
#region ElementEvent
|
||||
|
|
||||
|
private void PtzBtn_MouseDown(object? sender, PointerPressedEventArgs e) |
||||
|
{ |
||||
|
if (CameraSdk == null || sender is not Button btn) return; |
||||
|
PtzCmdType cmdType = PtzCmd.GetCmdType((btn.Name ?? string.Empty).Replace("Btn", "")); |
||||
|
int stop = 0; |
||||
|
PtzCameraCmd.PtzMove(CameraSdk, cmdType, new int[] { stop }); |
||||
|
} |
||||
|
|
||||
|
private void PtzBtn_MouseUp(object? sender, PointerReleasedEventArgs e) |
||||
|
{ |
||||
|
if (CameraSdk == null || sender is not Button btn) return; |
||||
|
PtzCmdType cmdType = PtzCmd.GetCmdType((btn.Name ?? string.Empty).Replace("Btn", "")); |
||||
|
int stop = 1; |
||||
|
PtzCameraCmd.PtzMove(CameraSdk, cmdType, new int[] { stop }); |
||||
|
} |
||||
|
|
||||
|
private void GotoBtn_Click(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
if (CameraSdk == null) return; |
||||
|
PtzCmdType cmdType = PtzCmdType.PresetGoto; |
||||
|
int presetId = int.Parse(PresetIdCbx.GetText()); |
||||
|
PtzCameraCmd.PtzMove(CameraSdk, cmdType, new int[] { presetId }); |
||||
|
} |
||||
|
|
||||
|
#endregion ElementEvent
|
||||
|
} |
@ -0,0 +1,22 @@ |
|||||
|
using JiLinApp.Biz.TransmitAlarm; |
||||
|
using JiLinApp.Docking.Military; |
||||
|
using JiLinApp.Docking.Ptz; |
||||
|
using System.Collections.Generic; |
||||
|
|
||||
|
namespace JiLinApp.Core; |
||||
|
|
||||
|
public class AppConfig |
||||
|
{ |
||||
|
public BaseConfig Base { get; set; } |
||||
|
|
||||
|
public MilitaryConfig Military { get; set; } |
||||
|
|
||||
|
public AlarmPlatformConfig AlarmPlatform { get; set; } |
||||
|
} |
||||
|
|
||||
|
public class BaseConfig |
||||
|
{ |
||||
|
public bool Console { get; set; } |
||||
|
|
||||
|
public List<PtzControlTypeConfig> PtzCtrlTypes { get; set; } |
||||
|
} |
@ -0,0 +1,65 @@ |
|||||
|
using EC.Util.CameraSDK; |
||||
|
using EC.Util.Common; |
||||
|
using JiLinApp.Biz.TransmitAlarm; |
||||
|
using JiLinApp.Docking.Alarm; |
||||
|
using JiLinApp.Docking.Military; |
||||
|
using JiLinApp.Docking.Ptz; |
||||
|
using NewLife.Configuration; |
||||
|
using System; |
||||
|
using System.IO; |
||||
|
|
||||
|
namespace JiLinApp.Core; |
||||
|
|
||||
|
public static class Global |
||||
|
{ |
||||
|
#region Fields
|
||||
|
|
||||
|
private static JsonConfigProvider ConfigProvider { get; } |
||||
|
|
||||
|
public static AppConfig AppConfig { get; } |
||||
|
|
||||
|
public static MilitaryService MilitaryService { get; } |
||||
|
|
||||
|
public static IAlarmService AlarmService { get; } |
||||
|
|
||||
|
#endregion Fields
|
||||
|
|
||||
|
static Global() |
||||
|
{ |
||||
|
try |
||||
|
{ |
||||
|
// Config
|
||||
|
string filePath = Path.Combine("config", "appconfig.json"); |
||||
|
if (!File.Exists(filePath)) throw new FileNotFoundException(filePath); |
||||
|
ConfigProvider = new() { FileName = filePath }; |
||||
|
AppConfig = new AppConfig(); |
||||
|
ConfigProvider.Bind(AppConfig); |
||||
|
|
||||
|
// BaseConfig
|
||||
|
BaseConfig baseConfig = AppConfig.Base; |
||||
|
// ptzCtrlTypes
|
||||
|
PtzControlTypeConfigHelper.Init(baseConfig.PtzCtrlTypes); |
||||
|
|
||||
|
// MilitaryConfig
|
||||
|
MilitaryConfig militaryConfig = AppConfig.Military; |
||||
|
MilitaryService = new MilitaryService(militaryConfig); |
||||
|
|
||||
|
// AlarmPlatformConfig
|
||||
|
AlarmPlatformConfig alarmPlatformConfig = AppConfig.AlarmPlatform; |
||||
|
AlarmService = AlarmServiceFactory.CreateService(alarmPlatformConfig); |
||||
|
AlarmService.Start(); |
||||
|
} |
||||
|
catch (Exception) |
||||
|
{ |
||||
|
throw; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static void Init() |
||||
|
{ |
||||
|
// 静态类在调用之后才会初始化静态类构造方法
|
||||
|
CameraFactory.VirtualInit(); |
||||
|
LogUnit.VirtualInit(); |
||||
|
AlarmCodeHelper.VirtualInit(); |
||||
|
} |
||||
|
} |
@ -0,0 +1,13 @@ |
|||||
|
using JiLinApp.Docking.FenceAlarm; |
||||
|
using JiLinApp.Docking.VibrateAlarm; |
||||
|
using ReactiveUI; |
||||
|
using System; |
||||
|
|
||||
|
namespace JiLinApp.Core.App; |
||||
|
|
||||
|
public class MessageEvent |
||||
|
{ |
||||
|
public static IObservable<TcpAlarmHostMessage> VibrateAlarm { get; } = MessageBus.Current.Listen<TcpAlarmHostMessage>("VibrateAlarm"); |
||||
|
|
||||
|
public static IObservable<UdpAlarmHostMessage> FenceAlarm { get; } = MessageBus.Current.Listen<UdpAlarmHostMessage>("FenceAlarm"); |
||||
|
} |
@ -0,0 +1,150 @@ |
|||||
|
using Avalonia.Controls; |
||||
|
using Material.Dialog; |
||||
|
using Material.Dialog.Icons; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Reflection; |
||||
|
using System.Threading.Tasks; |
||||
|
|
||||
|
namespace JiLinApp.Core.Avalonia; |
||||
|
|
||||
|
public static class ControlsUtil |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// 查找子控件
|
||||
|
/// </summary>
|
||||
|
/// <typeparam name="T">控件类型</typeparam>
|
||||
|
/// <param name="parent">父控件依赖对象</param>
|
||||
|
/// <param name="list">子控件列表</param>
|
||||
|
public static void FindChild<T>(Control parent, ref List<T> list) where T : Control |
||||
|
{ |
||||
|
if (parent == null) return; |
||||
|
if (parent is Panel pParent) |
||||
|
{ |
||||
|
foreach (Control item in pParent.Children) |
||||
|
{ |
||||
|
if (item is Panel panel) FindChild(panel, ref list); |
||||
|
else if (item is T child) list.Add(child); |
||||
|
} |
||||
|
} |
||||
|
else if (parent is Decorator dParent) |
||||
|
{ |
||||
|
if (dParent.Child != null) FindChild(dParent.Child, ref list); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
public static Window? GetWindow(Control control) |
||||
|
{ |
||||
|
Control? temp = control; |
||||
|
while (temp?.Parent != null) |
||||
|
{ |
||||
|
if (temp.Parent is Window w) return w; |
||||
|
else temp = temp.Parent is Control c ? c : null; |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
public static bool TryGetWindow(Control control, out Window? window) |
||||
|
{ |
||||
|
Control? temp = control; |
||||
|
window = null; |
||||
|
while (temp?.Parent != null) |
||||
|
{ |
||||
|
if (temp.Parent is Window w) { window = w; break; } |
||||
|
else temp = temp.Parent is Control c ? c : null; |
||||
|
} |
||||
|
return window != null; |
||||
|
} |
||||
|
|
||||
|
public static string GetText(this TextBox tb) |
||||
|
{ |
||||
|
return tb.Text ?? string.Empty; |
||||
|
} |
||||
|
|
||||
|
public static bool GetText(this TextBox tb, out string? text) |
||||
|
{ |
||||
|
text = tb.Text; |
||||
|
return text != null; |
||||
|
} |
||||
|
|
||||
|
public static string GetText(this ComboBox cbx) |
||||
|
{ |
||||
|
string? val = string.Empty; |
||||
|
var item = cbx.SelectedItem; |
||||
|
if (item == null) return val; |
||||
|
if (item is Control) |
||||
|
{ |
||||
|
if (TryGetValue(item, "Content", out object? content)) val = content?.ToString(); |
||||
|
else if (TryGetValue(item, "Text", out string? text)) val = text; |
||||
|
} |
||||
|
else val = item.ToString(); |
||||
|
return val ?? string.Empty; |
||||
|
} |
||||
|
|
||||
|
public static bool GetText(this ComboBox cbx, out string? val) |
||||
|
{ |
||||
|
var item = cbx.SelectedItem; |
||||
|
if (item is Control) |
||||
|
{ |
||||
|
if (TryGetValue(item, "Content", out object? content)) val = content?.ToString(); |
||||
|
else if (TryGetValue(item, "Text", out string? text)) val = text; |
||||
|
else val = null; |
||||
|
} |
||||
|
else val = item?.ToString(); |
||||
|
return val != null; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// 利用反射来判断对象是否包含某个属性
|
||||
|
/// </summary>
|
||||
|
/// <param name="instance">object</param>
|
||||
|
/// <param name="propertyName">需要判断的属性</param>
|
||||
|
/// <returns>是否包含</returns>
|
||||
|
private static bool ContainProperty(object instance, string propertyName) |
||||
|
{ |
||||
|
if (instance == null || string.IsNullOrEmpty(propertyName)) return false; |
||||
|
PropertyInfo? property = instance.GetType()?.GetProperty(propertyName); |
||||
|
return property != null; |
||||
|
} |
||||
|
|
||||
|
private static bool TryGetValue<T>(object instance, string propertyName, out T? val) |
||||
|
{ |
||||
|
if (instance == null || string.IsNullOrEmpty(propertyName)) |
||||
|
{ |
||||
|
val = default; |
||||
|
return false; |
||||
|
} |
||||
|
PropertyInfo? property = instance.GetType()?.GetProperty(propertyName); |
||||
|
val = (T?)property?.GetValue(instance, null); |
||||
|
return val != null; |
||||
|
} |
||||
|
|
||||
|
public static async Task<DialogResult> ShowDialog(Window? window, string title = "Info", string message = "") |
||||
|
{ |
||||
|
if (window == null) return DialogResult.NoResult; |
||||
|
var dialog = DialogHelper.CreateAlertDialog(new AlertDialogBuilderParams |
||||
|
{ |
||||
|
Borderless = true, |
||||
|
Width = 300, |
||||
|
DialogHeaderIcon = DialogIconKind.Info, |
||||
|
ContentHeader = title, |
||||
|
SupportingText = message, |
||||
|
StartupLocation = WindowStartupLocation.CenterOwner, |
||||
|
}); |
||||
|
return await dialog.ShowDialog(window); |
||||
|
} |
||||
|
|
||||
|
public static async Task<DialogResult> ShowWarnDialog(Window? window, string title = "Warning", string message = "") |
||||
|
{ |
||||
|
if (window == null) return DialogResult.NoResult; |
||||
|
var dialog = DialogHelper.CreateAlertDialog(new AlertDialogBuilderParams |
||||
|
{ |
||||
|
Borderless = true, |
||||
|
Width = 300, |
||||
|
DialogHeaderIcon = DialogIconKind.Warning, |
||||
|
ContentHeader = title, |
||||
|
SupportingText = message, |
||||
|
StartupLocation = WindowStartupLocation.CenterOwner, |
||||
|
}); |
||||
|
return await dialog.ShowDialog(window); |
||||
|
} |
||||
|
} |
@ -0,0 +1,54 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
||||
|
xmlns:controls="using:Material.Styles.Controls" |
||||
|
xmlns:assists="using:Material.Styles.Assists" |
||||
|
x:Class="JiLinApp.Pages.FenceServer.Fence" |
||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"> |
||||
|
<UserControl.Styles> |
||||
|
<Style Selector="#FencePanel TextBox"> |
||||
|
<Setter Property="Width" Value="200" /> |
||||
|
<Setter Property="UseFloatingWatermark" Value="True"/> |
||||
|
</Style> |
||||
|
<Style Selector="#FencePanel TextBlock[Name=PART_LabelText]"> |
||||
|
<Setter Property="Foreground" Value="#272727"/> |
||||
|
</Style> |
||||
|
<Style Selector="#FencePanel TextBox:focus TextBlock[Name=PART_LabelText]"> |
||||
|
<Setter Property="Foreground" Value="#2196f3"/> |
||||
|
</Style> |
||||
|
<Style Selector="#FencePanel StackPanel"> |
||||
|
<Setter Property="VerticalAlignment" Value="Center" /> |
||||
|
</Style> |
||||
|
<Style Selector="#FencePanel WrapPanel"> |
||||
|
<Setter Property="HorizontalAlignment" Value="Center" /> |
||||
|
<Setter Property="VerticalAlignment" Value="Center" /> |
||||
|
</Style> |
||||
|
<Style Selector="#FencePanel WrapPanel Button"> |
||||
|
<Setter Property="Width" Value="100" /> |
||||
|
<Setter Property="Margin" Value="5" /> |
||||
|
</Style> |
||||
|
</UserControl.Styles> |
||||
|
|
||||
|
<Grid Name="FencePanel" RowDefinitions="250,1*"> |
||||
|
<Border Grid.Row="0" BorderBrush="#2196f3" BorderThickness="1"> |
||||
|
<Grid RowDefinitions="30,1*"> |
||||
|
<Border Grid.Row="0" Height="30" Background="#2196f3" Padding="8 0 0 0"> |
||||
|
<TextBlock Text="优周围网服务器设置(UDP)" FontSize="14" VerticalAlignment="Center" MaxLines="1" Foreground="#F0F0F0" /> |
||||
|
</Border> |
||||
|
<Grid Grid.Row="1" RowDefinitions="1*,1*,1*" ColumnDefinitions="1*,1*,1*"> |
||||
|
<StackPanel Grid.Row="0" Grid.Column="0"> |
||||
|
<TextBox Name="ServerPortTb" Classes="outline" Text="23039" assists:TextFieldAssist.Label="本地端口" /> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="1" Grid.Column="0"> |
||||
|
<TextBox Name="HeartKeepTb" Classes="outline" Text="10" assists:TextFieldAssist.Label="心跳间隔" /> |
||||
|
</StackPanel> |
||||
|
<WrapPanel Grid.Row="2" Grid.Column="0"> |
||||
|
<Button Name="OpenBtn" Classes="Light" Content="开启服务" Width="100" Margin="5" /> |
||||
|
<Button Name="CloseBtn" Classes="Light" Content="关闭服务" Width="100" Margin="5" IsEnabled="False" /> |
||||
|
</WrapPanel> |
||||
|
</Grid> |
||||
|
</Grid> |
||||
|
</Border> |
||||
|
</Grid> |
||||
|
</UserControl> |
@ -0,0 +1,174 @@ |
|||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Interactivity; |
||||
|
using Avalonia.Media; |
||||
|
using EC.Util.Common; |
||||
|
using JiLinApp.Biz.TransmitAlarm; |
||||
|
using JiLinApp.Core; |
||||
|
using JiLinApp.Core.App; |
||||
|
using JiLinApp.Core.Avalonia; |
||||
|
using JiLinApp.Docking.FenceAlarm; |
||||
|
using Material.Dialog; |
||||
|
using Newtonsoft.Json.Linq; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Reactive.Linq; |
||||
|
|
||||
|
namespace JiLinApp.Pages.FenceServer; |
||||
|
|
||||
|
public partial class Fence : UserControl |
||||
|
{ |
||||
|
#region Fields
|
||||
|
|
||||
|
private UdpManager Manager { get; } = new(); |
||||
|
|
||||
|
private IAlarmService AlarmService { get; set; } |
||||
|
|
||||
|
private Window? _win; |
||||
|
|
||||
|
private Window? Wdw |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
_win ??= ControlsUtil.GetWindow(this); |
||||
|
return _win; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#endregion Fields
|
||||
|
|
||||
|
public Fence() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
|
||||
|
AlarmService = Global.AlarmService; |
||||
|
OpenBtn.Click += OpenBtn_Click; |
||||
|
CloseBtn.Click += CloseBtn_Click; |
||||
|
|
||||
|
Manager.OnFenceUdpDeviceState += Manager_OnFenceUdpDeviceState; |
||||
|
Manager.OnFenceUdpSectorState += Manager_OnFenceUdpSensorState; |
||||
|
Manager.OnFenceUdpAlarm += Manager_OnFenceUdpAlarm; |
||||
|
AlarmService.OnFenceUdpSendDevices += AlarmService_OnFenceUdpSendDevices; |
||||
|
AlarmService.OnFenceUdpSendSensors += AlarmService_OnFenceUdpSendSensors; |
||||
|
} |
||||
|
|
||||
|
#region ElementEvent
|
||||
|
|
||||
|
private void OpenBtn_Click(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
if (Manager.IsRunning()) return; |
||||
|
try |
||||
|
{ |
||||
|
UdpManagerConfig config = new() |
||||
|
{ |
||||
|
ServerPort = int.Parse(ServerPortTb.GetText()), |
||||
|
DeviceHeartKeep = int.Parse(HeartKeepTb.GetText()) |
||||
|
}; |
||||
|
Manager.Start(config); |
||||
|
ChangeServerBtnState(true); |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
_ = ControlsUtil.ShowWarnDialog(Wdw, message: ex.ToString()); |
||||
|
LogUnit.Error(ex); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void CloseBtn_Click(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
if (!Manager.IsRunning()) return; |
||||
|
try |
||||
|
{ |
||||
|
Manager.Stop(); |
||||
|
ChangeServerBtnState(false); |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
_ = ControlsUtil.ShowWarnDialog(Wdw, message: ex.ToString()); |
||||
|
LogUnit.Error(ex); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void ChangeServerBtnState(bool openState) |
||||
|
{ |
||||
|
OpenBtn.IsEnabled = !openState; |
||||
|
CloseBtn.IsEnabled = openState; |
||||
|
} |
||||
|
|
||||
|
#endregion ElementEvent
|
||||
|
|
||||
|
#region Manager Event
|
||||
|
|
||||
|
private void Manager_OnFenceUdpDeviceState(UdpAlarmHost device) |
||||
|
{ |
||||
|
object deviceObj = new |
||||
|
{ |
||||
|
id = device.DeviceId, |
||||
|
onlineState = device.OnlineState, |
||||
|
defenceState = device.DefenceState |
||||
|
}; |
||||
|
AlarmService.SendDeviceState(DeviceType.Fence, deviceObj); |
||||
|
} |
||||
|
|
||||
|
private void Manager_OnFenceUdpSensorState(SectorState sector) |
||||
|
{ |
||||
|
object sensorObj = new |
||||
|
{ |
||||
|
id = sector.Id, |
||||
|
deviceId = sector.DeviceId, |
||||
|
state = sector.State, |
||||
|
type = sector.Type, |
||||
|
}; |
||||
|
AlarmService.SendSensorState(DeviceType.Fence, sensorObj); |
||||
|
} |
||||
|
|
||||
|
private void Manager_OnFenceUdpAlarm(UdpAlarmHostMessage msg) |
||||
|
{ |
||||
|
AlarmMessage alarm = msg.ToAlarmMessage(); |
||||
|
AlarmService.SendAlarm(alarm); |
||||
|
MessageEvent.FenceAlarm.Publish(msg); |
||||
|
} |
||||
|
|
||||
|
#endregion Manager Event
|
||||
|
|
||||
|
#region SubCmd Event
|
||||
|
|
||||
|
private void AlarmService_OnFenceUdpSendDevices(JObject reqObj) |
||||
|
{ |
||||
|
List<object> respDeviceList = new(); |
||||
|
List<UdpAlarmHost> deviceList = Manager.GetDeviceList(); |
||||
|
foreach (var item in deviceList) |
||||
|
{ |
||||
|
if (item.DeviceId <= 0) continue; |
||||
|
respDeviceList.Add(new |
||||
|
{ |
||||
|
id = item.DeviceId, |
||||
|
//groupId = item.GroupId,
|
||||
|
//userId = item.UserId,
|
||||
|
onlineState = item.OnlineState, |
||||
|
defenceState = item.DefenceState |
||||
|
}); |
||||
|
} |
||||
|
AlarmService.SendDevices(DeviceType.Fence, respDeviceList); |
||||
|
} |
||||
|
|
||||
|
private void AlarmService_OnFenceUdpSendSensors(JObject reqObj) |
||||
|
{ |
||||
|
int deviceId = reqObj.GetValue("deviceId", StringComparison.OrdinalIgnoreCase).ToInt(); |
||||
|
List<SectorState> sectorList = Manager.TryGetDevice(deviceId, out UdpAlarmHost device) ? device.SectorDict.Values.ToList() : new(); |
||||
|
List<object> respSensorList = new(); |
||||
|
foreach (var item in sectorList) |
||||
|
{ |
||||
|
respSensorList.Add(new |
||||
|
{ |
||||
|
id = item.Id, |
||||
|
deviceId = item.DeviceId, |
||||
|
state = item.State, |
||||
|
type = item.Type, |
||||
|
}); |
||||
|
} |
||||
|
AlarmService.SendSensors(DeviceType.Fence, deviceId, respSensorList); |
||||
|
} |
||||
|
|
||||
|
#endregion SubCmd Event
|
||||
|
} |
@ -0,0 +1,10 @@ |
|||||
|
using JiLinApp.Core.Avalonia; |
||||
|
|
||||
|
namespace JiLinApp.Pages.FenceServer; |
||||
|
|
||||
|
public class FenceViewModel : ViewModelBase |
||||
|
{ |
||||
|
public FenceViewModel() |
||||
|
{ |
||||
|
} |
||||
|
} |
@ -1,20 +1,91 @@ |
|||||
<Window xmlns="https://github.com/avaloniaui" |
<Window xmlns="https://github.com/avaloniaui" |
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
||||
|
xmlns:controls="using:Material.Styles.Controls" |
||||
|
xmlns:icons="using:Material.Icons.Avalonia" |
||||
xmlns:vm="using:JiLinApp.Pages.Main" |
xmlns:vm="using:JiLinApp.Pages.Main" |
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" |
xmlns:fenceServer="using:JiLinApp.Pages.FenceServer" |
||||
|
xmlns:ptzServer="using:JiLinApp.Pages.PtzServer" |
||||
|
xmlns:vibrateServer="using:JiLinApp.Pages.VibrateServer" |
||||
x:Class="JiLinApp.Pages.Main.MainWindow" |
x:Class="JiLinApp.Pages.Main.MainWindow" |
||||
x:DataType="vm:MainWindowViewModel" |
x:DataType="vm:MainWindowViewModel" |
||||
|
Width="900" Height="560" MinWidth="775" MinHeight="560" |
||||
Icon="/Assets/avalonia-logo.ico" |
Icon="/Assets/avalonia-logo.ico" |
||||
Title="JiLinApp"> |
Title="JiLinApp"> |
||||
|
|
||||
<Design.DataContext> |
<Design.DataContext> |
||||
<!-- This only sets the DataContext for the previewer in an IDE, |
|
||||
to set the actual DataContext for runtime, set the DataContext property in code (look at App.axaml.cs) --> |
|
||||
<vm:MainWindowViewModel /> |
<vm:MainWindowViewModel /> |
||||
</Design.DataContext> |
</Design.DataContext> |
||||
|
|
||||
<TextBlock Text="{Binding Greeting}" HorizontalAlignment="Center" VerticalAlignment="Center"/> |
<Window.Styles> |
||||
|
<Style Selector="TabControl"> |
||||
|
<Setter Property="TabStripPlacement" Value="Left" /> |
||||
|
<Setter Property="Background" Value="#2196f3" /> |
||||
|
</Style> |
||||
|
<Style Selector="TabControl /template/ ContentPresenter"> |
||||
|
<Setter Property="Background" Value="#F0F0F0" /> |
||||
|
<Setter Property="Padding" Value="4" /> |
||||
|
</Style> |
||||
|
|
||||
|
<Style Selector="TabItem"> |
||||
|
<Setter Property="FontSize" Value="12" /> |
||||
|
<Setter Property="Width" Value="84" /> |
||||
|
<Setter Property="Height" Value="63" /> |
||||
|
<Setter Property="Background" Value="#2196f3" /> |
||||
|
<Setter Property="Foreground" Value="#F0F0F0" /> |
||||
|
</Style> |
||||
|
<Style Selector="TabItem TextBlock"> |
||||
|
<Setter Property="HorizontalAlignment" Value="Center" /> |
||||
|
</Style> |
||||
|
<Style Selector="TabItem /template/ ContentPresenter#PART_ContentPresenter"> |
||||
|
<Setter Property="Width" Value="80" /> |
||||
|
<Setter Property="Height" Value="56" /> |
||||
|
<Setter Property="HorizontalAlignment" Value="Center" /> |
||||
|
<Setter Property="VerticalAlignment" Value="Center" /> |
||||
|
<Setter Property="HorizontalContentAlignment" Value="Center" /> |
||||
|
<Setter Property="VerticalContentAlignment" Value="Center" /> |
||||
|
<Setter Property="Padding" Value="2 5 2 1" /> |
||||
|
</Style> |
||||
|
<Style Selector="TabItem:pointerover /template/ ContentPresenter#PART_ContentPresenter"> |
||||
|
<Setter Property="Foreground" Value="#2B579A" /> |
||||
|
<Setter Property="Background" Value="#F0F0F0" /> |
||||
|
</Style> |
||||
|
<Style Selector="TabItem:focus /template/ ContentPresenter#PART_ContentPresenter"> |
||||
|
<Setter Property="Foreground" Value="#2B579A" /> |
||||
|
<Setter Property="Background" Value="#F0F0F0" /> |
||||
|
</Style> |
||||
|
<Style Selector="TabItem:selected /template/ ContentPresenter#PART_ContentPresenter"> |
||||
|
<Setter Property="Foreground" Value="#2B579A" /> |
||||
|
<Setter Property="Background" Value="#F0F0F0" /> |
||||
|
</Style> |
||||
|
</Window.Styles> |
||||
|
|
||||
|
<TabControl> |
||||
|
<TabItem> |
||||
|
<TabItem.Header> |
||||
|
<StackPanel> |
||||
|
<icons:MaterialIcon Kind="CogOutline" Width="30" Height="30" /> |
||||
|
<TextBlock Text="Ptz服务" /> |
||||
|
</StackPanel> |
||||
|
</TabItem.Header> |
||||
|
<ptzServer:Ptz DataContext="{Binding PtzViewModel}" /> |
||||
|
</TabItem> |
||||
|
<TabItem> |
||||
|
<TabItem.Header> |
||||
|
<StackPanel> |
||||
|
<icons:MaterialIcon Kind="Server" Width="30" Height="30" /> |
||||
|
<TextBlock Text="震动报警服务" /> |
||||
|
</StackPanel> |
||||
|
</TabItem.Header> |
||||
|
<vibrateServer:Vibrate DataContext="{Binding VibrateViewModel}" /> |
||||
|
</TabItem> |
||||
|
<TabItem> |
||||
|
<TabItem.Header> |
||||
|
<StackPanel> |
||||
|
<icons:MaterialIcon Kind="Server" Width="30" Height="30" /> |
||||
|
<TextBlock Text="优周围网服务" /> |
||||
|
</StackPanel> |
||||
|
</TabItem.Header> |
||||
|
<fenceServer:Fence DataContext="{Binding FenceViewModel}"/> |
||||
|
</TabItem> |
||||
|
</TabControl> |
||||
</Window> |
</Window> |
@ -1,8 +1,19 @@ |
|||||
using JiLinApp.Core.Avalonia; |
using JiLinApp.Core.Avalonia; |
||||
|
using JiLinApp.Pages.FenceServer; |
||||
|
using JiLinApp.Pages.PtzServer; |
||||
|
using JiLinApp.Pages.VibrateServer; |
||||
|
|
||||
namespace JiLinApp.Pages.Main; |
namespace JiLinApp.Pages.Main; |
||||
|
|
||||
public class MainWindowViewModel : ViewModelBase |
public class MainWindowViewModel : ViewModelBase |
||||
{ |
{ |
||||
public string Greeting => "Welcome to Avalonia!"; |
#region Fields
|
||||
|
|
||||
|
internal PtzViewModel PtzViewModel { get; } = new(); |
||||
|
|
||||
|
internal VibrateViewModel VibrateViewModel { get; } = new(); |
||||
|
|
||||
|
internal FenceViewModel FenceViewModel { get; } = new(); |
||||
|
|
||||
|
#endregion Fields
|
||||
} |
} |
@ -0,0 +1,261 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
||||
|
xmlns:controls="using:Material.Styles.Controls" |
||||
|
xmlns:assists="using:Material.Styles.Assists" |
||||
|
xmlns:icons="using:Material.Icons.Avalonia" |
||||
|
x:Class="JiLinApp.Pages.PtzServer.Ptz" |
||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="550"> |
||||
|
<UserControl.Styles> |
||||
|
<Style Selector="StackPanel"> |
||||
|
<Setter Property="VerticalAlignment" Value="Center" /> |
||||
|
</Style> |
||||
|
|
||||
|
<!--ComSetPanel--> |
||||
|
<Style Selector="#ComSetPanel ComboBox"> |
||||
|
<Setter Property="Width" Value="200" /> |
||||
|
</Style> |
||||
|
<Style Selector="#ComSetPanel WrapPanel"> |
||||
|
<Setter Property="HorizontalAlignment" Value="Center" /> |
||||
|
<Setter Property="VerticalAlignment" Value="Center" /> |
||||
|
</Style> |
||||
|
<Style Selector="#ComSetPanel WrapPanel Button"> |
||||
|
<Setter Property="Width" Value="100" /> |
||||
|
<Setter Property="Margin" Value="5" /> |
||||
|
</Style> |
||||
|
|
||||
|
<!--DeviceSetPanel--> |
||||
|
<Style Selector="#DeviceSetPanel ComboBox"> |
||||
|
<Setter Property="Width" Value="200" /> |
||||
|
</Style> |
||||
|
<Style Selector="#DeviceSetPanel Button"> |
||||
|
<Setter Property="Width" Value="100" /> |
||||
|
<Setter Property="Margin" Value="5" /> |
||||
|
</Style> |
||||
|
|
||||
|
<!--PtzSetPanel--> |
||||
|
<Style Selector="#PtzSetPanel ComboBox"> |
||||
|
<Setter Property="Width" Value="160" /> |
||||
|
</Style> |
||||
|
<!--PtzSelectPanel--> |
||||
|
<!--PtzCtrlPanel--> |
||||
|
<Style Selector="#PtzSetPanel Grid[Name=PtzCtrlPanel]"> |
||||
|
<Setter Property="HorizontalAlignment" Value="Center" /> |
||||
|
</Style> |
||||
|
<Style Selector="#PtzCtrlPanel StackPanel"> |
||||
|
<Setter Property="HorizontalAlignment" Value="Center" /> |
||||
|
<Setter Property="VerticalAlignment" Value="Center" /> |
||||
|
</Style> |
||||
|
<Style Selector="#PtzCtrlPanel StackPanel Button"> |
||||
|
<Setter Property="Width" Value="45" /> |
||||
|
<Setter Property="Height" Value="45" /> |
||||
|
<Setter Property="Padding" Value="0" /> |
||||
|
</Style> |
||||
|
<Style Selector="#PtzCtrlPanel StackPanel[(Grid.Column)=4] Button"> |
||||
|
<Setter Property="Width" Value="35" /> |
||||
|
<Setter Property="Height" Value="35" /> |
||||
|
<Setter Property="Padding" Value="0" /> |
||||
|
</Style> |
||||
|
<Style Selector="#PtzCtrlPanel StackPanel[(Grid.Column)=5] TextBlock"> |
||||
|
<Setter Property="Foreground" Value="#2b1f19" /> |
||||
|
</Style> |
||||
|
<Style Selector="#PtzCtrlPanel StackPanel[(Grid.Column)=6] Button"> |
||||
|
<Setter Property="Width" Value="35" /> |
||||
|
<Setter Property="Height" Value="35" /> |
||||
|
<Setter Property="Padding" Value="0" /> |
||||
|
</Style> |
||||
|
<!--PtzPresetPanel--> |
||||
|
<Style Selector="#PtzPresetPanel Button"> |
||||
|
<Setter Property="Width" Value="105" /> |
||||
|
<Setter Property="Margin" Value="5" /> |
||||
|
</Style> |
||||
|
</UserControl.Styles> |
||||
|
|
||||
|
<Grid RowDefinitions="300,250,auto" ColumnDefinitions="2*,1*"> |
||||
|
<Border Name="ComSetPanel" Grid.Row="0" Grid.Column="0" BorderBrush="#2196f3" BorderThickness="1" Margin="0 0 4 0"> |
||||
|
<Grid RowDefinitions="30,1*"> |
||||
|
<Border Grid.Row="0" Height="30" Background="#2196f3" Padding="8 0 0 0"> |
||||
|
<TextBlock Text="串口设置" FontSize="14" VerticalAlignment="Center" MaxLines="1" Foreground="#F0F0F0" /> |
||||
|
</Border> |
||||
|
<Grid Grid.Row="1" RowDefinitions="1*,1*,1*,1*" ColumnDefinitions="1*,1*"> |
||||
|
<StackPanel Grid.Row="0" Grid.Column="0"> |
||||
|
<ComboBox Name="ComNameCbx" Classes="Outline" ContextFlyout="{x:Null}" assists:ComboBoxAssist.Label="本地端口" /> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="0" Grid.Column="1"> |
||||
|
<ComboBox Name="BaudRateCbx" Classes="Outline" ContextFlyout="{x:Null}" SelectedIndex="3" assists:ComboBoxAssist.Label="波特率"> |
||||
|
<ComboBoxItem Content="1200" /> |
||||
|
<ComboBoxItem Content="2400" /> |
||||
|
<ComboBoxItem Content="4800" /> |
||||
|
<ComboBoxItem Content="9600" /> |
||||
|
<ComboBoxItem Content="19200" /> |
||||
|
</ComboBox> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<StackPanel Grid.Row="1" Grid.Column="0"> |
||||
|
<ComboBox Name="ParityCbx" Classes="Outline" ContextFlyout="{x:Null}" SelectedIndex="0" assists:ComboBoxAssist.Label="校验位"> |
||||
|
<ComboBoxItem Content="无" /> |
||||
|
</ComboBox> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="1" Grid.Column="1"> |
||||
|
<ComboBox Name="DataBitsCbx" Classes="Outline" ContextFlyout="{x:Null}" SelectedIndex="4" assists:ComboBoxAssist.Label="数据位"> |
||||
|
<ComboBoxItem Content="4" /> |
||||
|
<ComboBoxItem Content="5" /> |
||||
|
<ComboBoxItem Content="6" /> |
||||
|
<ComboBoxItem Content="7" /> |
||||
|
<ComboBoxItem Content="8" /> |
||||
|
</ComboBox> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<StackPanel Grid.Row="2" Grid.Column="0"> |
||||
|
<ComboBox Name="StopBitsCbx" Classes="Outline" ContextFlyout="{x:Null}" SelectedIndex="0" assists:ComboBoxAssist.Label="停止位"> |
||||
|
<ComboBoxItem Content="1" /> |
||||
|
<ComboBoxItem Content="1.5" /> |
||||
|
<ComboBoxItem Content="2" /> |
||||
|
</ComboBox> |
||||
|
</StackPanel> |
||||
|
<WrapPanel Grid.Row="2" Grid.Column="1"> |
||||
|
<Button Name="OpenComBtn" Classes="Light" Content="连接" /> |
||||
|
<Button Name="CloseComBtn" Classes="Light" Content="关闭" IsEnabled="False" /> |
||||
|
</WrapPanel> |
||||
|
</Grid> |
||||
|
</Grid> |
||||
|
</Border> |
||||
|
|
||||
|
<Border Name="DeviceSetPanel" Grid.Row="0" Grid.Column="1" BorderBrush="#2196f3" BorderThickness="1"> |
||||
|
<Grid RowDefinitions="30,1*"> |
||||
|
<Border Grid.Row="0" Height="30" Background="#2196f3" Padding="8 0 0 0"> |
||||
|
<TextBlock Text="设备设置" FontSize="14" VerticalAlignment="Center" MaxLines="1" Foreground="#F0F0F0" /> |
||||
|
</Border> |
||||
|
<Grid Grid.Row="1" RowDefinitions="1*,1*,1*,1*"> |
||||
|
<StackPanel Grid.Row="0" Grid.Column="0"> |
||||
|
<ComboBox Name="CameraIpCbx" Classes="Outline" ContextFlyout="{x:Null}" assists:ComboBoxAssist.Label="相机Ip" /> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<StackPanel Grid.Row="1" Grid.Column="0"> |
||||
|
<Button Name="ShowLiveVideoBtn" Classes="Light" Content="实时视频" /> |
||||
|
</StackPanel> |
||||
|
</Grid> |
||||
|
</Grid> |
||||
|
</Border> |
||||
|
|
||||
|
<Border Name="PtzSetPanel" Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" BorderBrush="#2196f3" BorderThickness="1" Margin="0 4 0 0"> |
||||
|
<Grid RowDefinitions="30,1*"> |
||||
|
<Border Grid.Row="0" Height="30" Background="#2196f3" Padding="8 0 0 0"> |
||||
|
<TextBlock Text="云台控制" FontSize="14" VerticalAlignment="Center" MaxLines="1" Foreground="#F0F0F0" /> |
||||
|
</Border> |
||||
|
<Grid Grid.Row="1" ColumnDefinitions="1*,2*,1*"> |
||||
|
<Grid Name="PtzSelectPanel" Grid.Column="0" RowDefinitions="60,60,1*"> |
||||
|
<StackPanel Grid.Row="0"> |
||||
|
<ComboBox Name="ControlTypeNameCbx" Classes="Outline" ContextFlyout="{x:Null}" assists:ComboBoxAssist.Label="控制类型" /> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="1"> |
||||
|
<ComboBox Name="CameraIdCbx" Classes="Outline" ContextFlyout="{x:Null}" assists:ComboBoxAssist.Label="相机Id" /> |
||||
|
</StackPanel> |
||||
|
</Grid> |
||||
|
|
||||
|
<Grid Name="PtzCtrlPanel" Grid.Column="1" RowDefinitions="50,50,50,1*" ColumnDefinitions="50,50,50,15,40,40,40"> |
||||
|
<StackPanel Grid.Row="0" Grid.Column="0"> |
||||
|
<Button Name="LeftTopBtn" Classes="Outline"> |
||||
|
<icons:MaterialIcon Kind="ArrowTopLeft" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="0" Grid.Column="1"> |
||||
|
<Button Name="TopBtn" Classes="Outline"> |
||||
|
<icons:MaterialIcon Kind="ArrowTop" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="0" Grid.Column="2"> |
||||
|
<Button Name="RightTopBtn" Classes="Outline"> |
||||
|
<icons:MaterialIcon Kind="ArrowTopRight" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<StackPanel Grid.Row="1" Grid.Column="0"> |
||||
|
<Button Name="LeftBtn" Classes="Outline"> |
||||
|
<icons:MaterialIcon Kind="ArrowLeft" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="1" Grid.Column="1"> |
||||
|
<Button Name="AutoMoveBtn" Classes="Outline"> |
||||
|
<icons:MaterialIcon Kind="Circle" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="1" Grid.Column="2"> |
||||
|
<Button Name="RightBtn" Classes="Outline"> |
||||
|
<icons:MaterialIcon Kind="ArrowRight" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<StackPanel Grid.Row="2" Grid.Column="0"> |
||||
|
<Button Name="LeftDownBtn" Classes="Outline"> |
||||
|
<icons:MaterialIcon Kind="ArrowBottomLeft" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="2" Grid.Column="1"> |
||||
|
<Button Name="DownBtn" Classes="Outline"> |
||||
|
<icons:MaterialIcon Kind="ArrowBottom" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="2" Grid.Column="2"> |
||||
|
<Button Name="RightDownBtn" Classes="Outline"> |
||||
|
<icons:MaterialIcon Kind="ArrowBottomRight" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<StackPanel Grid.Row="0" Grid.Column="4"> |
||||
|
<Button Name="ZoomInBtn" Classes="Outline"> |
||||
|
<icons:MaterialIcon Kind="PlusBold" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="0" Grid.Column="5"> |
||||
|
<TextBlock Text="调焦" /> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="0" Grid.Column="6"> |
||||
|
<Button Name="ZoomOutBtn" Classes="Outline"> |
||||
|
<icons:MaterialIcon Kind="MinusThick" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<StackPanel Grid.Row="1" Grid.Column="4"> |
||||
|
<Button Name="FocusNearBtn" Classes="Outline"> |
||||
|
<icons:MaterialIcon Kind="PlusThick" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="1" Grid.Column="5"> |
||||
|
<TextBlock Text="聚焦" /> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="1" Grid.Column="6"> |
||||
|
<Button Name="FocusFarBtn" Classes="Outline"> |
||||
|
<icons:MaterialIcon Kind="MinusThick" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
|
||||
|
<StackPanel Grid.Row="2" Grid.Column="4"> |
||||
|
<Button Name="IrisOpenBtn" Classes="Outline"> |
||||
|
<icons:MaterialIcon Kind="PlusThick" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="2" Grid.Column="5"> |
||||
|
<TextBlock Text="光焦" /> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="2" Grid.Column="6"> |
||||
|
<Button Name="IrisCloseBtn" Classes="Outline"> |
||||
|
<icons:MaterialIcon Kind="MinusThick" /> |
||||
|
</Button> |
||||
|
</StackPanel> |
||||
|
</Grid> |
||||
|
|
||||
|
<Grid Name="PtzPresetPanel" Grid.Column="2" RowDefinitions="60,60,1*"> |
||||
|
<StackPanel Grid.Row="0"> |
||||
|
<ComboBox Name="PresetIdCbx" Classes="Outline" ContextFlyout="{x:Null}" assists:ComboBoxAssist.Label="预置点" /> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="1"> |
||||
|
<Button Name="GotoBtn" Classes="Light" Content="前往预置点" /> |
||||
|
</StackPanel> |
||||
|
</Grid> |
||||
|
</Grid> |
||||
|
</Grid> |
||||
|
</Border> |
||||
|
</Grid> |
||||
|
</UserControl> |
@ -0,0 +1,405 @@ |
|||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Input; |
||||
|
using Avalonia.Interactivity; |
||||
|
using Avalonia.Threading; |
||||
|
using EC.Util.CameraSDK; |
||||
|
using EC.Util.Common; |
||||
|
using EC.Util.Port; |
||||
|
using JiLinApp.Biz.TransmitAlarm; |
||||
|
using JiLinApp.Components; |
||||
|
using JiLinApp.Core; |
||||
|
using JiLinApp.Core.App; |
||||
|
using JiLinApp.Core.Avalonia; |
||||
|
using JiLinApp.Docking.FenceAlarm; |
||||
|
using JiLinApp.Docking.Military; |
||||
|
using JiLinApp.Docking.Ptz; |
||||
|
using JiLinApp.Docking.VibrateAlarm; |
||||
|
using System; |
||||
|
using System.Collections.Concurrent; |
||||
|
using System.Collections.Generic; |
||||
|
using System.IO.Ports; |
||||
|
using System.Linq; |
||||
|
using System.Text.RegularExpressions; |
||||
|
using System.Threading; |
||||
|
|
||||
|
namespace JiLinApp.Pages.PtzServer; |
||||
|
|
||||
|
public partial class Ptz : UserControl |
||||
|
{ |
||||
|
#region Fields
|
||||
|
|
||||
|
private AppConfig AppConfig { get; } = Global.AppConfig; |
||||
|
|
||||
|
private MilitaryService MilitaryService { get; } = Global.MilitaryService; |
||||
|
|
||||
|
private List<CameraLinkageInfo> CameraLinkageList { get; set; } = new(); |
||||
|
|
||||
|
private ConcurrentDictionary<string, ICameraSdk> CameraSdkDict { get; } = new(); |
||||
|
|
||||
|
private ConcurrentDictionary<string, CameraRealPlay> RealPlayDict { get; } = new(); |
||||
|
|
||||
|
private Window? _win; |
||||
|
|
||||
|
private Window? Wdw |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
_win ??= ControlsUtil.GetWindow(this); |
||||
|
return _win; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#endregion Fields
|
||||
|
|
||||
|
public Ptz() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
|
||||
|
//绑定串口服务开关响应事件
|
||||
|
OpenComBtn.Click += OpenComBtn_Click; |
||||
|
CloseComBtn.Click += CloseComBtn_Click; |
||||
|
//绑定实时视频响应事件
|
||||
|
ShowLiveVideoBtn.Click += ShowLiveVideoBtn_Click; |
||||
|
//绑定云台响应事件
|
||||
|
List<Button> btnList = new(); |
||||
|
ControlsUtil.FindChild(PtzCtrlPanel, ref btnList); |
||||
|
foreach (var btn in btnList) |
||||
|
{ |
||||
|
btn.AddHandler(PointerPressedEvent, PtzBtn_MouseDown, RoutingStrategies.Tunnel); |
||||
|
btn.AddHandler(PointerReleasedEvent, PtzBtn_MouseUp, RoutingStrategies.Tunnel); |
||||
|
} |
||||
|
GotoBtn.Click += GotoBtn_Click; |
||||
|
//绑定云台控制类型更改事件
|
||||
|
ControlTypeNameCbx.SelectionChanged += ControlTypeName_SelectionChanged; |
||||
|
|
||||
|
MessageEvent.VibrateAlarm.Subscribe(HandleVibrateAlarm); |
||||
|
MessageEvent.FenceAlarm.Subscribe(HandleFenceAlarm); |
||||
|
|
||||
|
// 初始化串口下拉框
|
||||
|
string[] ports = SerialPort.GetPortNames().OrderBy(s => int.Parse(Regex.Match(s, @"\d+").Value)).ToArray(); |
||||
|
foreach (string port in ports) ComNameCbx.Items.Add(new ComboBoxItem { Content = port }); |
||||
|
ComNameCbx.SelectedIndex = 0; |
||||
|
// 初始化相机 sdk 和相机 ip 下拉框
|
||||
|
CameraLinkageList = MilitaryService.GetCameraLinkageList(); |
||||
|
TaskUtil.RunCatch(() => Dispatcher.UIThread.Invoke(() => LoadCameraSdkDict(MilitaryService.GetCameraList()))); |
||||
|
// 初始化云台控制类型下拉框
|
||||
|
foreach (var cfg in AppConfig.Base.PtzCtrlTypes) ControlTypeNameCbx.Items.Add(new ComboBoxItem { Content = cfg.Name }); |
||||
|
ControlTypeNameCbx.SelectedIndex = 0; |
||||
|
// 初始化相机 id 下拉框
|
||||
|
for (int i = 1; i <= 5; i++) CameraIdCbx.Items.Add(new ComboBoxItem { Content = i }); |
||||
|
CameraIdCbx.SelectedIndex = 0; |
||||
|
// 初始化预置点 id 下拉框
|
||||
|
for (int i = 1; i <= 10; i++) PresetIdCbx.Items.Add(new ComboBoxItem { Content = i }); |
||||
|
PresetIdCbx.SelectedIndex = 0; |
||||
|
} |
||||
|
|
||||
|
#region Com
|
||||
|
|
||||
|
private YcSerialPort? Port { get; set; } |
||||
|
|
||||
|
private bool IsComConnect() |
||||
|
{ |
||||
|
return Port != null && Port.IsOpen(); |
||||
|
} |
||||
|
|
||||
|
private void ChangeState(bool openState) |
||||
|
{ |
||||
|
OpenComBtn.IsEnabled = !openState; |
||||
|
CloseComBtn.IsEnabled = openState; |
||||
|
} |
||||
|
|
||||
|
#endregion Com
|
||||
|
|
||||
|
#region Element Event
|
||||
|
|
||||
|
private void OpenComBtn_Click(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
if (IsComConnect()) return; |
||||
|
try |
||||
|
{ |
||||
|
SerialPortParam param = new() |
||||
|
{ |
||||
|
ComName = ComNameCbx.GetText(), |
||||
|
BaudRate = int.Parse(BaudRateCbx.GetText()), |
||||
|
Parity = 0, |
||||
|
DataBits = int.Parse(DataBitsCbx.GetText()), |
||||
|
StopBits = int.Parse(StopBitsCbx.GetText()), |
||||
|
}; |
||||
|
Port = new YcSerialPort(param); |
||||
|
Port.OpenCom(); |
||||
|
ChangeState(true); |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
Port = null; |
||||
|
_ = ControlsUtil.ShowWarnDialog(Wdw, message: ex.ToString()); |
||||
|
LogUnit.Error(ex); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void CloseComBtn_Click(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
if (!IsComConnect()) return; |
||||
|
try |
||||
|
{ |
||||
|
Port?.CloseCom(); |
||||
|
Port = null; |
||||
|
ChangeState(false); |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
_ = ControlsUtil.ShowWarnDialog(Wdw, message: ex.ToString()); |
||||
|
LogUnit.Error(ex); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void PtzBtn_MouseDown(object? sender, PointerPressedEventArgs e) |
||||
|
{ |
||||
|
if (sender is not Button btn) return; |
||||
|
PtzControlType ctrlType = PtzControlTypeConfigHelper.GetControlType(ControlTypeNameCbx.GetText()); |
||||
|
PtzCmdType cmdType = PtzCmd.GetCmdType((btn.Name ?? string.Empty).Replace("Btn", "")); |
||||
|
switch (ctrlType) |
||||
|
{ |
||||
|
case PtzControlType.PelcoD: |
||||
|
case PtzControlType.PelcoP: |
||||
|
if (!IsComConnect()) break; |
||||
|
byte cameraId = byte.Parse(CameraIdCbx.GetText()); |
||||
|
byte[] cmd = PtzComCmd.GetCmd(ctrlType, cmdType, new object[] { cameraId }); |
||||
|
if (cmd != null && cmd.Length > 0) Port?.SendHex(cmd); |
||||
|
break; |
||||
|
|
||||
|
case PtzControlType.DCamera: |
||||
|
if (!IsComConnect()) break; |
||||
|
cmd = PtzComCmd.GetCmd(ctrlType, cmdType); |
||||
|
if (cmd != null && cmd.Length > 0) Port?.SendHex(cmd); |
||||
|
break; |
||||
|
|
||||
|
case PtzControlType.CameraSdk: |
||||
|
string cameraIp = CameraIpCbx.GetText(); |
||||
|
CameraSdkDict.TryGetValue(cameraIp, out ICameraSdk? cameraSdk); |
||||
|
if (cameraSdk == null) break; |
||||
|
int stop = 0; |
||||
|
PtzCameraCmd.PtzMove(cameraSdk, cmdType, new int[] { stop }); |
||||
|
break; |
||||
|
|
||||
|
default: break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void PtzBtn_MouseUp(object? sender, PointerReleasedEventArgs e) |
||||
|
{ |
||||
|
if (sender is not Button btn) return; |
||||
|
PtzControlType ctrlType = PtzControlTypeConfigHelper.GetControlType(ControlTypeNameCbx.GetText()); |
||||
|
PtzCmdType cmdType = PtzCmdType.Stop; |
||||
|
switch (ctrlType) |
||||
|
{ |
||||
|
case PtzControlType.PelcoD: |
||||
|
case PtzControlType.PelcoP: |
||||
|
if (!IsComConnect()) break; |
||||
|
byte cameraId = byte.Parse(CameraIdCbx.GetText()); |
||||
|
byte[] cmd = PtzComCmd.GetCmd(ctrlType, cmdType, new object[] { cameraId }); |
||||
|
if (cmd != null && cmd.Length > 0) Port?.SendHex(cmd); |
||||
|
break; |
||||
|
|
||||
|
case PtzControlType.DCamera: |
||||
|
if (!IsComConnect()) break; |
||||
|
cmd = PtzComCmd.GetCmd(ctrlType, cmdType); |
||||
|
if (cmd != null && cmd.Length > 0) Port?.SendHex(cmd); |
||||
|
break; |
||||
|
|
||||
|
case PtzControlType.CameraSdk: |
||||
|
string cameraIp = CameraIpCbx.GetText(); |
||||
|
CameraSdkDict.TryGetValue(cameraIp, out ICameraSdk? cameraSdk); |
||||
|
if (cameraSdk == null) break; |
||||
|
cmdType = PtzCmd.GetCmdType((btn.Name ?? string.Empty).Replace("Btn", "")); |
||||
|
int stop = 1; |
||||
|
PtzCameraCmd.PtzMove(cameraSdk, cmdType, new int[] { stop }); |
||||
|
break; |
||||
|
|
||||
|
default: break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void GotoBtn_Click(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
PtzControlType ctrlType = PtzControlTypeConfigHelper.GetControlType(ControlTypeNameCbx.GetText()); |
||||
|
PtzCmdType cmdType = PtzCmdType.PresetGoto; |
||||
|
byte presetId = byte.Parse(PresetIdCbx.GetText()); |
||||
|
switch (ctrlType) |
||||
|
{ |
||||
|
case PtzControlType.PelcoD: |
||||
|
case PtzControlType.PelcoP: |
||||
|
if (!IsComConnect()) break; |
||||
|
byte cameraId = byte.Parse(CameraIdCbx.GetText()); |
||||
|
byte[] cmd = PtzComCmd.GetCmd(ctrlType, cmdType, new object[] { cameraId, presetId }); |
||||
|
if (cmd != null && cmd.Length > 0) Port?.SendHex(cmd); |
||||
|
break; |
||||
|
|
||||
|
case PtzControlType.CameraSdk: |
||||
|
string cameraIp = CameraIpCbx.GetText(); |
||||
|
CameraSdkDict.TryGetValue(cameraIp, out ICameraSdk? cameraSdk); |
||||
|
if (cameraSdk == null) break; |
||||
|
PtzCameraCmd.PtzMove(cameraSdk, cmdType, new int[] { presetId }); |
||||
|
break; |
||||
|
|
||||
|
default: break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void ShowLiveVideoBtn_Click(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
string cameraIp = CameraIpCbx.GetText(); |
||||
|
if (!CameraSdkDict.TryGetValue(cameraIp, out ICameraSdk? sdk)) return; |
||||
|
Dispatcher.UIThread.Invoke(() => ShowLiveVideo(sdk)); |
||||
|
} |
||||
|
|
||||
|
private void ControlTypeName_SelectionChanged(object? sender, SelectionChangedEventArgs e) |
||||
|
{ |
||||
|
if (e.AddedItems[0] is not ComboBoxItem cbxItem) return; |
||||
|
string ctrlTypeName = cbxItem?.Content?.ToString() ?? string.Empty; |
||||
|
PtzControlType ctrlType = PtzControlTypeConfigHelper.GetControlType(ctrlTypeName); |
||||
|
switch (ctrlType) |
||||
|
{ |
||||
|
case PtzControlType.PelcoD: |
||||
|
case PtzControlType.PelcoP: |
||||
|
case PtzControlType.DCamera: |
||||
|
CameraIdCbx.IsEnabled = true; |
||||
|
CameraIpCbx.IsEnabled = false; |
||||
|
ShowLiveVideoBtn.IsEnabled = false; |
||||
|
break; |
||||
|
|
||||
|
case PtzControlType.CameraSdk: |
||||
|
CameraIdCbx.IsEnabled = false; |
||||
|
CameraIpCbx.IsEnabled = true; |
||||
|
ShowLiveVideoBtn.IsEnabled = true; |
||||
|
break; |
||||
|
|
||||
|
default: |
||||
|
CameraIdCbx.IsEnabled = false; |
||||
|
CameraIpCbx.IsEnabled = false; |
||||
|
ShowLiveVideoBtn.IsEnabled = false; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#endregion Element Event
|
||||
|
|
||||
|
#region Invoke Event
|
||||
|
|
||||
|
private void ShowLiveVideo(ICameraSdk sdk) |
||||
|
{ |
||||
|
if (!sdk.ConnectSuccess()) { LogUnit.Error(this, $"CameraSdk(cameraIp:{sdk.CameraInfo.Ip}) connect failure."); return; } |
||||
|
if (!ControlsUtil.TryGetWindow(this, out Window? w)) return; |
||||
|
string cameraIp = sdk.CameraInfo.Ip; |
||||
|
RealPlayDict.TryGetValue(cameraIp, out CameraRealPlay? realPlay); |
||||
|
if (realPlay == null || realPlay.IsClosed) |
||||
|
{ |
||||
|
realPlay = new(sdk) |
||||
|
{ |
||||
|
Title = $"RealPlay({sdk.CameraInfo.Name})", |
||||
|
CanResize = false, |
||||
|
ShowInTaskbar = true |
||||
|
}; |
||||
|
RealPlayDict[cameraIp] = realPlay; |
||||
|
} |
||||
|
realPlay.Show(w); |
||||
|
realPlay.WindowState = WindowState.Normal; |
||||
|
realPlay.StartPlay(); |
||||
|
} |
||||
|
|
||||
|
private void HandleVibrateAlarm(TcpAlarmHostMessage msg) |
||||
|
{ |
||||
|
AlarmMessage alarm = msg.ToAlarmMessage(); |
||||
|
TaskUtil.RunCatch(() => HandleAlarmInvoke(alarm)); |
||||
|
} |
||||
|
|
||||
|
private void HandleFenceAlarm(UdpAlarmHostMessage msg) |
||||
|
{ |
||||
|
AlarmMessage alarm = msg.ToAlarmMessage(); |
||||
|
TaskUtil.RunCatch(() => HandleAlarmInvoke(alarm)); |
||||
|
} |
||||
|
|
||||
|
private void HandleAlarmInvoke(AlarmMessage alarm) |
||||
|
{ |
||||
|
if (alarm == null) return; |
||||
|
bool realPlay = AppConfig.AlarmPlatform.RealPlay; |
||||
|
string deviceId = alarm.LabelCode; |
||||
|
string sensorId = alarm.ChannelId; |
||||
|
List<CameraLinkageInfo> cameraLinkages = GetCameraLinkageList(sensorId); |
||||
|
foreach (var item in cameraLinkages) |
||||
|
{ |
||||
|
if (item == null) { LogUnit.Error(this, $"CameraLinkageInfo(sensorId:{sensorId}) not found."); return; } |
||||
|
string cameraId = item.CameraId; |
||||
|
ICameraSdk? cameraSdk = GetCameraSdk(cameraId); |
||||
|
if (cameraSdk == null) { LogUnit.Error(this, $"CameraSdk(cameraId:{cameraId}) not found."); return; } |
||||
|
if (realPlay) Dispatcher.UIThread.Invoke(() => ShowLiveVideo(cameraSdk)); |
||||
|
// TODO: 设计 PriorityQueue
|
||||
|
int len = item.PresetIds.Length; |
||||
|
for (int i = 0; i < len; i++) |
||||
|
{ |
||||
|
int presetId = item.PresetIds[i]; |
||||
|
PtzCameraCmd.PtzMove(cameraSdk, PtzCmdType.PresetGoto, new int[] { presetId }); |
||||
|
if (i != len) Thread.Sleep(5000); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#endregion Invoke Event
|
||||
|
|
||||
|
#region Military
|
||||
|
|
||||
|
private void LoadCameraSdkDict(List<CameraInfo> cameraList) |
||||
|
{ |
||||
|
int tryTime = 5, tryInterval = 500; |
||||
|
for (int i = 0; i < cameraList.Count; i++) |
||||
|
{ |
||||
|
CameraInfo info = cameraList[i]; |
||||
|
string ip = info.Ip; |
||||
|
if (CameraSdkDict.ContainsKey(ip)) continue; |
||||
|
ICameraSdk sdk = CameraFactory.BuildCameraSdk(info); |
||||
|
CameraSdkDict[ip] = sdk; |
||||
|
CameraIpCbx.Items.Add(new ComboBoxItem { Content = ip }); |
||||
|
TaskUtil.RunCatch(() => |
||||
|
{ |
||||
|
bool flag = false; |
||||
|
for (int i = 0; i < tryTime; i++) |
||||
|
{ |
||||
|
flag = sdk.Init(); |
||||
|
if (flag) break; |
||||
|
Thread.Sleep(tryInterval); |
||||
|
} |
||||
|
}); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private CameraLinkageInfo? GetCameraLinkage(string sensorId) |
||||
|
{ |
||||
|
foreach (var item in CameraLinkageList) |
||||
|
{ |
||||
|
if (sensorId.Equals(item.SensorId)) return item; |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
private List<CameraLinkageInfo> GetCameraLinkageList(string sensorId) |
||||
|
{ |
||||
|
List<CameraLinkageInfo> list = new(); |
||||
|
foreach (var item in CameraLinkageList) |
||||
|
{ |
||||
|
if (sensorId.Equals(item.SensorId)) list.Add(item); |
||||
|
} |
||||
|
return list; |
||||
|
} |
||||
|
|
||||
|
private ICameraSdk? GetCameraSdk(string cameraId) |
||||
|
{ |
||||
|
foreach (var item in CameraSdkDict.Values) |
||||
|
{ |
||||
|
if (item == null) continue; |
||||
|
if (cameraId.Equals(item.CameraInfo.Id)) return item; |
||||
|
} |
||||
|
return null; |
||||
|
} |
||||
|
|
||||
|
#endregion Military
|
||||
|
} |
@ -0,0 +1,10 @@ |
|||||
|
using JiLinApp.Core.Avalonia; |
||||
|
|
||||
|
namespace JiLinApp.Pages.PtzServer; |
||||
|
|
||||
|
public class PtzViewModel : ViewModelBase |
||||
|
{ |
||||
|
public PtzViewModel() |
||||
|
{ |
||||
|
} |
||||
|
} |
@ -0,0 +1,54 @@ |
|||||
|
<UserControl xmlns="https://github.com/avaloniaui" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" |
||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" |
||||
|
xmlns:controls="using:Material.Styles.Controls" |
||||
|
xmlns:assists="using:Material.Styles.Assists" |
||||
|
x:Class="JiLinApp.Pages.VibrateServer.Vibrate" |
||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"> |
||||
|
<UserControl.Styles> |
||||
|
<Style Selector="#VibratePanel TextBox"> |
||||
|
<Setter Property="Width" Value="200" /> |
||||
|
<Setter Property="UseFloatingWatermark" Value="True"/> |
||||
|
</Style> |
||||
|
<Style Selector="#VibratePanel TextBlock[Name=PART_LabelText]"> |
||||
|
<Setter Property="Foreground" Value="#272727"/> |
||||
|
</Style> |
||||
|
<Style Selector="#VibratePanel TextBox:focus TextBlock[Name=PART_LabelText]"> |
||||
|
<Setter Property="Foreground" Value="#2196f3"/> |
||||
|
</Style> |
||||
|
<Style Selector="#VibratePanel StackPanel"> |
||||
|
<Setter Property="VerticalAlignment" Value="Center" /> |
||||
|
</Style> |
||||
|
<Style Selector="#VibratePanel WrapPanel"> |
||||
|
<Setter Property="HorizontalAlignment" Value="Center" /> |
||||
|
<Setter Property="VerticalAlignment" Value="Center" /> |
||||
|
</Style> |
||||
|
<Style Selector="#VibratePanel WrapPanel Button"> |
||||
|
<Setter Property="Width" Value="100" /> |
||||
|
<Setter Property="Margin" Value="5" /> |
||||
|
</Style> |
||||
|
</UserControl.Styles> |
||||
|
|
||||
|
<Grid RowDefinitions="250,1*"> |
||||
|
<Border Name="VibratePanel" Grid.Row="0" BorderBrush="#2196f3" BorderThickness="1"> |
||||
|
<Grid RowDefinitions="30,1*"> |
||||
|
<Border Grid.Row="0" Height="30" Background="#2196f3" Padding="8 0 0 0"> |
||||
|
<TextBlock Text="震动报警服务器设置(TCP)" FontSize="14" VerticalAlignment="Center" MaxLines="1" Foreground="#F0F0F0" /> |
||||
|
</Border> |
||||
|
<Grid Grid.Row="1" RowDefinitions="1*,1*,1*" ColumnDefinitions="1*,1*,1*"> |
||||
|
<StackPanel Grid.Row="0" Grid.Column="0"> |
||||
|
<TextBox Name="ServerPortTb" Classes="outline" Text="9000" assists:TextFieldAssist.Label="本地端口" /> |
||||
|
</StackPanel> |
||||
|
<StackPanel Grid.Row="1" Grid.Column="0"> |
||||
|
<TextBox Name="HeartKeepTb" Classes="outline" Text="10" assists:TextFieldAssist.Label="心跳间隔" /> |
||||
|
</StackPanel> |
||||
|
<WrapPanel Grid.Row="2" Grid.Column="0"> |
||||
|
<Button Name="OpenBtn" Classes="Light" Content="开启服务" Width="100" Margin="5" /> |
||||
|
<Button Name="CloseBtn" Classes="Light" Content="关闭服务" Width="100" Margin="5" IsEnabled="False" /> |
||||
|
</WrapPanel> |
||||
|
</Grid> |
||||
|
</Grid> |
||||
|
</Border> |
||||
|
</Grid> |
||||
|
</UserControl> |
@ -0,0 +1,168 @@ |
|||||
|
using Avalonia.Controls; |
||||
|
using Avalonia.Interactivity; |
||||
|
using EC.Util.Common; |
||||
|
using JiLinApp.Biz.TransmitAlarm; |
||||
|
using JiLinApp.Core; |
||||
|
using JiLinApp.Core.App; |
||||
|
using JiLinApp.Core.Avalonia; |
||||
|
using JiLinApp.Docking.VibrateAlarm; |
||||
|
using Newtonsoft.Json.Linq; |
||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Linq; |
||||
|
using System.Reactive.Linq; |
||||
|
|
||||
|
namespace JiLinApp.Pages.VibrateServer; |
||||
|
|
||||
|
public partial class Vibrate : UserControl |
||||
|
{ |
||||
|
#region Fields
|
||||
|
|
||||
|
private TcpManager Manager { get; } = new(); |
||||
|
|
||||
|
private IAlarmService AlarmService { get; set; } |
||||
|
|
||||
|
private Window? _win; |
||||
|
|
||||
|
private Window? Wdw |
||||
|
{ |
||||
|
get |
||||
|
{ |
||||
|
_win ??= ControlsUtil.GetWindow(this); |
||||
|
return _win; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#endregion Fields
|
||||
|
|
||||
|
public Vibrate() |
||||
|
{ |
||||
|
InitializeComponent(); |
||||
|
|
||||
|
AlarmService = Global.AlarmService; |
||||
|
OpenBtn.Click += OpenBtn_Click; |
||||
|
CloseBtn.Click += CloseBtn_Click; |
||||
|
|
||||
|
Manager.OnVibrateTcpDeviceState += Manager_OnVibrateTcpDeviceState; |
||||
|
Manager.OnVibrateTcpSensorState += Manager_OnVibrateTcpSensorSate; |
||||
|
Manager.OnVibrateTcpAlarm += Manager_OnVibrateTcpAlarm; |
||||
|
AlarmService.OnVibrateTcpSendDevices += AlarmService_OnVibrateTcpSendDevices; |
||||
|
AlarmService.OnVibrateTcpSendSensors += AlarmService_OnVibrateTcpSendSensors; |
||||
|
} |
||||
|
|
||||
|
#region ElementEvent
|
||||
|
|
||||
|
private void OpenBtn_Click(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
if (Manager.IsRunning()) return; |
||||
|
try |
||||
|
{ |
||||
|
TcpManagerConfig config = new() |
||||
|
{ |
||||
|
ServerPort = int.Parse(ServerPortTb.GetText()), |
||||
|
DeviceHeartKeep = int.Parse(HeartKeepTb.GetText()) |
||||
|
}; |
||||
|
Manager.Start(config); |
||||
|
ChangeServerBtnState(true); |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
_ = ControlsUtil.ShowWarnDialog(Wdw, message: ex.ToString()); |
||||
|
LogUnit.Error(ex); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void CloseBtn_Click(object? sender, RoutedEventArgs e) |
||||
|
{ |
||||
|
if (!Manager.IsRunning()) return; |
||||
|
try |
||||
|
{ |
||||
|
Manager.Stop(); |
||||
|
ChangeServerBtnState(false); |
||||
|
} |
||||
|
catch (Exception ex) |
||||
|
{ |
||||
|
_ = ControlsUtil.ShowWarnDialog(Wdw, message: ex.ToString()); |
||||
|
LogUnit.Error(ex); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
private void ChangeServerBtnState(bool openState) |
||||
|
{ |
||||
|
OpenBtn.IsEnabled = !openState; |
||||
|
CloseBtn.IsEnabled = openState; |
||||
|
} |
||||
|
|
||||
|
#endregion ElementEvent
|
||||
|
|
||||
|
#region Manager Event
|
||||
|
|
||||
|
private void Manager_OnVibrateTcpDeviceState(ClientMessage device) |
||||
|
{ |
||||
|
object deviceObj = new |
||||
|
{ |
||||
|
id = device.Host.Id, |
||||
|
onlineState = device.OnlineState |
||||
|
}; |
||||
|
AlarmService.SendDeviceState(DeviceType.Vibrate, deviceObj); |
||||
|
} |
||||
|
|
||||
|
private void Manager_OnVibrateTcpSensorSate(SensorState sensor) |
||||
|
{ |
||||
|
object sensorObj = new |
||||
|
{ |
||||
|
id = sensor.Addr, |
||||
|
deviceId = sensor.DeviceId, |
||||
|
onlineState = sensor.OnlineState, |
||||
|
alarmState = sensor.AlarmState, |
||||
|
}; |
||||
|
AlarmService.SendSensorState(DeviceType.Vibrate, sensorObj); |
||||
|
} |
||||
|
|
||||
|
private void Manager_OnVibrateTcpAlarm(TcpAlarmHostMessage msg) |
||||
|
{ |
||||
|
AlarmMessage alarm = msg.ToAlarmMessage(); |
||||
|
AlarmService.SendAlarm(alarm); |
||||
|
MessageEvent.VibrateAlarm.Publish(msg); |
||||
|
} |
||||
|
|
||||
|
#endregion Manager Event
|
||||
|
|
||||
|
#region SubCmd Event
|
||||
|
|
||||
|
private void AlarmService_OnVibrateTcpSendDevices(JObject reqObj) |
||||
|
{ |
||||
|
List<object> respDeviceList = new(); |
||||
|
List<ClientMessage> deviceList = Manager.GetDeviceList(); |
||||
|
foreach (var item in deviceList) |
||||
|
{ |
||||
|
if (item.Host.Id <= 0) continue; |
||||
|
respDeviceList.Add(new |
||||
|
{ |
||||
|
id = item.Host.Id, |
||||
|
onlineState = item.OnlineState |
||||
|
}); |
||||
|
} |
||||
|
AlarmService.SendDevices(DeviceType.Vibrate, respDeviceList); |
||||
|
} |
||||
|
|
||||
|
private void AlarmService_OnVibrateTcpSendSensors(JObject reqObj) |
||||
|
{ |
||||
|
int deviceId = reqObj.GetValue("deviceId", StringComparison.OrdinalIgnoreCase).ToInt(); |
||||
|
List<SensorState> sensorList = Manager.TryGetDevice(deviceId, out ClientMessage device) ? device.SensorDict.Values.ToList() : new(); |
||||
|
List<object> respSensorList = new(); |
||||
|
foreach (var item in sensorList) |
||||
|
{ |
||||
|
respSensorList.Add(new |
||||
|
{ |
||||
|
id = item.Addr, |
||||
|
deviceId = item.DeviceId, |
||||
|
onlineState = item.OnlineState, |
||||
|
alarmState = item.AlarmState, |
||||
|
}); |
||||
|
} |
||||
|
AlarmService.SendSensors(DeviceType.Vibrate, deviceId, respSensorList); |
||||
|
} |
||||
|
|
||||
|
#endregion SubCmd Event
|
||||
|
} |
@ -0,0 +1,10 @@ |
|||||
|
using JiLinApp.Core.Avalonia; |
||||
|
|
||||
|
namespace JiLinApp.Pages.VibrateServer; |
||||
|
|
||||
|
public class VibrateViewModel : ViewModelBase |
||||
|
{ |
||||
|
public VibrateViewModel() |
||||
|
{ |
||||
|
} |
||||
|
} |
@ -0,0 +1,50 @@ |
|||||
|
{ |
||||
|
"base": { |
||||
|
"console": true, |
||||
|
"ptzCtrlTypes": [ |
||||
|
{ |
||||
|
"type": "CameraSdk", |
||||
|
"Name": "协议HDY" |
||||
|
}, |
||||
|
{ |
||||
|
"type": "PelcoD", |
||||
|
"Name": "协议Pd" |
||||
|
}, |
||||
|
{ |
||||
|
"type": "PelcoP", |
||||
|
"Name": "协议Pp" |
||||
|
}, |
||||
|
{ |
||||
|
"type": "DCamera", |
||||
|
"Name": "协议D508" |
||||
|
} |
||||
|
|
||||
|
] |
||||
|
}, |
||||
|
"military": { |
||||
|
"url": "http://192.168.1.119:8080/military", |
||||
|
"username": "admin", |
||||
|
"password": "123456", |
||||
|
"requestTryTime": "5", |
||||
|
"requestTryInterval": "200" |
||||
|
}, |
||||
|
"alarmPlatform": { |
||||
|
"realPlay": true, |
||||
|
"type": "mqtt", |
||||
|
"mqtt": { |
||||
|
"ip": "192.168.1.200", |
||||
|
"port": "1883", |
||||
|
"username": "admin", |
||||
|
"password": "public", |
||||
|
"clientId": "alarm-platform1", |
||||
|
"retryTime": "5", |
||||
|
"retryInterval": "200", |
||||
|
"pubDevicesTopic": "PPS/Devices", |
||||
|
"pubSensorsTopic": "PPS/Sensors", |
||||
|
"pubDeviceStateTopic": "PPS/DeviceState", |
||||
|
"pubSensorStateTopic": "PPS/SensorState", |
||||
|
"pubAlarmTopic": "PPS/AlarmMessage/Fence", |
||||
|
"subCmdTopic": "PPS/Cmd" |
||||
|
} |
||||
|
} |
||||
|
} |
Loading…
Reference in new issue