├── .gitignore
├── LICENSE
├── TemperatureReader.ClientApp
├── App.xaml
├── App.xaml.cs
├── Assets
│ ├── LockScreenLogo.scale-200.png
│ ├── SplashScreen.scale-200.png
│ ├── Square150x150Logo.scale-200.png
│ ├── Square44x44Logo.scale-200.png
│ ├── Square44x44Logo.targetsize-24_altform-unplated.png
│ ├── StoreLogo.png
│ ├── TileIconLarge.png
│ ├── TileIconSmall.png
│ └── Wide310x150Logo.scale-200.png
├── Behaviors
│ └── BlinkBehavior.cs
├── Converters
│ └── BoolToVisibilityConverter.cs
├── Helpers
│ ├── ErrorLogger.cs
│ ├── IErrorLogger.cs
│ ├── IMessageDisplayer.cs
│ └── Toaster.cs
├── MainPage.xaml
├── MainPage.xaml.cs
├── Messages
│ ├── DataReceivedMessage.cs
│ └── ResumeMessage.cs
├── Models
│ ├── BandOperator.cs
│ ├── BandUiController.cs
│ ├── BandUiDefinitions.cs
│ ├── DateTimeExtensions.cs
│ ├── IBandOperator.cs
│ ├── ITemperatureListener.cs
│ └── TemperatureListener.cs
├── Package.appxmanifest
├── Properties
│ ├── AssemblyInfo.cs
│ └── Default.rd.xml
├── TemperatureReader.ClientApp.csproj
├── TemperatureReader.ClientApp_TemporaryKey.pfx
├── ViewModels
│ ├── CrashLoggerViewModel.cs
│ └── MainViewModel.cs
├── project.json
└── project.lock.json
├── TemperatureReader.Logic
├── Devices
│ ├── AnalogTemperatureSensorController.cs
│ ├── GpioService.cs
│ ├── IAnalogTemperatureSensorController.cs
│ ├── IGpioService.cs
│ ├── StatusLed.cs
│ └── SwitchDevice.cs
├── Models
│ └── Thermometer.cs
├── Properties
│ ├── AssemblyInfo.cs
│ └── TemperatureReader.Logic.rd.xml
├── TemperatureReader.Logic.csproj
├── Utilities
│ └── SynchronousWaiter.cs
├── project.json
└── project.lock.json
├── TemperatureReader.ServiceBus
├── FanSwitchQueueClient.cs
├── IQueueClient.cs
├── Properties
│ ├── AssemblyInfo.cs
│ └── TemperatureReader.ServiceBus.rd.xml
├── QueueClient.cs
├── QueueMode.cs
├── TemperatureQueueClient.cs
├── TemperatureReader.ServiceBus.csproj
├── project.json
└── project.lock.json
├── TemperatureReader.Shared
├── FanStatus.cs
├── FanSwitchCommand.cs
├── Properties
│ └── AssemblyInfo.cs
├── Settings.cs
├── TemperatureData.cs
└── TemperatureReader.Shared.csproj
├── TemperatureReader
├── App.xaml
├── App.xaml.cs
├── Assets
│ ├── LockScreenLogo.scale-200.png
│ ├── SplashScreen.scale-200.png
│ ├── Square150x150Logo.scale-200.png
│ ├── Square44x44Logo.scale-200.png
│ ├── Square44x44Logo.targetsize-24_altform-unplated.png
│ ├── StoreLogo.png
│ └── Wide310x150Logo.scale-200.png
├── MainPage.xaml
├── MainPage.xaml.cs
├── Package.appxmanifest
├── Properties
│ ├── AssemblyInfo.cs
│ └── Default.rd.xml
├── TemperatureReader.csproj
├── TemperatureReader_TemporaryKey.pfx
├── project.json
└── project.lock.json
└── TemperatureReaderDemo.sln
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 |
4 | # User-specific files
5 | *.suo
6 | *.user
7 | *.userosscache
8 | *.sln.docstates
9 |
10 | # User-specific files (MonoDevelop/Xamarin Studio)
11 | *.userprefs
12 |
13 | # Build results
14 | [Dd]ebug/
15 | [Dd]ebugPublic/
16 | [Rr]elease/
17 | [Rr]eleases/
18 | x64/
19 | x86/
20 | build/
21 | bld/
22 | [Bb]in/
23 | [Oo]bj/
24 |
25 | # Visual Studo 2015 cache/options directory
26 | .vs/
27 |
28 | # MSTest test Results
29 | [Tt]est[Rr]esult*/
30 | [Bb]uild[Ll]og.*
31 |
32 | # NUNIT
33 | *.VisualState.xml
34 | TestResult.xml
35 |
36 | # Build Results of an ATL Project
37 | [Dd]ebugPS/
38 | [Rr]eleasePS/
39 | dlldata.c
40 |
41 | *_i.c
42 | *_p.c
43 | *_i.h
44 | *.ilk
45 | *.meta
46 | *.obj
47 | *.pch
48 | *.pdb
49 | *.pgc
50 | *.pgd
51 | *.rsp
52 | *.sbr
53 | *.tlb
54 | *.tli
55 | *.tlh
56 | *.tmp
57 | *.tmp_proj
58 | *.log
59 | *.vspscc
60 | *.vssscc
61 | .builds
62 | *.pidb
63 | *.svclog
64 | *.scc
65 |
66 | # Chutzpah Test files
67 | _Chutzpah*
68 |
69 | # Visual C++ cache files
70 | ipch/
71 | *.aps
72 | *.ncb
73 | *.opensdf
74 | *.sdf
75 | *.cachefile
76 |
77 | # Visual Studio profiler
78 | *.psess
79 | *.vsp
80 | *.vspx
81 |
82 | # TFS 2012 Local Workspace
83 | $tf/
84 |
85 | # Guidance Automation Toolkit
86 | *.gpState
87 |
88 | # ReSharper is a .NET coding add-in
89 | _ReSharper*/
90 | *.[Rr]e[Ss]harper
91 | *.DotSettings.user
92 |
93 | # JustCode is a .NET coding addin-in
94 | .JustCode
95 |
96 | # TeamCity is a build add-in
97 | _TeamCity*
98 |
99 | # DotCover is a Code Coverage Tool
100 | *.dotCover
101 |
102 | # NCrunch
103 | _NCrunch_*
104 | .*crunch*.local.xml
105 |
106 | # MightyMoose
107 | *.mm.*
108 | AutoTest.Net/
109 |
110 | # Web workbench (sass)
111 | .sass-cache/
112 |
113 | # Installshield output folder
114 | [Ee]xpress/
115 |
116 | # DocProject is a documentation generator add-in
117 | DocProject/buildhelp/
118 | DocProject/Help/*.HxT
119 | DocProject/Help/*.HxC
120 | DocProject/Help/*.hhc
121 | DocProject/Help/*.hhk
122 | DocProject/Help/*.hhp
123 | DocProject/Help/Html2
124 | DocProject/Help/html
125 |
126 | # Click-Once directory
127 | publish/
128 |
129 | # Publish Web Output
130 | *.[Pp]ublish.xml
131 | *.azurePubxml
132 | # TODO: Comment the next line if you want to checkin your web deploy settings
133 | # but database connection strings (with potential passwords) will be unencrypted
134 | *.pubxml
135 | *.publishproj
136 |
137 | # NuGet Packages
138 | *.nupkg
139 | # The packages folder can be ignored because of Package Restore
140 | **/packages/*
141 | # except build/, which is used as an MSBuild target.
142 | !**/packages/build/
143 | # Uncomment if necessary however generally it will be regenerated when needed
144 | #!**/packages/repositories.config
145 |
146 | # Windows Azure Build Output
147 | csx/
148 | *.build.csdef
149 |
150 | # Windows Store app package directory
151 | AppPackages/
152 |
153 | # Others
154 | *.[Cc]ache
155 | ClientBin/
156 | [Ss]tyle[Cc]op.*
157 | ~$*
158 | *~
159 | *.dbmdl
160 | *.dbproj.schemaview
161 | *.publishsettings
162 | node_modules/
163 | bower_components/
164 |
165 | # RIA/Silverlight projects
166 | Generated_Code/
167 |
168 | # Backup & report files from converting an old project file
169 | # to a newer Visual Studio version. Backup files are not needed,
170 | # because we have git ;-)
171 | _UpgradeReport_Files/
172 | Backup*/
173 | UpgradeLog*.XML
174 | UpgradeLog*.htm
175 |
176 | # SQL Server files
177 | *.mdf
178 | *.ldf
179 |
180 | # Business Intelligence projects
181 | *.rdl.data
182 | *.bim.layout
183 | *.bim_*.settings
184 |
185 | # Microsoft Fakes
186 | FakesAssemblies/
187 |
188 | # Node.js Tools for Visual Studio
189 | .ntvs_analysis.dat
190 |
191 | # Visual Studio 6 build log
192 | *.plg
193 |
194 | # Visual Studio 6 workspace options file
195 | *.opt
196 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Joost van Schaik
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/App.xaml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Diagnostics;
4 | using System.IO;
5 | using System.Linq;
6 | using System.Runtime.InteropServices.WindowsRuntime;
7 | using System.Threading.Tasks;
8 | using Windows.ApplicationModel;
9 | using Windows.ApplicationModel.Activation;
10 | using Windows.Foundation;
11 | using Windows.Foundation.Collections;
12 | using Windows.UI.ViewManagement;
13 | using Windows.UI.Xaml;
14 | using Windows.UI.Xaml.Controls;
15 | using Windows.UI.Xaml.Controls.Primitives;
16 | using Windows.UI.Xaml.Data;
17 | using Windows.UI.Xaml.Input;
18 | using Windows.UI.Xaml.Media;
19 | using Windows.UI.Xaml.Navigation;
20 | using GalaSoft.MvvmLight.Ioc;
21 | using GalaSoft.MvvmLight.Messaging;
22 | using GalaSoft.MvvmLight.Threading;
23 | using TemperatureReader.ClientApp.Helpers;
24 | using TemperatureReader.ClientApp.Messages;
25 | using TemperatureReader.ClientApp.ViewModels;
26 |
27 | namespace TemperatureReader.ClientApp
28 | {
29 | ///
30 | /// Provides application-specific behavior to supplement the default Application class.
31 | ///
32 | sealed partial class App : Application
33 | {
34 | ///
35 | /// Initializes the singleton application object. This is the first line of authored code
36 | /// executed, and as such is the logical equivalent of main() or WinMain().
37 | ///
38 | public App()
39 | {
40 | SimpleIoc.Default.Register();
41 | SimpleIoc.Default.Register();
42 | InitializeComponent();
43 | Suspending += OnSuspending;
44 | UnhandledException += SimpleIoc.Default.GetInstance().LogUnhandledException;
45 | UnhandledException += App_UnhandledException;
46 | Resuming += App_Resuming;
47 | }
48 |
49 | private void App_Resuming(object sender, object e)
50 | {
51 | Messenger.Default.Send(new ResumeMessage());
52 | }
53 |
54 | private void App_UnhandledException(object sender, UnhandledExceptionEventArgs e)
55 | {
56 | SimpleIoc.Default.GetInstance().ShowMessage ($"Crashed: {e.Message}");
57 | }
58 |
59 | ///
60 | /// Invoked when the application is launched normally by the end user. Other entry points
61 | /// will be used such as when the application is launched to open a specific file.
62 | ///
63 | /// Details about the launch request and process.
64 | protected override void OnLaunched(LaunchActivatedEventArgs e)
65 | {
66 | DispatcherHelper.Initialize();
67 |
68 | MainViewModel.Instance.Init();
69 | #if DEBUG
70 | if (System.Diagnostics.Debugger.IsAttached)
71 | {
72 | //this.DebugSettings.EnableFrameRateCounter = true;
73 | }
74 | #endif
75 |
76 |
77 | Frame rootFrame = Window.Current.Content as Frame;
78 |
79 | // Do not repeat app initialization when the Window already has content,
80 | // just ensure that the window is active
81 | if (rootFrame == null)
82 | {
83 | // Create a Frame to act as the navigation context and navigate to the first page
84 | rootFrame = new Frame();
85 |
86 | rootFrame.NavigationFailed += OnNavigationFailed;
87 |
88 | if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
89 | {
90 | //TODO: Load state from previously suspended application
91 | }
92 |
93 | // Place the frame in the current Window
94 | Window.Current.Content = rootFrame;
95 | }
96 |
97 | if (rootFrame.Content == null)
98 | {
99 | // When the navigation stack isn't restored navigate to the first page,
100 | // configuring the new page by passing required information as a navigation
101 | // parameter
102 | rootFrame.Navigate(typeof(MainPage), e.Arguments);
103 | }
104 | // Ensure the current window is active
105 |
106 | Window.Current.Activate();
107 | }
108 |
109 | ///
110 | /// Invoked when Navigation to a certain page fails
111 | ///
112 | /// The Frame which failed navigation
113 | /// Details about the navigation failure
114 | void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
115 | {
116 | throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
117 | }
118 |
119 | ///
120 | /// Invoked when application execution is being suspended. Application state is saved
121 | /// without knowing whether the application will be terminated or resumed with the contents
122 | /// of memory still intact.
123 | ///
124 | /// The source of the suspend request.
125 | /// Details about the suspend request.
126 | private async void OnSuspending(object sender, SuspendingEventArgs e)
127 | {
128 | var deferral = e.SuspendingOperation.GetDeferral();
129 | await MainViewModel.Instance.OnSuspend();
130 | //TODO: Save application state and stop any background activity
131 | deferral.Complete();
132 | }
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/Assets/LockScreenLogo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LocalJoost/TemperatureReaderDemo/181701369c4bad7bfdc1891d011fd27994c8f6f3/TemperatureReader.ClientApp/Assets/LockScreenLogo.scale-200.png
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/Assets/SplashScreen.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LocalJoost/TemperatureReaderDemo/181701369c4bad7bfdc1891d011fd27994c8f6f3/TemperatureReader.ClientApp/Assets/SplashScreen.scale-200.png
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/Assets/Square150x150Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LocalJoost/TemperatureReaderDemo/181701369c4bad7bfdc1891d011fd27994c8f6f3/TemperatureReader.ClientApp/Assets/Square150x150Logo.scale-200.png
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/Assets/Square44x44Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LocalJoost/TemperatureReaderDemo/181701369c4bad7bfdc1891d011fd27994c8f6f3/TemperatureReader.ClientApp/Assets/Square44x44Logo.scale-200.png
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LocalJoost/TemperatureReaderDemo/181701369c4bad7bfdc1891d011fd27994c8f6f3/TemperatureReader.ClientApp/Assets/Square44x44Logo.targetsize-24_altform-unplated.png
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/Assets/StoreLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LocalJoost/TemperatureReaderDemo/181701369c4bad7bfdc1891d011fd27994c8f6f3/TemperatureReader.ClientApp/Assets/StoreLogo.png
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/Assets/TileIconLarge.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LocalJoost/TemperatureReaderDemo/181701369c4bad7bfdc1891d011fd27994c8f6f3/TemperatureReader.ClientApp/Assets/TileIconLarge.png
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/Assets/TileIconSmall.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LocalJoost/TemperatureReaderDemo/181701369c4bad7bfdc1891d011fd27994c8f6f3/TemperatureReader.ClientApp/Assets/TileIconSmall.png
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/Assets/Wide310x150Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LocalJoost/TemperatureReaderDemo/181701369c4bad7bfdc1891d011fd27994c8f6f3/TemperatureReader.ClientApp/Assets/Wide310x150Logo.scale-200.png
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/Behaviors/BlinkBehavior.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using Windows.UI.Xaml;
3 | using Windows.UI.Xaml.Media;
4 | using Windows.UI.Xaml.Shapes;
5 | using GalaSoft.MvvmLight.Messaging;
6 | using Microsoft.Xaml.Interactivity;
7 | using TemperatureReader.ClientApp.Messages;
8 |
9 | namespace TemperatureReader.ClientApp.Behaviors
10 | {
11 | public class BlinkBehavior : DependencyObject, IBehavior
12 | {
13 | private Shape _shape;
14 | private Brush _originalFillBrush;
15 | private readonly Brush _blinkBrush = Application.Current.Resources["SystemControlHighlightAccentBrush"] as SolidColorBrush;
16 |
17 | public void Attach(DependencyObject associatedObject)
18 | {
19 | AssociatedObject = associatedObject;
20 | _shape = associatedObject as Shape;
21 | if (_shape != null)
22 | {
23 | _originalFillBrush = _shape.Fill;
24 | Messenger.Default.Register(this, OnDateReceivedMessage);
25 | }
26 | }
27 |
28 | private async void OnDateReceivedMessage(DataReceivedMessage mes)
29 | {
30 | _shape.Fill = _blinkBrush;
31 |
32 | await Task.Delay(500);
33 | _shape.Fill = _originalFillBrush;
34 | }
35 |
36 | public void Detach()
37 | {
38 | Messenger.Default.Unregister(this);
39 | if (_shape != null)
40 | {
41 | _shape.Fill = _originalFillBrush;
42 | }
43 | }
44 |
45 | public DependencyObject AssociatedObject { get; private set; }
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/Converters/BoolToVisibilityConverter.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Windows.UI.Xaml;
3 | using Windows.UI.Xaml.Data;
4 |
5 | namespace TemperatureReader.ClientApp.Converters
6 | {
7 | ///
8 | /// Converts true to the value of parameter
9 | ///
10 | public class BoolToVisibilityConverter : IValueConverter
11 | {
12 | public object Convert(object value, Type targetType, object parameter, string language)
13 | {
14 | if (parameter == null)
15 | {
16 | parameter = Visibility.Visible;
17 | }
18 |
19 | if (value is bool)
20 | {
21 | var bValue = (bool)value;
22 | var visibility = (Visibility)Enum.Parse(typeof(Visibility), parameter.ToString(), true);
23 | if (bValue) return visibility;
24 | return visibility == Visibility.Visible ? Visibility.Collapsed : Visibility.Visible;
25 | }
26 | return parameter;
27 | }
28 |
29 | public object ConvertBack(object value, Type targetType, object parameter, string language)
30 | {
31 | throw new NotImplementedException();
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/Helpers/ErrorLogger.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Threading.Tasks;
4 | using Windows.Storage;
5 | using Windows.UI.Xaml;
6 |
7 | namespace TemperatureReader.ClientApp.Helpers
8 | {
9 | public class ErrorLogger : IErrorLogger
10 | {
11 | private const string LogFile = "crashlog.txt";
12 | public async void LogUnhandledException(object sender, UnhandledExceptionEventArgs e)
13 | {
14 | await LogException(e.Exception);
15 | }
16 |
17 | public async Task LogException(Exception ex)
18 | {
19 | try
20 | {
21 | var folder = ApplicationData.Current.LocalFolder;
22 | var logFile = await folder.CreateFileAsync(LogFile, CreationCollisionOption.OpenIfExists);
23 | var lines = new List
24 | {
25 | "------------------------",
26 | "Error at " + DateTimeOffset.Now.ToString("yy-MM-yyyy HH:mm:ss"),
27 | };
28 | if (!string.IsNullOrWhiteSpace(ex.Message)) lines.Add(ex.Message);
29 | if (!string.IsNullOrWhiteSpace(ex.StackTrace)) lines.Add(ex.StackTrace);
30 | await FileIO.AppendLinesAsync(logFile, lines);
31 | }
32 | catch (Exception)
33 | {
34 | }
35 | }
36 |
37 | public async Task> GetLogContents()
38 | {
39 | var result = new List();
40 | var logFile = await ApplicationData.Current.LocalFolder.TryGetItemAsync(LogFile);
41 | var file = logFile as StorageFile;
42 | if (file != null)
43 | {
44 | var lines = await FileIO.ReadLinesAsync(file);
45 | result.AddRange(lines);
46 | }
47 | return result;
48 | }
49 |
50 | public async Task DeleteLog()
51 | {
52 | var logFile = await ApplicationData.Current.LocalFolder.TryGetItemAsync(LogFile);
53 | var file = logFile as StorageFile;
54 | if (file != null)
55 | {
56 | await file.DeleteAsync();
57 | }
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/Helpers/IErrorLogger.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Threading.Tasks;
4 | using Windows.UI.Xaml;
5 |
6 | namespace TemperatureReader.ClientApp.Helpers
7 | {
8 | public interface IErrorLogger
9 | {
10 | Task DeleteLog();
11 | Task> GetLogContents();
12 | void LogUnhandledException(object sender, UnhandledExceptionEventArgs e);
13 | Task LogException(Exception ex);
14 | }
15 | }
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/Helpers/IMessageDisplayer.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace TemperatureReader.ClientApp.Helpers
4 | {
5 | public interface IMessageDisplayer
6 | {
7 | Task ShowMessage(string text);
8 | }
9 | }
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/Helpers/Toaster.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using Windows.UI.Notifications;
3 | using NotificationsExtensions.Toasts;
4 |
5 | namespace TemperatureReader.ClientApp.Helpers
6 | {
7 | public class Toaster : IMessageDisplayer
8 | {
9 | public async Task ShowMessage(string text)
10 | {
11 | var content = new ToastContent()
12 | {
13 |
14 | Visual = new ToastVisual()
15 | {
16 | TitleText = new ToastText()
17 | {
18 | Text = "Temperature Listener"
19 | },
20 |
21 | BodyTextLine1 = new ToastText()
22 | {
23 | Text = text
24 | }
25 | }
26 | };
27 |
28 | var toast = new ToastNotification(content.GetXml());
29 |
30 | var toastNotifier = ToastNotificationManager.CreateToastNotifier();
31 | toastNotifier.Show(toast);
32 | }
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/MainPage.xaml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 |
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/MainPage.xaml.cs:
--------------------------------------------------------------------------------
1 | using Windows.UI.Xaml.Controls;
2 | using Windows.UI.Xaml.Data;
3 | using Windows.UI.Xaml.Navigation;
4 | using TemperatureReader.ClientApp.ViewModels;
5 |
6 | namespace TemperatureReader.ClientApp
7 | {
8 | ///
9 | /// An empty page that can be used on its own or navigated to within a Frame.
10 | ///
11 | public sealed partial class MainPage : Page
12 | {
13 | public MainPage()
14 | {
15 | this.InitializeComponent();
16 | }
17 |
18 | public MainViewModel ViewModel
19 | {
20 | get { return MainViewModel.Instance; }
21 | }
22 |
23 | public CrashLoggerViewModel CrashViewModel
24 | {
25 | get { return CrashLoggerViewModel.Instance; }
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/Messages/DataReceivedMessage.cs:
--------------------------------------------------------------------------------
1 | using GalaSoft.MvvmLight.Messaging;
2 |
3 | namespace TemperatureReader.ClientApp.Messages
4 | {
5 | public class DataReceivedMessage : MessageBase
6 | {
7 | }
8 | }
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/Messages/ResumeMessage.cs:
--------------------------------------------------------------------------------
1 | using GalaSoft.MvvmLight.Messaging;
2 |
3 | namespace TemperatureReader.ClientApp.Messages
4 | {
5 | public class ResumeMessage : MessageBase
6 | {
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/Models/BandOperator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Microsoft.Band;
6 | using Microsoft.Band.Notifications;
7 | using Microsoft.Band.Tiles;
8 | using TemperatureReader.ServiceBus;
9 | using TemperatureReader.Shared;
10 |
11 | namespace TemperatureReader.ClientApp.Models
12 | {
13 | public class BandOperator : IBandOperator
14 | {
15 | private TemperatureData _lastTemperatureData;
16 | private DateTimeOffset _lastToggleUse = DateTimeOffset.MinValue;
17 | private FanStatus _lastFanStatus = FanStatus.Off;
18 | private bool _isProcessing = false;
19 |
20 | private IBandClient _bandClient;
21 | private readonly IQueueClient _fanStatusPoster;
22 |
23 | public BandOperator(IQueueClient fanStatusPoster)
24 | {
25 | _fanStatusPoster = fanStatusPoster;
26 | }
27 |
28 | private async Task GetBandClient(bool forceFreshClient = false)
29 | {
30 | if (_bandClient == null || forceFreshClient)
31 | {
32 | TryClearExistingBand();
33 | _bandClient = await GetNewBandClient();
34 | }
35 | try
36 | {
37 | var t = _bandClient.NotificationManager;
38 | Debug.WriteLine($"Notifcation manager succesfull accessed {t}");
39 | }
40 | catch (Exception)
41 | {
42 | TryClearExistingBand();
43 | _bandClient = await GetNewBandClient();
44 | }
45 | return _bandClient;
46 | }
47 |
48 | private bool TryClearExistingBand()
49 | {
50 | try
51 | {
52 | if (_bandClient != null)
53 | {
54 | _bandClient.Dispose();
55 | _bandClient = null;
56 | }
57 | }
58 | catch (Exception)
59 | {
60 | return false;
61 | }
62 | return true;
63 | }
64 |
65 | private async Task GetNewBandClient()
66 | {
67 | var retries = 0;
68 | var waitTime = 500;
69 | while (retries++ < 10)
70 | {
71 | try
72 | {
73 | var pairedBands = await BandClientManager.Instance.GetBandsAsync();
74 | if (pairedBands != null && pairedBands.Any())
75 | {
76 | return await BandClientManager.Instance.ConnectAsync(pairedBands.First());
77 | }
78 | }
79 | catch (Exception)
80 | {
81 | await Task.Delay(waitTime += 100);
82 | }
83 | }
84 | return null;
85 |
86 | }
87 |
88 | public bool IsRunning { get; private set; }
89 |
90 |
91 | public async Task Start(bool forceFreshClient = false)
92 | {
93 | var tilePresent = false;
94 | var bandClient = await GetBandClient(forceFreshClient);
95 | if (bandClient != null)
96 | {
97 | var currentTiles = await bandClient.TileManager.GetTilesAsync();
98 | var temperatureTile = currentTiles.FirstOrDefault(p => p.TileId == BandUiDefinitions.TileId);
99 | if (temperatureTile == null)
100 | {
101 | var buc = new BandUiController(bandClient);
102 | tilePresent = await buc.BuildTile();
103 | }
104 | else
105 | {
106 | tilePresent = true;
107 | }
108 |
109 | if (tilePresent)
110 | {
111 | await bandClient.TileManager.StartReadingsAsync();
112 | bandClient.TileManager.TileOpened += TileManager_TileOpened;
113 | bandClient.TileManager.TileButtonPressed += TileManager_TileButtonPressed;
114 | }
115 | }
116 | IsRunning = tilePresent;
117 | return tilePresent;
118 | }
119 |
120 | private async void TileManager_TileButtonPressed(object sender, BandTileEventArgs e)
121 | {
122 | var te = e.TileEvent;
123 | if (te.TileId == BandUiDefinitions.TileId && te.PageId == BandUiDefinitions.Page1Id && te.ElementId == BandUiDefinitions.ButtonToggleFanId)
124 | {
125 | if (!_isProcessing)
126 | {
127 | _lastToggleUse = DateTime.UtcNow;
128 | _isProcessing = true;
129 | var cmd = new FanSwitchCommand(_lastFanStatus, true);
130 | Debug.WriteLine($"Sending fan command {cmd.Status}");
131 | await UpdateFirstPageStatus();
132 | await _fanStatusPoster.PostData(cmd);
133 | }
134 | }
135 | }
136 |
137 | private async Task UpdateFirstPageStatus()
138 | {
139 | var bandClient = await GetBandClient();
140 | if (bandClient != null)
141 | {
142 | var text = GetFanStatusText();
143 | var buc = new BandUiController(bandClient);
144 | await buc.SetUiValues($"{_lastTemperatureData.Temperature}°C", text);
145 | }
146 | }
147 |
148 | public async Task Stop()
149 | {
150 | var bandClient = await GetBandClient();
151 | if (bandClient != null)
152 | {
153 | await bandClient.TileManager.StopReadingsAsync();
154 | bandClient.TileManager.TileOpened -= TileManager_TileOpened;
155 | bandClient.TileManager.TileButtonPressed -= TileManager_TileButtonPressed;
156 | TryClearExistingBand();
157 | }
158 | IsRunning = false;
159 | }
160 |
161 | public async Task RemoveTile()
162 | {
163 | await Stop();
164 | var bandClient = await GetBandClient();
165 | if (bandClient != null)
166 | {
167 | var buc = new BandUiController(_bandClient);
168 | await buc.RemoveTile();
169 | }
170 | }
171 |
172 | public async void HandleNewTemperature(object sender, TemperatureData data)
173 | {
174 | Debug.WriteLine($"New temperature data received {data.Temperature} fanstatus = {data.FanStatus}");
175 | _lastTemperatureData = data;
176 | _lastTemperatureData.Timestamp = DateTimeOffset.UtcNow;
177 | if (_lastFanStatus != _lastTemperatureData.FanStatus && _isProcessing)
178 | {
179 | _isProcessing = false;
180 | _lastFanStatus = _lastTemperatureData.FanStatus;
181 | await UpdateFirstPageStatus();
182 | }
183 | else if (_lastToggleUse.IsSecondsAgo(Settings.FanSwitchQueueTtl) && _isProcessing)
184 | {
185 | _isProcessing = false;
186 | _lastFanStatus = _lastTemperatureData.FanStatus;
187 | await UpdateFirstPageStatus();
188 | }
189 | else if (!_isProcessing)
190 | {
191 | _lastFanStatus = _lastTemperatureData.FanStatus;
192 | }
193 | }
194 |
195 | private async void TileManager_TileOpened(object sender, BandTileEventArgs e)
196 | {
197 | var bandClient = await GetBandClient();
198 | if (bandClient != null)
199 | {
200 | if (e.TileEvent.TileId == BandUiDefinitions.TileId && _lastTemperatureData != null)
201 | {
202 | var buc = new BandUiController(bandClient);
203 | await buc.SetUiValues(
204 | _lastTemperatureData.Timestamp.ToLocalTime().ToString("HH:mm:ss"),
205 | _lastTemperatureData.Timestamp.ToLocalTime().ToString("dd-MM-yyyy"),
206 | $"{_lastTemperatureData.Temperature}°C",
207 | GetFanStatusText());
208 | await bandClient.NotificationManager.VibrateAsync(VibrationType.NotificationOneTone);
209 | }
210 | }
211 | }
212 |
213 | public async Task SendVibrate()
214 | {
215 | var bandClient = await GetBandClient();
216 | if (bandClient != null)
217 | {
218 | await bandClient.NotificationManager.VibrateAsync(VibrationType.ThreeToneHigh);
219 | }
220 | }
221 |
222 | private string GetFanStatusText()
223 | {
224 | return _isProcessing ? "Processing" : _lastTemperatureData.FanStatus == FanStatus.On ? "Stop fan" : "Start fan";
225 | }
226 | }
227 | }
228 |
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/Models/BandUiController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Threading.Tasks;
5 | using Windows.Storage;
6 | using Windows.UI.Xaml.Media.Imaging;
7 | using Microsoft.Band;
8 | using Microsoft.Band.Tiles;
9 | using Microsoft.Band.Tiles.Pages;
10 |
11 | namespace TemperatureReader.ClientApp.Models
12 | {
13 | public class BandUiController
14 | {
15 | private readonly IBandClient _bandClient;
16 |
17 | public BandUiController(IBandClient bandClient)
18 | {
19 | _bandClient = bandClient;
20 | }
21 |
22 | public async Task BuildTile()
23 | {
24 | if (_bandClient != null)
25 | {
26 | var cap = await _bandClient.TileManager.GetRemainingTileCapacityAsync();
27 | if (cap > 0)
28 | {
29 | var tile = new BandTile(BandUiDefinitions.TileId)
30 | {
31 | Name = "Temperature reader",
32 | TileIcon = await LoadIcon("ms-appx:///Assets/TileIconLarge.png"),
33 | SmallIcon = await LoadIcon("ms-appx:///Assets/TileIconSmall.png"),
34 | };
35 |
36 | foreach (var page in BuildTileUi())
37 | {
38 | tile.PageLayouts.Add(page);
39 | }
40 | await _bandClient.TileManager.AddTileAsync(tile);
41 | await _bandClient.TileManager.RemovePagesAsync(BandUiDefinitions.TileId);
42 | await _bandClient.TileManager.SetPagesAsync(BandUiDefinitions.TileId, BuildIntialTileData());
43 | return true;
44 | }
45 | }
46 | return false;
47 | }
48 |
49 | public async Task SetUiValues(string timeText, string dateText, string temperature, string buttonText)
50 | {
51 | var pageData = BuildTileData(timeText, dateText, temperature, buttonText);
52 | await _bandClient.TileManager.SetPagesAsync(BandUiDefinitions.TileId, pageData);
53 | }
54 |
55 | public async Task SetUiValues(string temperature, string buttonText)
56 | {
57 | await
58 | _bandClient.TileManager.SetPagesAsync(BandUiDefinitions.TileId,
59 | BuildTileDataPage1(temperature, buttonText));
60 | }
61 |
62 | public async Task RemoveTile()
63 | {
64 | var currentTiles = await _bandClient.TileManager.GetTilesAsync();
65 | var temperatureTile = currentTiles.FirstOrDefault(p => p.TileId == BandUiDefinitions.TileId);
66 | if (temperatureTile != null)
67 | {
68 | await _bandClient.TileManager.RemoveTileAsync(temperatureTile);
69 | }
70 |
71 | }
72 |
73 | private IEnumerable BuildTileUi()
74 | {
75 | var bandUi = new List();
76 | var page1Elements = new List
77 | {
78 | new Icon {ElementId = BandUiDefinitions.IconId, Rect = new PageRect(60,10,24,24)},
79 | new TextBlock {ElementId = BandUiDefinitions.TextTemperatureId, Rect = new PageRect(90, 10, 50, 40)},
80 | new TextButton {ElementId = BandUiDefinitions.ButtonToggleFanId, Rect = new PageRect(10, 50, 220, 40), HorizontalAlignment = HorizontalAlignment.Center}
81 | };
82 | var firstPanel = new FilledPanel(page1Elements) { Rect = new PageRect(0, 0, 240, 150) };
83 |
84 | var page2Elements = new List
85 | {
86 | new TextBlock {ElementId = BandUiDefinitions.TextTimeId, Rect = new PageRect(10, 10, 220, 40)},
87 | new TextBlock {ElementId = BandUiDefinitions.TextDateId, Rect = new PageRect(10, 58, 220, 40)}
88 | };
89 | var secondPanel = new FilledPanel(page2Elements) { Rect = new PageRect(0, 0, 240, 150) };
90 |
91 | bandUi.Add(new PageLayout(firstPanel));
92 | bandUi.Add(new PageLayout(secondPanel));
93 |
94 | return bandUi;
95 | }
96 |
97 |
98 | private List BuildIntialTileData()
99 | {
100 | return BuildTileData(
101 | "not yet set",
102 | "not yet set",
103 | "--.-°C",
104 | "not yet set");
105 | }
106 |
107 | private async Task LoadIcon(string uri)
108 | {
109 | var imageFile = await StorageFile.GetFileFromApplicationUriAsync(new Uri(uri));
110 |
111 | using (var fileStream = await imageFile.OpenAsync(FileAccessMode.Read))
112 | {
113 | var bitmap = new WriteableBitmap(1, 1);
114 | await bitmap.SetSourceAsync(fileStream);
115 | return bitmap.ToBandIcon();
116 | }
117 | }
118 |
119 | private List BuildTileData(string timeText, string dateText, string temperature, string buttonText)
120 | {
121 | var result = new List
122 | {
123 | BuildTileDataPage2(timeText, dateText),
124 | BuildTileDataPage1(temperature, buttonText)
125 | };
126 | return result;
127 | }
128 |
129 | private PageData BuildTileDataPage1(string temperature, string buttonText)
130 | {
131 | return new PageData(BandUiDefinitions.Page1Id, 0, new IconData(BandUiDefinitions.IconId, 1),
132 | new TextButtonData(BandUiDefinitions.ButtonToggleFanId, buttonText),
133 | new TextBlockData(BandUiDefinitions.TextTemperatureId, $": {temperature}"));
134 | }
135 |
136 | private PageData BuildTileDataPage2(string timeText, string dateText)
137 | {
138 | return new PageData(BandUiDefinitions.Page2Id, 1,
139 | new TextBlockData(BandUiDefinitions.TextTimeId, $"Time: {timeText}"), new TextBlockData(BandUiDefinitions.TextDateId, $"Date: {dateText}"));
140 | }
141 | }
142 | }
143 |
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/Models/BandUiDefinitions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace TemperatureReader.ClientApp.Models
4 | {
5 | public static class BandUiDefinitions
6 | {
7 | public static readonly Guid TileId = new Guid("567FF10C-E373-4AEC-85B4-EF30EE294174");
8 | public static readonly Guid Page1Id = new Guid("7E494E17-B498-4610-A6A6-3D0C3AF20226");
9 | public static readonly Guid Page2Id = new Guid("BB4EB700-A57B-4B8E-983B-72974A98D19E");
10 | public const short IconId = 1;
11 |
12 | public const short ButtonToggleFanId = 2;
13 | public const short TextTemperatureId = 3;
14 | public const short TextTimeId = 4;
15 | public const short TextDateId = 5;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/Models/DateTimeExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace TemperatureReader.ClientApp.Models
4 | {
5 | public static class DateTimeExtensions
6 | {
7 | public static bool IsSecondsAgo(this DateTimeOffset time, int seconds)
8 | {
9 | return (DateTimeOffset.UtcNow - time).TotalSeconds > seconds;
10 | }
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/Models/IBandOperator.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 | using TemperatureReader.Shared;
3 |
4 | namespace TemperatureReader.ClientApp.Models
5 | {
6 | public interface IBandOperator
7 | {
8 | Task Start(bool forceFreshClient = false);
9 |
10 | Task SendVibrate();
11 |
12 | Task Stop ();
13 |
14 | Task RemoveTile();
15 |
16 | void HandleNewTemperature(object sender, TemperatureData data);
17 |
18 | bool IsRunning { get; }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/Models/ITemperatureListener.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using TemperatureReader.Shared;
4 |
5 | namespace TemperatureReader.ClientApp.Models
6 | {
7 | public interface ITemperatureListener
8 | {
9 | Task Start();
10 |
11 | void Stop();
12 |
13 | bool IsRunning { get; }
14 |
15 | event EventHandler OnTemperatureDataReceived;
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/Models/TemperatureListener.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using TemperatureReader.ServiceBus;
4 | using TemperatureReader.Shared;
5 |
6 | namespace TemperatureReader.ClientApp.Models
7 | {
8 | public class TemperatureListener : ITemperatureListener
9 | {
10 | private readonly TemperatureQueueClient _client;
11 | public TemperatureListener()
12 | {
13 | _client = new TemperatureQueueClient(QueueMode.Listen);
14 | _client.OnDataReceived += ProcessTemperatureData;
15 | }
16 |
17 | private void ProcessTemperatureData(object sender,
18 | TemperatureData temperatureData)
19 | {
20 | OnTemperatureDataReceived?.Invoke(this, temperatureData);
21 | }
22 |
23 | public async Task Start()
24 | {
25 | await _client.Start();
26 | IsRunning = true;
27 | }
28 |
29 | public bool IsRunning { get; private set; }
30 |
31 | public void Stop()
32 | {
33 | _client.Stop();
34 | IsRunning = false;
35 | }
36 |
37 | public event EventHandler OnTemperatureDataReceived;
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/Package.appxmanifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | TemperatureReader.ClientAppApp
7 | joost
8 | Assets\StoreLogo.png
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("TemperatureReader.ClientAppApp")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("TemperatureReader.ClientAppApp")]
13 | [assembly: AssemblyCopyright("Copyright © 2015")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Version information for an assembly consists of the following four values:
18 | //
19 | // Major Version
20 | // Minor Version
21 | // Build Number
22 | // Revision
23 | //
24 | // You can specify all the values or you can default the Build and Revision Numbers
25 | // by using the '*' as shown below:
26 | // [assembly: AssemblyVersion("1.0.*")]
27 | [assembly: AssemblyVersion("1.0.0.0")]
28 | [assembly: AssemblyFileVersion("1.0.0.0")]
29 | [assembly: ComVisible(false)]
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/Properties/Default.rd.xml:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
20 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/TemperatureReader.ClientApp.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | x86
7 | {545E5193-A400-49AA-B7ED-84FD679ABBCB}
8 | AppContainerExe
9 | Properties
10 | TemperatureReader.ClientApp
11 | TemperatureReader.ClientApp
12 | en-US
13 | UAP
14 | 10.0.10586.0
15 | 10.0.10240.0
16 | 14
17 | true
18 | 512
19 | {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
20 | TemperatureReader.ClientApp_TemporaryKey.pfx
21 | /subscriptions/85f40e16-f427-4432-8757-1224d37207c3/resourcegroups/Default-ApplicationInsights-CentralUS/providers/microsoft.insights/components/TemperatureReader.ClientApp
22 | True
23 | C:\AppPackages\
24 | arm
25 |
26 |
27 | true
28 | bin\ARM\Debug\
29 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
30 | ;2008
31 | full
32 | ARM
33 | false
34 | prompt
35 | true
36 |
37 |
38 | bin\ARM\Release\
39 | TRACE;NETFX_CORE;WINDOWS_UWP
40 | true
41 | ;2008
42 | pdbonly
43 | ARM
44 | false
45 | prompt
46 | true
47 | true
48 |
49 |
50 | true
51 | bin\x64\Debug\
52 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
53 | ;2008
54 | full
55 | x64
56 | false
57 | prompt
58 | true
59 |
60 |
61 | bin\x64\Release\
62 | TRACE;NETFX_CORE;WINDOWS_UWP
63 | true
64 | ;2008
65 | pdbonly
66 | x64
67 | false
68 | prompt
69 | true
70 | true
71 |
72 |
73 | true
74 | bin\x86\Debug\
75 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
76 | ;2008
77 | full
78 | x86
79 | false
80 | prompt
81 | true
82 |
83 |
84 | bin\x86\Release\
85 | TRACE;NETFX_CORE;WINDOWS_UWP
86 | true
87 | ;2008
88 | pdbonly
89 | x86
90 | false
91 | prompt
92 | true
93 | true
94 |
95 |
96 |
97 |
98 |
99 |
100 |
101 | App.xaml
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 | MainPage.xaml
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 | Designer
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 | MSBuild:Compile
146 | Designer
147 |
148 |
149 | MSBuild:Compile
150 | Designer
151 |
152 |
153 |
154 |
155 | {D4967767-6F42-4305-9BAB-6C2336A2E3FA}
156 | TemperatureReader.ServiceBus
157 |
158 |
159 | {ecd216bf-ba5e-4504-a052-ac037e2f8591}
160 | TemperatureReader.Shared
161 |
162 |
163 |
164 |
165 | Behaviors SDK %28XAML%29
166 |
167 |
168 |
169 | 14.0
170 |
171 |
172 |
179 |
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/TemperatureReader.ClientApp_TemporaryKey.pfx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LocalJoost/TemperatureReaderDemo/181701369c4bad7bfdc1891d011fd27994c8f6f3/TemperatureReader.ClientApp/TemperatureReader.ClientApp_TemporaryKey.pfx
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/ViewModels/CrashLoggerViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.ObjectModel;
3 | using System.Threading.Tasks;
4 | using System.Windows.Input;
5 | using GalaSoft.MvvmLight;
6 | using GalaSoft.MvvmLight.Command;
7 | using TemperatureReader.ClientApp.Helpers;
8 |
9 | namespace TemperatureReader.ClientApp.ViewModels
10 | {
11 | public class CrashLoggerViewModel : ViewModelBase
12 | {
13 | private readonly IErrorLogger _crashLogger;
14 |
15 | public CrashLoggerViewModel(IErrorLogger crashLogger)
16 | {
17 | _crashLogger = crashLogger;
18 | ErrorLogLines = new ObservableCollection();
19 | }
20 |
21 | public ObservableCollection ErrorLogLines { get; }
22 |
23 |
24 | private bool _isLoggerVisible;
25 |
26 | public bool IsLoggerVisible
27 | {
28 | get { return _isLoggerVisible; }
29 | set { Set(() => IsLoggerVisible, ref _isLoggerVisible, value); }
30 | }
31 |
32 | public async Task ToggleLog()
33 | {
34 | if (!IsLoggerVisible)
35 | {
36 | try
37 | {
38 | var lines = await _crashLogger.GetLogContents();
39 | foreach (var line in lines)
40 | {
41 | ErrorLogLines.Add(line);
42 | }
43 | }
44 | catch (Exception ex)
45 | {
46 | var a = ex;
47 | }
48 |
49 | }
50 | else
51 | {
52 | ErrorLogLines.Clear();
53 | }
54 | IsLoggerVisible = !IsLoggerVisible;
55 | }
56 |
57 | public async Task ClearLog()
58 | {
59 | ErrorLogLines.Clear();
60 | await _crashLogger.DeleteLog();
61 | }
62 |
63 | private static CrashLoggerViewModel _instance;
64 |
65 | public static CrashLoggerViewModel Instance
66 | {
67 | get { return _instance ?? (_instance = CreateNew()); }
68 | set { _instance = value; }
69 | }
70 |
71 | public static CrashLoggerViewModel CreateNew()
72 | {
73 | var crashLogger = new ErrorLogger();
74 | return new CrashLoggerViewModel(crashLogger);
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/ViewModels/MainViewModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Globalization;
3 | using System.Threading.Tasks;
4 | using Windows.ApplicationModel.ExtendedExecution;
5 | using Windows.Devices.Geolocation;
6 | using GalaSoft.MvvmLight;
7 | using GalaSoft.MvvmLight.Ioc;
8 | using GalaSoft.MvvmLight.Messaging;
9 | using GalaSoft.MvvmLight.Threading;
10 | using TemperatureReader.ClientApp.Helpers;
11 | using TemperatureReader.ClientApp.Messages;
12 | using TemperatureReader.ClientApp.Models;
13 | using TemperatureReader.ServiceBus;
14 |
15 | namespace TemperatureReader.ClientApp.ViewModels
16 | {
17 | public class MainViewModel : ViewModelBase
18 | {
19 | private readonly ITemperatureListener _listener;
20 | private readonly IBandOperator _bandOperator;
21 | private readonly IMessageDisplayer _messageDisplayer;
22 | private readonly IErrorLogger _errorLogger;
23 |
24 |
25 | public MainViewModel(ITemperatureListener listener, IBandOperator bandOperator,
26 | IMessageDisplayer messageDisplayer, IErrorLogger errorLogger)
27 | {
28 | _listener = listener;
29 | _bandOperator = bandOperator;
30 | _messageDisplayer = messageDisplayer;
31 | _errorLogger = errorLogger;
32 | }
33 |
34 | public void Init()
35 | {
36 | Messenger.Default.Register(this, async msg => await OnResume());
37 | }
38 |
39 | public async Task RemoveTile()
40 | {
41 | IsBusy = true;
42 | await Task.Delay(1);
43 | await _bandOperator.RemoveTile();
44 | IsBusy = false;
45 | }
46 |
47 | private void Listener_OnTemperatureDataReceived(object sender, Shared.TemperatureData e)
48 | {
49 | if (e.IsValid)
50 | {
51 | DispatcherHelper.CheckBeginInvokeOnUI(() =>
52 | {
53 | Messenger.Default.Send(new DataReceivedMessage());
54 | Temperature = e.Temperature.ToString(CultureInfo.InvariantCulture);
55 | LastDateTimeReceived = e.Timestamp.ToLocalTime().ToString("HH:mm:ss dd-MM-yyyy");
56 | FanStatus = e.FanStatus == Shared.FanStatus.On ? "on" : "off";
57 | });
58 | }
59 | }
60 |
61 | public async Task OnSuspend()
62 | {
63 | if (_bandOperator != null && _bandOperator.IsRunning)
64 | {
65 | await _bandOperator.Stop();
66 | await _messageDisplayer.ShowMessage("Suspended");
67 | }
68 | }
69 |
70 |
71 | private async Task Start()
72 | {
73 | IsBusy = true;
74 | await Task.Delay(1);
75 | _listener.OnTemperatureDataReceived += Listener_OnTemperatureDataReceived;
76 | _listener.OnTemperatureDataReceived += _bandOperator.HandleNewTemperature;
77 | await _listener.Start();
78 | await StartBackgroundSession();
79 | await _bandOperator.Start();
80 | await _bandOperator.SendVibrate();
81 | IsBusy = false;
82 | }
83 |
84 | private async Task Stop()
85 | {
86 | IsBusy = true;
87 | await Task.Delay(1);
88 | _listener.OnTemperatureDataReceived -= Listener_OnTemperatureDataReceived;
89 | _listener.OnTemperatureDataReceived -= _bandOperator.HandleNewTemperature;
90 | _listener.Stop();
91 | await _bandOperator.Stop();
92 | _session.Dispose();
93 | _session = null;
94 | IsBusy = false;
95 | }
96 |
97 | private async Task Toggle()
98 | {
99 | if (_listener.IsRunning)
100 | {
101 | await Stop();
102 | }
103 | else
104 | {
105 | await Start();
106 | }
107 | RaisePropertyChanged(() => IsListening);
108 | }
109 |
110 | public async Task OnResume()
111 | {
112 | if ( IsListening && _bandOperator != null)
113 | {
114 | try
115 | {
116 | IsBusy = true;
117 | await Task.Delay(1);
118 | await StartBackgroundSession();
119 | await _bandOperator.Start(true);
120 | await _bandOperator.SendVibrate();
121 | IsBusy = false;
122 |
123 | }
124 | catch (Exception ex)
125 | {
126 | await _errorLogger.LogException(ex);
127 | await _messageDisplayer.ShowMessage($"Error restarting Band {ex.Message}");
128 | }
129 | }
130 | }
131 |
132 | public bool IsListening
133 | {
134 | get
135 | {
136 | return _listener?.IsRunning ?? false;
137 | }
138 | set
139 | {
140 | if (_listener != null)
141 | {
142 | if (value != _listener.IsRunning)
143 | {
144 | Toggle();
145 | }
146 | }
147 | }
148 | }
149 |
150 | private string _temperature = "--.-";
151 | public string Temperature
152 | {
153 | get { return _temperature; }
154 | set { Set(() => Temperature, ref _temperature, value); }
155 | }
156 |
157 | private string _lastDateTimeReceived = "--:--:-- ----------";
158 | public string LastDateTimeReceived
159 | {
160 | get { return _lastDateTimeReceived; }
161 | set { Set(() => LastDateTimeReceived, ref _lastDateTimeReceived, value); }
162 | }
163 |
164 | private string _fanStatus = "???";
165 | public string FanStatus
166 | {
167 | get { return _fanStatus; }
168 | set { Set(() => FanStatus, ref _fanStatus, value); }
169 | }
170 |
171 | private bool _isBusy;
172 | public bool IsBusy
173 | {
174 | get { return _isBusy; }
175 | set { Set(() => IsBusy, ref _isBusy, value); }
176 | }
177 |
178 | private ExtendedExecutionSession _session;
179 | private async Task StartBackgroundSession()
180 | {
181 | if (_session != null)
182 | {
183 | try
184 | {
185 | _session.Dispose();
186 | }
187 | catch (Exception){}
188 | }
189 | _session = null;
190 | {
191 | _session = new ExtendedExecutionSession
192 | {
193 | Description = "Temperature tracking",
194 | Reason = ExtendedExecutionReason.LocationTracking
195 | };
196 | StartFakeGeoLocator();
197 |
198 | _session.Revoked += async (p, q) => { await OnRevoke(); };
199 |
200 | var result = await _session.RequestExtensionAsync();
201 | return result != ExtendedExecutionResult.Denied;
202 | }
203 | return false;
204 | }
205 |
206 | private Geolocator _locator;
207 |
208 | private void StartFakeGeoLocator()
209 | {
210 | _locator = new Geolocator
211 | {
212 | DesiredAccuracy = PositionAccuracy.Default,
213 | DesiredAccuracyInMeters = 1,
214 | MovementThreshold = 1,
215 | ReportInterval = 5000
216 | };
217 | _locator.PositionChanged += LocatorPositionChanged;
218 | }
219 |
220 | private void LocatorPositionChanged(Geolocator sender, PositionChangedEventArgs args)
221 | {
222 | }
223 |
224 | private async Task OnRevoke()
225 | {
226 | await StartBackgroundSession();
227 | }
228 |
229 | private static MainViewModel _instance;
230 |
231 | public static MainViewModel Instance
232 | {
233 | get { return _instance ?? (_instance = CreateNew()); }
234 | set { _instance = value; }
235 | }
236 |
237 | public static MainViewModel CreateNew()
238 | {
239 | var fanStatusPoster = new FanSwitchQueueClient(QueueMode.Send);
240 | fanStatusPoster.Start();
241 | var listener = new TemperatureListener();
242 | var errorLogger = SimpleIoc.Default.GetInstance();
243 | var messageDisplayer = SimpleIoc.Default.GetInstance();
244 | var bandOperator = new BandOperator(fanStatusPoster);
245 | return (new MainViewModel(
246 | listener, bandOperator,
247 | messageDisplayer, errorLogger));
248 | }
249 | }
250 | }
251 |
--------------------------------------------------------------------------------
/TemperatureReader.ClientApp/project.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "Microsoft.AspNet.SignalR.Client": "2.2.0",
4 | "Microsoft.Band": "1.3.10929",
5 | "Microsoft.NETCore.UniversalWindowsPlatform": "5.0.0",
6 | "MvvmLightLibs": "5.2.0",
7 | "NotificationsExtensions.Win10": "10586.0.0"
8 | },
9 | "frameworks": {
10 | "uap10.0": {}
11 | },
12 | "runtimes": {
13 | "win10-arm": {},
14 | "win10-arm-aot": {},
15 | "win10-x86": {},
16 | "win10-x86-aot": {},
17 | "win10-x64": {},
18 | "win10-x64-aot": {}
19 | }
20 | }
--------------------------------------------------------------------------------
/TemperatureReader.Logic/Devices/AnalogTemperatureSensorController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading;
3 | using System.Threading.Tasks;
4 | using Windows.Devices.Gpio;
5 | using TemperatureReader.Logic.Utilities;
6 | using TemperatureReader.Shared;
7 |
8 | namespace TemperatureReader.Logic.Devices
9 | {
10 | public class AnalogTemperatureSensorController : IAnalogTemperatureSensorController
11 | {
12 | private readonly int _adcCsPinId;
13 | private readonly int _adcClkPinId;
14 | private readonly int _adcDigitalIoPinId;
15 |
16 | private readonly IGpioService _gpioCtrl;
17 | private GpioPin _adcCsPin;
18 | private GpioPin _adcClkPin;
19 | private GpioPin _adcDigitalIoPin;
20 |
21 | private Task _task;
22 | private CancellationTokenSource _cancellationTokenSource;
23 | private DateTimeOffset _lastExecutionTime = DateTimeOffset.MinValue;
24 | private readonly int _delayMilliSeconds;
25 | private readonly int _maxRetries;
26 |
27 |
28 | public AnalogTemperatureSensorController(
29 | IGpioService gpioCtrl,
30 | int adcCsPinId = Settings.AdcCsPinId,
31 | int adcClkPinId = Settings.AdcClkPinId,
32 | int adcDigitalIoPinId = Settings.AdcDigitalIoPinId,
33 | int delayMilliSeconds = Settings.DefaultTemperaturePostingDelay,
34 | int maxRetries = Settings.MaxReadRetry)
35 | {
36 | _gpioCtrl = gpioCtrl;
37 | _adcCsPinId = adcCsPinId;
38 | _adcClkPinId = adcClkPinId;
39 | _adcDigitalIoPinId = adcDigitalIoPinId;
40 | _delayMilliSeconds = delayMilliSeconds;
41 | _maxRetries = maxRetries;
42 | IsMeasuring = false;
43 | }
44 |
45 | public bool IsMeasuring { get; private set; }
46 |
47 | public bool Start()
48 | {
49 | if (_gpioCtrl?.Controller != null)
50 | {
51 | IsMeasuring = true;
52 |
53 | if (_adcDigitalIoPin == null)
54 | {
55 | _adcCsPin = _gpioCtrl.Controller.OpenPin(_adcCsPinId);
56 | _adcClkPin = _gpioCtrl.Controller.OpenPin(_adcClkPinId);
57 | _adcDigitalIoPin = _gpioCtrl.Controller.OpenPin(_adcDigitalIoPinId);
58 | }
59 |
60 | if (_task == null)
61 | {
62 | _cancellationTokenSource = new CancellationTokenSource();
63 | InitReadSession();
64 | _task = new Task(async () =>
65 | await ExecuteMeasuring(_cancellationTokenSource.Token));
66 | _task.Start();
67 | }
68 | }
69 | return IsMeasuring;
70 | }
71 |
72 | public void Stop()
73 | {
74 | _cancellationTokenSource.Cancel();
75 | _adcCsPin.Dispose();
76 | _adcCsPin = null;
77 | _adcClkPin.Dispose();
78 | _adcClkPin = null;
79 | _adcDigitalIoPin.Dispose();
80 | _adcDigitalIoPin = null;
81 | IsMeasuring = false;
82 | }
83 |
84 | private async Task ExecuteMeasuring(CancellationToken cancellationToken)
85 | {
86 | while (!cancellationToken.IsCancellationRequested)
87 | {
88 | var timePassed = DateTimeOffset.UtcNow - _lastExecutionTime;
89 | if (timePassed > TimeSpan.FromMilliseconds(_delayMilliSeconds))
90 | {
91 | var retries = 0;
92 | var readStatus = false;
93 |
94 | while (!readStatus && retries++ < _maxRetries)
95 | {
96 | readStatus = ReadData();
97 | _lastExecutionTime = DateTimeOffset.UtcNow;
98 | }
99 |
100 | if (retries >= _maxRetries)
101 | {
102 | OnTemperatureMeasured?.Invoke(this, new TemperatureData {IsValid = false});
103 | }
104 | _lastExecutionTime = DateTimeOffset.UtcNow;
105 | }
106 | else
107 | {
108 | var waitTime = _delayMilliSeconds - timePassed.TotalMilliseconds;
109 |
110 | if (waitTime > 0)
111 | {
112 | await Task.Delay(Convert.ToInt32(waitTime), cancellationToken);
113 | }
114 | }
115 | }
116 | }
117 |
118 | private void InitReadSession()
119 | {
120 | _adcClkPin.SetDriveMode(GpioPinDriveMode.Output);
121 | _adcCsPin.SetDriveMode(GpioPinDriveMode.Output);
122 | _adcDigitalIoPin.SetDriveMode(GpioPinDriveMode.Output);
123 | }
124 |
125 | private void InitAdConverter(SynchronousWaiter waiter)
126 | {
127 | _adcCsPin.Write(GpioPinValue.Low);
128 | _adcClkPin.Write(GpioPinValue.Low);
129 | _adcDigitalIoPin.Write(GpioPinValue.High); waiter.Wait(2);
130 | _adcClkPin.Write(GpioPinValue.High); waiter.Wait(2);
131 |
132 | _adcClkPin.Write(GpioPinValue.Low);
133 | _adcDigitalIoPin.Write(GpioPinValue.High); waiter.Wait(2);
134 | _adcClkPin.Write(GpioPinValue.High); waiter.Wait(2);
135 |
136 | _adcClkPin.Write(GpioPinValue.Low);
137 | _adcDigitalIoPin.Write(GpioPinValue.Low); waiter.Wait(2);
138 | _adcClkPin.Write(GpioPinValue.High);
139 | _adcDigitalIoPin.Write(GpioPinValue.High); waiter.Wait(2);
140 | _adcClkPin.Write(GpioPinValue.Low);
141 | _adcDigitalIoPin.Write(GpioPinValue.High); waiter.Wait(2);
142 |
143 | _adcDigitalIoPin.SetDriveMode(GpioPinDriveMode.Input);
144 | }
145 |
146 | private bool ReadData()
147 | {
148 | int sequence1 = 0, sequence2 = 0;
149 | _adcCsPin.Write(GpioPinValue.Low);
150 |
151 | InitReadSession();
152 | var waiter = new SynchronousWaiter();
153 | InitAdConverter(waiter);
154 |
155 | //Read the first sequence
156 | for (var i = 0; i < 8; i++)
157 | {
158 | _adcClkPin.Write(GpioPinValue.High);
159 | waiter.Wait(2);
160 | _adcClkPin.Write(GpioPinValue.Low);
161 | waiter.Wait(2);
162 | sequence1 = sequence1 << 1 | (int)_adcDigitalIoPin.Read();
163 | }
164 |
165 | //Read the second sequence
166 | for (var i = 0; i < 8; i++)
167 | {
168 | sequence2 = sequence2 | (int)_adcDigitalIoPin.Read() << i;
169 |
170 | _adcClkPin.Write(GpioPinValue.High);
171 | waiter.Wait(2);
172 | _adcClkPin.Write(GpioPinValue.Low);
173 | waiter.Wait(2);
174 | }
175 |
176 | _adcCsPin.Write(GpioPinValue.High);
177 |
178 | if (sequence1 == sequence2)
179 | {
180 | OnTemperatureMeasured?.Invoke(this,
181 | new TemperatureData { IsValid = true, Temperature =
182 | Math.Round(((255 - sequence1) - 121) * 0.21875,1) + 21.8, Timestamp = DateTimeOffset.UtcNow});
183 | return true;
184 | }
185 |
186 | return false;
187 | }
188 |
189 | public event EventHandler OnTemperatureMeasured;
190 | }
191 | }
192 |
--------------------------------------------------------------------------------
/TemperatureReader.Logic/Devices/GpioService.cs:
--------------------------------------------------------------------------------
1 | using Windows.Devices.Gpio;
2 |
3 | namespace TemperatureReader.Logic.Devices
4 | {
5 | public class GpioService : IGpioService
6 | {
7 | public GpioService()
8 | {
9 |
10 | if (Windows.Foundation.Metadata.ApiInformation.IsTypePresent(
11 | "Windows.Devices.Gpio.GpioController"))
12 | {
13 | if (Controller == null)
14 | {
15 | Controller = GpioController.GetDefault();
16 | }
17 | }
18 | }
19 | public GpioController Controller { get; private set; }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/TemperatureReader.Logic/Devices/IAnalogTemperatureSensorController.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using TemperatureReader.Shared;
3 |
4 | namespace TemperatureReader.Logic.Devices
5 | {
6 | public interface IAnalogTemperatureSensorController
7 | {
8 | bool IsMeasuring { get; }
9 | event EventHandler OnTemperatureMeasured;
10 | bool Start();
11 | void Stop();
12 | }
13 | }
--------------------------------------------------------------------------------
/TemperatureReader.Logic/Devices/IGpioService.cs:
--------------------------------------------------------------------------------
1 | using Windows.Devices.Gpio;
2 |
3 | namespace TemperatureReader.Logic.Devices
4 | {
5 | public interface IGpioService
6 | {
7 | GpioController Controller { get; }
8 | }
9 | }
--------------------------------------------------------------------------------
/TemperatureReader.Logic/Devices/StatusLed.cs:
--------------------------------------------------------------------------------
1 | using System.Threading.Tasks;
2 |
3 | namespace TemperatureReader.Logic.Devices
4 | {
5 | public class StatusLed : SwitchDevice
6 | {
7 | public StatusLed(IGpioService gpioCtrl, int pinId) : base(gpioCtrl,pinId)
8 | {
9 | }
10 |
11 | public async Task Flash(int milliseconds)
12 | {
13 | SwitchOn(true);
14 | await Task.Delay(milliseconds);
15 | SwitchOn(false);
16 | }
17 | }
18 | }
--------------------------------------------------------------------------------
/TemperatureReader.Logic/Devices/SwitchDevice.cs:
--------------------------------------------------------------------------------
1 | using Windows.Devices.Gpio;
2 |
3 | namespace TemperatureReader.Logic.Devices
4 | {
5 | public class SwitchDevice
6 | {
7 | private readonly int _pinId;
8 | private readonly IGpioService _gpioCtrl;
9 | private GpioPin _pin;
10 |
11 | public SwitchDevice(IGpioService gpioCtrl, int pinId)
12 | {
13 | _pinId = pinId;
14 | _gpioCtrl = gpioCtrl;
15 | SwitchOn(false);
16 | }
17 |
18 | public void SwitchOn(bool @on)
19 | {
20 | GpioPin pin;
21 | if ((pin = GetPin()) != null)
22 | {
23 | pin.Write(@on? GpioPinValue.High : GpioPinValue.Low);
24 | }
25 | }
26 |
27 | public void Toggle()
28 | {
29 | SwitchOn(!IsOn);
30 | }
31 |
32 | public bool IsOn
33 | {
34 | get
35 | {
36 | GpioPin pin;
37 | if ((pin = GetPin()) != null)
38 | {
39 | var currentPinValue = pin.Read();
40 | return currentPinValue == GpioPinValue.High;
41 | }
42 | return false;
43 | }
44 | }
45 |
46 | protected GpioPin GetPin()
47 | {
48 | if (_pin == null)
49 | {
50 | if (_gpioCtrl?.Controller != null)
51 | {
52 | _pin = _gpioCtrl.Controller.OpenPin(_pinId);
53 | _pin.SetDriveMode(GpioPinDriveMode.Output);
54 | }
55 | }
56 | return _pin;
57 | }
58 | }
59 | }
--------------------------------------------------------------------------------
/TemperatureReader.Logic/Models/Thermometer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 | using TemperatureReader.Logic.Devices;
4 | using TemperatureReader.Shared;
5 |
6 | namespace TemperatureReader.Logic.Models
7 | {
8 | public class Thermometer
9 | {
10 | private const int WaitTimeBeforeStartup = 5000;
11 |
12 | private readonly int _errorPinId;
13 | private readonly int _dataPinId;
14 |
15 | private readonly int _longFlashTime;
16 | private readonly int _shortFlashTime;
17 |
18 | private StatusLed _errorLed;
19 | private StatusLed _dataPinLed;
20 |
21 | private readonly IGpioService _gpioService;
22 | private readonly IAnalogTemperatureSensorController _temperatureSensorController ;
23 |
24 | public Thermometer(IGpioService gpioService,
25 | IAnalogTemperatureSensorController temperatureSensorController,
26 | int errorPinId = Settings.ErrorPinId, int dataPinId = Settings.DataPinId,
27 | int longFlashTime = Settings.LongFlashTime, int shortFlashTime = Settings.ShortFlashTime)
28 | {
29 | _gpioService = gpioService;
30 | _errorPinId = errorPinId;
31 | _dataPinId = dataPinId;
32 | _longFlashTime = longFlashTime;
33 | _shortFlashTime = shortFlashTime;
34 | _temperatureSensorController = temperatureSensorController;
35 | }
36 |
37 | public async Task Start()
38 | {
39 | _errorLed = new StatusLed(_gpioService, _errorPinId);
40 | _dataPinLed = new StatusLed(_gpioService, _dataPinId);
41 |
42 | await ShowStartup();
43 | await Task.Delay(WaitTimeBeforeStartup);
44 |
45 | _temperatureSensorController.OnTemperatureMeasured += HandleTemperatureMeasured;
46 | _temperatureSensorController.Start();
47 | }
48 |
49 | public void Stop()
50 | {
51 | //TODO!!!
52 | }
53 |
54 | private async void HandleTemperatureMeasured(object sender, TemperatureData e)
55 | {
56 | if (e.IsValid)
57 | {
58 | await _dataPinLed.Flash(_longFlashTime);
59 | OnTemperatureMeasured?.Invoke(this, e);
60 | }
61 | else
62 | {
63 | await _errorLed.Flash(_longFlashTime);
64 | }
65 | }
66 |
67 | private async Task ShowStartup()
68 | {
69 | for (var c = 0; c < 3; c++)
70 | {
71 | _errorLed.SwitchOn(true);
72 | await Task.Delay(_shortFlashTime);
73 | _dataPinLed.SwitchOn(true);
74 | _errorLed.SwitchOn(false);
75 | await Task.Delay(_shortFlashTime);
76 | _dataPinLed.SwitchOn(false);
77 | await Task.Delay(_shortFlashTime);
78 | }
79 | }
80 |
81 | public event EventHandler OnTemperatureMeasured;
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/TemperatureReader.Logic/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("TemperatureReader.Logic")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("TemperatureReader.Logic")]
13 | [assembly: AssemblyCopyright("Copyright © 2015")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Version information for an assembly consists of the following four values:
18 | //
19 | // Major Version
20 | // Minor Version
21 | // Build Number
22 | // Revision
23 | //
24 | // You can specify all the values or you can default the Build and Revision Numbers
25 | // by using the '*' as shown below:
26 | // [assembly: AssemblyVersion("1.0.*")]
27 | [assembly: AssemblyVersion("1.0.0.0")]
28 | [assembly: AssemblyFileVersion("1.0.0.0")]
29 | [assembly: ComVisible(false)]
--------------------------------------------------------------------------------
/TemperatureReader.Logic/Properties/TemperatureReader.Logic.rd.xml:
--------------------------------------------------------------------------------
1 |
2 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/TemperatureReader.Logic/TemperatureReader.Logic.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {8C77F671-5CA3-49FD-B600-05CF848E14DC}
8 | Library
9 | Properties
10 | TemperatureReader.Logic
11 | TemperatureReader.Logic
12 | en-US
13 | UAP
14 | 10.0.10586.0
15 | 10.0.10240.0
16 | 14
17 | 512
18 | {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
19 |
20 |
21 | AnyCPU
22 | true
23 | full
24 | false
25 | bin\Debug\
26 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
27 | prompt
28 | 4
29 |
30 |
31 | AnyCPU
32 | pdbonly
33 | true
34 | bin\Release\
35 | TRACE;NETFX_CORE;WINDOWS_UWP
36 | prompt
37 | 4
38 |
39 |
40 | ARM
41 | true
42 | bin\ARM\Debug\
43 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
44 | ;2008
45 | full
46 | ARM
47 | false
48 | prompt
49 | true
50 |
51 |
52 | ARM
53 | bin\ARM\Release\
54 | TRACE;NETFX_CORE;WINDOWS_UWP
55 | true
56 | ;2008
57 | pdbonly
58 | ARM
59 | false
60 | prompt
61 | true
62 |
63 |
64 | x64
65 | true
66 | bin\x64\Debug\
67 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
68 | ;2008
69 | full
70 | x64
71 | false
72 | prompt
73 | true
74 |
75 |
76 | x64
77 | bin\x64\Release\
78 | TRACE;NETFX_CORE;WINDOWS_UWP
79 | true
80 | ;2008
81 | pdbonly
82 | x64
83 | false
84 | prompt
85 | true
86 |
87 |
88 | x86
89 | true
90 | bin\x86\Debug\
91 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
92 | ;2008
93 | full
94 | x86
95 | false
96 | prompt
97 | true
98 |
99 |
100 | x86
101 | bin\x86\Release\
102 | TRACE;NETFX_CORE;WINDOWS_UWP
103 | true
104 | ;2008
105 | pdbonly
106 | x86
107 | false
108 | prompt
109 | true
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 | {d4967767-6f42-4305-9bab-6c2336a2e3fa}
130 | TemperatureReader.ServiceBus
131 |
132 |
133 | {ecd216bf-ba5e-4504-a052-ac037e2f8591}
134 | TemperatureReader.Shared
135 |
136 |
137 |
138 |
139 | Windows IoT Extensions for the UWP
140 |
141 |
142 |
143 | 14.0
144 |
145 |
146 |
153 |
--------------------------------------------------------------------------------
/TemperatureReader.Logic/Utilities/SynchronousWaiter.cs:
--------------------------------------------------------------------------------
1 | using System.Diagnostics;
2 |
3 | namespace TemperatureReader.Logic.Utilities
4 | {
5 | class SynchronousWaiter
6 | {
7 | readonly Stopwatch _stopwatch;
8 | public SynchronousWaiter()
9 | {
10 | _stopwatch = Stopwatch.StartNew();
11 | }
12 |
13 | public void Wait(double milliseconds)
14 | {
15 | var initialTick = _stopwatch.ElapsedTicks;
16 | var desiredTicks = milliseconds / 1000.0 * Stopwatch.Frequency;
17 | var finalTick = initialTick + desiredTicks;
18 | while (_stopwatch.ElapsedTicks < finalTick)
19 | {
20 |
21 | }
22 | }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/TemperatureReader.Logic/project.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "Microsoft.NETCore.UniversalWindowsPlatform": "5.0.0"
4 | },
5 | "frameworks": {
6 | "uap10.0": {}
7 | },
8 | "runtimes": {
9 | "win10-arm": {},
10 | "win10-arm-aot": {},
11 | "win10-x86": {},
12 | "win10-x86-aot": {},
13 | "win10-x64": {},
14 | "win10-x64-aot": {}
15 | }
16 | }
--------------------------------------------------------------------------------
/TemperatureReader.ServiceBus/FanSwitchQueueClient.cs:
--------------------------------------------------------------------------------
1 | using TemperatureReader.Shared;
2 |
3 | namespace TemperatureReader.ServiceBus
4 | {
5 | public class FanSwitchQueueClient : QueueClient
6 | {
7 | public FanSwitchQueueClient(QueueMode mode = QueueMode.Listen) : base(Settings.FanSwitchQueue, Settings.TemperatureBusConnectionString, mode, Settings.FanSwitchQueueTtl)
8 | {
9 | }
10 |
11 | }
12 | }
13 |
--------------------------------------------------------------------------------
/TemperatureReader.ServiceBus/IQueueClient.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Threading.Tasks;
3 |
4 | namespace TemperatureReader.ServiceBus
5 | {
6 | public interface IQueueClient
7 | {
8 | event EventHandler OnDataReceived;
9 |
10 | Task PostData(T tData);
11 | Task Start();
12 | void Stop();
13 | }
14 | }
--------------------------------------------------------------------------------
/TemperatureReader.ServiceBus/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("TemperatureReader.ServiceBus")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("TemperatureReader.ServiceBus")]
13 | [assembly: AssemblyCopyright("Copyright © 2015")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Version information for an assembly consists of the following four values:
18 | //
19 | // Major Version
20 | // Minor Version
21 | // Build Number
22 | // Revision
23 | //
24 | // You can specify all the values or you can default the Build and Revision Numbers
25 | // by using the '*' as shown below:
26 | // [assembly: AssemblyVersion("1.0.*")]
27 | [assembly: AssemblyVersion("1.0.0.0")]
28 | [assembly: AssemblyFileVersion("1.0.0.0")]
29 | [assembly: ComVisible(false)]
--------------------------------------------------------------------------------
/TemperatureReader.ServiceBus/Properties/TemperatureReader.ServiceBus.rd.xml:
--------------------------------------------------------------------------------
1 |
2 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/TemperatureReader.ServiceBus/QueueClient.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Threading.Tasks;
4 | using Microsoft.WindowsAzure.Messaging;
5 |
6 | namespace TemperatureReader.ServiceBus
7 | {
8 | public class QueueClient : IQueueClient
9 | {
10 | private readonly string _queueName;
11 | private readonly string _connectionString;
12 | private readonly int _messageTimeToLive;
13 | private readonly QueueMode _queueMode;
14 | private Queue _queue;
15 |
16 | public QueueClient(string queueName, string connectionString,
17 | QueueMode mode = QueueMode.Send, int messageTimeToLive = 10)
18 | {
19 | _queueName = queueName;
20 | _connectionString = connectionString;
21 | _queueMode = mode;
22 | _messageTimeToLive = messageTimeToLive;
23 | }
24 |
25 |
26 | public async virtual Task Start()
27 | {
28 | try
29 | {
30 | var settings = new QueueSettings { DefaultMessageTimeToLive = TimeSpan.FromSeconds(_messageTimeToLive) };
31 | await Queue.CreateAsync(_queueName, _connectionString, settings);
32 | Debug.WriteLine($"Queue {_queueName} created");
33 | }
34 | catch (Exception)
35 | {
36 | Debug.WriteLine($"Queue {_queueName} already exists");
37 | }
38 |
39 | _queue = new Queue(_queueName, _connectionString);
40 | if (_queueMode == QueueMode.Listen)
41 | {
42 | _queue.OnMessage(message =>
43 | {
44 | var data = message.GetBody();
45 | OnDataReceived?.Invoke(this, data);
46 | });
47 | }
48 | }
49 |
50 | public void Stop()
51 | {
52 | if (_queue != null)
53 | {
54 | _queue.Dispose();
55 | _queue = null;
56 | }
57 | }
58 |
59 | public virtual async Task PostData(T tData)
60 | {
61 | if (this._queueMode == QueueMode.Send)
62 | {
63 | await _queue.SendAsync(tData);
64 | }
65 | else
66 | {
67 | throw new ArgumentException("Cannot send data using a QueueMode.Listen client");
68 | }
69 | }
70 |
71 | public event EventHandler OnDataReceived;
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/TemperatureReader.ServiceBus/QueueMode.cs:
--------------------------------------------------------------------------------
1 | namespace TemperatureReader.ServiceBus
2 | {
3 | public enum QueueMode
4 | {
5 | Send,
6 | Listen
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/TemperatureReader.ServiceBus/TemperatureQueueClient.cs:
--------------------------------------------------------------------------------
1 | using TemperatureReader.Shared;
2 |
3 | namespace TemperatureReader.ServiceBus
4 | {
5 | public class TemperatureQueueClient : QueueClient
6 | {
7 | public TemperatureQueueClient(QueueMode mode = QueueMode.Listen) :
8 | base(Settings.TemperatureQueue,
9 | Settings.TemperatureBusConnectionString, mode,
10 | Settings.TemperatureQueueTtl)
11 | {
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/TemperatureReader.ServiceBus/TemperatureReader.ServiceBus.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | AnyCPU
7 | {D4967767-6F42-4305-9BAB-6C2336A2E3FA}
8 | Library
9 | Properties
10 | TemperatureReader.ServiceBus
11 | TemperatureReader.ServiceBus
12 | en-US
13 | UAP
14 | 10.0.10586.0
15 | 10.0.10240.0
16 | 14
17 | 512
18 | {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
19 |
20 |
21 | AnyCPU
22 | true
23 | full
24 | false
25 | bin\Debug\
26 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
27 | prompt
28 | 4
29 |
30 |
31 | AnyCPU
32 | pdbonly
33 | true
34 | bin\Release\
35 | TRACE;NETFX_CORE;WINDOWS_UWP
36 | prompt
37 | 4
38 |
39 |
40 | ARM
41 | true
42 | bin\ARM\Debug\
43 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
44 | ;2008
45 | full
46 | ARM
47 | false
48 | prompt
49 | true
50 |
51 |
52 | ARM
53 | bin\ARM\Release\
54 | TRACE;NETFX_CORE;WINDOWS_UWP
55 | true
56 | ;2008
57 | pdbonly
58 | ARM
59 | false
60 | prompt
61 | true
62 |
63 |
64 | x64
65 | true
66 | bin\x64\Debug\
67 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
68 | ;2008
69 | full
70 | x64
71 | false
72 | prompt
73 | true
74 |
75 |
76 | x64
77 | bin\x64\Release\
78 | TRACE;NETFX_CORE;WINDOWS_UWP
79 | true
80 | ;2008
81 | pdbonly
82 | x64
83 | false
84 | prompt
85 | true
86 |
87 |
88 | x86
89 | true
90 | bin\x86\Debug\
91 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
92 | ;2008
93 | full
94 | x86
95 | false
96 | prompt
97 | true
98 |
99 |
100 | x86
101 | bin\x86\Release\
102 | TRACE;NETFX_CORE;WINDOWS_UWP
103 | true
104 | ;2008
105 | pdbonly
106 | x86
107 | false
108 | prompt
109 | true
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 | {ecd216bf-ba5e-4504-a052-ac037e2f8591}
127 | TemperatureReader.Shared
128 |
129 |
130 |
131 | 14.0
132 |
133 |
134 |
141 |
--------------------------------------------------------------------------------
/TemperatureReader.ServiceBus/project.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "Microsoft.NETCore.UniversalWindowsPlatform": "5.0.0",
4 | "WindowsAzure.Messaging.Managed": "0.1.7.9"
5 | },
6 | "frameworks": {
7 | "uap10.0": {}
8 | },
9 | "runtimes": {
10 | "win10-arm": {},
11 | "win10-arm-aot": {},
12 | "win10-x86": {},
13 | "win10-x86-aot": {},
14 | "win10-x64": {},
15 | "win10-x64-aot": {}
16 | }
17 | }
--------------------------------------------------------------------------------
/TemperatureReader.Shared/FanStatus.cs:
--------------------------------------------------------------------------------
1 | namespace TemperatureReader.Shared
2 | {
3 | public enum FanStatus
4 | {
5 | Off,
6 | On
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/TemperatureReader.Shared/FanSwitchCommand.cs:
--------------------------------------------------------------------------------
1 | namespace TemperatureReader.Shared
2 | {
3 | public class FanSwitchCommand
4 | {
5 |
6 | public FanSwitchCommand()
7 | {
8 | }
9 |
10 | public FanSwitchCommand(FanStatus status, bool toggle = false)
11 | {
12 | if (toggle)
13 | {
14 | Status = status == FanStatus.Off ? FanStatus.On: FanStatus.Off;
15 | }
16 | else
17 | {
18 | Status = status;
19 | }
20 | }
21 | public FanStatus Status { get; set; }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/TemperatureReader.Shared/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Resources;
2 | using System.Reflection;
3 | using System.Runtime.CompilerServices;
4 | using System.Runtime.InteropServices;
5 |
6 | // General Information about an assembly is controlled through the following
7 | // set of attributes. Change these attribute values to modify the information
8 | // associated with an assembly.
9 | [assembly: AssemblyTitle("TemperatureReader.Shared")]
10 | [assembly: AssemblyDescription("")]
11 | [assembly: AssemblyConfiguration("")]
12 | [assembly: AssemblyCompany("")]
13 | [assembly: AssemblyProduct("TemperatureReader.Shared")]
14 | [assembly: AssemblyCopyright("Copyright © 2015")]
15 | [assembly: AssemblyTrademark("")]
16 | [assembly: AssemblyCulture("")]
17 | [assembly: NeutralResourcesLanguage("en")]
18 |
19 | // Version information for an assembly consists of the following four values:
20 | //
21 | // Major Version
22 | // Minor Version
23 | // Build Number
24 | // Revision
25 | //
26 | // You can specify all the values or you can default the Build and Revision Numbers
27 | // by using the '*' as shown below:
28 | // [assembly: AssemblyVersion("1.0.*")]
29 | [assembly: AssemblyVersion("1.0.0.0")]
30 | [assembly: AssemblyFileVersion("1.0.0.0")]
31 |
--------------------------------------------------------------------------------
/TemperatureReader.Shared/Settings.cs:
--------------------------------------------------------------------------------
1 | namespace TemperatureReader.Shared
2 | {
3 | public static class Settings
4 | {
5 |
6 | public static readonly string TemperatureBusConnectionString =
7 | "Endpoint=sb://yournamespace.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=XXXXXXXXXXXXXXXXXYOURKEYHEREXXXXXXXXXXXXXXXX";";
8 |
9 | public static readonly string TemperatureQueue = "temperaturedatabus";
10 | public static readonly int TemperatureQueueTtl = 10;
11 |
12 | public static readonly string FanSwitchQueue = "fanswitchcommandbus";
13 | public static readonly int FanSwitchQueueTtl = 10;
14 |
15 | public const int ErrorPinId = 12;
16 | public const int DataPinId = 16;
17 | public const int LongFlashTime = 250;
18 | public const int ShortFlashTime = 125;
19 |
20 | public const int AdcCsPinId = 5;
21 | public const int AdcClkPinId = 6;
22 | public const int AdcDigitalIoPinId = 13;
23 | public const int DefaultTemperaturePostingDelay = 5000;
24 | public const int MaxReadRetry = 10;
25 |
26 | public const int SwitchPinId = 18;
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/TemperatureReader.Shared/TemperatureData.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | namespace TemperatureReader.Shared
4 | {
5 | public class TemperatureData
6 | {
7 | public TemperatureData()
8 | {
9 | }
10 |
11 | public TemperatureData(double temperature, bool isValid = true )
12 | {
13 | Temperature = temperature;
14 | IsValid = isValid;
15 | Timestamp = DateTimeOffset.UtcNow;
16 | }
17 |
18 | public DateTimeOffset Timestamp { get; set; }
19 |
20 | public double Temperature { get; set; }
21 |
22 | public bool IsValid { get; set; }
23 |
24 | public FanStatus FanStatus { get; set; }
25 |
26 | }
27 | }
--------------------------------------------------------------------------------
/TemperatureReader.Shared/TemperatureReader.Shared.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | 11.0
6 | Debug
7 | AnyCPU
8 | {ECD216BF-BA5E-4504-A052-AC037E2F8591}
9 | Library
10 | Properties
11 | TemperatureReader.Shared
12 | TemperatureReader.Shared
13 | en-US
14 | 512
15 | {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
16 | Profile111
17 | v4.5
18 |
19 |
20 | true
21 | full
22 | false
23 | bin\Debug\
24 | DEBUG;TRACE
25 | prompt
26 | 4
27 |
28 |
29 | pdbonly
30 | true
31 | bin\Release\
32 | TRACE
33 | prompt
34 | 4
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
54 |
--------------------------------------------------------------------------------
/TemperatureReader/App.xaml:
--------------------------------------------------------------------------------
1 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/TemperatureReader/App.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using Windows.ApplicationModel;
3 | using Windows.ApplicationModel.Activation;
4 | using Windows.UI.Xaml;
5 | using Windows.UI.Xaml.Controls;
6 | using Windows.UI.Xaml.Navigation;
7 |
8 | namespace TemperatureReader
9 | {
10 | ///
11 | /// Provides application-specific behavior to supplement the default Application class.
12 | ///
13 | sealed partial class App : Application
14 | {
15 | ///
16 | /// Initializes the singleton application object. This is the first line of authored code
17 | /// executed, and as such is the logical equivalent of main() or WinMain().
18 | ///
19 | public App()
20 | {
21 | this.InitializeComponent();
22 | this.Suspending += OnSuspending;
23 | }
24 |
25 | ///
26 | /// Invoked when the application is launched normally by the end user. Other entry points
27 | /// will be used such as when the application is launched to open a specific file.
28 | ///
29 | /// Details about the launch request and process.
30 | protected override void OnLaunched(LaunchActivatedEventArgs e)
31 | {
32 |
33 | #if DEBUG
34 | if (System.Diagnostics.Debugger.IsAttached)
35 | {
36 | this.DebugSettings.EnableFrameRateCounter = true;
37 | }
38 | #endif
39 |
40 | Frame rootFrame = Window.Current.Content as Frame;
41 |
42 | // Do not repeat app initialization when the Window already has content,
43 | // just ensure that the window is active
44 | if (rootFrame == null)
45 | {
46 | // Create a Frame to act as the navigation context and navigate to the first page
47 | rootFrame = new Frame();
48 |
49 | rootFrame.NavigationFailed += OnNavigationFailed;
50 |
51 | if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
52 | {
53 | //TODO: Load state from previously suspended application
54 | }
55 |
56 | // Place the frame in the current Window
57 | Window.Current.Content = rootFrame;
58 | }
59 |
60 | if (rootFrame.Content == null)
61 | {
62 | // When the navigation stack isn't restored navigate to the first page,
63 | // configuring the new page by passing required information as a navigation
64 | // parameter
65 | rootFrame.Navigate(typeof(MainPage), e.Arguments);
66 | }
67 | // Ensure the current window is active
68 | Window.Current.Activate();
69 | }
70 |
71 | ///
72 | /// Invoked when Navigation to a certain page fails
73 | ///
74 | /// The Frame which failed navigation
75 | /// Details about the navigation failure
76 | void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
77 | {
78 | throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
79 | }
80 |
81 | ///
82 | /// Invoked when application execution is being suspended. Application state is saved
83 | /// without knowing whether the application will be terminated or resumed with the contents
84 | /// of memory still intact.
85 | ///
86 | /// The source of the suspend request.
87 | /// Details about the suspend request.
88 | private void OnSuspending(object sender, SuspendingEventArgs e)
89 | {
90 | var deferral = e.SuspendingOperation.GetDeferral();
91 | //TODO: Save application state and stop any background activity
92 | deferral.Complete();
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/TemperatureReader/Assets/LockScreenLogo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LocalJoost/TemperatureReaderDemo/181701369c4bad7bfdc1891d011fd27994c8f6f3/TemperatureReader/Assets/LockScreenLogo.scale-200.png
--------------------------------------------------------------------------------
/TemperatureReader/Assets/SplashScreen.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LocalJoost/TemperatureReaderDemo/181701369c4bad7bfdc1891d011fd27994c8f6f3/TemperatureReader/Assets/SplashScreen.scale-200.png
--------------------------------------------------------------------------------
/TemperatureReader/Assets/Square150x150Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LocalJoost/TemperatureReaderDemo/181701369c4bad7bfdc1891d011fd27994c8f6f3/TemperatureReader/Assets/Square150x150Logo.scale-200.png
--------------------------------------------------------------------------------
/TemperatureReader/Assets/Square44x44Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LocalJoost/TemperatureReaderDemo/181701369c4bad7bfdc1891d011fd27994c8f6f3/TemperatureReader/Assets/Square44x44Logo.scale-200.png
--------------------------------------------------------------------------------
/TemperatureReader/Assets/Square44x44Logo.targetsize-24_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LocalJoost/TemperatureReaderDemo/181701369c4bad7bfdc1891d011fd27994c8f6f3/TemperatureReader/Assets/Square44x44Logo.targetsize-24_altform-unplated.png
--------------------------------------------------------------------------------
/TemperatureReader/Assets/StoreLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LocalJoost/TemperatureReaderDemo/181701369c4bad7bfdc1891d011fd27994c8f6f3/TemperatureReader/Assets/StoreLogo.png
--------------------------------------------------------------------------------
/TemperatureReader/Assets/Wide310x150Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LocalJoost/TemperatureReaderDemo/181701369c4bad7bfdc1891d011fd27994c8f6f3/TemperatureReader/Assets/Wide310x150Logo.scale-200.png
--------------------------------------------------------------------------------
/TemperatureReader/MainPage.xaml:
--------------------------------------------------------------------------------
1 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/TemperatureReader/MainPage.xaml.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Diagnostics;
3 | using System.Threading.Tasks;
4 | using Windows.UI;
5 | using Windows.UI.Core;
6 | using Windows.UI.Xaml.Controls;
7 | using Windows.UI.Xaml.Media;
8 | using TemperatureReader.Logic.Devices;
9 | using TemperatureReader.Logic.Models;
10 | using TemperatureReader.ServiceBus;
11 | using TemperatureReader.Shared;
12 |
13 | namespace TemperatureReader
14 | {
15 | ///
16 | /// An empty page that can be used on its own or navigated to within a Frame.
17 | ///
18 | public sealed partial class MainPage : Page
19 | {
20 | public MainPage()
21 | {
22 | this.InitializeComponent();
23 | this.Loaded += MainPage_Loaded;
24 | }
25 |
26 | private async void MainPage_Loaded(object sender, Windows.UI.Xaml.RoutedEventArgs e)
27 | {
28 | var gpioService = new GpioService();
29 | var fanSwitch = new SwitchDevice(gpioService, Settings.SwitchPinId);
30 | var controller = new AnalogTemperatureSensorController(gpioService);
31 | var thermometer = new Thermometer(gpioService, controller);
32 | var poster = new TemperatureQueueClient(QueueMode.Send);
33 | var fanCommandListener = new FanSwitchQueueClient(QueueMode.Listen);
34 | await fanCommandListener.Start();
35 |
36 | fanCommandListener.OnDataReceived += (cs, cmd) =>
37 | {
38 | Debug.WriteLine($"Fanswitchcommand received {cmd.Status}; current status fan on = {fanSwitch.IsOn} at {DateTime.Now}");
39 |
40 | var newStatus = cmd.Status == FanStatus.On;
41 | if (newStatus != fanSwitch.IsOn)
42 | {
43 | fanSwitch.Toggle();
44 | }
45 | };
46 |
47 | thermometer.OnTemperatureMeasured += OnTemperatureMeasured;
48 | thermometer.OnTemperatureMeasured += async (thObject, data) =>
49 | {
50 | data.FanStatus = fanSwitch.IsOn ? FanStatus.On : FanStatus.Off;
51 | await poster.PostData(data);
52 | };
53 |
54 | await poster.Start();
55 | await thermometer.Start();
56 | }
57 |
58 | private async void OnTemperatureMeasured(object sender, TemperatureData e)
59 | {
60 | Debug.WriteLine($"MainPage.OnTemperatureMeasured {e.Temperature}: {e.IsValid} at {DateTime.Now}");
61 | if (e.IsValid)
62 | {
63 | await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
64 | {
65 | var brush = TemperatureText.Foreground;
66 | TemperatureText.Text = $"{e.Temperature}°C";
67 | TemperatureText.Foreground = new SolidColorBrush(Colors.Red);
68 | await Task.Delay(250);
69 | TemperatureText.Foreground = brush;
70 | });
71 | }
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/TemperatureReader/Package.appxmanifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
9 |
13 |
14 |
15 |
16 |
17 | TemperatureReader
18 | joost
19 | Assets\StoreLogo.png
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
34 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/TemperatureReader/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | using System.Reflection;
2 | using System.Runtime.CompilerServices;
3 | using System.Runtime.InteropServices;
4 |
5 | // General Information about an assembly is controlled through the following
6 | // set of attributes. Change these attribute values to modify the information
7 | // associated with an assembly.
8 | [assembly: AssemblyTitle("TemperatureReader")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("TemperatureReader")]
13 | [assembly: AssemblyCopyright("Copyright © 2015")]
14 | [assembly: AssemblyTrademark("")]
15 | [assembly: AssemblyCulture("")]
16 |
17 | // Version information for an assembly consists of the following four values:
18 | //
19 | // Major Version
20 | // Minor Version
21 | // Build Number
22 | // Revision
23 | //
24 | // You can specify all the values or you can default the Build and Revision Numbers
25 | // by using the '*' as shown below:
26 | // [assembly: AssemblyVersion("1.0.*")]
27 | [assembly: AssemblyVersion("1.0.0.0")]
28 | [assembly: AssemblyFileVersion("1.0.0.0")]
29 | [assembly: ComVisible(false)]
--------------------------------------------------------------------------------
/TemperatureReader/Properties/Default.rd.xml:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
20 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/TemperatureReader/TemperatureReader.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | x86
7 | {736B87D7-1739-4F09-B7C5-D93762AE2AF4}
8 | AppContainerExe
9 | Properties
10 | TemperatureReader
11 | TemperatureReader
12 | en-US
13 | UAP
14 | 10.0.10586.0
15 | 10.0.10240.0
16 | 14
17 | true
18 | 512
19 | {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}
20 | TemperatureReader_TemporaryKey.pfx
21 | /subscriptions/85f40e16-f427-4432-8757-1224d37207c3/resourcegroups/Default-ApplicationInsights-CentralUS/providers/microsoft.insights/components/TemperatureReader
22 |
23 |
24 | true
25 | bin\ARM\Debug\
26 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
27 | ;2008
28 | full
29 | ARM
30 | false
31 | prompt
32 | true
33 |
34 |
35 | bin\ARM\Release\
36 | TRACE;NETFX_CORE;WINDOWS_UWP
37 | true
38 | ;2008
39 | pdbonly
40 | ARM
41 | false
42 | prompt
43 | true
44 | true
45 |
46 |
47 | true
48 | bin\x64\Debug\
49 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
50 | ;2008
51 | full
52 | x64
53 | false
54 | prompt
55 | true
56 |
57 |
58 | bin\x64\Release\
59 | TRACE;NETFX_CORE;WINDOWS_UWP
60 | true
61 | ;2008
62 | pdbonly
63 | x64
64 | false
65 | prompt
66 | true
67 | true
68 |
69 |
70 | true
71 | bin\x86\Debug\
72 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
73 | ;2008
74 | full
75 | x86
76 | false
77 | prompt
78 | true
79 |
80 |
81 | bin\x86\Release\
82 | TRACE;NETFX_CORE;WINDOWS_UWP
83 | true
84 | ;2008
85 | pdbonly
86 | x86
87 | false
88 | prompt
89 | true
90 | true
91 |
92 |
93 |
94 |
95 |
96 |
97 |
98 | App.xaml
99 |
100 |
101 | MainPage.xaml
102 |
103 |
104 |
105 |
106 |
107 | Designer
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 | MSBuild:Compile
124 | Designer
125 |
126 |
127 | MSBuild:Compile
128 | Designer
129 |
130 |
131 |
132 |
133 | {8c77f671-5ca3-49fd-b600-05cf848e14dc}
134 | TemperatureReader.Logic
135 |
136 |
137 | {d4967767-6f42-4305-9bab-6c2336a2e3fa}
138 | TemperatureReader.ServiceBus
139 |
140 |
141 | {ecd216bf-ba5e-4504-a052-ac037e2f8591}
142 | TemperatureReader.Shared
143 |
144 |
145 |
146 | 14.0
147 |
148 |
149 |
156 |
--------------------------------------------------------------------------------
/TemperatureReader/TemperatureReader_TemporaryKey.pfx:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/LocalJoost/TemperatureReaderDemo/181701369c4bad7bfdc1891d011fd27994c8f6f3/TemperatureReader/TemperatureReader_TemporaryKey.pfx
--------------------------------------------------------------------------------
/TemperatureReader/project.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "Microsoft.NETCore.UniversalWindowsPlatform": "5.0.0"
4 | },
5 | "frameworks": {
6 | "uap10.0": {}
7 | },
8 | "runtimes": {
9 | "win10-arm": {},
10 | "win10-arm-aot": {},
11 | "win10-x86": {},
12 | "win10-x86-aot": {},
13 | "win10-x64": {},
14 | "win10-x64-aot": {}
15 | }
16 | }
--------------------------------------------------------------------------------
/TemperatureReaderDemo.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.23107.0
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TemperatureReader.Shared", "TemperatureReader.Shared\TemperatureReader.Shared.csproj", "{ECD216BF-BA5E-4504-A052-AC037E2F8591}"
7 | EndProject
8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TemperatureReader.Logic", "TemperatureReader.Logic\TemperatureReader.Logic.csproj", "{8C77F671-5CA3-49FD-B600-05CF848E14DC}"
9 | EndProject
10 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TemperatureReader", "TemperatureReader\TemperatureReader.csproj", "{736B87D7-1739-4F09-B7C5-D93762AE2AF4}"
11 | EndProject
12 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TemperatureReader.ClientApp", "TemperatureReader.ClientApp\TemperatureReader.ClientApp.csproj", "{545E5193-A400-49AA-B7ED-84FD679ABBCB}"
13 | EndProject
14 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TemperatureReader.ServiceBus", "TemperatureReader.ServiceBus\TemperatureReader.ServiceBus.csproj", "{D4967767-6F42-4305-9BAB-6C2336A2E3FA}"
15 | EndProject
16 | Global
17 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
18 | Debug|Any CPU = Debug|Any CPU
19 | Debug|ARM = Debug|ARM
20 | Debug|x64 = Debug|x64
21 | Debug|x86 = Debug|x86
22 | Release|Any CPU = Release|Any CPU
23 | Release|ARM = Release|ARM
24 | Release|x64 = Release|x64
25 | Release|x86 = Release|x86
26 | EndGlobalSection
27 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
28 | {ECD216BF-BA5E-4504-A052-AC037E2F8591}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29 | {ECD216BF-BA5E-4504-A052-AC037E2F8591}.Debug|Any CPU.Build.0 = Debug|Any CPU
30 | {ECD216BF-BA5E-4504-A052-AC037E2F8591}.Debug|ARM.ActiveCfg = Debug|Any CPU
31 | {ECD216BF-BA5E-4504-A052-AC037E2F8591}.Debug|ARM.Build.0 = Debug|Any CPU
32 | {ECD216BF-BA5E-4504-A052-AC037E2F8591}.Debug|x64.ActiveCfg = Debug|Any CPU
33 | {ECD216BF-BA5E-4504-A052-AC037E2F8591}.Debug|x64.Build.0 = Debug|Any CPU
34 | {ECD216BF-BA5E-4504-A052-AC037E2F8591}.Debug|x86.ActiveCfg = Debug|Any CPU
35 | {ECD216BF-BA5E-4504-A052-AC037E2F8591}.Debug|x86.Build.0 = Debug|Any CPU
36 | {ECD216BF-BA5E-4504-A052-AC037E2F8591}.Release|Any CPU.ActiveCfg = Release|Any CPU
37 | {ECD216BF-BA5E-4504-A052-AC037E2F8591}.Release|Any CPU.Build.0 = Release|Any CPU
38 | {ECD216BF-BA5E-4504-A052-AC037E2F8591}.Release|ARM.ActiveCfg = Release|Any CPU
39 | {ECD216BF-BA5E-4504-A052-AC037E2F8591}.Release|ARM.Build.0 = Release|Any CPU
40 | {ECD216BF-BA5E-4504-A052-AC037E2F8591}.Release|x64.ActiveCfg = Release|Any CPU
41 | {ECD216BF-BA5E-4504-A052-AC037E2F8591}.Release|x64.Build.0 = Release|Any CPU
42 | {ECD216BF-BA5E-4504-A052-AC037E2F8591}.Release|x86.ActiveCfg = Release|Any CPU
43 | {ECD216BF-BA5E-4504-A052-AC037E2F8591}.Release|x86.Build.0 = Release|Any CPU
44 | {8C77F671-5CA3-49FD-B600-05CF848E14DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
45 | {8C77F671-5CA3-49FD-B600-05CF848E14DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
46 | {8C77F671-5CA3-49FD-B600-05CF848E14DC}.Debug|ARM.ActiveCfg = Debug|ARM
47 | {8C77F671-5CA3-49FD-B600-05CF848E14DC}.Debug|ARM.Build.0 = Debug|ARM
48 | {8C77F671-5CA3-49FD-B600-05CF848E14DC}.Debug|x64.ActiveCfg = Debug|x64
49 | {8C77F671-5CA3-49FD-B600-05CF848E14DC}.Debug|x64.Build.0 = Debug|x64
50 | {8C77F671-5CA3-49FD-B600-05CF848E14DC}.Debug|x86.ActiveCfg = Debug|x86
51 | {8C77F671-5CA3-49FD-B600-05CF848E14DC}.Debug|x86.Build.0 = Debug|x86
52 | {8C77F671-5CA3-49FD-B600-05CF848E14DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
53 | {8C77F671-5CA3-49FD-B600-05CF848E14DC}.Release|Any CPU.Build.0 = Release|Any CPU
54 | {8C77F671-5CA3-49FD-B600-05CF848E14DC}.Release|ARM.ActiveCfg = Release|ARM
55 | {8C77F671-5CA3-49FD-B600-05CF848E14DC}.Release|ARM.Build.0 = Release|ARM
56 | {8C77F671-5CA3-49FD-B600-05CF848E14DC}.Release|x64.ActiveCfg = Release|x64
57 | {8C77F671-5CA3-49FD-B600-05CF848E14DC}.Release|x64.Build.0 = Release|x64
58 | {8C77F671-5CA3-49FD-B600-05CF848E14DC}.Release|x86.ActiveCfg = Release|x86
59 | {8C77F671-5CA3-49FD-B600-05CF848E14DC}.Release|x86.Build.0 = Release|x86
60 | {736B87D7-1739-4F09-B7C5-D93762AE2AF4}.Debug|Any CPU.ActiveCfg = Debug|x86
61 | {736B87D7-1739-4F09-B7C5-D93762AE2AF4}.Debug|ARM.ActiveCfg = Debug|ARM
62 | {736B87D7-1739-4F09-B7C5-D93762AE2AF4}.Debug|ARM.Build.0 = Debug|ARM
63 | {736B87D7-1739-4F09-B7C5-D93762AE2AF4}.Debug|ARM.Deploy.0 = Debug|ARM
64 | {736B87D7-1739-4F09-B7C5-D93762AE2AF4}.Debug|x64.ActiveCfg = Debug|x64
65 | {736B87D7-1739-4F09-B7C5-D93762AE2AF4}.Debug|x64.Build.0 = Debug|x64
66 | {736B87D7-1739-4F09-B7C5-D93762AE2AF4}.Debug|x64.Deploy.0 = Debug|x64
67 | {736B87D7-1739-4F09-B7C5-D93762AE2AF4}.Debug|x86.ActiveCfg = Debug|x86
68 | {736B87D7-1739-4F09-B7C5-D93762AE2AF4}.Debug|x86.Build.0 = Debug|x86
69 | {736B87D7-1739-4F09-B7C5-D93762AE2AF4}.Debug|x86.Deploy.0 = Debug|x86
70 | {736B87D7-1739-4F09-B7C5-D93762AE2AF4}.Release|Any CPU.ActiveCfg = Release|x86
71 | {736B87D7-1739-4F09-B7C5-D93762AE2AF4}.Release|ARM.ActiveCfg = Release|ARM
72 | {736B87D7-1739-4F09-B7C5-D93762AE2AF4}.Release|ARM.Build.0 = Release|ARM
73 | {736B87D7-1739-4F09-B7C5-D93762AE2AF4}.Release|ARM.Deploy.0 = Release|ARM
74 | {736B87D7-1739-4F09-B7C5-D93762AE2AF4}.Release|x64.ActiveCfg = Release|x64
75 | {736B87D7-1739-4F09-B7C5-D93762AE2AF4}.Release|x64.Build.0 = Release|x64
76 | {736B87D7-1739-4F09-B7C5-D93762AE2AF4}.Release|x64.Deploy.0 = Release|x64
77 | {736B87D7-1739-4F09-B7C5-D93762AE2AF4}.Release|x86.ActiveCfg = Release|x86
78 | {736B87D7-1739-4F09-B7C5-D93762AE2AF4}.Release|x86.Build.0 = Release|x86
79 | {736B87D7-1739-4F09-B7C5-D93762AE2AF4}.Release|x86.Deploy.0 = Release|x86
80 | {545E5193-A400-49AA-B7ED-84FD679ABBCB}.Debug|Any CPU.ActiveCfg = Debug|x86
81 | {545E5193-A400-49AA-B7ED-84FD679ABBCB}.Debug|ARM.ActiveCfg = Debug|ARM
82 | {545E5193-A400-49AA-B7ED-84FD679ABBCB}.Debug|ARM.Build.0 = Debug|ARM
83 | {545E5193-A400-49AA-B7ED-84FD679ABBCB}.Debug|ARM.Deploy.0 = Debug|ARM
84 | {545E5193-A400-49AA-B7ED-84FD679ABBCB}.Debug|x64.ActiveCfg = Debug|x64
85 | {545E5193-A400-49AA-B7ED-84FD679ABBCB}.Debug|x64.Build.0 = Debug|x64
86 | {545E5193-A400-49AA-B7ED-84FD679ABBCB}.Debug|x64.Deploy.0 = Debug|x64
87 | {545E5193-A400-49AA-B7ED-84FD679ABBCB}.Debug|x86.ActiveCfg = Debug|x86
88 | {545E5193-A400-49AA-B7ED-84FD679ABBCB}.Debug|x86.Build.0 = Debug|x86
89 | {545E5193-A400-49AA-B7ED-84FD679ABBCB}.Debug|x86.Deploy.0 = Debug|x86
90 | {545E5193-A400-49AA-B7ED-84FD679ABBCB}.Release|Any CPU.ActiveCfg = Release|x86
91 | {545E5193-A400-49AA-B7ED-84FD679ABBCB}.Release|ARM.ActiveCfg = Release|ARM
92 | {545E5193-A400-49AA-B7ED-84FD679ABBCB}.Release|ARM.Build.0 = Release|ARM
93 | {545E5193-A400-49AA-B7ED-84FD679ABBCB}.Release|ARM.Deploy.0 = Release|ARM
94 | {545E5193-A400-49AA-B7ED-84FD679ABBCB}.Release|x64.ActiveCfg = Release|x64
95 | {545E5193-A400-49AA-B7ED-84FD679ABBCB}.Release|x64.Build.0 = Release|x64
96 | {545E5193-A400-49AA-B7ED-84FD679ABBCB}.Release|x64.Deploy.0 = Release|x64
97 | {545E5193-A400-49AA-B7ED-84FD679ABBCB}.Release|x86.ActiveCfg = Release|x86
98 | {545E5193-A400-49AA-B7ED-84FD679ABBCB}.Release|x86.Build.0 = Release|x86
99 | {545E5193-A400-49AA-B7ED-84FD679ABBCB}.Release|x86.Deploy.0 = Release|x86
100 | {D4967767-6F42-4305-9BAB-6C2336A2E3FA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
101 | {D4967767-6F42-4305-9BAB-6C2336A2E3FA}.Debug|Any CPU.Build.0 = Debug|Any CPU
102 | {D4967767-6F42-4305-9BAB-6C2336A2E3FA}.Debug|ARM.ActiveCfg = Debug|ARM
103 | {D4967767-6F42-4305-9BAB-6C2336A2E3FA}.Debug|ARM.Build.0 = Debug|ARM
104 | {D4967767-6F42-4305-9BAB-6C2336A2E3FA}.Debug|x64.ActiveCfg = Debug|x64
105 | {D4967767-6F42-4305-9BAB-6C2336A2E3FA}.Debug|x64.Build.0 = Debug|x64
106 | {D4967767-6F42-4305-9BAB-6C2336A2E3FA}.Debug|x86.ActiveCfg = Debug|x86
107 | {D4967767-6F42-4305-9BAB-6C2336A2E3FA}.Debug|x86.Build.0 = Debug|x86
108 | {D4967767-6F42-4305-9BAB-6C2336A2E3FA}.Release|Any CPU.ActiveCfg = Release|Any CPU
109 | {D4967767-6F42-4305-9BAB-6C2336A2E3FA}.Release|Any CPU.Build.0 = Release|Any CPU
110 | {D4967767-6F42-4305-9BAB-6C2336A2E3FA}.Release|ARM.ActiveCfg = Release|ARM
111 | {D4967767-6F42-4305-9BAB-6C2336A2E3FA}.Release|ARM.Build.0 = Release|ARM
112 | {D4967767-6F42-4305-9BAB-6C2336A2E3FA}.Release|x64.ActiveCfg = Release|x64
113 | {D4967767-6F42-4305-9BAB-6C2336A2E3FA}.Release|x64.Build.0 = Release|x64
114 | {D4967767-6F42-4305-9BAB-6C2336A2E3FA}.Release|x86.ActiveCfg = Release|x86
115 | {D4967767-6F42-4305-9BAB-6C2336A2E3FA}.Release|x86.Build.0 = Release|x86
116 | EndGlobalSection
117 | GlobalSection(SolutionProperties) = preSolution
118 | HideSolutionNode = FALSE
119 | EndGlobalSection
120 | EndGlobal
121 |
--------------------------------------------------------------------------------