├── Third Party Notices.txt
├── PlantSensor
├── Assets
│ ├── StoreLogo.png
│ ├── LockScreenLogo.scale-200.png
│ ├── SplashScreen.scale-200.png
│ ├── Square44x44Logo.scale-200.png
│ ├── Wide310x150Logo.scale-200.png
│ ├── Square150x150Logo.scale-200.png
│ └── Square44x44Logo.targetsize-24_altform-unplated.png
├── App.xaml
├── project.json
├── Utility
│ └── FileNames.cs
├── PlantSensor.nuget.targets
├── Properties
│ ├── AssemblyInfo.cs
│ └── Default.rd.xml
├── Package.appxmanifest
├── Sensors
│ ├── MCP3008.cs
│ └── BMP280.cs
├── View
│ ├── SettingsPage.xaml
│ ├── SettingsPage.xaml.cs
│ ├── TwitterPage.xaml.cs
│ ├── TwitterPage.xaml
│ ├── MainPage.xaml.cs
│ ├── MainPage.xaml
│ ├── HistoryPage.xaml
│ └── HistoryPage.xaml.cs
├── SensorDataProvider.cs
├── PlantSensor.csproj
└── App.xaml.cs
├── README.md
├── LICENSE.txt
├── PlantSensor.sln
└── .gitignore
/Third Party Notices.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ms-iot/PlantSensor/HEAD/Third Party Notices.txt
--------------------------------------------------------------------------------
/PlantSensor/Assets/StoreLogo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ms-iot/PlantSensor/HEAD/PlantSensor/Assets/StoreLogo.png
--------------------------------------------------------------------------------
/PlantSensor/Assets/LockScreenLogo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ms-iot/PlantSensor/HEAD/PlantSensor/Assets/LockScreenLogo.scale-200.png
--------------------------------------------------------------------------------
/PlantSensor/Assets/SplashScreen.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ms-iot/PlantSensor/HEAD/PlantSensor/Assets/SplashScreen.scale-200.png
--------------------------------------------------------------------------------
/PlantSensor/Assets/Square44x44Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ms-iot/PlantSensor/HEAD/PlantSensor/Assets/Square44x44Logo.scale-200.png
--------------------------------------------------------------------------------
/PlantSensor/Assets/Wide310x150Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ms-iot/PlantSensor/HEAD/PlantSensor/Assets/Wide310x150Logo.scale-200.png
--------------------------------------------------------------------------------
/PlantSensor/Assets/Square150x150Logo.scale-200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ms-iot/PlantSensor/HEAD/PlantSensor/Assets/Square150x150Logo.scale-200.png
--------------------------------------------------------------------------------
/PlantSensor/Assets/Square44x44Logo.targetsize-24_altform-unplated.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ms-iot/PlantSensor/HEAD/PlantSensor/Assets/Square44x44Logo.targetsize-24_altform-unplated.png
--------------------------------------------------------------------------------
/PlantSensor/App.xaml:
--------------------------------------------------------------------------------
1 |
2 |
8 |
9 |
--------------------------------------------------------------------------------
/PlantSensor/project.json:
--------------------------------------------------------------------------------
1 | {
2 | "dependencies": {
3 | "Microsoft.NETCore.UniversalWindowsPlatform": "5.0.0",
4 | "TweetinviAPI": "1.0.0",
5 | "WinRTXamlToolkit.Controls.DataVisualization": "2.0.0"
6 | },
7 | "frameworks": {
8 | "uap10.0": {}
9 | },
10 | "runtimes": {
11 | "win10-arm": {},
12 | "win10-arm-aot": {},
13 | "win10-x86": {},
14 | "win10-x86-aot": {},
15 | "win10-x64": {},
16 | "win10-x64-aot": {}
17 | }
18 | }
--------------------------------------------------------------------------------
/PlantSensor/Utility/FileNames.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft. All rights reserved.
2 | namespace PlantSensor
3 | {
4 | class FileNames
5 | {
6 | public const string BrightnessfileName = "BrightnessHistoryTextFile.txt";
7 | public const string TemperaturefileName = "TemperatureHistoryTextFile.txt";
8 | public const string SoilMoisturefileName = "SoilMoistureHistoryTextFile.txt";
9 | public const string SettingsfileName = "settings.txt";
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/PlantSensor/PlantSensor.nuget.targets:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | $(UserProfile)\.nuget\packages\
5 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Windows IoT Plant Sensor
2 | digiPlant is a Universal Windows Platform app that helps users monitor their plant. The app collects and displays tempoerature, brightness, and soil moisture data from various sensors. It runs on a Raspberry Pi and Windows 10 IoT Core. The Twitter page is currently a work in progress.
3 |
4 | ## Cloning the project
5 |
6 | - Use Command Prompt to navigate to the folder where you want the project:
7 | ```cd ```
8 | - Run the git clone command:
9 | ```git clone https://github.com/ms-iot/PlantSensor.git```
10 |
11 | The step-by-step instruction for building this project can be found on https://www.hackster.io/MasayukiN/plant-app-v-1-0-1167ed?ref=user&ref_id=100482&offset=0
12 |
13 |
14 | ===
15 |
16 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
--------------------------------------------------------------------------------
/PlantSensor/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("PlantSensor")]
9 | [assembly: AssemblyDescription("")]
10 | [assembly: AssemblyConfiguration("")]
11 | [assembly: AssemblyCompany("")]
12 | [assembly: AssemblyProduct("PlantSensor")]
13 | [assembly: AssemblyCopyright("Copyright © 2016")]
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)]
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) Microsoft Open Technologies, Inc. All rights reserved.
2 |
3 | The MIT License (MIT)
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
13 | all 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
21 | THE SOFTWARE.
22 |
23 |
--------------------------------------------------------------------------------
/PlantSensor/Properties/Default.rd.xml:
--------------------------------------------------------------------------------
1 |
17 |
18 |
19 |
20 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/PlantSensor/Package.appxmanifest:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | PlantSensor
7 | t-managa
8 | Assets\StoreLogo.png
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/PlantSensor.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 14
4 | VisualStudioVersion = 14.0.25420.1
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PlantSensor", "PlantSensor\PlantSensor.csproj", "{75E178AC-7A35-48A1-B019-8404A10D4D19}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|ARM = Debug|ARM
11 | Debug|x64 = Debug|x64
12 | Debug|x86 = Debug|x86
13 | Release|ARM = Release|ARM
14 | Release|x64 = Release|x64
15 | Release|x86 = Release|x86
16 | EndGlobalSection
17 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
18 | {75E178AC-7A35-48A1-B019-8404A10D4D19}.Debug|ARM.ActiveCfg = Debug|ARM
19 | {75E178AC-7A35-48A1-B019-8404A10D4D19}.Debug|ARM.Build.0 = Debug|ARM
20 | {75E178AC-7A35-48A1-B019-8404A10D4D19}.Debug|ARM.Deploy.0 = Debug|ARM
21 | {75E178AC-7A35-48A1-B019-8404A10D4D19}.Debug|x64.ActiveCfg = Debug|x64
22 | {75E178AC-7A35-48A1-B019-8404A10D4D19}.Debug|x64.Build.0 = Debug|x64
23 | {75E178AC-7A35-48A1-B019-8404A10D4D19}.Debug|x64.Deploy.0 = Debug|x64
24 | {75E178AC-7A35-48A1-B019-8404A10D4D19}.Debug|x86.ActiveCfg = Debug|x86
25 | {75E178AC-7A35-48A1-B019-8404A10D4D19}.Debug|x86.Build.0 = Debug|x86
26 | {75E178AC-7A35-48A1-B019-8404A10D4D19}.Debug|x86.Deploy.0 = Debug|x86
27 | {75E178AC-7A35-48A1-B019-8404A10D4D19}.Release|ARM.ActiveCfg = Release|ARM
28 | {75E178AC-7A35-48A1-B019-8404A10D4D19}.Release|ARM.Build.0 = Release|ARM
29 | {75E178AC-7A35-48A1-B019-8404A10D4D19}.Release|ARM.Deploy.0 = Release|ARM
30 | {75E178AC-7A35-48A1-B019-8404A10D4D19}.Release|x64.ActiveCfg = Release|x64
31 | {75E178AC-7A35-48A1-B019-8404A10D4D19}.Release|x64.Build.0 = Release|x64
32 | {75E178AC-7A35-48A1-B019-8404A10D4D19}.Release|x64.Deploy.0 = Release|x64
33 | {75E178AC-7A35-48A1-B019-8404A10D4D19}.Release|x86.ActiveCfg = Release|x86
34 | {75E178AC-7A35-48A1-B019-8404A10D4D19}.Release|x86.Build.0 = Release|x86
35 | {75E178AC-7A35-48A1-B019-8404A10D4D19}.Release|x86.Deploy.0 = Release|x86
36 | EndGlobalSection
37 | GlobalSection(SolutionProperties) = preSolution
38 | HideSolutionNode = FALSE
39 | EndGlobalSection
40 | EndGlobal
41 |
--------------------------------------------------------------------------------
/.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 | [Gg]enerated Files/
19 | x64/
20 | x86/
21 | build/
22 | bld/
23 | [Bb]in/
24 | [Oo]bj/
25 |
26 | # Visual Studo 2015 cache/options directory
27 | .vs/
28 |
29 | # MSTest test Results
30 | [Tt]est[Rr]esult*/
31 | [Bb]uild[Ll]og.*
32 |
33 | # NUNIT
34 | *.VisualState.xml
35 | TestResult.xml
36 |
37 | # Build Results of an ATL Project
38 | [Dd]ebugPS/
39 | [Rr]eleasePS/
40 | dlldata.c
41 |
42 | *_i.c
43 | *_p.c
44 | *_i.h
45 | *.ilk
46 | *.meta
47 | *.obj
48 | *.pch
49 | *.pdb
50 | *.pgc
51 | *.pgd
52 | *.rsp
53 | *.sbr
54 | *.tlb
55 | *.tli
56 | *.tlh
57 | *.tmp
58 | *.tmp_proj
59 | *.log
60 | *.vspscc
61 | *.vssscc
62 | .builds
63 | *.pidb
64 | *.svclog
65 | *.scc
66 |
67 | # Chutzpah Test files
68 | _Chutzpah*
69 |
70 | # Visual C++ cache files
71 | ipch/
72 | *.aps
73 | *.ncb
74 | *.opensdf
75 | *.sdf
76 | *.cachefile
77 | *.VC.db
78 | *.VC.VC.opendb
79 |
80 | # Visual Studio profiler
81 | *.psess
82 | *.vsp
83 | *.vspx
84 |
85 | # TFS 2012 Local Workspace
86 | $tf/
87 |
88 | # Guidance Automation Toolkit
89 | *.gpState
90 |
91 | # ReSharper is a .NET coding add-in
92 | _ReSharper*/
93 | *.[Rr]e[Ss]harper
94 | *.DotSettings.user
95 |
96 | # JustCode is a .NET coding addin-in
97 | .JustCode
98 |
99 | # TeamCity is a build add-in
100 | _TeamCity*
101 |
102 | # DotCover is a Code Coverage Tool
103 | *.dotCover
104 |
105 | # NCrunch
106 | _NCrunch_*
107 | .*crunch*.local.xml
108 |
109 | # MightyMoose
110 | *.mm.*
111 | AutoTest.Net/
112 |
113 | # Web workbench (sass)
114 | .sass-cache/
115 |
116 | # Installshield output folder
117 | [Ee]xpress/
118 |
119 | # DocProject is a documentation generator add-in
120 | DocProject/buildhelp/
121 | DocProject/Help/*.HxT
122 | DocProject/Help/*.HxC
123 | DocProject/Help/*.hhc
124 | DocProject/Help/*.hhk
125 | DocProject/Help/*.hhp
126 | DocProject/Help/Html2
127 | DocProject/Help/html
128 |
129 | # Click-Once directory
130 | publish/
131 |
132 | # Publish Web Output
133 | *.[Pp]ublish.xml
134 | *.azurePubxml
135 | # TODO: Comment the next line if you want to checkin your web deploy settings
136 | # but database connection strings (with potential passwords) will be unencrypted
137 | *.pubxml
138 | *.publishproj
139 |
140 | # NuGet Packages
141 | *.nupkg
142 | # The packages folder can be ignored because of Package Restore
143 | **/packages/*
144 | # except build/, which is used as an MSBuild target.
145 | !**/packages/build/
146 | # Uncomment if necessary however generally it will be regenerated when needed
147 | #!**/packages/repositories.config
148 |
149 | # Windows Azure Build Output
150 | csx/
151 | *.build.csdef
152 |
153 | # Windows Store app package directory
154 | AppPackages/
155 |
156 | # Others
157 | *.[Cc]ache
158 | ClientBin/
159 | [Ss]tyle[Cc]op.*
160 | ~$*
161 | *~
162 | *.dbmdl
163 | *.dbproj.schemaview
164 | *.pfx
165 | *.publishsettings
166 | node_modules/
167 | bower_components/
168 |
169 | # RIA/Silverlight projects
170 | Generated_Code/
171 |
172 | # Backup & report files from converting an old project file
173 | # to a newer Visual Studio version. Backup files are not needed,
174 | # because we have git ;-)
175 | _UpgradeReport_Files/
176 | Backup*/
177 | UpgradeLog*.XML
178 | UpgradeLog*.htm
179 |
180 | # SQL Server files
181 | *.mdf
182 | *.ldf
183 |
184 | # Business Intelligence projects
185 | *.rdl.data
186 | *.bim.layout
187 | *.bim_*.settings
188 |
189 | # Microsoft Fakes
190 | FakesAssemblies/
191 |
192 | # Node.js Tools for Visual Studio
193 | .ntvs_analysis.dat
194 |
195 | # Visual Studio 6 build log
196 | *.plg
197 |
198 | # Visual Studio 6 workspace options file
199 | *.opt
200 |
201 | # Custom ignores
202 | gallery.xml
203 | project.lock.json
204 |
--------------------------------------------------------------------------------
/PlantSensor/Sensors/MCP3008.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft. All rights reserved.
2 | using Windows.Devices.Enumeration;
3 | using Windows.Devices.Spi;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using System.Diagnostics;
10 |
11 | namespace PlantSensor
12 | {
13 | public class MCP3008
14 | {
15 | // Constants for the SPI controller chip interface
16 | public SpiDevice mcp3008;
17 | const int SPI_CHIP_SELECT_LINE = 0; // SPI0 CS0 pin 24
18 |
19 | // ADC chip operation constants
20 | const byte MCP3008_SingleEnded = 0x08;
21 | const byte MCP3008_Differential = 0x00;
22 |
23 | // These are used when we calculate the voltage from the ADC units
24 | float ReferenceVoltage;
25 | public const uint Min = 0;
26 | public const uint Max = 1023;
27 |
28 |
29 | public MCP3008(float referenceVolgate)
30 | {
31 | Debug.WriteLine("MCP3008::New MCP3008");
32 |
33 | // Store the reference voltage value for later use in the voltage calculation.
34 | ReferenceVoltage = referenceVolgate;
35 | }
36 |
37 | ///
38 | /// This method is used to configure the Pi2 to communicate over the SPI bus to the MCP3008 ADC chip.
39 | ///
40 | public async Task Initialize()
41 | {
42 | Debug.WriteLine("MCP3008::Initialize");
43 | try
44 | {
45 | // Setup the SPI bus configuration
46 | var settings = new SpiConnectionSettings(SPI_CHIP_SELECT_LINE);
47 | // 3.6MHz is the rated speed of the MCP3008 at 5v
48 | settings.ClockFrequency = 3600000;
49 | settings.Mode = SpiMode.Mode0;
50 |
51 | // Ask Windows for the list of SpiDevices
52 |
53 | // Get a selector string that will return all SPI controllers on the system
54 | string aqs = SpiDevice.GetDeviceSelector();
55 |
56 | // Find the SPI bus controller devices with our selector string
57 | var dis = await DeviceInformation.FindAllAsync(aqs);
58 |
59 | // Create an SpiDevice with our bus controller and SPI settings
60 | mcp3008 = await SpiDevice.FromIdAsync(dis[0].Id, settings);
61 |
62 | if (mcp3008 == null)
63 | {
64 | Debug.WriteLine(
65 | "SPI Controller {0} is currently in use by another application. Please ensure that no other applications are using SPI.",
66 | dis[0].Id);
67 | return;
68 | }
69 |
70 | }
71 | catch (Exception e)
72 | {
73 | Debug.WriteLine("Exception: " + e.Message + "\n" + e.StackTrace);
74 | throw;
75 | }
76 | }
77 |
78 | ///
79 | /// This method does the actual work of communicating over the SPI bus with the chip.
80 | /// To line everything up for ease of reading back (on byte boundary) we
81 | /// will pad the command start bit with 7 leading "0" bits
82 | ///
83 | /// Write 0000 000S GDDD xxxx xxxx xxxx
84 | /// Read ???? ???? ???? ?N98 7654 3210
85 | /// S = start bit
86 | /// G = Single / Differential
87 | /// D = Chanel data
88 | /// ? = undefined, ignore
89 | /// N = 0 "Null bit"
90 | /// 9-0 = 10 data bits
91 | ///
92 | public int ReadADC(byte whichChannel)
93 | {
94 | byte command = whichChannel;
95 | command |= MCP3008_SingleEnded;
96 | command <<= 4;
97 |
98 | byte[] commandBuf = new byte[] { 0x01, command, 0x00 };
99 |
100 | byte[] readBuf = new byte[] { 0x00, 0x00, 0x00 };
101 |
102 | mcp3008.TransferFullDuplex(commandBuf, readBuf);
103 |
104 | int sample = readBuf[2] + ((readBuf[1] & 0x03) << 8);
105 | int s2 = sample & 0x3FF;
106 | Debug.Assert(sample == s2);
107 |
108 | return sample;
109 | }
110 |
111 | ///
112 | /// Returns the ADC value (uint) as a float voltage based on the configured reference voltage
113 | ///
114 | /// the ADC value to convert
115 | /// The computed voltage based on the reference voltage
116 | public float ADCToVoltage(int adc)
117 | {
118 | return (float)adc * ReferenceVoltage / (float)Max;
119 | }
120 | }
121 |
122 | }
123 |
--------------------------------------------------------------------------------
/PlantSensor/View/SettingsPage.xaml:
--------------------------------------------------------------------------------
1 |
2 |
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 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/PlantSensor/View/SettingsPage.xaml.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft. All rights reserved.
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Diagnostics;
5 | using System.IO;
6 | using System.Linq;
7 | using System.Runtime.InteropServices.WindowsRuntime;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 | using System.Xml.Serialization;
11 | using Windows.ApplicationModel;
12 | using Windows.ApplicationModel.Activation;
13 | using Windows.Foundation;
14 | using Windows.Foundation.Collections;
15 | using Windows.Storage;
16 | using Windows.UI.Xaml;
17 | using Windows.UI.Xaml.Controls;
18 | using Windows.UI.Xaml.Controls.Primitives;
19 | using Windows.UI.Xaml.Data;
20 | using Windows.UI.Xaml.Input;
21 | using Windows.UI.Xaml.Media;
22 | using Windows.UI.Xaml.Navigation;
23 |
24 | namespace PlantSensor
25 | {
26 | ///
27 | /// This settings page allows the user to change the settings relavent to the app and the user experience
28 | ///
29 | public sealed partial class SettingsPage : Page
30 | {
31 | public SettingsPage()
32 | {
33 | this.InitializeComponent();
34 | Status.Text = "Save Status: all changes unsaved";
35 | NameOfPlantTextBox.Text = App.PlantSettings.NameOfPlant;
36 | PlantTwitterAccountTextBox.Text = App.PlantSettings.PlantTwitterAccount;
37 | IdealTempTextBox.Text = App.PlantSettings.IdealTemp.ToString();
38 | IdealBrightTextBox.Text = App.PlantSettings.IdealBright.ToString();
39 | IdealSoilTextBox.Text = App.PlantSettings.IdealSoilMoist.ToString();
40 | }
41 |
42 | private void SettingsSave_Click(object sender, Windows.UI.Xaml.RoutedEventArgs e)
43 | {
44 | App.PlantSettings.NameOfPlant = NameOfPlantTextBox.Text;
45 | App.PlantSettings.PlantTwitterAccount = PlantTwitterAccountTextBox.Text;
46 | //check if actual numbers not strings
47 | //cant enter text in those textboxes
48 | int idealTempFromString;
49 | int idealBrightFromString;
50 | int idealSoilMoistFromString;
51 | if (Int32.TryParse(IdealTempTextBox.Text, out idealTempFromString)
52 | && Int32.TryParse(IdealBrightTextBox.Text, out idealBrightFromString)
53 | && Int32.TryParse(IdealSoilTextBox.Text, out idealSoilMoistFromString))
54 | {
55 | App.PlantSettings.IdealTemp = idealTempFromString;
56 | App.PlantSettings.IdealBright = idealBrightFromString;
57 | App.PlantSettings.IdealSoilMoist = idealSoilMoistFromString;
58 | Status.Text = "Save Status: you have succesfully saved!";
59 | }
60 | else
61 | {
62 | Status.Text = "Save Status: ideal values must be integers";
63 | }
64 | App.PlantSettings.Save();
65 | }
66 |
67 | private void SettingsCalendarAppBar_Click(object sender, RoutedEventArgs e)
68 | {
69 | Frame.Navigate(typeof(HistoryPage));
70 | }
71 |
72 | private void SettingsHomeAppBar_Click(object sender, RoutedEventArgs e)
73 | {
74 | Frame.Navigate(typeof(MainPage));
75 | }
76 |
77 | private void SettingsTweetAppBar_Click(object sender, RoutedEventArgs e)
78 | {
79 | Frame.Navigate(typeof(TwitterPage));
80 | }
81 |
82 | private void SettingsSettingsAppBar_Click(object sender, RoutedEventArgs e)
83 | {
84 |
85 | }
86 | }
87 |
88 | public class Settings
89 | {
90 | public string NameOfPlant = "";
91 | public string PlantTwitterAccount = "";
92 | public int IdealTemp= 0;
93 | public int IdealBright=0;
94 | public int IdealSoilMoist=0;
95 | public string ConsumerKeySetting = "";
96 | public string ConsumerSecretSetting = "";
97 | public string AccessKeySetting = "";
98 | public string AccessTokenSetting = "";
99 |
100 | public async void Save()
101 | {
102 | XmlSerializer serializer = new XmlSerializer(typeof(Settings));
103 | StorageFolder folder = ApplicationData.Current.LocalFolder;
104 | StorageFile file = await folder.CreateFileAsync(FileNames.SettingsfileName, CreationCollisionOption.ReplaceExisting);
105 | Stream stream = await file.OpenStreamForWriteAsync();
106 |
107 | using (stream)
108 | {
109 | serializer.Serialize(stream, this);
110 | }
111 | }
112 |
113 | public async static Task Load(string filename)
114 | {
115 | Settings objectFromXml = new Settings();
116 | var serializer = new XmlSerializer(typeof(Settings));
117 | StorageFolder folder = ApplicationData.Current.LocalFolder;
118 | StorageFile file = await folder.GetFileAsync(filename);
119 | Stream stream = await file.OpenStreamForReadAsync();
120 | objectFromXml = (Settings)serializer.Deserialize(stream);
121 | stream.Dispose();
122 | return objectFromXml;
123 | }
124 | }
125 | }
126 |
--------------------------------------------------------------------------------
/PlantSensor/SensorDataProvider.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft. All rights reserved.
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Diagnostics;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 | using Windows.UI.Core;
10 |
11 | namespace PlantSensor
12 | {
13 | public delegate void DataReceivedEventHandler(object sender, SensorDataEventArgs e);
14 | public class SensorDataProvider
15 | {
16 | const byte SoilMoistureChannel = 3;
17 | const float ReferenceVoltage = 5.0F;
18 | public event DataReceivedEventHandler DataReceived;
19 | public MCP3008 mcp3008;
20 |
21 | //Barometric Sensor
22 | public BMP280 BMP280;
23 |
24 | // Values for which channels we will be using from the ADC chip
25 | const byte LowPotentiometerADCChannel = 0;
26 | const byte HighPotentiometerADCChannel = 1;
27 | const byte CDSADCChannel = 2;
28 |
29 | private Timer timer;
30 | private Timer writeToFile;
31 | Random rand = new Random();
32 |
33 | public SensorDataProvider()
34 | {
35 | mcp3008 = new MCP3008(ReferenceVoltage);
36 | BMP280 = new BMP280();
37 | }
38 |
39 | public void StartTimer()
40 | {
41 | timer = new Timer(timerCallback, this, 0, 3000);
42 | writeToFile = new Timer(writeToFileTimerCallback, this, 20000, 9000);
43 | }
44 | private async void writeToFileTimerCallback(object state)
45 | {
46 | for (int ii = 0; ii < App.BrightnessList.Count; ii++)
47 | {
48 | App.Brightnessresult.Add(App.BrightnessList[ii]);
49 | await Windows.Storage.FileIO.AppendTextAsync(App.BrightnessFile, App.BrightnessList[ii]);
50 | Debug.WriteLine("Brightness File" + App.BrightnessList[ii]);
51 | }
52 |
53 | for (int ii = 0; ii < App.TemperatureList.Count; ii++)
54 | {
55 | App.Temperatureresult.Add(App.TemperatureList[ii]);
56 | await Windows.Storage.FileIO.AppendTextAsync(App.TemperatureFile, App.TemperatureList[ii]);
57 | }
58 |
59 | for (int ii = 0; ii < App.SoilMoistureList.Count; ii++)
60 | {
61 | App.SoilMoistureresult.Add(App.SoilMoistureList[ii]);
62 | await Windows.Storage.FileIO.AppendTextAsync(App.SoilMoistureFile, App.SoilMoistureList[ii]);
63 | }
64 | App.BrightnessList.Clear();
65 | App.TemperatureList.Clear();
66 | App.SoilMoistureList.Clear();
67 | }
68 |
69 | /**
70 | * This method records on a timer the data measured by the temperature, brightness, and soil moisture sensor,
71 | * then organizes all of the information collected.
72 | * */
73 | private async void timerCallback(object state)
74 | {
75 | //ensures that the temperature sensor is initialized before it is measured from
76 | if (BMP280 == null)
77 | {
78 | Debug.WriteLine("BMP280 is null");
79 | }
80 | else
81 | {
82 | //receives the value from the temperature sensor and saves
83 | //the data in the SensorDataEventArgs class, which holds
84 | //the sensor name, the data point, and the time the value was measured.
85 | //this data is then sent back to the main page and the UI is adjusted based
86 | //off of the measurement.
87 | //float currentTemperature = (float) rand.NextDouble() * 10;
88 | float currentTemperature = await BMP280.ReadTemperature();
89 | var tempArgs = new SensorDataEventArgs()
90 | {
91 | SensorName = "Temperature",
92 | SensorValue = currentTemperature,
93 | Timestamp = DateTime.Now
94 | };
95 | OnDataReceived(tempArgs);
96 | }
97 |
98 | //MCP3008 is an ADC and checks to see if this is initialized.
99 | //the soil moisture sensor and the photocell are on different channels of the ADC
100 | if (mcp3008 == null)
101 | {
102 | Debug.WriteLine("mcp3008 is null");
103 | }
104 | else
105 | {
106 | //The first line reads a value from the ADC from the photo cell sensor usually between 0 and 1023.
107 | //then the second line maps this number to a voltage that represents this number
108 | int cdsReadVal = mcp3008.ReadADC(CDSADCChannel);
109 | float cdsVoltage = mcp3008.ADCToVoltage(cdsReadVal);
110 |
111 | //float currentBrightness = (float)rand.NextDouble() * 10;
112 | float currentBrightness = cdsVoltage;
113 | var brightnessArgs = new SensorDataEventArgs()
114 | {
115 | SensorName = "Brightness",
116 | SensorValue = currentBrightness,
117 | Timestamp = DateTime.Now
118 | };
119 | OnDataReceived(brightnessArgs);
120 |
121 | //float currentSoilMoisture = (float)rand.NextDouble() * 10;
122 | float currentSoilMoisture = mcp3008.ReadADC(SoilMoistureChannel);
123 | Debug.WriteLine(currentSoilMoisture);
124 | var soilmoistureArgs = new SensorDataEventArgs()
125 | {
126 | SensorName = "SoilMoisture",
127 | SensorValue = currentSoilMoisture,
128 | Timestamp = DateTime.Now
129 | };
130 | OnDataReceived(soilmoistureArgs);
131 | }
132 | }
133 |
134 | protected virtual void OnDataReceived(SensorDataEventArgs e)
135 | {
136 | if (DataReceived != null)
137 | {
138 | DataReceived(this, e);
139 | }
140 | }
141 | }
142 | public class SensorDataEventArgs : EventArgs
143 | {
144 | public string SensorName;
145 | public float SensorValue;
146 | public DateTime Timestamp;
147 | }
148 | }
149 |
--------------------------------------------------------------------------------
/PlantSensor/View/TwitterPage.xaml.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft. All rights reserved.
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Collections.ObjectModel;
5 | using System.Diagnostics;
6 | using System.IO;
7 | using System.Linq;
8 | using System.Runtime.InteropServices.WindowsRuntime;
9 | using System.Threading;
10 | using Tweetinvi;
11 | using Windows.Foundation;
12 | using Windows.Foundation.Collections;
13 | using Windows.UI.Core;
14 | using Windows.UI.Xaml;
15 | using Windows.UI.Xaml.Controls;
16 | using Windows.UI.Xaml.Controls.Primitives;
17 | using Windows.UI.Xaml.Data;
18 | using Windows.UI.Xaml.Input;
19 | using Windows.UI.Xaml.Media;
20 | using Windows.UI.Xaml.Navigation;
21 |
22 | namespace PlantSensor
23 | {
24 | //Class that stores with instance variables of the tweets and when they were tweeted
25 | public class twitterListClass
26 | {
27 | public string Tweet { get; set;}
28 | public string TweetDate { get; set; }
29 | }
30 | ///
31 | /// This page allows you to tweet and see past history tweets
32 | ///
33 | public sealed partial class TwitterPage : Page
34 | {
35 | Boolean hasAccount;
36 | Timer twitterTimerLive;
37 | ObservableCollection listOfTweets;
38 |
39 | //Inside the constructor, the settings are set. Based off of these settings,
40 | //the code attempts to login the user. If the settings credentials does not correlate to
41 | //a real twitter account, then it tells the user accordingly.
42 | public TwitterPage()
43 | {
44 | this.InitializeComponent();
45 | ConsumerKeyTextBlock.Text = App.TwitterSettings.ConsumerKeySetting;
46 | ConsumerSecretTextBlock.Text = App.TwitterSettings.ConsumerSecretSetting;
47 | AccessSecretTextBlock.Text = App.TwitterSettings.AccessKeySetting;
48 | AccessTokenTextBlock.Text = App.TwitterSettings.AccessTokenSetting;
49 | TwitterStatusText.Text = "If you have made changes: unsaved";
50 |
51 | try
52 | {
53 | setUpUser();
54 | }
55 |
56 | catch
57 | {
58 | TwitterStatusText.Text = "These credentials do not match any twitter account";
59 | hasAccount = false;
60 | }
61 | }
62 |
63 | /*
64 | * Authenticates the users
65 | * gets the users tweets
66 | * add them to the obersvable collection linked to the UI
67 | * */
68 | private void setUpUser()
69 | {
70 | Auth.SetUserCredentials(App.TwitterSettings.ConsumerKeySetting, App.TwitterSettings.ConsumerSecretSetting, App.TwitterSettings.AccessTokenSetting, App.TwitterSettings.AccessKeySetting);
71 | var user = User.GetAuthenticatedUser();
72 | var tweets = Timeline.GetUserTimeline(user);
73 | listOfTweets = new ObservableCollection();
74 | foreach (Tweetinvi.Models.ITweet twitterInUI in tweets)
75 | {
76 | String twitterDateStringInUI = twitterInUI.CreatedAt.ToString();
77 | String twitterStringInUI = twitterInUI.FullText.ToString();
78 | listOfTweets.Add(new twitterListClass { Tweet = twitterStringInUI, TweetDate = twitterDateStringInUI });
79 | }
80 | HistoryTweetList.ItemsSource = listOfTweets;
81 | hasAccount = true;
82 | }
83 |
84 | protected override void OnNavigatedTo(NavigationEventArgs navArgs)
85 | {
86 | Debug.WriteLine("Twitter Page reached");
87 | }
88 |
89 | /*
90 | * Tweets these on a timer
91 | * */
92 | private async void twitterTimerLiveMethod(object state)
93 | {
94 | String TweetInTimer = determineTweet();
95 | //tweets the determined tweet
96 | var firstTweet = Tweet.PublishTweet(TweetInTimer);
97 | await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
98 | {
99 | //instead of adding string to list, add object from class
100 | listOfTweets.Add(new twitterListClass { Tweet = TweetInTimer, TweetDate = DateTime.Now.ToString() });
101 | });
102 | }
103 |
104 | private string determineTweet()
105 | {
106 | return "Brightness: "+ MainPage.currentBrightness + Environment.NewLine + "Temperature: " + MainPage.currentTemperature + Environment.NewLine + "Soil Moisture: " + MainPage.currentSoilMoisture;
107 | }
108 |
109 | private void TwitterCalendarAppBar_Click(object sender, RoutedEventArgs e)
110 | {
111 | Frame.Navigate(typeof(HistoryPage));
112 | }
113 |
114 | private void TwitterSettingsAppBar_Click(object sender, RoutedEventArgs e)
115 | {
116 | Frame.Navigate(typeof(SettingsPage));
117 | }
118 |
119 | private void TwitterHomeAppBar_Click(object sender, RoutedEventArgs e)
120 | {
121 | Frame.Navigate(typeof(MainPage));
122 | }
123 |
124 | private void TwitterTwitterAppBar_Click(object sender, RoutedEventArgs e)
125 | {
126 |
127 | }
128 |
129 | /**
130 | * Checks if the enable tweets is toggled
131 | * */
132 | private void toggleSwitchTwitter_Toggled(object sender, RoutedEventArgs e)
133 | {
134 | ToggleSwitch toggleSwitch = sender as ToggleSwitch;
135 | if (toggleSwitch != null)
136 | {
137 | if(toggleSwitch.IsOn == true)
138 | {
139 | if (hasAccount)
140 | {
141 | twitterTimerLive = new Timer(twitterTimerLiveMethod, this, 0, 3000);
142 | }
143 | }
144 | else
145 | {
146 | twitterTimerLive.Change(Timeout.Infinite, Timeout.Infinite);
147 | }
148 | }
149 | }
150 |
151 | /**
152 | * Saves all of the settings and checks to see if the new settings
153 | * correlate to a real account
154 | * */
155 | private void TwitterSaveButton_Click(object sender, RoutedEventArgs e)
156 | {
157 | App.TwitterSettings.ConsumerKeySetting = ConsumerKeyTextBlock.Text;
158 | App.TwitterSettings.ConsumerSecretSetting = ConsumerSecretTextBlock.Text;
159 | App.TwitterSettings.AccessKeySetting = AccessSecretTextBlock.Text;
160 | App.TwitterSettings.AccessTokenSetting = AccessTokenTextBlock.Text;
161 | App.TwitterSettings.Save();
162 | try
163 | {
164 | setUpUser();
165 | TwitterStatusText.Text = "Account Successfully made";
166 | }
167 | catch
168 | {
169 | TwitterStatusText.Text = "These credentials do not match any twitter account";
170 | }
171 | }
172 | }
173 | }
174 |
--------------------------------------------------------------------------------
/PlantSensor/PlantSensor.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | x86
7 | {75E178AC-7A35-48A1-B019-8404A10D4D19}
8 | AppContainerExe
9 | Properties
10 | PlantSensor
11 | PlantSensor
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 | PlantApp_TemporaryKey.pfx
20 |
21 |
22 | true
23 | bin\x86\Debug\
24 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
25 | ;2008
26 | full
27 | x86
28 | false
29 | prompt
30 | true
31 |
32 |
33 | bin\x86\Release\
34 | TRACE;NETFX_CORE;WINDOWS_UWP
35 | true
36 | ;2008
37 | pdbonly
38 | x86
39 | false
40 | prompt
41 | true
42 | true
43 |
44 |
45 | true
46 | bin\ARM\Debug\
47 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
48 | ;2008
49 | full
50 | ARM
51 | false
52 | prompt
53 | true
54 |
55 |
56 | bin\ARM\Release\
57 | TRACE;NETFX_CORE;WINDOWS_UWP
58 | true
59 | ;2008
60 | pdbonly
61 | ARM
62 | false
63 | prompt
64 | true
65 | true
66 |
67 |
68 | true
69 | bin\x64\Debug\
70 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP
71 | ;2008
72 | full
73 | x64
74 | false
75 | prompt
76 | true
77 |
78 |
79 | bin\x64\Release\
80 | TRACE;NETFX_CORE;WINDOWS_UWP
81 | true
82 | ;2008
83 | pdbonly
84 | x64
85 | false
86 | prompt
87 | true
88 | true
89 |
90 |
91 |
92 |
93 |
94 |
95 |
96 | App.xaml
97 |
98 |
99 |
100 |
101 |
102 |
103 | HistoryPage.xaml
104 |
105 |
106 | MainPage.xaml
107 |
108 |
109 |
110 | SettingsPage.xaml
111 |
112 |
113 | TwitterPage.xaml
114 |
115 |
116 |
117 |
118 | Designer
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 | MSBuild:Compile
135 | Designer
136 |
137 |
138 | Designer
139 | MSBuild:Compile
140 |
141 |
142 | MSBuild:Compile
143 | Designer
144 |
145 |
146 | Designer
147 | MSBuild:Compile
148 |
149 |
150 | Designer
151 | MSBuild:Compile
152 |
153 |
154 |
155 |
156 | Windows IoT Extensions for the UWP
157 |
158 |
159 |
160 | 14.0
161 |
162 |
163 |
170 |
--------------------------------------------------------------------------------
/PlantSensor/View/TwitterPage.xaml:
--------------------------------------------------------------------------------
1 |
2 |
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 |
56 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
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 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
--------------------------------------------------------------------------------
/PlantSensor/App.xaml.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft. All rights reserved.
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Diagnostics;
5 | using System.IO;
6 | using System.Linq;
7 | using System.Runtime.InteropServices.WindowsRuntime;
8 | using System.Threading;
9 | using System.Threading.Tasks;
10 | using Windows.ApplicationModel;
11 | using Windows.ApplicationModel.Activation;
12 | using Windows.Foundation;
13 | using Windows.Foundation.Collections;
14 | using Windows.UI.Xaml;
15 | using Windows.UI.Xaml.Controls;
16 | using Windows.UI.Xaml.Controls.Primitives;
17 | using Windows.UI.Xaml.Data;
18 | using Windows.UI.Xaml.Input;
19 | using Windows.UI.Xaml.Media;
20 | using Windows.UI.Xaml.Navigation;
21 |
22 | namespace PlantSensor
23 | {
24 | ///
25 | /// Provides application-specific behavior to supplement the default Application class.
26 | ///
27 | sealed partial class App : Application
28 | {
29 | //this helps find the data from the sensors
30 | public static SensorDataProvider SensorProvider;
31 |
32 | //these are the files that the app reads from for the sensors
33 | public static Windows.Storage.StorageFile BrightnessFile;
34 | public static Windows.Storage.StorageFile TemperatureFile;
35 | public static Windows.Storage.StorageFile SoilMoistureFile;
36 | public static Windows.Storage.StorageFile TwitterFile;
37 |
38 | //this is the folder in which the files are stored
39 | static Windows.Storage.StorageFolder storageFolder;
40 |
41 | //when the files are read, then they are stored in these lists
42 | public static IList Brightnessresult;
43 | public static IList Temperatureresult;
44 | public static IList SoilMoistureresult;
45 | public static IList Twitterresult;
46 |
47 | //these lists are where new data is temporarily stored so that we are not
48 | //readong and writing to files that often
49 | public static List BrightnessList;
50 | public static List TemperatureList;
51 | public static List SoilMoistureList;
52 |
53 | //this variable holds the settings for the plant
54 | public static Settings PlantSettings;
55 | public static Settings TwitterSettings;
56 |
57 | ///
58 | /// Initializes the singleton application object. This is the first line of authored code
59 | /// executed, and as such is the logical equivalent of main() or WinMain().
60 | ///
61 | public App()
62 | {
63 | PlantSettings = new Settings();
64 | TwitterSettings = new Settings();
65 | this.InitializeComponent();
66 | this.Suspending += OnSuspending;
67 | SensorProvider = new SensorDataProvider();
68 | }
69 |
70 | public async Task setUpFile()
71 | {
72 | storageFolder = Windows.Storage.ApplicationData.Current.LocalFolder;
73 | try
74 | {
75 | BrightnessFile = await storageFolder.GetFileAsync(FileNames.BrightnessfileName);
76 | }
77 | catch (FileNotFoundException e)
78 | {
79 | BrightnessFile = await storageFolder.CreateFileAsync(FileNames.BrightnessfileName);
80 | }
81 |
82 | try
83 | {
84 | TemperatureFile = await storageFolder.GetFileAsync(FileNames.TemperaturefileName);
85 | }
86 | catch (FileNotFoundException e)
87 | {
88 | TemperatureFile = await storageFolder.CreateFileAsync(FileNames.TemperaturefileName);
89 | }
90 |
91 | try
92 | {
93 | SoilMoistureFile = await storageFolder.GetFileAsync(FileNames.SoilMoisturefileName);
94 | Debug.WriteLine("Old Files are used");
95 | }
96 | catch (FileNotFoundException e)
97 | {
98 | SoilMoistureFile = await storageFolder.CreateFileAsync(FileNames.SoilMoisturefileName);
99 | Debug.WriteLine("New Files were created");
100 | }
101 |
102 | try
103 | {
104 | TwitterFile = await storageFolder.GetFileAsync(FileNames.SettingsfileName);
105 | Debug.WriteLine("Old settings Files are used");
106 | }
107 | catch (FileNotFoundException e)
108 | {
109 | TwitterFile = await storageFolder.CreateFileAsync(FileNames.SettingsfileName);
110 | Debug.WriteLine("new settingsFiles are used");
111 | }
112 |
113 | Brightnessresult = await Windows.Storage.FileIO.ReadLinesAsync(BrightnessFile);
114 | Temperatureresult = await Windows.Storage.FileIO.ReadLinesAsync(TemperatureFile);
115 | SoilMoistureresult = await Windows.Storage.FileIO.ReadLinesAsync(SoilMoistureFile);
116 | Twitterresult = await Windows.Storage.FileIO.ReadLinesAsync(TwitterFile);
117 |
118 | BrightnessList = new List();
119 | TemperatureList = new List();
120 | SoilMoistureList = new List();
121 |
122 | }
123 | ///
124 | /// Invoked when the application is launched normally by the end user. Other entry points
125 | /// will be used such as when the application is launched to open a specific file.
126 | ///
127 | /// Details about the launch request and process.
128 | protected async override void OnLaunched(LaunchActivatedEventArgs e)
129 | {
130 | await setUpFile();
131 | await App.SensorProvider.mcp3008.Initialize();
132 | await App.SensorProvider.BMP280.Initialize();
133 | try
134 | {
135 | PlantSettings = await Settings.Load(FileNames.SettingsfileName);
136 | }
137 | catch
138 | {
139 |
140 | }
141 | try
142 | {
143 | TwitterSettings = await Settings.Load(FileNames.SettingsfileName);
144 | }
145 | catch
146 | {
147 |
148 | }
149 | #if DEBUG
150 | if (System.Diagnostics.Debugger.IsAttached)
151 | {
152 | //this.DebugSettings.EnableFrameRateCounter = true;
153 | }
154 | #endif
155 | Frame rootFrame = Window.Current.Content as Frame;
156 |
157 | // Do not repeat app initialization when the Window already has content,
158 | // just ensure that the window is active
159 | if (rootFrame == null)
160 | {
161 | // Create a Frame to act as the navigation context and navigate to the first page
162 | rootFrame = new Frame();
163 |
164 | rootFrame.NavigationFailed += OnNavigationFailed;
165 |
166 | if (e.PreviousExecutionState == ApplicationExecutionState.Terminated)
167 | {
168 | //TODO: Load state from previously suspended application
169 | }
170 |
171 | // Place the frame in the current Window
172 | Window.Current.Content = rootFrame;
173 | }
174 |
175 | if (e.PrelaunchActivated == false)
176 | {
177 | if (rootFrame.Content == null)
178 | {
179 | // When the navigation stack isn't restored navigate to the first page,
180 | // configuring the new page by passing required information as a navigation
181 | // parameter
182 | rootFrame.Navigate(typeof(MainPage), e.Arguments);
183 | }
184 | // Ensure the current window is active
185 | Window.Current.Activate();
186 | }
187 | }
188 |
189 | ///
190 | /// Invoked when Navigation to a certain page fails
191 | ///
192 | /// The Frame which failed navigation
193 | /// Details about the navigation failure
194 | void OnNavigationFailed(object sender, NavigationFailedEventArgs e)
195 | {
196 | throw new Exception("Failed to load Page " + e.SourcePageType.FullName);
197 | }
198 |
199 | ///
200 | /// Invoked when application execution is being suspended. Application state is saved
201 | /// without knowing whether the application will be terminated or resumed with the contents
202 | /// of memory still intact.
203 | ///
204 | /// The source of the suspend request.
205 | /// Details about the suspend request.
206 | private void OnSuspending(object sender, SuspendingEventArgs e)
207 | {
208 | var deferral = e.SuspendingOperation.GetDeferral();
209 | //TODO: Save application state and stop any background activity
210 | deferral.Complete();
211 | }
212 | }
213 | }
214 |
--------------------------------------------------------------------------------
/PlantSensor/View/MainPage.xaml.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft. All rights reserved.
2 | using System;
3 | using System.Threading;
4 | using Windows.UI;
5 | using Windows.UI.Core;
6 | using Windows.UI.Xaml;
7 | using Windows.UI.Xaml.Controls;
8 | using Windows.UI.Xaml.Media;
9 | using Windows.UI.Xaml.Navigation;
10 |
11 | namespace PlantSensor
12 | {
13 | public sealed partial class MainPage : Page
14 | {
15 | //This controls the timer on the panel
16 | public Timer controlPanelTimer;
17 |
18 | //This is the timer for the altitude and pressure
19 | public Timer altPressTimer;
20 | //This will be able to be set by the user in the next sprint
21 | int idealTemperature;
22 | int idealSoilMoisture;
23 | int idealBrightness;
24 |
25 | //These colors dictate what the tabs that determine time span look like
26 | Color colorBlue;
27 | Color colorlightBlue;
28 | Color colorWhite;
29 | Color colorlightRed;
30 | Color colorRed;
31 | SolidColorBrush SolidColorBrushBlue;
32 | SolidColorBrush SolidColorBrushLightBlue;
33 | SolidColorBrush SolidColorBrushWhite;
34 | SolidColorBrush SolidColorBrushLightRed;
35 | SolidColorBrush SolidColorBrushRed;
36 |
37 | public static float currentBrightness;
38 | public static float currentTemperature;
39 | public static float currentSoilMoisture;
40 |
41 | /**
42 | * sets all of the variables that were described above
43 | **/
44 | public MainPage()
45 | {
46 | this.InitializeComponent();
47 | controlPanelTimer = new Timer(timerControlPanel, this, 0, 1000);
48 |
49 | idealTemperature = App.PlantSettings.IdealTemp;
50 | idealSoilMoisture = App.PlantSettings.IdealSoilMoist;
51 | idealBrightness = App.PlantSettings.IdealBright;
52 |
53 | colorBlue = Color.FromArgb(255, 85, 98, 112);
54 | colorlightBlue = Color.FromArgb(255, 78, 205, 196);
55 | colorWhite = Color.FromArgb(255, 199, 244, 100);
56 | colorlightRed = Color.FromArgb(255, 236, 107, 107);
57 | colorRed = Color.FromArgb(255, 196, 77, 88);
58 | SolidColorBrushBlue = new SolidColorBrush(colorBlue);
59 | SolidColorBrushLightBlue = new SolidColorBrush(colorlightBlue);
60 | SolidColorBrushWhite = new SolidColorBrush(colorWhite);
61 | SolidColorBrushLightRed = new SolidColorBrush(colorlightRed);
62 | SolidColorBrushRed = new SolidColorBrush(colorRed);
63 |
64 | DateTime Now = DateTime.Now;
65 | Random rand = new Random();
66 | TimeSpan oneDay = new TimeSpan(1, 0, 0, 0);
67 | TimeSpan oneHour = new TimeSpan(1, 0, 0);
68 | DateTime LowerBound = Now - oneDay;
69 | while (LowerBound < Now)
70 | {
71 | float randomValue = (float)rand.NextDouble() * 10;
72 | String nextValue = randomValue + "," + LowerBound + Environment.NewLine;
73 | App.TemperatureList.Add(nextValue);
74 |
75 | randomValue = (float)rand.NextDouble() * 10;
76 | nextValue = randomValue + "," + LowerBound + Environment.NewLine;
77 | App.BrightnessList.Add(nextValue);
78 |
79 | randomValue = (float)rand.NextDouble() * 10;
80 | nextValue = randomValue + "," + LowerBound + Environment.NewLine;
81 | App.SoilMoistureList.Add(nextValue);
82 |
83 | LowerBound += oneHour;
84 | }
85 | }
86 |
87 | /**
88 | * updates the UI when the sensors make a new reading
89 | * */
90 | private async void SensorProvider_DataReceived(object sender, SensorDataEventArgs e)
91 | {
92 | String format = formatOfSensorValue(e.SensorValue);
93 | String nextValue = e.SensorValue + "," + DateTime.Now + Environment.NewLine;
94 | SolidColorBrush ellipseFill;
95 | switch (e.SensorName)
96 | {
97 | case "Brightness":
98 | await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
99 | {
100 | currentBrightness = e.SensorValue;
101 | float suggestionBrightness = idealBrightness - e.SensorValue;
102 | CurrentBrightnessNumber.Text = e.SensorValue.ToString(format);
103 | OurSuggestionNumberBrightness.Text = suggestionBrightness.ToString(format);
104 | ellipseFill = FigureOutFill(suggestionBrightness);
105 | BrightnessOutsideEllipse.Fill = ellipseFill;
106 |
107 | BrightnessUnitsMain.Foreground = ellipseFill;
108 | IdealBrightnessText.Foreground = ellipseFill;
109 | IdealBrightnessNumber.Foreground = ellipseFill;
110 | CurrentBrightnessNumber.Foreground = ellipseFill;
111 | CurrentBrightnessText.Foreground = ellipseFill;
112 | OurSuggestionTextBrightness.Foreground = ellipseFill;
113 | OurSuggestionNumberBrightness.Foreground = ellipseFill;
114 |
115 | App.BrightnessList.Add(nextValue);
116 | });
117 | break;
118 | case "Temperature":
119 | await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
120 | {
121 | currentTemperature = e.SensorValue;
122 | float suggestionTemperature = idealTemperature - e.SensorValue;
123 | CurrentTemperatureNumber.Text = e.SensorValue.ToString(format);
124 | OurSuggestionNumberTemperature.Text = suggestionTemperature.ToString(format);
125 | ellipseFill = FigureOutFill(suggestionTemperature);
126 | TemperatureOutsideEllipse.Fill = ellipseFill;
127 |
128 | TemperatureUnitsMain.Foreground = ellipseFill;
129 | IdealTemperatureText.Foreground = ellipseFill;
130 | IdealTemperatureNumber.Foreground = ellipseFill;
131 | CurrentTemperatureNumber.Foreground = ellipseFill;
132 | CurrentTemperatureText.Foreground = ellipseFill;
133 | OurSuggestionTextTemperature.Foreground = ellipseFill;
134 | OurSuggestionNumberTemperature.Foreground = ellipseFill;
135 |
136 | App.TemperatureList.Add(nextValue);
137 | });
138 | break;
139 | case "SoilMoisture":
140 | await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
141 | {
142 | currentSoilMoisture = e.SensorValue;
143 | float suggestionSoilMoisture = idealSoilMoisture - e.SensorValue;
144 | CurrentSoilMoistureNumber.Text = e.SensorValue.ToString(format);
145 | OurSuggestionNumberSoilMoisture.Text = suggestionSoilMoisture.ToString(format);
146 | ellipseFill = FigureOutFill(suggestionSoilMoisture);
147 | SoilMoistureOutsideEllipse.Fill = ellipseFill;
148 |
149 | SoilMoistureUnitsMain.Foreground = ellipseFill;
150 | IdealSoilMoistureText.Foreground = ellipseFill;
151 | IdealSoilMoistureNumber.Foreground = ellipseFill;
152 | CurrentSoilMoistureNumber.Foreground = ellipseFill;
153 | CurrentSoilMoistureText.Foreground = ellipseFill;
154 | OurSuggestionTextSoilMoisture.Foreground = ellipseFill;
155 | OurSuggestionNumberSoilMoisture.Foreground = ellipseFill;
156 |
157 | App.SoilMoistureList.Add(nextValue);
158 | });
159 | break;
160 | }
161 | }
162 |
163 | /**
164 | * this method returns what format the value should be displayed wiht
165 | * */
166 | private String formatOfSensorValue(float value)
167 | {
168 | if(value == Math.Floor(value))
169 | {
170 | return "000";
171 | }
172 | return "####0.0";
173 | }
174 |
175 | /**
176 | * This code runs when the Main page gets reached
177 | * */
178 |
179 | protected override void OnNavigatedTo(NavigationEventArgs navArgs)
180 | {
181 | App.SensorProvider.StartTimer();
182 |
183 | IdealTemperatureNumber.Text = idealTemperature.ToString();
184 | IdealBrightnessNumber.Text = idealBrightness.ToString();
185 | IdealSoilMoistureNumber.Text = idealSoilMoisture.ToString();
186 |
187 | App.SensorProvider.DataReceived += SensorProvider_DataReceived;
188 |
189 |
190 | }
191 |
192 | /**
193 | * updates the time on the control panel
194 | * */
195 | private async void timerControlPanel(object state)
196 | {
197 | await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
198 | {
199 | string formatTime = "HH:mm";
200 | string formatDate = "MM/dd/yy";
201 | ControlPanelTime.Text = DateTime.Now.ToString(formatTime);
202 | ControlPanelDate.Text = DateTime.Now.ToString(formatDate);
203 | });
204 | }
205 |
206 | /**
207 | * Evaluates what color the Ellipse should be
208 | * */
209 | public SolidColorBrush FigureOutFill(float suggestion)
210 | {
211 | if (suggestion > 9)
212 | {
213 | return SolidColorBrushBlue;
214 | }
215 | else if (suggestion > 3)
216 | {
217 | return SolidColorBrushLightBlue;
218 | }
219 | else if (suggestion > -3)
220 | {
221 | return SolidColorBrushWhite;
222 | }
223 | else if (suggestion > -9)
224 | {
225 | return SolidColorBrushLightRed;
226 | }
227 | else
228 | {
229 | return SolidColorBrushRed;
230 | }
231 | }
232 |
233 | /**
234 | * If the user presses the history button, they will go to the appropriate page
235 | * */
236 | private void HistoryButton_Click(object sender, RoutedEventArgs e)
237 | {
238 | Frame.Navigate(typeof(HistoryPage));
239 | }
240 |
241 | private void SettingsButton_Click(object sender, RoutedEventArgs e)
242 | {
243 | Frame.Navigate(typeof(SettingsPage));
244 | }
245 |
246 | private void Twitter_Click(object sender, RoutedEventArgs e)
247 | {
248 | Frame.Navigate(typeof(TwitterPage));
249 | }
250 |
251 | private void AppBarButton_Click(object sender, RoutedEventArgs e)
252 | {
253 |
254 | }
255 | }
256 | }
257 |
--------------------------------------------------------------------------------
/PlantSensor/Sensors/BMP280.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft. All rights reserved.
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Diagnostics;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using Windows.Devices.I2c;
9 | using Windows.Devices.Enumeration;
10 |
11 | namespace PlantSensor
12 | {
13 | public class BMP280_CalibrationData
14 | {
15 | //BMP280 Registers
16 | public UInt16 dig_T1 { get; set; }
17 | public Int16 dig_T2 { get; set; }
18 | public Int16 dig_T3 { get; set; }
19 |
20 | public UInt16 dig_P1 { get; set; }
21 | public Int16 dig_P2 { get; set; }
22 | public Int16 dig_P3 { get; set; }
23 | public Int16 dig_P4 { get; set; }
24 | public Int16 dig_P5 { get; set; }
25 | public Int16 dig_P6 { get; set; }
26 | public Int16 dig_P7 { get; set; }
27 | public Int16 dig_P8 { get; set; }
28 | public Int16 dig_P9 { get; set; }
29 | }
30 | public class BMP280
31 | {
32 | //The BMP280 register addresses according the the datasheet: http://www.adafruit.com/datasheets/BST-BMP280-DS001-11.pdf
33 | const byte BMP280_Address = 0x77;
34 | const byte BMP280_Signature = 0x58;
35 |
36 | enum eRegisters : byte
37 | {
38 | BMP280_REGISTER_DIG_T1 = 0x88,
39 | BMP280_REGISTER_DIG_T2 = 0x8A,
40 | BMP280_REGISTER_DIG_T3 = 0x8C,
41 |
42 | BMP280_REGISTER_DIG_P1 = 0x8E,
43 | BMP280_REGISTER_DIG_P2 = 0x90,
44 | BMP280_REGISTER_DIG_P3 = 0x92,
45 | BMP280_REGISTER_DIG_P4 = 0x94,
46 | BMP280_REGISTER_DIG_P5 = 0x96,
47 | BMP280_REGISTER_DIG_P6 = 0x98,
48 | BMP280_REGISTER_DIG_P7 = 0x9A,
49 | BMP280_REGISTER_DIG_P8 = 0x9C,
50 | BMP280_REGISTER_DIG_P9 = 0x9E,
51 |
52 | BMP280_REGISTER_CHIPID = 0xD0,
53 | BMP280_REGISTER_VERSION = 0xD1,
54 | BMP280_REGISTER_SOFTRESET = 0xE0,
55 |
56 | BMP280_REGISTER_CAL26 = 0xE1, // R calibration stored in 0xE1-0xF0
57 |
58 | BMP280_REGISTER_CONTROLHUMID = 0xF2,
59 | BMP280_REGISTER_CONTROL = 0xF4,
60 | BMP280_REGISTER_CONFIG = 0xF5,
61 |
62 | BMP280_REGISTER_PRESSUREDATA_MSB = 0xF7,
63 | BMP280_REGISTER_PRESSUREDATA_LSB = 0xF8,
64 | BMP280_REGISTER_PRESSUREDATA_XLSB = 0xF9, // bits <7:4>
65 |
66 | BMP280_REGISTER_TEMPDATA_MSB = 0xFA,
67 | BMP280_REGISTER_TEMPDATA_LSB = 0xFB,
68 | BMP280_REGISTER_TEMPDATA_XLSB = 0xFC, // bits <7:4>
69 |
70 | BMP280_REGISTER_HUMIDDATA_MSB = 0xFD,
71 | BMP280_REGISTER_HUMIDDATA_LSB = 0xFE,
72 | };
73 |
74 | //String for the friendly name of the I2C bus
75 | const string I2CControllerName = "I2C1";
76 | //Create an I2C device
77 | private I2cDevice bmp280 = null;
78 | //Create new calibration data for the sensor
79 | BMP280_CalibrationData CalibrationData;
80 | //Variable to check if device is initialized
81 | bool init = false;
82 |
83 | //Method to initialize the BMP280 sensor
84 | public async Task Initialize()
85 | {
86 | Debug.WriteLine("BMP280::Initialize");
87 |
88 | try
89 | {
90 | //Instantiate the I2CConnectionSettings using the device address of the BMP280
91 | I2cConnectionSettings settings = new I2cConnectionSettings(BMP280_Address);
92 | //Set the I2C bus speed of connection to fast mode
93 | settings.BusSpeed = I2cBusSpeed.FastMode;
94 | //Use the I2CBus device selector to create an advanced query syntax string
95 | string aqs = I2cDevice.GetDeviceSelector(I2CControllerName);
96 | //Use the Windows.Devices.Enumeration.DeviceInformation class to create a collection using the advanced query syntax string
97 | DeviceInformationCollection dis = await DeviceInformation.FindAllAsync(aqs);
98 | //Instantiate the the BMP280 I2C device using the device id of the I2CBus and the I2CConnectionSettings
99 | bmp280 = await I2cDevice.FromIdAsync(dis[0].Id, settings);
100 | //Check if device was found
101 | if (bmp280 == null)
102 | {
103 | Debug.WriteLine("Device not found");
104 | }
105 | }
106 | catch (Exception e)
107 | {
108 | Debug.WriteLine("Exception: " + e.Message + "\n" + e.StackTrace);
109 | throw;
110 | }
111 | }
112 |
113 | private async Task Begin()
114 | {
115 | Debug.WriteLine("BMP280::Begin");
116 | byte[] WriteBuffer = new byte[] { (byte)eRegisters.BMP280_REGISTER_CHIPID };
117 | byte[] ReadBuffer = new byte[] { 0xFF };
118 |
119 | //Read the device signature
120 | bmp280.WriteRead(WriteBuffer, ReadBuffer);
121 | Debug.WriteLine("BMP280 Signature: " + ReadBuffer[0].ToString());
122 |
123 | //Verify the device signature
124 | if (ReadBuffer[0] != BMP280_Signature)
125 | {
126 | Debug.WriteLine("BMP280::Begin Signature Mismatch.");
127 | return;
128 | }
129 |
130 | //Set the initalize variable to true
131 | init = true;
132 |
133 | //Read the coefficients table
134 | CalibrationData = await ReadCoefficeints();
135 |
136 | //Write control register
137 | await WriteControlRegister();
138 |
139 | //Write humidity control register
140 | await WriteControlRegisterHumidity();
141 | }
142 | //Method to write 0x03 to the humidity control register
143 | private async Task WriteControlRegisterHumidity()
144 | {
145 | byte[] WriteBuffer = new byte[] { (byte)eRegisters.BMP280_REGISTER_CONTROLHUMID, 0x03 };
146 | bmp280.Write(WriteBuffer);
147 | await Task.Delay(1);
148 | return;
149 | }
150 |
151 | //Method to write 0x3F to the control register
152 | private async Task WriteControlRegister()
153 | {
154 | byte[] WriteBuffer = new byte[] { (byte)eRegisters.BMP280_REGISTER_CONTROL, 0x3F };
155 | bmp280.Write(WriteBuffer);
156 | await Task.Delay(1);
157 | return;
158 | }
159 |
160 | //Method to read a 16-bit value from a register and return it in little endian format
161 | private UInt16 ReadUInt16_LittleEndian(byte register)
162 | {
163 | UInt16 value = 0;
164 | byte[] writeBuffer = new byte[] { 0x00 };
165 | byte[] readBuffer = new byte[] { 0x00, 0x00 };
166 |
167 | writeBuffer[0] = register;
168 |
169 | bmp280.WriteRead(writeBuffer, readBuffer);
170 | int h = readBuffer[1] << 8;
171 | int l = readBuffer[0];
172 | value = (UInt16)(h + l);
173 | return value;
174 | }
175 |
176 | //Method to read an 8-bit value from a register
177 | private byte ReadByte(byte register)
178 | {
179 | byte value = 0;
180 | byte[] writeBuffer = new byte[] { 0x00 };
181 | byte[] readBuffer = new byte[] { 0x00 };
182 |
183 | writeBuffer[0] = register;
184 |
185 | bmp280.WriteRead(writeBuffer, readBuffer);
186 | value = readBuffer[0];
187 | return value;
188 | }
189 |
190 | //Method to read the caliberation data from the registers
191 | private async Task ReadCoefficeints()
192 | {
193 | // 16 bit calibration data is stored as Little Endian, the helper method will do the byte swap.
194 | CalibrationData = new BMP280_CalibrationData();
195 |
196 | // Read temperature calibration data
197 | CalibrationData.dig_T1 = ReadUInt16_LittleEndian((byte)eRegisters.BMP280_REGISTER_DIG_T1);
198 | CalibrationData.dig_T2 = (Int16)ReadUInt16_LittleEndian((byte)eRegisters.BMP280_REGISTER_DIG_T2);
199 | CalibrationData.dig_T3 = (Int16)ReadUInt16_LittleEndian((byte)eRegisters.BMP280_REGISTER_DIG_T3);
200 |
201 | // Read presure calibration data
202 | CalibrationData.dig_P1 = ReadUInt16_LittleEndian((byte)eRegisters.BMP280_REGISTER_DIG_P1);
203 | CalibrationData.dig_P2 = (Int16)ReadUInt16_LittleEndian((byte)eRegisters.BMP280_REGISTER_DIG_P2);
204 | CalibrationData.dig_P3 = (Int16)ReadUInt16_LittleEndian((byte)eRegisters.BMP280_REGISTER_DIG_P3);
205 | CalibrationData.dig_P4 = (Int16)ReadUInt16_LittleEndian((byte)eRegisters.BMP280_REGISTER_DIG_P4);
206 | CalibrationData.dig_P5 = (Int16)ReadUInt16_LittleEndian((byte)eRegisters.BMP280_REGISTER_DIG_P5);
207 | CalibrationData.dig_P6 = (Int16)ReadUInt16_LittleEndian((byte)eRegisters.BMP280_REGISTER_DIG_P6);
208 | CalibrationData.dig_P7 = (Int16)ReadUInt16_LittleEndian((byte)eRegisters.BMP280_REGISTER_DIG_P7);
209 | CalibrationData.dig_P8 = (Int16)ReadUInt16_LittleEndian((byte)eRegisters.BMP280_REGISTER_DIG_P8);
210 | CalibrationData.dig_P9 = (Int16)ReadUInt16_LittleEndian((byte)eRegisters.BMP280_REGISTER_DIG_P9);
211 |
212 | await Task.Delay(1);
213 | return CalibrationData;
214 | }
215 |
216 |
217 | //t_fine carries fine temperature as global value
218 | Int32 t_fine = Int32.MinValue;
219 | //Method to return the temperature in DegC. Resolution is 0.01 DegC. Output value of “5123” equals 51.23 DegC.
220 | private double BMP280_compensate_T_double(Int32 adc_T)
221 | {
222 | double var1, var2, T;
223 |
224 | //The temperature is calculated using the compensation formula in the BMP280 datasheet
225 | var1 = ((adc_T / 16384.0) - (CalibrationData.dig_T1 / 1024.0)) * CalibrationData.dig_T2;
226 | var2 = ((adc_T / 131072.0) - (CalibrationData.dig_T1 / 8192.0)) * CalibrationData.dig_T3;
227 |
228 | t_fine = (Int32)(var1 + var2);
229 |
230 | T = (var1 + var2) / 5120.0;
231 | return T;
232 | }
233 |
234 |
235 | //Method to returns the pressure in Pa, in Q24.8 format (24 integer bits and 8 fractional bits).
236 | //Output value of “24674867” represents 24674867/256 = 96386.2 Pa = 963.862 hPa
237 | private Int64 BMP280_compensate_P_Int64(Int32 adc_P)
238 | {
239 | Int64 var1, var2, p;
240 |
241 | //The pressure is calculated using the compensation formula in the BMP280 datasheet
242 | var1 = t_fine - 128000;
243 | var2 = var1 * var1 * (Int64)CalibrationData.dig_P6;
244 | var2 = var2 + ((var1 * (Int64)CalibrationData.dig_P5) << 17);
245 | var2 = var2 + ((Int64)CalibrationData.dig_P4 << 35);
246 | var1 = ((var1 * var1 * (Int64)CalibrationData.dig_P3) >> 8) + ((var1 * (Int64)CalibrationData.dig_P2) << 12);
247 | var1 = (((((Int64)1 << 47) + var1)) * (Int64)CalibrationData.dig_P1) >> 33;
248 | if (var1 == 0)
249 | {
250 | Debug.WriteLine("BMP280_compensate_P_Int64 Jump out to avoid / 0");
251 | return 0; //Avoid exception caused by division by zero
252 | }
253 | //Perform calibration operations as per datasheet: http://www.adafruit.com/datasheets/BST-BMP280-DS001-11.pdf
254 | p = 1048576 - adc_P;
255 | p = (((p << 31) - var2) * 3125) / var1;
256 | var1 = ((Int64)CalibrationData.dig_P9 * (p >> 13) * (p >> 13)) >> 25;
257 | var2 = ((Int64)CalibrationData.dig_P8 * p) >> 19;
258 | p = ((p + var1 + var2) >> 8) + ((Int64)CalibrationData.dig_P7 << 4);
259 | return p;
260 | }
261 |
262 |
263 | public async Task ReadTemperature()
264 | {
265 | //Make sure the I2C device is initialized
266 | if (!init) await Begin();
267 |
268 | //Read the MSB, LSB and bits 7:4 (XLSB) of the temperature from the BMP280 registers
269 | byte tmsb = ReadByte((byte)eRegisters.BMP280_REGISTER_TEMPDATA_MSB);
270 | byte tlsb = ReadByte((byte)eRegisters.BMP280_REGISTER_TEMPDATA_LSB);
271 | byte txlsb = ReadByte((byte)eRegisters.BMP280_REGISTER_TEMPDATA_XLSB); // bits 7:4
272 |
273 | //Combine the values into a 32-bit integer
274 | Int32 t = (tmsb << 12) + (tlsb << 4) + (txlsb >> 4);
275 |
276 | //Convert the raw value to the temperature in degC
277 | double temp = BMP280_compensate_T_double(t);
278 |
279 | //Return the temperature as a float value
280 | return (float)temp;
281 | }
282 |
283 | public async Task ReadPreasure()
284 | {
285 | //Make sure the I2C device is initialized
286 | if (!init) await Begin();
287 |
288 | //Read the temperature first to load the t_fine value for compensation
289 | if (t_fine == Int32.MinValue)
290 | {
291 | await ReadTemperature();
292 | }
293 |
294 | //Read the MSB, LSB and bits 7:4 (XLSB) of the pressure from the BMP280 registers
295 | byte tmsb = ReadByte((byte)eRegisters.BMP280_REGISTER_PRESSUREDATA_MSB);
296 | byte tlsb = ReadByte((byte)eRegisters.BMP280_REGISTER_PRESSUREDATA_LSB);
297 | byte txlsb = ReadByte((byte)eRegisters.BMP280_REGISTER_PRESSUREDATA_XLSB); // bits 7:4
298 |
299 | //Combine the values into a 32-bit integer
300 | Int32 t = (tmsb << 12) + (tlsb << 4) + (txlsb >> 4);
301 |
302 | //Convert the raw value to the pressure in Pa
303 | Int64 pres = BMP280_compensate_P_Int64(t);
304 |
305 | //Return the temperature as a float value
306 | return ((float)pres) / 256;
307 | }
308 |
309 | //Method to take the sea level pressure in Hectopascals(hPa) as a parameter and calculate the altitude using current pressure.
310 | public async Task ReadAltitude(float seaLevel)
311 | {
312 | //Make sure the I2C device is initialized
313 | if (!init) await Begin();
314 |
315 | //Read the pressure first
316 | float pressure = await ReadPreasure();
317 | //Convert the pressure to Hectopascals(hPa)
318 | pressure /= 100;
319 |
320 | //Calculate and return the altitude using the international barometric formula
321 | return 44330.0f * (1.0f - (float)Math.Pow((pressure / seaLevel), 0.1903f));
322 | }
323 | }
324 | }
325 |
--------------------------------------------------------------------------------
/PlantSensor/View/MainPage.xaml:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
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 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
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 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
190 |
191 |
192 |
193 |
194 |
195 |
196 |
197 |
--------------------------------------------------------------------------------
/PlantSensor/View/HistoryPage.xaml:
--------------------------------------------------------------------------------
1 |
2 |
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 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
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 |
99 |
100 |
101 |
102 |
103 |
104 |
105 |
106 |
107 |
108 |
109 |
110 |
111 |
112 |
113 |
114 |
115 |
116 |
117 |
118 |
119 |
120 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
145 |
146 |
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 |
158 |
159 |
160 |
161 |
162 |
163 |
164 |
165 |
166 |
167 |
168 |
169 |
170 |
171 |
172 |
173 |
174 |
175 |
176 |
177 |
178 |
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 |
187 |
188 |
189 |
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 |
208 |
209 |
210 |
211 |
212 |
213 |
214 |
215 |
216 |
217 |
218 |
219 |
220 |
221 |
222 |
223 |
224 |
225 |
226 |
227 |
228 |
229 |
230 |
231 |
232 |
233 |
234 |
235 |
236 |
237 |
238 |
239 |
240 |
241 |
242 |
243 |
244 |
245 |
246 |
--------------------------------------------------------------------------------
/PlantSensor/View/HistoryPage.xaml.cs:
--------------------------------------------------------------------------------
1 | // Copyright (c) Microsoft. All rights reserved.
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Collections.ObjectModel;
5 | using System.Diagnostics;
6 | using System.Linq;
7 | using System.Threading.Tasks;
8 | using Windows.System.Threading;
9 | using Windows.UI;
10 | using Windows.UI.Core;
11 | using Windows.UI.Xaml;
12 | using Windows.UI.Xaml.Controls;
13 | using Windows.UI.Xaml.Media;
14 | using Windows.UI.Xaml.Navigation;
15 | using WinRTXamlToolkit.Controls.DataVisualization.Charting;
16 |
17 | //If the sensors are meausuring, does the history page update when the next hour comes with the sensor measurements?
18 | namespace PlantSensor
19 | {
20 | public class ChartDataPoint
21 | {
22 | public string Name { get; set; }
23 | public float Amount { get; set; }
24 | }
25 | public sealed partial class HistoryPage : Page
26 | {
27 | //The Observable Collection Lists are the lists directly connected to the UI
28 | private ObservableCollection SoilMoistureList;
29 | private ObservableCollection TemperatureList;
30 | private ObservableCollection BrightnessList;
31 |
32 | private ObservableCollection IdealTemperatureList;
33 | private ObservableCollection IdealBrightnessList;
34 | private ObservableCollection IdealSoilMoistureList;
35 |
36 |
37 | //These lists determine what data to show based on time frame and type of sensor
38 | private List masterDayBrightnessList;
39 | private List masterHourBrightnessList;
40 | private List masterWeekBrightnessList;
41 | private List masterDayTemperatureList;
42 | private List masterHourTemperatureList;
43 | private List masterWeekTemperatureList;
44 | private List masterDaySoilMoistureList;
45 | private List masterHourSoilMoistureList;
46 | private List masterWeekSoilMoistureList;
47 |
48 | //the number of data points required for each of these time frames
49 | int dataPointsForDay;
50 | int dataPointsForWeek;
51 | int dataPointsForTwoWeeks;
52 | int dataPointsForFourWeeks;
53 | int dataPointsForEightWeeks;
54 |
55 | //These colors dictate what the tabs that determine time span look like
56 | Color colorBlue;
57 | Color colorlightBlue;
58 | Color colorWhite;
59 | Color colorlightRed;
60 | Color colorRed;
61 | Color colorGrey;
62 | SolidColorBrush SolidColorBrushGrey;
63 | SolidColorBrush SolidColorBrushBlue;
64 | SolidColorBrush SolidColorBrushLightBlue;
65 | SolidColorBrush SolidColorBrushWhite;
66 | SolidColorBrush SolidColorBrushLightRed;
67 | SolidColorBrush SolidColorBrushRed;
68 | SolidColorBrush Black = new SolidColorBrush(Colors.Black);
69 |
70 | //the delimeter (",") which will split up the data from the date
71 | Char delimiter;
72 |
73 | /**
74 | * sets all of the variables that were described above
75 | **/
76 | public HistoryPage()
77 | {
78 | this.InitializeComponent();
79 |
80 | SoilMoistureList = new ObservableCollection();
81 | TemperatureList = new ObservableCollection();
82 | BrightnessList = new ObservableCollection();
83 |
84 | IdealTemperatureList = new ObservableCollection();
85 | IdealBrightnessList = new ObservableCollection();
86 | IdealSoilMoistureList = new ObservableCollection();
87 |
88 | masterDayBrightnessList = new List();
89 | masterHourBrightnessList = new List();
90 | masterWeekBrightnessList = new List();
91 |
92 | masterDayTemperatureList = new List();
93 | masterHourTemperatureList = new List();
94 | masterWeekTemperatureList = new List();
95 |
96 | masterDaySoilMoistureList = new List();
97 | masterHourSoilMoistureList = new List();
98 | masterWeekSoilMoistureList = new List();
99 |
100 | dataPointsForDay = 24;
101 | dataPointsForWeek = 7;
102 | dataPointsForTwoWeeks = 14;
103 | dataPointsForFourWeeks = 28;
104 | dataPointsForEightWeeks = 56;
105 |
106 | colorBlue = Color.FromArgb(255, 105, 210, 231);
107 | colorlightBlue = Color.FromArgb(255, 167, 219, 216);
108 | colorWhite = Color.FromArgb(255, 224, 228, 204);
109 | colorlightRed = Color.FromArgb(255, 243, 134, 48);
110 | colorRed = Color.FromArgb(255, 250, 105, 0);
111 | colorGrey = Color.FromArgb(255, 50, 50, 50);
112 | SolidColorBrushGrey = new SolidColorBrush(colorGrey);
113 | SolidColorBrushBlue = new SolidColorBrush(colorBlue);
114 | SolidColorBrushLightBlue = new SolidColorBrush(colorlightBlue);
115 | SolidColorBrushWhite = new SolidColorBrush(colorWhite);
116 | SolidColorBrushLightRed = new SolidColorBrush(colorlightRed);
117 | SolidColorBrushRed = new SolidColorBrush(colorRed);
118 |
119 | delimiter = ',';
120 | }
121 |
122 | /**
123 | * This method is reached when the history page is reached
124 | * It sets up all of the lists for the various timeframes.
125 | * It also automatically loads one week as the default time frame
126 | **/
127 | protected async override void OnNavigatedTo(NavigationEventArgs navArgs)
128 | {
129 | Stopwatch stopWatch = new Stopwatch();
130 | stopWatch.Start();
131 | await setUpChart();
132 | stopWatch.Stop();
133 | Debug.WriteLine("Set up chart" + stopWatch.Elapsed);
134 |
135 | stopWatch.Start();
136 | await resetPreviousUI();
137 |
138 | //These run simultaneously so should not be awaited
139 | ThreadPool.RunAsync(async (s) =>
140 | {
141 | Stopwatch sw = new Stopwatch();
142 | sw.Start();
143 | var generalHourDictionary = setUpGeneralMasterListPerHour(App.Brightnessresult, masterHourBrightnessList);
144 | setUpGeneralMasterListPerDay(generalHourDictionary, masterDayBrightnessList);
145 | setUpGeneralMasterListPerWeek(masterDayBrightnessList, masterWeekBrightnessList);
146 | sw.Stop();
147 | Debug.WriteLine("Set up brightness chart" + stopWatch.Elapsed);
148 | await reloadChart(BrightnessList, masterDayBrightnessList, Math.Min(masterDayBrightnessList.Count, dataPointsForWeek));
149 | await createUI(IdealBrightnessList, BrightnessList, App.PlantSettings.IdealBright);
150 | await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
151 | {
152 | HistoryBrightnessProgressRing.IsActive = false;
153 | });
154 | });
155 |
156 | ThreadPool.RunAsync(async (s) =>
157 | {
158 | Stopwatch sw = new Stopwatch();
159 | sw.Start();
160 | var generalHourDictionary = setUpGeneralMasterListPerHour(App.Temperatureresult, masterHourTemperatureList);
161 | setUpGeneralMasterListPerDay(generalHourDictionary, masterDayTemperatureList);
162 | setUpGeneralMasterListPerWeek(masterDayTemperatureList, masterWeekTemperatureList);
163 | sw.Stop();
164 | Debug.WriteLine("Set up temperature chart" + stopWatch.Elapsed);
165 | await reloadChart(TemperatureList, masterDayTemperatureList, Math.Min(masterDayTemperatureList.Count, dataPointsForWeek));
166 | await createUI(IdealTemperatureList, TemperatureList, App.PlantSettings.IdealTemp);
167 | await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
168 | {
169 | HistoryTemperatureProgressRing.IsActive = false;
170 | });
171 | });
172 |
173 | ThreadPool.RunAsync(async (s) =>
174 | {
175 | Stopwatch sw = new Stopwatch();
176 | sw.Start();
177 | var generalHourDictionary = setUpGeneralMasterListPerHour(App.SoilMoistureresult, masterHourSoilMoistureList);
178 | setUpGeneralMasterListPerDay(generalHourDictionary, masterDaySoilMoistureList);
179 | setUpGeneralMasterListPerWeek(masterDaySoilMoistureList, masterWeekSoilMoistureList);
180 | sw.Stop();
181 | Debug.WriteLine("Set up soil chart" + stopWatch.Elapsed);
182 | await reloadChart(SoilMoistureList, masterDaySoilMoistureList, Math.Min(masterDaySoilMoistureList.Count, dataPointsForWeek));
183 | await createUI(IdealSoilMoistureList, SoilMoistureList, App.PlantSettings.IdealSoilMoist);
184 | await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
185 | {
186 | HistorySoilMoistProgressRing.IsActive = false;
187 | });
188 | });
189 |
190 | stopWatch.Stop();
191 | Debug.WriteLine("Finished!" + stopWatch.Elapsed);
192 |
193 | await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
194 | {
195 | await resetTemperatureButtonColor();
196 | await resetBrightnessButtonColor();
197 | await resetSoilMoistureButtonColor();
198 | d3BrightnessButton.Foreground = Black;
199 | d3BrightnessButton.Background = SolidColorBrushLightBlue;
200 | d3TemperatureButton.Foreground = Black;
201 | d3TemperatureButton.Background = SolidColorBrushLightBlue;
202 | d3SoilMoistureButton.Foreground = Black;
203 | d3SoilMoistureButton.Background = SolidColorBrushLightBlue;
204 | });
205 | }
206 |
207 | /**
208 | * attaches the list data structures to the chart
209 | * */
210 | public async Task setUpChart()
211 | {
212 | await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
213 | {
214 | (SoilMoistureChart.Series[0] as LineSeries).ItemsSource = SoilMoistureList;
215 | (TemperatureChart.Series[0] as LineSeries).ItemsSource = TemperatureList;
216 | (BrightnessChart.Series[0] as LineSeries).ItemsSource = BrightnessList;
217 |
218 | (TemperatureChart.Series[1] as LineSeries).ItemsSource = IdealTemperatureList;
219 | (BrightnessChart.Series[1] as LineSeries).ItemsSource = IdealBrightnessList;
220 | (SoilMoistureChart.Series[1] as LineSeries).ItemsSource = IdealSoilMoistureList;
221 | });
222 |
223 | }
224 |
225 | /**
226 | * sets up the list by hour
227 | * returns hourDictionary: the hour dictionary will be used in the day sorting method
228 | * */
229 | public Dictionary> setUpGeneralMasterListPerHour(IList fileList, List masterList)
230 | {
231 | //creates a dictionary where all of the information is stored.
232 | Dictionary> hourDictionary = new Dictionary>();
233 | DateTime upperBound = DateTime.Now;
234 | TimeSpan fiftySixDays = new TimeSpan(56,0, 0, 0);
235 | TimeSpan twentyFourHours = new TimeSpan(24, 0, 0);
236 | //the earliest date that the chart will show is in the lowerBound variable
237 | DateTime lowerBound = upperBound - fiftySixDays;
238 | DateTime currentDate;
239 | DateTime comparedDate = DateTime.Now;
240 | DateTime oldDate;
241 | //goes through every data point that the sensors have collected
242 | for(int ii = 0; ii < fileList.Count; ii++)
243 | {
244 | String nextString = fileList[ii];
245 | String[] subStrings = nextString.Split(delimiter);
246 | //nextFloat holds the sensor data
247 | float nextFloat = float.Parse(subStrings[0]);
248 | //currentDate holds the time that the nextFloat value was measured
249 | currentDate = DateTime.Parse(subStrings[1]);
250 | if (currentDate > lowerBound && currentDate <= upperBound)
251 | {
252 | //the minute and the second data is not valuable in the hour view
253 | comparedDate = new DateTime(currentDate.Year, currentDate.Month, currentDate.Day, currentDate.Hour, 0, 0);
254 | if (hourDictionary.ContainsKey(comparedDate))
255 | {
256 | hourDictionary[comparedDate].Add(nextFloat);
257 | //changes the date
258 | oldDate = comparedDate;
259 | }
260 | else
261 | {
262 | List newList = new List();
263 | newList.Add(nextFloat);
264 | hourDictionary.Add(comparedDate, newList);
265 | }
266 | }
267 | }
268 | foreach(DateTime hour in hourDictionary.Keys)
269 | {
270 | //we only need the last twenty four hours
271 | lowerBound = comparedDate - twentyFourHours;
272 | if (hour > lowerBound && hour <= comparedDate)
273 | {
274 | masterList.Add(new ChartDataPoint() { Name = hour.ToString("HH:00"), Amount = hourDictionary[hour].Average() });
275 | }
276 | }
277 | return hourDictionary;
278 | }
279 |
280 | /**
281 | * sets up the list by day
282 | * */
283 | public void setUpGeneralMasterListPerDay(Dictionary> hourDictionary, List masterList)
284 | {
285 | //the DateTime in the dictionary is the day the sensors got their measurements
286 | //the list is the list of values that the sensor measured during that day
287 | var dayDictionary = new Dictionary>();
288 | DateTime upperBound = DateTime.Now;
289 | //my graph does not display more than 56 days, so there is no reason to be reading
290 | //data from before that time
291 | TimeSpan fiftySixDays = new TimeSpan(56, 0, 0, 0);
292 | DateTime lowerBound = upperBound - fiftySixDays;
293 | DateTime currentDate;
294 | foreach(DateTime comparedDate in hourDictionary.Keys)
295 | {
296 | currentDate = new DateTime(comparedDate.Year, comparedDate.Month, comparedDate.Day, 0, 0, 0);
297 | if (currentDate >= lowerBound && currentDate <= upperBound)
298 | {
299 | //checks to see if its a new day. If not then, the sensor value will be added onto the
300 | //already existing day. If it is a new day, then a new key is made in the dictionary
301 | if (dayDictionary.ContainsKey(currentDate))
302 | {
303 | dayDictionary[currentDate].Add(hourDictionary[comparedDate].Average());
304 | }
305 | else
306 | {
307 | List newList = new List();
308 | newList.Add(hourDictionary[comparedDate].Average());
309 | dayDictionary.Add(currentDate, newList);
310 | }
311 | }
312 | }
313 | foreach (DateTime day in dayDictionary.Keys)
314 | {
315 | masterList.Add(new ChartDataPoint() { Name = day.ToString("MM/dd/yy"), Amount = dayDictionary[day].Average() });
316 | }
317 |
318 | }
319 | /**
320 | * sets up the list by week
321 | * */
322 | public void setUpGeneralMasterListPerWeek(List masterDayList, List masterWeekList)
323 | {
324 | if (masterDayList.Count != 0)
325 | {
326 | int daysInWeek = 7;
327 | int numberOfWeeks = dataPointsForEightWeeks / daysInWeek;
328 | //the number of weeks is set, but the number of data points per week
329 | //is not, so an array of lists is used.
330 | List[] weekList = new List[numberOfWeeks];
331 |
332 | TimeSpan oneWeek = new TimeSpan(7, 0, 0, 0);
333 | DateTime firstDate = DateTime.Parse(masterDayList[0].Name);
334 | DateTime[] weekDates = new DateTime[numberOfWeeks];
335 | //loops through the number of weeks and assign lists and floats
336 | for (int ii = 0; ii < numberOfWeeks; ii++)
337 | {
338 | weekList[ii] = new List();
339 | weekDates[ii] = firstDate + TimeSpan.FromTicks(oneWeek.Ticks * (ii + 1));
340 | }
341 | int weekCounter = 0;
342 | //loops through the masterDayList(the average value of the sensors per day)
343 | //and identifies the date into the week
344 | for (int ii = 0; ii < masterDayList.Count(); ii++)
345 | {
346 | DateTime comparedDate = DateTime.Parse(masterDayList[ii].Name);
347 | if (comparedDate > weekDates[weekCounter])
348 | {
349 | for (int jj = weekCounter; jj < weekDates.Count(); jj++)
350 | {
351 | if (comparedDate < weekDates[jj])
352 | {
353 | weekCounter = jj;
354 | break;
355 | }
356 | }
357 | }
358 | //adds the value to that week
359 | float nextFloat = masterDayList[ii].Amount;
360 | weekList[weekCounter].Add(nextFloat);
361 | }
362 |
363 | for (int ii = 0; ii < weekList.Count(); ii++)
364 | {
365 | //if size of list is zero, then it shouldnt be on the list
366 | if (weekList[ii].Count() != 0)
367 | {
368 | DateTime beginningOfWeek = weekDates[ii] - oneWeek;
369 | String weekName = beginningOfWeek.ToString("MM/dd") + "-" + weekDates[ii].ToString("MM/dd");
370 | masterWeekList.Add(new ChartDataPoint() { Name = weekName, Amount = weekList[ii].Average() });
371 | }
372 | }
373 | }
374 | }
375 |
376 | /**
377 | * when the user wants to change time frames, then the UI gets reset to make it look like the user has changed time
378 | * */
379 | public async Task resetPreviousUI()
380 | {
381 | await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
382 | {
383 | BrightnessList.Clear();
384 | TemperatureList.Clear();
385 | SoilMoistureList.Clear();
386 | });
387 |
388 | }
389 |
390 | /**
391 | * When the user wants to change time frames, the chart reloads
392 | * */
393 | public async Task reloadChart(ObservableCollection list, List masterList, int subtraction)
394 | {
395 | Debug.WriteLine("reloadChart");
396 | await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
397 | {
398 | list.Clear();
399 |
400 | for (int ii = masterList.Count - subtraction; ii < masterList.Count; ii++)
401 | {
402 | list.Add(masterList[ii]);
403 | }
404 | });
405 | }
406 |
407 | //should be float
408 | public async Task createUI(ObservableCollection idealList, ObservableCollection list, float settings)
409 | {
410 | await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
411 | {
412 | idealList.Clear();
413 | foreach (ChartDataPoint point in list)
414 | {
415 | idealList.Add(new ChartDataPoint()
416 | {
417 | Name = point.Name,
418 | Amount = settings
419 | });
420 | }
421 | });
422 | }
423 | /**
424 | * These reset the UI for the different sensors when user changes time frame
425 | * */
426 | public async Task resetTemperatureButtonColor()
427 | {
428 | await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
429 | {
430 | d1TemperatureButton.Foreground = SolidColorBrushBlue;
431 | d1TemperatureButton.Background = SolidColorBrushGrey;
432 | d3TemperatureButton.Foreground = SolidColorBrushLightBlue;
433 | d3TemperatureButton.Background = SolidColorBrushGrey;
434 | d5TemperatureButton.Foreground = SolidColorBrushWhite;
435 | d5TemperatureButton.Background = SolidColorBrushGrey;
436 | d7TemperatureButton.Foreground = SolidColorBrushLightRed;
437 | d7TemperatureButton.Background = SolidColorBrushGrey;
438 | d9TemperatureButton.Foreground = SolidColorBrushRed;
439 | d9TemperatureButton.Background = SolidColorBrushGrey;
440 | });
441 | }
442 |
443 | public async Task resetBrightnessButtonColor()
444 | {
445 | await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
446 | {
447 | d1BrightnessButton.Foreground = SolidColorBrushBlue;
448 | d1BrightnessButton.Background = SolidColorBrushGrey;
449 | d3BrightnessButton.Foreground = SolidColorBrushLightBlue;
450 | d3BrightnessButton.Background = SolidColorBrushGrey;
451 | d5BrightnessButton.Foreground = SolidColorBrushWhite;
452 | d5BrightnessButton.Background = SolidColorBrushGrey;
453 | d7BrightnessButton.Foreground = SolidColorBrushLightRed;
454 | d7BrightnessButton.Background = SolidColorBrushGrey;
455 | Brightness9dButton.Foreground = SolidColorBrushRed;
456 | Brightness9dButton.Background = SolidColorBrushGrey;
457 | });
458 | }
459 |
460 | public async Task resetSoilMoistureButtonColor()
461 | {
462 | await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, () =>
463 | {
464 | d1SoilMoistureButton.Foreground = SolidColorBrushBlue;
465 | d1SoilMoistureButton.Background = SolidColorBrushGrey;
466 | d3SoilMoistureButton.Foreground = SolidColorBrushLightBlue;
467 | d3SoilMoistureButton.Background = SolidColorBrushGrey;
468 | d5SoilMoistureButton.Foreground = SolidColorBrushWhite;
469 | d5SoilMoistureButton.Background = SolidColorBrushGrey;
470 | d7SoilMoistureButton.Foreground = SolidColorBrushLightRed;
471 | d7SoilMoistureButton.Background = SolidColorBrushGrey;
472 | d9SoilMoistureButton.Foreground = SolidColorBrushRed;
473 | d9SoilMoistureButton.Background = SolidColorBrushGrey;
474 | });
475 | }
476 | /**
477 | * All of these reset the list in the chart when the user changes tabs
478 | * */
479 | private async void d1BrightnessButton_Click(object sender, RoutedEventArgs e)
480 | {
481 | await reloadChart(BrightnessList, masterHourBrightnessList, Math.Min(masterHourBrightnessList.Count,dataPointsForDay));
482 | await createUI(IdealBrightnessList, BrightnessList, App.PlantSettings.IdealBright);
483 | await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
484 | {
485 | BrightnessUnits.Text = "Hours";
486 | await resetBrightnessButtonColor();
487 | d1BrightnessButton.Foreground = Black;
488 | d1BrightnessButton.Background = SolidColorBrushBlue;
489 | });
490 | }
491 |
492 | private async void d3BrightnessButton_Click(object sender, RoutedEventArgs e)
493 | {
494 | await reloadChart(BrightnessList, masterDayBrightnessList, Math.Min(masterDayBrightnessList.Count,dataPointsForWeek));
495 | await createUI(IdealBrightnessList, BrightnessList, App.PlantSettings.IdealBright);
496 | await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
497 | {
498 | BrightnessUnits.Text = "Days";
499 | await resetBrightnessButtonColor();
500 | d3BrightnessButton.Foreground = Black;
501 | d3BrightnessButton.Background = SolidColorBrushLightBlue;
502 | });
503 | }
504 |
505 | private async void d5BrightnessButton_Click(object sender, RoutedEventArgs e)
506 | {
507 | await reloadChart(BrightnessList, masterDayBrightnessList, Math.Min(masterDayBrightnessList.Count,dataPointsForTwoWeeks));
508 | await createUI(IdealBrightnessList, BrightnessList, App.PlantSettings.IdealBright);
509 | await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
510 | {
511 | BrightnessUnits.Text = "Days";
512 | await resetBrightnessButtonColor();
513 | d5BrightnessButton.Foreground = Black;
514 | d5BrightnessButton.Background = SolidColorBrushWhite;
515 | });
516 | }
517 |
518 | private async void d7BrightnessButton_Click(object sender, RoutedEventArgs e)
519 | {
520 | await reloadChart(BrightnessList, masterDayBrightnessList, Math.Min(masterDayBrightnessList.Count, dataPointsForFourWeeks));
521 | await createUI(IdealBrightnessList, BrightnessList, App.PlantSettings.IdealBright);
522 | await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
523 | {
524 | BrightnessUnits.Text = "Days";
525 | await resetBrightnessButtonColor();
526 | d7BrightnessButton.Foreground = Black;
527 | d7BrightnessButton.Background = SolidColorBrushLightRed;
528 | });
529 | }
530 |
531 | private async void Brightness9dButton_Click(object sender, RoutedEventArgs e)
532 | {
533 | await reloadChart(BrightnessList, masterWeekBrightnessList, Math.Min(masterWeekBrightnessList.Count,dataPointsForEightWeeks));
534 | await createUI(IdealBrightnessList, BrightnessList, App.PlantSettings.IdealBright);
535 | await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
536 | {
537 | BrightnessUnits.Text = "Weeks";
538 | await resetBrightnessButtonColor();
539 | Brightness9dButton.Foreground = Black;
540 | Brightness9dButton.Background = SolidColorBrushRed;
541 | });
542 | }
543 |
544 | private async void d1TemperatureButton_Click(object sender, RoutedEventArgs e)
545 | {
546 | await reloadChart(TemperatureList, masterHourTemperatureList, Math.Min(masterHourTemperatureList.Count,dataPointsForDay));
547 | await createUI(IdealTemperatureList, TemperatureList, App.PlantSettings.IdealTemp);
548 | await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
549 | {
550 | TemperatureUnits.Text = "Hours";
551 | await resetTemperatureButtonColor();
552 | d1TemperatureButton.Foreground = Black;
553 | d1TemperatureButton.Background = SolidColorBrushBlue;
554 | });
555 | }
556 |
557 | private async void d3TemperatureButton_Click(object sender, RoutedEventArgs e)
558 | {
559 | await reloadChart(TemperatureList, masterDayTemperatureList, Math.Min(masterDayTemperatureList.Count,dataPointsForWeek));
560 | await createUI(IdealTemperatureList, TemperatureList, App.PlantSettings.IdealTemp);
561 | await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
562 | {
563 | TemperatureUnits.Text = "Days";
564 | await resetTemperatureButtonColor();
565 | d3TemperatureButton.Foreground = Black;
566 | d3TemperatureButton.Background = SolidColorBrushLightBlue;
567 | });
568 | }
569 |
570 | private async void d5TemperatureButton_Click(object sender, RoutedEventArgs e)
571 | {
572 | await reloadChart(TemperatureList, masterDayTemperatureList, Math.Min(masterDayTemperatureList.Count,dataPointsForTwoWeeks));
573 | await createUI(IdealTemperatureList, TemperatureList, App.PlantSettings.IdealTemp);
574 | await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
575 | {
576 | TemperatureUnits.Text = "Days";
577 | await resetTemperatureButtonColor();
578 | d5TemperatureButton.Foreground = Black;
579 | d5TemperatureButton.Background = SolidColorBrushWhite;
580 | });
581 | }
582 |
583 | private async void d7TemperatureButton_Click(object sender, RoutedEventArgs e)
584 | {
585 | await reloadChart(TemperatureList, masterDayTemperatureList, Math.Min(masterDayTemperatureList.Count, dataPointsForFourWeeks));
586 | await createUI(IdealTemperatureList, TemperatureList, App.PlantSettings.IdealTemp);
587 | await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
588 | {
589 | TemperatureUnits.Text = "Days";
590 | await resetTemperatureButtonColor();
591 | d7TemperatureButton.Foreground = Black;
592 | d7TemperatureButton.Background = SolidColorBrushLightRed;
593 | });
594 | }
595 |
596 | private async void d9TemperatureButton_Click(object sender, RoutedEventArgs e)
597 | {
598 | await reloadChart(TemperatureList, masterWeekTemperatureList, Math.Min(masterWeekTemperatureList.Count,dataPointsForEightWeeks));
599 | await createUI(IdealTemperatureList, TemperatureList, App.PlantSettings.IdealTemp);
600 | await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
601 | {
602 | TemperatureUnits.Text = "Weeks";
603 | await resetTemperatureButtonColor();
604 | d9TemperatureButton.Foreground = Black;
605 | d9TemperatureButton.Background = SolidColorBrushRed;
606 | });
607 | }
608 |
609 | private async void d1SoilMoistureButton_Click(object sender, RoutedEventArgs e)
610 | {
611 | await reloadChart(SoilMoistureList, masterHourSoilMoistureList, Math.Min(masterHourSoilMoistureList.Count,dataPointsForDay));
612 | await createUI(IdealSoilMoistureList, SoilMoistureList, App.PlantSettings.IdealSoilMoist);
613 | await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
614 | {
615 | SoilMoistureUnits.Text = "Hours";
616 | await resetSoilMoistureButtonColor();
617 | d1SoilMoistureButton.Foreground = Black;
618 | d1SoilMoistureButton.Background = SolidColorBrushBlue;
619 | });
620 | }
621 |
622 | private async void d3SoilMoistureButton_Click(object sender, RoutedEventArgs e)
623 | {
624 | await reloadChart(SoilMoistureList, masterDaySoilMoistureList, Math.Min(masterDaySoilMoistureList.Count,dataPointsForWeek));
625 | await createUI(IdealSoilMoistureList, SoilMoistureList, App.PlantSettings.IdealSoilMoist);
626 | await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
627 | {
628 | SoilMoistureUnits.Text = "Days";
629 | await resetSoilMoistureButtonColor();
630 | d3SoilMoistureButton.Foreground = Black;
631 | d3SoilMoistureButton.Background = SolidColorBrushLightBlue;
632 | });
633 | }
634 |
635 | private async void d5SoilMoistureButton_Click(object sender, RoutedEventArgs e)
636 | {
637 | await reloadChart(SoilMoistureList, masterDaySoilMoistureList, Math.Min(masterDaySoilMoistureList.Count,dataPointsForTwoWeeks));
638 | await createUI(IdealSoilMoistureList, SoilMoistureList, App.PlantSettings.IdealSoilMoist);
639 | await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
640 | {
641 | SoilMoistureUnits.Text = "Days";
642 | await resetSoilMoistureButtonColor();
643 | d5SoilMoistureButton.Foreground = Black;
644 | d5SoilMoistureButton.Background = SolidColorBrushWhite;
645 | });
646 | }
647 |
648 | private async void d7SoilMoistureButton_Click(object sender, RoutedEventArgs e)
649 | {
650 | await reloadChart(SoilMoistureList, masterDaySoilMoistureList, Math.Min(masterDaySoilMoistureList.Count,dataPointsForFourWeeks));
651 | await createUI(IdealSoilMoistureList, SoilMoistureList, App.PlantSettings.IdealSoilMoist);
652 | await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
653 | {
654 | SoilMoistureUnits.Text = "Days";
655 | await resetSoilMoistureButtonColor();
656 | d7SoilMoistureButton.Foreground = Black;
657 | d7SoilMoistureButton.Background = SolidColorBrushLightRed;
658 | });
659 | }
660 |
661 | private async void d9SoilMoistureButton_Click(object sender, RoutedEventArgs e)
662 | {
663 | await reloadChart(SoilMoistureList, masterWeekSoilMoistureList, Math.Min(masterWeekSoilMoistureList.Count,dataPointsForEightWeeks));
664 | await createUI(IdealSoilMoistureList, SoilMoistureList, App.PlantSettings.IdealSoilMoist);
665 | await Dispatcher.RunAsync(CoreDispatcherPriority.Normal, async () =>
666 | {
667 | SoilMoistureUnits.Text = "Weeks";
668 | await resetSoilMoistureButtonColor();
669 | d9SoilMoistureButton.Foreground = Black;
670 | d9SoilMoistureButton.Background = SolidColorBrushRed;
671 | });
672 | }
673 |
674 | /**
675 | * When the user returns to the last page
676 | * */
677 | private void return_Click(object sender, RoutedEventArgs e)
678 | {
679 | Frame.Navigate(typeof(MainPage));
680 | }
681 |
682 | private void Setting_Click(object sender, RoutedEventArgs e)
683 | {
684 | Frame.Navigate(typeof(SettingsPage));
685 | }
686 |
687 | private void Twitter_Click(object sender, RoutedEventArgs e)
688 | {
689 | Frame.Navigate(typeof(TwitterPage));
690 | }
691 |
692 | private void AppBarButton_Click(object sender, RoutedEventArgs e)
693 | {
694 |
695 | }
696 | }
697 | }
698 |
--------------------------------------------------------------------------------