23.05.04 Day67

오윤범·2023년 5월 4일
0

MiniProject

목록 보기
5/8

MQTT EXPLORER로 가상 데이터 뿌리기

MainWindow.xaml

<mah:MetroWindow x:Class="FakeIotDevice.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        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:mah="http://metro.mahapps.com/winfx/xaml/controls"
        xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
        xmlns:local="clr-namespace:FakeIotDevice"
        mc:Ignorable="d"
        Title="Fake IOT Device" Height="500" Width="580" MinHeight="400" MinWidth="500" Closing="MetroWindow_Closing"
                 Loaded="MetroWindow_Loaded">
    <mah:MetroWindow.IconTemplate>
        <DataTemplate>
            <iconPacks:PackIconSimpleIcons Kind="EclipseMosquitto" Foreground="White"
                                           Margin="5,7,0,0" Width="24"/>
        </DataTemplate>
    </mah:MetroWindow.IconTemplate>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="40"/>
            <RowDefinition Height="1*"/>
        </Grid.RowDefinitions>

        <StackPanel Grid.Row="0" Orientation="Horizontal">
            <Label Content="MQTT Broker IP Address" VerticalAlignment="Center"/>
            <TextBox x:Name="TxtMqttBrokerIp" Width="250" Margin="5" VerticalAlignment="Center"
                     mah:TextBoxHelper.Watermark="브로커 아이피를 입력하세요"/>
            <Button x:Name="BtnConnect" Content="Connect" Margin="5"
                    Style="{StaticResource MahApps.Styles.Button.Square.Accent}" Click="BtnConnect_Click"/>
        </StackPanel>

        <RichTextBox Grid.Row="1" x:Name="RtbLog" Margin="10" VerticalScrollBarVisibility="Visible">
            <RichTextBox.Resources>
                <Style TargetType="{x:Type Paragraph}">
                    <Setter Property="Margin" Value="0"/>
                </Style>
            </RichTextBox.Resources>
        </RichTextBox>

    </Grid>
</mah:MetroWindow>

MainWindow.xaml.cs

using System.Windows;
using MahApps.Metro.Controls;
using Newtonsoft.Json;
using MahApps.Metro.Controls.Dialogs;
using Bogus;
using FakeIotDevice.Models;
using uPLibrary.Networking.M2Mqtt;
using System.Threading;
using System.Diagnostics;
using System.Text;
using System;
using System.Windows.Documents;

namespace FakeIotDevice
{
    /// <summary>
    /// MainWindow.xaml에 대한 상호 작용 논리
    /// </summary>
    public partial class MainWindow : MetroWindow
    {
        Faker<SensorInfo> FakeHomeSensor { get;set; } = null; // 가짜 스마트홈 센서값
        MqttClient Client { get; set; }
        Thread MqttThread { get; set; }

        public MainWindow()
        {
            InitializeComponent();
            InitFakeData();
        }

        private void InitFakeData()
        {
            var Rooms = new[] { "Bed", "Bath", "Living", "Dining" };
            FakeHomeSensor = new Faker<SensorInfo>()
                .RuleFor(s => s.Home_Id, "D101H703") // 임의로 픽스된 홈 아이디 101동 703호
                .RuleFor(s => s.Room_Name, f => f.PickRandom(Rooms)) // 실행할때마다 방이름이 계속 변경
                .RuleFor(s => s.Sensing_DateTime, f => f.Date.Past(0)) // 현재시각이 생성
                .RuleFor(s => s.Temp, f => f.Random.Float(20.0f, 30.0f)) // 20~30도 사이의 실수값 생성
                .RuleFor(s => s.Humid, f => f.Random.Float(40.0f, 64.0f)); // 40~64% 사이의 습도값
        }

        private async void BtnConnect_Click(object sender, RoutedEventArgs e)
        {
            if(string.IsNullOrEmpty(TxtMqttBrokerIp.Text))
            {
                await this.ShowMessageAsync("오류", "브로커 아이피를 입력하세요");
                return;
            }
            // 브로커아이피로 접속
            ConnectMqttBroker();

            //하위 로직 무한반복
            StartPublish();

            // 가짜 스마트홈 센서값 생성

            // 센서값 MQTT 브로커에 전송

            // RtbLog에 접속
        }
        // 핵심처리 센싱된 데이터값을 MQTT 브로커로 전송
        private void StartPublish()
        {
            MqttThread = new Thread(() =>
            {
                while (true)
                {
                    //가짜 스마트홈 센서값 생성
                    SensorInfo Info = FakeHomeSensor.Generate();
                    //릴리즈(배포) 시 주석처리 
                    Debug.WriteLine($"{Info.Home_Id} / {Info.Room_Name} / {Info.Sensing_DateTime} / {Info.Temp}");
                    // 객체 직렬화(객체데이터를 xml이나 json등의 문자열로 변환)
                    var jsonValue = JsonConvert.SerializeObject(Info, Formatting.Indented);
                    // 센서값 MQTT 브로커에 전송(Publish)
                    Client.Publish("SmartHome/IotData/", Encoding.Default.GetBytes(jsonValue));
                    //Thread , UI Thread 충돌 안나도록 변경
                    this.Invoke(new Action(delegate ()
                    {
                        RtbLog.AppendText($"{jsonValue}\n");
                        RtbLog.ScrollToEnd();
                    }));

                    //1초동안 대기
                    Thread.Sleep(1000);
                }
            });
            MqttThread.Start();
        }

        private void ConnectMqttBroker()
        {
            Client = new MqttClient(TxtMqttBrokerIp.Text);
            Client.Connect("SmartHomeDev");//publish Client ID를 지정
        }

        // 접속 끊지 않으면 메모리상에 계속 남아있는 경우 발생
        private void MetroWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            if (Client != null && Client.IsConnected == true)
            {
                Client.Disconnect();//접속끊음
            }
            if(MqttThread!=null)
            {
                MqttThread.Abort();//Abort로 접속을 끊어주지 않으면 프로그램 종료 후에도 메모리에 남아있음
            }
        }

        private void MetroWindow_Loaded(object sender, RoutedEventArgs e)
        {
            TxtMqttBrokerIp.Focus();
        }
    }
}

실행화면

설정한 대로 임의의 데이터가 실시간으로 뿌려지는것을 볼 수 있음

SmartHomeMonitoringApp 제작

세팅

  • 누겟 패키지 설치 및 MahApps 세팅
    1) MahApps.Metro 설치
    2) MahApps.Metro.icon 설치
    3) Bogus 설치
    4) Newtonsoft.Json 설치
    5) Mysql.Data 설치
    6) LiveCharts.Wpf.Core 설치
    7) OxyPlot.Wpf 설치

Main 화면 디자인

MainWindow.xaml

<mah:MetroWindow x:Class="SmartHomeMonitoringApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        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:local="clr-namespace:SmartHomeMonitoringApp"
        xmlns:mah="http://metro.mahapps.com/winfx/xaml/controls"
        xmlns:iconPacks="http://metro.mahapps.com/winfx/xaml/iconpacks"
        mc:Ignorable="d"
        Title="Smart Monitoring system" Height="450" Width="800"
                 Loaded="MetroWindow_Loaded" FontFamily="NanumGothic">
    <mah:MetroWindow.IconTemplate>
        <DataTemplate>
            <iconPacks:PackIconSimpleIcons Kind="HomeAssistant" Width="24" Margin="5,7,0,0" Foreground="White"/>
        </DataTemplate>
    </mah:MetroWindow.IconTemplate>
    <Grid>
        <Grid.RowDefinitions>
            <RowDefinition Height="Auto"/>
            <RowDefinition Height="1*"/>
            <RowDefinition Height="Auto"/>
        </Grid.RowDefinitions>

        <!--메뉴바/툴바-->
        <StackPanel Grid.Row="0">
            <Menu IsMainMenu="True" Style="{StaticResource MahApps.Styles.Menu}">
                <MenuItem Header="파일">
                    <MenuItem.Icon>
                        <iconPacks:PackIconJamIcons Kind="FileF"/>
                    </MenuItem.Icon>
                    <MenuItem x:Name="MnuStartSubscribe" Header="시작">
                        <MenuItem.Icon>
                            <iconPacks:PackIconJamIcons Kind="PlayCircleF"/>
                        </MenuItem.Icon>
                    </MenuItem>
                    <MenuItem x:Name="MnuStopSubscribe" Header="중지">
                        <MenuItem.Icon>
                            <iconPacks:PackIconBootstrapIcons Kind="PauseCircleFill"/>
                        </MenuItem.Icon>
                    </MenuItem>
                    <Separator/>
                    <MenuItem x:Name="MnuExitProgram" Header="끝내기" Click="MnuExitProgram_Click">
                        <MenuItem.Icon>
                            <iconPacks:PackIconMaterialDesign Kind="ExitToApp"/>
                        </MenuItem.Icon>
                    </MenuItem>
                </MenuItem>
                <MenuItem Header="화면">
                    <MenuItem.Icon>
                        <iconPacks:PackIconJamIcons Kind="ScreenF"/>
                    </MenuItem.Icon>
                    <MenuItem x:Name="MnuDataBaseMon" Header="DB모니터링">
                        <MenuItem.Icon>
                            <iconPacks:PackIconOcticons Kind="Database"/>
                        </MenuItem.Icon>
                    </MenuItem>
                    <MenuItem x:Name="MnuRealTimeMon" Header="실시간모니터링">
                        <MenuItem.Icon>
                            <iconPacks:PackIconMaterial Kind="GaugeLow"/>
                        </MenuItem.Icon>
                    </MenuItem>
                    <MenuItem x:Name="MnuVisualization" Header="시각화">
                        <MenuItem.Icon>
                            <iconPacks:PackIconMaterial Kind="ChartMultiline"/>
                        </MenuItem.Icon>
                    </MenuItem>
                </MenuItem>
                <MenuItem Header="디자인">
                    <MenuItem.Icon>
                        <iconPacks:PackIconRemixIcon Kind="Brush2Fill"/>
                    </MenuItem.Icon>
                </MenuItem>
                <MenuItem Header="도움말">
                    <MenuItem.Icon>
                        <iconPacks:PackIconMaterial Kind="HelpBox"/>
                    </MenuItem.Icon>
                    <MenuItem x:Name="MnuAbout" Header="이 프로그램">
                        <MenuItem.Icon>
                            <iconPacks:PackIconBoxIcons Kind="SolidInfoCircle"/>
                        </MenuItem.Icon>
                    </MenuItem>
                </MenuItem>
            </Menu>

            <ToolBarTray>
                <ToolBar Style="{StaticResource MahApps.Styles.ToolBar}">
                    <Button x:Name="BtnStartSubscribe" ToolTip="구독 시작">
                        <iconPacks:PackIconJamIcons Kind="PlayCircleF"/>
                    </Button>
                    <Button x:Name="BtnStopSubscribe" ToolTip="구독 중지">
                        <iconPacks:PackIconBootstrapIcons Kind="PauseCircleFill"/>
                    </Button>
                    <Separator/>
                    <Button x:Name="BtnExitProgram" ToolTip="프로그램 끝내기">
                        <iconPacks:PackIconForkAwesome Kind="SignOut"/>
                    </Button>
                </ToolBar>
            </ToolBarTray>
        </StackPanel>

        <Grid Grid.Row="1">
            <!--사용자 정의 컨트롤로 만든 DataBaseControl.xaml과 연동-->
            <ContentControl x:Name="ActiveItem" Background="Gainsboro"/>
        </Grid>

        <StatusBar Grid.Row="2">
            <StatusBarItem>SmartHome Solution</StatusBarItem>
            <Separator Style="{StaticResource MahApps.Styles.Separator.StatusBar}"/>
            <StatusBarItem>선택화면 :</StatusBarItem>
            <StatusBarItem x:Name="StsSelScreen"></StatusBarItem>
        </StatusBar>
    </Grid>
</mah:MetroWindow>

실행화면

이어서 계속 ~

0개의 댓글