本网页已闲置超过3分钟,按键盘任意键或点击空白处,即可回到网页

基于Windows 10 UWP的扎啤机

发布时间:2022-09-07
分享到:

基于Windows 10 UWP的扎啤机

发布时间:2022-09-07
分享到:

使用 Windows 10 UWP 应用程序的强大功能来控制和监控啤酒桶,让您的饮料保持凉爽、新鲜和随时可用。

注意:首先,这个项目绝不会提倡使用或滥用酒精,这完全取决于用户在这个 kegerator 中的内容是什么饮料。 

这个项目的诞生是为了更好地管理扎啤机。扎啤机的基本原理是保持饮料低温以及将饮料碳酸保持在一定的 PSI 下。此外,仅仅给自己倒一杯冷饮,你根本不知道桶里还剩多少。

所以这个项目的目标是:

  • 保持饮料的一致温度,确保饮料不会过热或过冷并冻结
  • 确保将可接受的碳酸化量应用于小桶以保持最佳风味
  • 跟踪每个桶中的饮料量并提供视觉反馈,以确保为大型比赛准备充足的饮料。
  • 跟踪用于碳酸饮料的罐中剩余的二氧化碳量

基本电子元件及其用途:

  • 冷藏柜用于冷却装置并提供框架以制作精美的家具
  • Raspberry PI 2 Running Windows 10 IoT core 被用作操作的大脑
  • 小型邮资秤用于测量每个小桶和二氧化碳罐的重量,这些邮资秤移除了电子设备,并在秤中内置了称重传感器放大器和小型 Arduino。这些秤将通过 I2C 与 Raspberry PI 2 通信(稍后会详细介绍)
  • 设备上安装了 5 个数字温度传感器,一个在冷冻柜的底部,一个安装在顶部的下侧,一个安装在水龙头把手所在的塔架上(稍后会详细介绍)和一个安装在设备外部以测量环境温度。这些温度传感器连接到一个小型 Arduino,还通过 I2C 与 Raspberry PI 2 通信
  • 霍尼韦尔压力传感器连接到用于为小桶提供碳酸化作用的空气管路上。虽然 PSI 的调整是手动的(目前),但这将提供一个准确的计量器来确定桶中的二氧化碳量。
  • 5V 电源用于为 Raspberry PI2 供电。选择了更大的版本(提供高达 6 安培),因此它也可以为可寻址的 LED 灯条供电。
  • 一个简单的继电器与压缩机电源串联。使用这个继电器,可以从压缩机施加和断开电源,然后压缩机将依次控制 kegerator 的温度(稍后会详细介绍)

云连接

Ultimate Kegerator 包含一个 Web 服务器,允许通过 REST 服务进行远程配置以及当前状态的简单静态视图。可以通过http://slsys.homeip.net:9501访问该网站  。

此外,Ultimate Kegerator 将其重要统计数据上传到 Windows Azure 事件中心。虽然无法使用标准 Nuget 包与事件中心对话,但是你可以使用 Windows Embedded MVP  Paolo Patierno提供的易于实现的库,网址为

https://www.nuget.org/packages/AzureSBLite/

数据被推送到WindowsAzure上的事件中心:

通过流分析进行最终处理

WindowsAzure上的流分析正在处理的数据:

流分析的最终计划是:

1) 监控并通知温度是否过热或过冷

2) 监测并通知 CO2 罐何时过低

3) 监测并通知 CO2 罐是否检测到泄漏(重量逐渐减轻)

以下是组装过程的一些附加图片:

电子秤组装

称重传感器:

测试+5VDC 稳压器:

在测试压缩机继电器时准备连接:

电源:

CPU:

连接温度传感器:

Arduino的最终封装:

压力传感器及其+5VDC至+3.3VDC稳压器:

最终成果:

Kegerator Class:

using LagoVista.Common.Commanding;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using Windows.Devices.Enumeration;
using Windows.Devices.I2c;

namespace LagoVista.IoT.Common.Kegerator
{
    public class Kegerator : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        private Models.Keg _keg1;
        private Models.Keg _keg2;
        private Models.Keg _keg3;
        private Models.Keg _keg4;
        private CO2.CO2Tank _co2Tank; 

        private Kegerator() { }

        public List<DeviceBase> _devices = new List<DeviceBase>();

        private void RaisePropertyChanged([CallerMemberName] string propertyName = null)
        {
            var eventHandler = this.PropertyChanged;
            if (eventHandler != null)
            {
                eventHandler(this, new PropertyChangedEventArgs(propertyName));
            }
        }

        private bool Set<T>(ref T storage, T value, string columnName = null, [CallerMemberName] string propertyName = null)
        {
            if (object.Equals(storage, value)) return false;

            storage = value;
            this.RaisePropertyChanged(propertyName);
            return true;
        }

        byte[] _scalesAddresses = { 0x43, 0x41, 0x40, 0x42 };

        private const string I2C_CONTROLLER_NAME = "I2C1";

        private Thermo.Temperatures _temperatures;
        private Thermo.Controller _tempController;

        private Scales.Scale _co2Scale;
        private Dictionary<int, Scales.Scale> _kegScales;

        private CO2.PressureSensor _pressureSensor;
        private LED.LEDManager _ledManager;

        private REST.KegeratorServices _kegServices;

        private static Kegerator _kegerator = new Kegerator();
        public static Kegerator Instance { get { return _kegerator; } }

        private CloudServices.EventHubClient _eventHubClient;

        System.Threading.Timer _timer;


        private bool _initialized = false;

        public async Task Init()
        {
            if (!_initialized)
            {
                _initialized = true;
                var selector = I2cDevice.GetDeviceSelector(I2C_CONTROLLER_NAME);  /* Find the selector string for the I2C bus controller                   */
                var deviceInfo = (await DeviceInformation.FindAllAsync(selector)).FirstOrDefault();            /* Find the I2C bus controller device with our selector string           */

                var deviceId = deviceInfo == null ? (string)null : deviceInfo.Id;
                _temperatures = new Thermo.Temperatures(0x48);
                await _temperatures.Init(deviceId);
                _devices.Add(_temperatures);

                _tempController = new Thermo.Controller();
                _tempController.Init(_temperatures);
                _devices.Add(_tempController);

                _pressureSensor = new CO2.PressureSensor();
                await _pressureSensor.Init(deviceId, TimeSpan.FromSeconds(1));
                _devices.Add(_pressureSensor);

                _co2Scale = new Scales.Scale(0x44);
                await _co2Scale.Init(deviceId, TimeSpan.FromSeconds(1));
                _devices.Add(_co2Scale);

                _co2Tank = new CO2.CO2Tank(_co2Scale, TimeSpan.FromSeconds(2));
                _co2Tank.Load();
                _devices.Add(_co2Tank);

                _kegScales = new Dictionary<int, Scales.Scale>();

                _eventHubClient = new CloudServices.EventHubClient(this, TimeSpan.FromSeconds(2));
                _devices.Add(_eventHubClient);

                for (var idx = 0; idx < 4; ++idx)
                {
                    var scale = new Scales.Scale(_scalesAddresses[idx]);
                    await scale.Init(deviceId, TimeSpan.FromMilliseconds(500));
                    _kegScales.Add(idx, scale);
                    _devices.Add(scale);
                }

                _keg1 = new Models.Keg(1, _kegScales[0], TimeSpan.FromMilliseconds(500));
                _keg1.Load();
                _devices.Add(_keg1);
                _keg2 = new Models.Keg(2, _kegScales[1], TimeSpan.FromMilliseconds(500));
                _keg2.Load();
                _devices.Add(_keg2);
                _keg3 = new Models.Keg(3, _kegScales[2], TimeSpan.FromMilliseconds(500));
                _keg3.Load();
                _devices.Add(_keg3);
                _keg4 = new Models.Keg(4, _kegScales[3], TimeSpan.FromMilliseconds(500));
                _keg4.Load();
                _devices.Add(_keg4);

                DateInitialized = DateTime.Now.ToString();

                Web.WebServer.Instance.StartServer();

                _kegServices = new REST.KegeratorServices() { Port = 9500 };
                _kegServices.EventContent += _kegServices_EventContent;
                _kegServices.StartServer();

                _timer = new System.Threading.Timer((state) =>
                {
                    Refresh();
                }, null, 0, 250);
            }

        }

        private void _kegServices_EventContent(object sender, string e)
        {
            var parts = e.Split('/');
            if (parts.Count() > 0)
            {
                switch (parts[1])
                {
                    case "zero":
                        {
                            var scaleIndex = Convert.ToInt32(parts[2]);
                            _kegScales[scaleIndex].StoreOffset();
                        }
                        break;
                    case "cal":
                        {
                            var scaleIndex = Convert.ToInt32(parts[2]);
                            _kegScales[scaleIndex].CalibrationWeight = Convert.ToDouble(parts[3]);
                            _kegScales[scaleIndex].Calibrate();
                        }
                        break;
                }
            }
        }

        public void Refresh()
        {
            foreach (var device in _devices)
            {
                if (DateTime.Now > (device.LastUpdated + device.UpdateInterval))
                    device.Refresh();
            }

            LagoVista.Common.PlatformSupport.Services.DispatcherServices.Invoke(() =>
            {
                CurrentTimeDisplay = DateTime.Now.ToString();
                RaisePropertyChanged("CurrentTimeDisplay");
            });
        }

        public Thermo.Temperatures Temperatures { get { return _temperatures; } }


        public Thermo.Controller TemperatureController { get { return _tempController; } }


        private String _statusMessage;
        public String StatusMessage
        {
            get { return _statusMessage; }
            set { Set(ref _statusMessage, value); }
        }

        public List<Scales.Scale> KegScales
        {
            get { return _kegScales.Values.ToList(); }
        }

        public void ToggleCompressor()
        {
            if (_tempController.IsCompressorOn)
                _tempController.CompressorOff();
            else
                _tempController.CompressorOn();
        }

        public String DateInitialized
        {
            get;
            set;
        }

        public String CurrentTimeDisplay
        {
            get;
            set;
        }

        public Scales.Scale CO2Scale
        {
            get { return _co2Scale; }
        }

        public CO2.PressureSensor PressureSensor
        {
            get { return _pressureSensor; }
        }


        public Models.Keg Keg1 { get { return _keg1; } }
        public Models.Keg Keg2 { get { return _keg2; } }
        public Models.Keg Keg3 { get { return _keg3; } }
        public Models.Keg Keg4 { get { return _keg4; } }

        public CO2.CO2Tank CO2Tank { get { return _co2Tank; } }

        public RelayCommand ToggleCompressorCommand { get { return new RelayCommand(ToggleCompressor); } }
    }
}

如果您对此项目有任何想法、意见或问题,请在下方留言。

以上内容翻译自网络,原作者:Kevin D Wolf,如涉及侵权,可联系删除。

加入微信技术交流群

技术交流,职业进阶

关注与非网服务号

获取电子工程师福利

加入电路城 QQ 交流群

与技术大牛交朋友

讨论