티스토리 뷰

반응형

지난 글에서 I2C를 이용해서 온도센서를 제어하는 Application을 Windows 10 IoT core로 기반에 만들어봤다. 이번에는 온도센서의 Data를 Trigger로 받고 Output으로 LED를 켜보는 것을 하려한다. 이는 집안의 Home Automation의 초기버전으로 볼수 있는데, 온도에 따라 자동으로 에어컨을 켜고 끌수 있는 솔루션으로 만들 수 있기 때문이다. RaspberryPi와 Windows 10 IoT core를 가지고 Home Automation의 첫 번째 단추를 꿰어보자.

<시나리오>

집안의 온도가 27 이상이면 LED를 켜주고 27도 아래면 LED를 꺼준다.

지난번 글에서 32도라고 시나리오를 작성했는데, 32도까지 상태를 만들려니 내가 더워서, Trigger 를 27도로 하였다. 또한 온도변화를 모니터에 출력해주고, LED의 켜짐과 커짐도 출력해주자. 실제 LED를 보고 확인할 수 있음은 물론이다.

# 회로구성

LED는 PIN 5번에 연결하고, 3.3V를 공급한다. 온도센서는 I2C통신으로 5V와 SCL, SDA 선을 연결하여 통신하도록 구성한다. 특별히 새로 구입한 RaspberryPI 확장 핀을 연결해서 보다 쉽게 연결했다.

빵판이 부족하지만, 나중에 더 복잡한 연결을 할때 그럭저럭 쓸만한다. 대롱대롱 매달리게 만든게 온도센서이다. 제어하는 자세한 방법은 이전을 참고하자.(http://hero-space.tistory.com/25)

# UI 작성

UI는 GPIO와 센서의 Initialize가 됬다는 TextBlock 2개와 GPIO On/Off에 따른 Elipse으로 이루어지게 만들 것이다.

<Ellipse x:Name="LED" Fill="LightGray" Stroke="White" Width="100" Height="100" Margin="0,310,10,10"/>

<TextBlock x:Name="textBlock" HorizontalAlignment="Center" Margin="0,210,0,0" TextWrapping="Wrap" Text="Temperature : Not Initialized" VerticalAlignment="Top" Height="67" Width="640" FontSize="40" TextAlignment="Center"/>

<TextBlock x:Name="GpioStatus" Text="Waiting to initialize GPIO..." Margin="10,280,10,10" TextAlignment="Center" FontSize="26.667" />

C# 코드에서 Name로 적힌 부분을 ID로 받아서 Text를 수정할 수 있기 때문에 Name 부분을 잘 기억하자.

# Main 코드 작성

사실 기존에 했던 온도 센서 제어코드와, LED 제어코드를 병합해 놓은 것과 같다. 전체 로직을 말로 설명해보면,

1. GPIO PIN Initialize

2. 온도 센서 Initiailize

3. Timer Callback 세팅(1초간격)

4. 1초간격으로 Callback이 왔을 때, 온도센서로부터 온도 값 확인

5. 온도가 27도 이상이면 LED를 켜고, 아니면 끈다. 이때, Elipse 색깔을 변하게 하고, Text도 수정되게 한다.

<전체 CS 코드>

주의할 사항이 있다면 Timer Callback이 걸렸을때, UI의 값을 변경하는 경우 Dispatcher 내에서 해주어야한다.

(var task = this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>)


using Windows.UI.Xaml.Controls;
using Windows.UI.Xaml.Media;
using Windows.Devices.Gpio;
using Windows.Devices.I2c;
using Windows.Devices.Enumeration;
using System.Diagnostics;
using System.Threading;
using System;

namespace Home_Automation
{
    /// <summary>
    /// 자체적으로 사용하거나 프레임 내에서 탐색할 수 있는 빈 페이지입니다.
    /// </summary>
    public sealed partial class MainPage : Page
    {
        private SolidColorBrush redBrush = new SolidColorBrush(Windows.UI.Colors.Red);
        private SolidColorBrush grayBrush = new SolidColorBrush(Windows.UI.Colors.LightGray);
        private I2cDevice LM75;
        private Timer periodicTimer;
        private const byte I2C_TEMPERATURE_ADD = 0x48;

        private const int LED_PIN = 5;
        private GpioPin pin;
        private GpioPinValue pinValue;

        public MainPage()
        {
            this.InitializeComponent();
            InitGPIO();
            InitLM75();
        }

        private async void InitLM75()
        {
            try
            {
                string aqs = I2cDevice.GetDeviceSelector();
                var dis = await DeviceInformation.FindAllAsync(aqs);
                var settings = new I2cConnectionSettings(I2C_TEMPERATURE_ADD);
                settings.BusSpeed = I2cBusSpeed.FastMode;
                LM75 = await I2cDevice.FromIdAsync(dis[0].Id, settings);
            }
            catch (Exception error)
            {
                Debug.WriteLine("Exception: " + error.Message);
            }

            periodicTimer = new Timer(this.TimerCallback, null, 0, 1000);
        }

        private void InitGPIO()
        {
            var gpio = GpioController.GetDefault();

            // Show an error if there is no GPIO controller
            if (gpio == null)
            {
                pin = null;
                GpioStatus.Text = "There is no GPIO controller on this device.";
                return;
            }
            pin = gpio.OpenPin(LED_PIN);
            pinValue = GpioPinValue.Low;
            pin.Write(pinValue);
            pin.SetDriveMode(GpioPinDriveMode.Output);
            GpioStatus.Text = "GPIO pin initialized correctly.";
        }
        private void TimerCallback(object state)
        {
            string TemperatureText;
            byte[] readBuf = new byte[2];
            try
            {
                LM75.Read(readBuf);
            }
            catch (Exception error)
            {
                Debug.WriteLine("Exception: ", error.Message);
            }
            int valh = ((int)readBuf[0]);
            int vall = ((int)readBuf[1]);
            double temperature = CalcTemperature(valh, vall);
            Debug.WriteLine(temperature);
            TemperatureText = String.Format("Temperature : {0:F4} ℃", temperature);
            var task = this.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            {
                textBlock.Text = TemperatureText;
                if (temperature >= 27)
                {
                    if (pinValue != GpioPinValue.Low)
                    {
                        GpioStatus.Text = "GPIO pin ON.";
                        LED.Fill = redBrush;
                        pinValue = GpioPinValue.Low;
                        Debug.WriteLine(pinValue);
                        pin.Write(pinValue);
                    }
                }
                else
                {
                    pinValue = GpioPinValue.High;
                    GpioStatus.Text = "GPIO pin OFF.";
                    LED.Fill = grayBrush;
                    Debug.WriteLine(pinValue);
                    pin.Write(pinValue);
                }
            });
        
        private static double CalcTemperature(int valh, int vall)
        {
            int val = (valh << 3) + (vall >> 5);
            if (val > 1024)
            {
                val = -1 * (2048 - val);
            }
            double temperature = val * 0.125;
            return temperature;
        }
    }
}

<결과 동영상>

현재 집안의 온도는 27.37도 이기 때문에 GPIO LED가 On되어 있는 상태이다. 에어콘을 켜서 온도를 떨어뜨려 본다. 물론 지금 에어콘을 끄고 키는걸 직접하지만, 에어콘의 Wifi control만 가능하다면 지금 작성한 Home Automation application으로 온도에 따라 에어콘을 끄고 킬수 있게 된다.

아직은 실행자체를 Visual Studio에서 Debug 모드로 실행하고 있다. App을 Deploy해서 RaspberryPI를 키면서 바로 실행되게 하도록 하기 위해서는 별도의 절차가 필요한데 이는 다음 글에서 설명하도록 할것이다. 오늘은 여기까지~!

반응형
댓글