I was planning to build a web based temperature/humidity monitoring app with Raspberry PI 3 and Windows 10 IoT Core. I have playing around with Raspbian for a while now and this time I wanted to try something different. I have been using Python to write application for Raspberry PI, Windows IoT Core with C# will be something new for me and therefore, this time I choose to go with Windows 10 IoT Core.
Here is the list of things to get started:
Setting up the PI with Windows 10 IoT Core is a very straight forward process. You can read about it more here. I recommend to connect the device to your Wi-Fi network. This will give you a benefit to move your device around. The problem for the first time users will be that the device will not auto-connect to the Wi-Fi network. To solve this problem, you need to use a wired LAN connection from the network or from the local computer. Once plugged in you will be able to see the device in the IoT dashboard from where you can go to Device Portal
and connect to the Wi-Fi network. After the connection is successful, you can then remove the LAN cable. To follow the exact steps, head over to this documentation. This is how your device will get displayed in the IoT dashboard.
You can set up things in the cloud from the Azure Portal as well as from the IoT Dashboard itself. From dashboard you can create and provisioned a new IoT Hub and register the device in that Hub. Here is how you can do that. First sign-in to your Azure account by clicking the Sign-In option in the left hand side bar. After the sign-in is successful, you will be prompted with the below screen where you can provision a new IoT Hub and add your current device in the hub.
I am skipping the step for setting the IoT Hub from the Azure Portal as there is a good documentation available at Azure Docs. Pushing data to the IoT Hub with the SDK is easy but you can’t make use of the IoT Hub alone to read that data and do your work. Therefore, you also need to set up a Queue to read that data. As of now, you cannot create a Queue from the new Azure Portal instead you have to head towards the old portal at manage.windowsazure.com and create a queue from there. To create a queue, click the New>App Services>Service Bus>Queue>Quick Create
. Fill in the details to create a new queue.
Make sure that the region you are selecting here for the queue, it should be the same as your IoT Hub region. If you select a different region than that of your IoT Hub, you will not be able to associate this queue with the hub endpoint.
In the Azure Portal, to associate this queue with the IoT Hub endpoint, click the Endpoints
and then click Add
to add the queue to the endpoint.
Now as you have the device and the OS ready, you can now build the circuit. The BME280 sensor can be used with both I2C and SPI. For the project, I am using I2C. Below is the Fritzing diagram for your reference. You can download the Fritzing sketch file on Github repo.
I am using Visual Studio 2017 Enterprise Edition to build the device application and the web monitor application which I will be hosting in the cloud. For creating the device application, start with selection the Windows Universal project templates and then select Blank App (Universal)
template.
There is a project template available for Visual Studio which will let you build applications for Raspberry PI. The problem with that project type is that you will not be able to make use of the libraries or the SDK available for .NET yet. You can still build applications with this project type but you have to make use of REST API and using REST API is not as straight-forward as SDKs.
After the project creation is successful, you need to add below dependencies which will let you connect to IoT Hub and have a device to cloud communication. Below are the NuGet packages you need to install.
This package will enable you to have a device to cloud communication.
Install-Package BuildAzure.IoT.Adafruit.BME280
This package is the wrapper for the BME280 sensor.
Install-Package Microsoft.Azure.Devices.Client
Add the below namespaces in the Main.xaml.cs
file.
using Newtonsoft.Json; using Microsoft.Azure.Devices.Client; using BuildAzure.IoT.Adafruit.BME280;
Declare the variables.
private DeviceClient _deviceClient; private BME280Sensor _sensor; private string iotHubUri = "piiothub.azure-devices.net"; private string deviceKey = "Tj60asOk5ffVAT6a6SvZKMOqo8DYKSwWV7eQ2pLf0/k=";
The iothuburi
is the URL for the IoT Hub created in the Azure portal or from the IoT dashboard. You can get the device key from the Device Explorer
section in the IoT Hub. You can see how to get the Key
from the Device Explorer
from the below screen shot. I am using the Primary Key
as a devicekey
in my code.
In the constructor, initialize the DeviceClient
and BME280Sensor
objects. I have commented out the InitializeComponent()
, but if you want you can keep it as it is.
public MainPage() { //this.InitializeComponent(); deviceClient = DeviceClient.Create(iotHubUri, new DeviceAuthenticationWithRegistrySymmetricKey("raspberrypi", deviceKey), TransportType.Mqtt); _sensor = new BME280Sensor(); DeviceToCloudMessage(); }
Now add a function named DeviceToCloudMessage
which will connect to the IoT Hub using the device key, read the sensor data, serialize the data in JSON format and send it to the IoT Hub. Add this at the very bottom of the constructor.
private async void DeviceToCloudMessage() { await _sensor.Initialize(); float temperature = 0.00f; float humidity = 0.00f; while (true) { temperature = await _sensor.ReadTemperature(); humidity = await _sensor.ReadHumidity(); var sensorData = new { date = String.Format("{0}, {1}, {2}", DateTime.Now.ToLocalTime().TimeOfDay.Hours, DateTime.Now.ToLocalTime().TimeOfDay.Minutes, DateTime.Now.ToLocalTime().TimeOfDay.Seconds), temp = Math.Round(temperature, 2), humid = Math.Round(humidity, 2) }; var messageString = JsonConvert.SerializeObject(sensorData); var message = new Message(Encoding.ASCII.GetBytes(messageString)); await deviceClient.SendEventAsync(message); //Debug.WriteLine("{0} > Sending message: {1}", DateTime.Now, messageString); Task.Delay(5000).Wait(); } }
The date
property in the sensorData
type is being set in this specific way because we want to see the graph continuously moving. I can also read Pressure
from the sensor but as I am not interested in showing this data, I am skipping it out. If you want you can use it but you also have to change the web app to show this reading. Before I can send this data to the IoT Hub, I am serializing the sensorData
object and use ASCII encoding to get the byte[]
and pass it to the Message
class constructor. The last step is to send the message to the hub by using the DeviceClient
class SendEventAsync
method. In the last line I am adding a delay of 5 seconds between each reading. You can increase the time and see how the chart renders. I recommend not to go below this time delay as this might give you some false readings from the sensor.
I took this code from the documentation here and tweaked it to have the real data from the sensor connected to the device. Press Ctrl+Shift+B to build the solution. Navigate to Project
and then click <project> Properties
. Under Debug
section, set the Start Options
as shown below. Notice that the Platform
is set to ARM
and Configuration
is Active (Debug)
. When you are done with debugging the code and ready to deploy the code to the device you need to change it to Release
.
Unlike Raspbian, where we ssh or RDP into the device and compile or build the code, Windows 10 IoT works in a different way. You need to remote deploy the application from Visual Studio. Also, if you have enabled the remote debugging on the device, you also have to add the port number
to the Remote Machine
value and set the Authentication Mode
to None
.
NOTE: When you make changes to device application, you also need to change/increment the version of the application in the Package.appxmanifest file. If you miss this step then the application deployment will fail.
To deploy the app to the device, click the Build
menu and select Deploy <Project Name>
. If you are deploying the application for the first time, it will take some time to get deployed. After the deployment is successful, you will see the application under the App
section. At this moment, the application is stopped. To start the application in the, click the Play
button in the list to start the application. The App Type
show the type of application or you can say the mode it is running on. When I created the application, I selected the UWP
application and therefore, it will always run in the Foreground
type. The reason I choose this application type (UWP) is because I can then use the SDK to communicate with the IoT Hub. If you want to create a Background
application type then you can download this Visual Studio Extension for 2017 and this for Visual Studio 2015 which will let you build the background application. Keep in mind that you cannot use any SDK library with this project type. All you have now is the power of REST API which is not very easy to use.
You can build any kind of app to visualize the data, but because the SDK support for .NET is good I am going to set up a simple MVC application using .NET Framework. As of now, you cannot use Azure SDK with .NET Core application and also it looks like the team does not have any plans to shift their focus for releasing the SDK for .NET Core anytime soon.
Start with installing NuGet packages. First with the package that will let you read the data from the Queue.
Install-Package WindowsAzure.ServiceBus
Because this is a real-time application you also need to install SignalR
Install-Package Microsoft.AspNet.SignalR
After these packages are installed, You need a way to visualize the temperature and humidity received from the queue. To do this you can use any jquery chart plugin or any other library of your choice. I will be using Google Charts in my app, Line Charts to be precise. Installation is straight forward for the charts and you can play around with different options to tweak the look and feel of the chart. I am going to add the chart code in the Index.cshtml
file. Below is the complete code for the chart to render.
<script type="text/javascript" src="https://www.gstatic.com/charts/loader.js"></script> <div id="chart_div"></div> <script> var data = []; var chart; google.charts.load('current', { packages: ['corechart', 'line'] }); google.charts.setOnLoadCallback(loadChart); var hub = $.connection.ioTHub; $.connection.hub.start(); hub.client.iotHubNotification = function (d) { console.log(d); var pi = JSON.parse(d); var time = pi.date.split(','); var temp = pi.temp; var humid = pi.humid; data.addRows([[[parseInt(time[0]), parseInt(time[1]), parseInt(time[2])], temp, humid]]); var options = { height: 250, hAxis: { title: 'Time' }, vAxis: { title: 'Temperature / Humidity', gridlines: { count: 22 } } }; chart.draw(data, options); }; function loadChart() { data = new google.visualization.DataTable(); data.addColumn('timeofday', 'Time'); data.addColumn('number', 'Temperature'); data.addColumn('number', 'Humidity'); var options = { height: 250, hAxis: { title: 'Time' }, vAxis: { title: 'Temperarture / Humidity', gridlines: { count: 22 } } }; chart = new google.visualization.LineChart(document.getElementById('chart_div')); chart.draw(data, options); } </script>
I make use of the sample code from the examples at Google Charts and used it along with some minor tweaks to suite my needs. loadChart()
function is called for the first time when the page is loaded and then I have a SignalR hub which updates the chart with the same option sets that I have in the loadChart()
function. I add 3 data columns to display the data in the chart. There are few things that I would like to talk about in the above code. First is the timeofday
is displayed on a X-Axis
because time is continuous and I want to update the chart with time. Second, the gridlines
property of the vAxis
let you set how many horizontal rows you want to see in the graph. I have increased it to quite a significant number because I want to see the graph in more detail. You can play around with these settings and see what looks better for you. Third, the response I receive in the hub
is in string format and therefore, I have parsed that string to JSON in order to read it and set to the rows. Also note that I have leave the console.log
in the above code so that when you run the web app you can see the raw data in the console.
In the HomeController.cs
, first I will set the connection string to the queue which I have associated with the IoT Hub endpoint in Azure and set the queue name along with the IHubContext
for SignalR communication.
private string connectionString = "Endpoint=sb://iothubqueue-ns.servicebus.windows.net/;SharedAccessKeyName=RootManageSharedAccessKey;SharedAccessKey=88kJcD1mvJnO1jtiiY+AcUtIoinW//V/lF2WicOJ50s="; private string queueName = "iothubqueue"; private IHubContext _hubContext;
In the constructor, initialize the IHubContext
object.
_hubContext = GlobalHost.ConnectionManager.GetHubContext<IoTHub>();
Here is the code for the IoTHub
class:
using Microsoft.AspNet.SignalR; namespace IoTHubTempWebApp.Hubs { public class IoTHub : Hub { public void IoTHubNotification(string value) { Clients.All.iotHubNotification(value); } } }
And the code for Startup
class (Startup.cs)
using Microsoft.Owin; using Owin; [assembly: OwinStartup(typeof(IoTHubTempWebApp.Startup))] namespace IoTHubTempWebApp { public class Startup { public void Configuration(IAppBuilder app) { app.MapSignalR(); } } }
In the Index ActionResult
, I will start a task which will read the messages from the queue and then SignalR will broadcast it to the client side which in turn update the chart with the latest data or temperature/humidity readings.
public ActionResult Index() { Task task = Task.Run(() => { QueueClient client = QueueClient.CreateFromConnectionString(connectionString, queueName, ReceiveMode.ReceiveAndDelete); client.OnMessage(message => { Stream stream = message.GetBody<Stream>(); StreamReader reader = new StreamReader(stream, Encoding.ASCII); string s = reader.ReadToEnd(); _hubContext.Clients.All.ioTHubNotification(s); }); }); task.Wait(); return View(); }
First I create a QueueClient
object with the connection string and queue name along with the ReceiveMode
. I have set ReceiveMode
to ReceiveAndDelete
as I want to delete the data from the queue once it has been read. Though you have an option to have the data in the queue for the maximum of 7 days in Azure. The QueueClient
has an OnMessage
event which process a message in an event-driven message pump, which means that as soon as the something is being added to the queue, this event is fired. I get the message body in the form of Stream
, read the message to the end and pass the message to SignalR hub which in turn updates my chart in real-time. Here is the final output I have now.
If you look closely, you will notice that the temperature line is not as smooth as you thought it would be. This is because every time when Raspberry PI read the data from the sensor there is a slight change in the temperature only with a few decimal places. If you don’t like this then you can change the gridlines
property of the vAxis
in the chart. Also you can try changing the time delay on the device to see if that impacts the lines on the chart. try changing both time delay in the device application and the gridlines
in the web application to see how the chart renders.
Mostly all web applications out there has some way or the other amazing ways to upload a single or multiple files. While surfing on Github I found this amazing library to upload the files to the server in a unique way with lot of configurations. It support parallel uploads along with cancellation of the files which are in the upload queue along with a good looking progress bar to show the progress of upload.
I get the drag and drop to work in just like 5 minutes. It is super easy and that with some powerful configurations. To install Dropzone you can use the Nuget command.
PM> Install-Package dropzone
Add reference of js and css files on your page. To get the UI ready use this HTML.
<div class="row"> <div class="col-md-9"> <div id="dropzone"> <form action="/Home/Upload" class="dropzone needsclick dz-clickable" id="uploader"> <div class="dz-message needsclick"> Drop files here or click to upload.<br> </div> </form> </div> </div> </div>
The output of the above HTML looks like this.
There are few points to be noted here in the above HTML. Notice the action
and class
attributes for the form
element. You will also be needing the id
attribute as well. Here the action
attribute points to the ActionResult
which is responsible to handle the file upload. I have pointed it to the Upload
ActionResult in my controller class which accepts a parameter of type IFormFile. In case of a MVC application, we would have used HttpPostedFileBase class. Here is the complete code which handles the file upload.
[HttpPost] public async Task<IActionResult> Upload(IFormFile file) { var uploads = Path.Combine(_environment.WebRootPath, "uploads"); if (file.Length > 0) { using (var fileStream = new FileStream(Path.Combine(uploads, file.FileName), FileMode.Create)) { await file.CopyToAsync(fileStream); } } return RedirectToAction("Index"); }
The _environment
variable you see in the above code is the instance of IHostingEnvironment
interface which I have injected in the controller. Always use IHostingEnvironment
interface to resolve the paths. You can hard code the file path but it may not work on other platforms. The combine method returns the correct path based on the platform the code is executing. The WebRootPath
property returns the path of wwwroot
folder and the second parameter uploads
is then appended correctly with the path.
Now it is time to make some adjustment in the Dropzone configuration. Recall the id
attribute of the form
element. I named it uploader. The Dropzone library has a unique way to set the configuration. Like this.
<script> $(document).ready(function () { Dropzone.options.uploader = { paramName: "file", maxFilesize: 2, accept: function (file, done) { if (file.name == "test.jpg") { alert("Can't upload a test file."); } else { //Show a confirm alert and display the image on the page. } } }; }); </script>
You have to be a bit careful when setting this configuration. In the configuration above the paramName
states the name that will be used to transfer the file. This name should be the same as the IFormFile
parameter of the Upload
method in the controller. In this case I am using file
and the same has to be there in the param of the Upload
method. If the names mis-match the files will not be uploaded. The other parameter I am using is the maxFileSize
and is very much self-explanatory. I have set the size to be 2 MB
and because of this configuration, any file above this limit will not be uploaded. Here is an example of such kind of failure.
All the other files were uploaded successfully except one file which is 4.32 MB
and is way beyond the limit I set in my Dropzone configuration. If you hover the file, you will see why it got failed.
This is the simplest approach through which you can have drag and drop upload support in your applications. The configuration I am using here is the simplest and minimalistic configuration that can get you started in no time. There are some more powerful configurations like parallelUploads and uploadMultiple that you should look into and use it.
There is no time better to be a developer. With the cloud, you can compose solutions that were never possible before. You can release new features to millions of users within minutes. You can push the boundaries of current technological limitations in days. Developers can turn ideas from the ground up to successful businesses in only months. Companies need apps that allow them to maximize customer engagement and differentiate against competitors. Teams must have agility with app development for faster time to market. Developers need a flexible platform to scale up and down based on business demands, yet rock-solid resources that can withstand failure.
This guide breaks down the “why” and “how” for scenarios suited to the cloud with a focus on building apps using platform services available in Microsoft Azure. The second half of the guide showcases the breadth and depth of the Azure platform and services designed to help developers make truly competitive and differentiated applications.
The intended audience for this guide includes:
Developers wanting to understand why Azure is the best cloud platform for creating applications and how to get started quickly based on the app you want to build today.
Technical leaders considering Azure to support new or existing application development.
I run a custom blog engine I wrote myself on MVC 4 and as you would have thought it is on Windows hosting. I am re-writing my blog engine in .NET Core so that I can get it running on a Linux hosting as well. I am using Windows machine and Visual Studio Community Edition to write it and using a Ubuntu VM box to test it. My current blog uses SQL Server as a back-end but Linux does not support SQL Server and therefore I have to move to MySQL or any other No-SQL database available for Linux distros. For now I will be saving everything on the disk in JSON format.
The problem comes when I switch from database to file system. Both Windows and Linux file systems are different, so when working I hard-coded the data folder which holds all the posts for my blog. I publish the solution and deploy it to Ubuntu VM. I started the server and it ended up showing me this error in the console.
Notice the path of the data folder in the above screenshot. The path I am referring in the code ends up with backward slash which is not a UNIX format. Also a thing to note here is that UNIX follows a strict naming convention unlike Windows. For example, in Windows Data and data are same, but in UNIX they are not. Because I have hard-coded the path in my application while developing, it will end up in an error on UNIX machine.
To make the paths consistent in your application, I have to make use of the System.IO namespace Path class’s Combine method. Combine
method is an overloaded method. If you are hearing this method for the first time then make sure you read the documentation. This method renders the correct path based on the platform my code is executing. So instead of doing something like this.
var _posts = Directory.EnumerateFiles("Data\\Posts");
I have done something like this.
string posts = Path.Combine("Data", "Posts"); _files = Directory.EnumerateFiles(posts);
In short, if you are developing a .NET Core application targeting Windows along with UNIX and OSX, then make sure that you follow this approach to get the correct paths or else you will end up with an exception and your website inaccessible.
I have been playing a lot with Raspberry PI and Python these days and have also started a side project to create robot car controller with a Xbox 360 wireless controller. I am planning to controller a robot car using a custom interface from my Windows machine. Initially I tried with PyQt but I dropped the idea for now as Python is not my primary expertise and it will take some time for me to learn the basics and get into some serious coding. Controlling something remotely or visualizing the information from your device on the UI is always better. For a proof of concept I built a Windows Forms application which will request the output from Raspberry PI over TCP and then visualize it on the UI using a wonderful chart library that I found today. There is a slight change in the Python code as I have to transmit readings from Raspberry PI over TCP so my Windows Forms application can read the output and utilize it to visualize it.
Reading the ADXL345 output is fairly simple and you can do this without any problem by using Adafruit’s ADXL345 Python library. This library will get you started in a jiffy and you will have your readings. I am not going into the details about the different features of the library I am using and ADXL345. The only thing you will have to do is to wire ADXL345 to your Raspberry PI and fire the example code you got from Adafruit’s repository from Github. If you have set it up correctly this, you will see X, Y, Z values on your terminal. If the terminal displays 0s
for all the three axis then there is something wrong with the wiring (assuming you are using the example code). This is how your writing should be like.
Now I have made slight changes in the code so that I can send the data over TCP. I have created a simple TCP server which exposes Raspberry PI through IP address and a port number. This is the complete code for reading values from ADXL345.
import Adafruit_ADXL345 import socket HOST = "192.168.1.8" PORT = 50007 accel = Adafruit_ADXL345.ADXL345() s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.bind((HOST, PORT)) s.listen(1) conn, addr = s.accept() while 1: data = conn.recv(1024) if data.strip() == "adxl": x, y, z = accel.read() data = 'X:' + str(x) + '|Y:' + str(y) + '|Z:' + str(z) conn.send(data)
In the code, you can see that I am not just transmitting the readings just like that. I only transmit when there is a request from another application is there to get the readings. This is a good approach as I don’t the PI to transmit the readings even if nobody is requesting it. I am sending a single string as a response which I am going to read at my Windows Forms application and use it.
You need to change the IP address and port number according to your Pi’s configuration.
Once this is done you can then execute the script from the terminal by firing the below command
sudo python adxl.py
This is it from Raspberry PI side. Let’s take a look from the Windows side now.
This will be a simple Windows Forms application which will connect to the Raspberry PI using the Pi’s IP address and the port on which the server is running. The Windows Form application is also a TCP client which sends a request to Raspberry PI for the updated readings from ADXL345. As I mentioned above in the Python code that the readings are not just being transmitted but a client has to send a request to to get the readings.
Let’s get started with the visualizing part. While was searching for a perfect charting library, I came across this wonderful library called Live Charts. This library is open-source, easy to use, has lots of awesome charts and a very robust documentation and moreover it supports Windows Forms as well as on WPF applications. I highly recommend you to look at the examples to get the idea about this library.
As usual, I will be using Nuget command to install the library.
PM> Install-Package LiveCharts.WinForms
You also have to add the custom controls in the toolbox. You can follow the steps here to add the Live Charts control in the toolbox. In the design mode, choose the Cartesian Chart
control from the toolbox and add it to the form. After adding the control to the form, I have dock it to the top of the form so I can utilize the lower section of the form to display the readings in numbers. Here is how my form looks like in design mode.
After the designing for the form is complete, I can initialize the chart to display the readings from Raspberry PI. The chart require few things to be setup before it can start displaying the data correctly. The accelerometer I am using is a 3-axis accelerometer and therefore it is going to send me readings for 3 axis i.e X, Y and Z. This means I will be needing 3 line series to visualize the information from accelerometer. To have 3 line series display the data I have to use CharValues
class which will let me display the readings in the line series. As I have to update my chart when I request the new readings from Raspberry PI, I have to use ObservableValue
type. The ObservableValue
will make sure that whenever there is a change in the value, it gets reflected in the chart and therefore keeping the chart always up to date.
public ChartValues<ObservableValue> Values_X { get; set; } public ChartValues<ObservableValue> Values_Y { get; set; } public ChartValues<ObservableValue> Values_Z { get; set; }
Because I am going to make request to the server running on my Raspberry PI and request for the ADXL345 readings, I have to create a TCP client in order to do so.
Socket server; IPEndPoint ipEndPoint; byte[] data;
When the application is loaded, I want to make connection to Raspberry PI by using it’s IP address and port number on which the server is running on. To do this I will add the below code to the constructor of my application.
ipEndPoint = new IPEndPoint( IPAddress.Parse("192.168.1.8"), 50007); server = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); try { server.Connect(ipEndPoint); } catch (SocketException) { MessageBox.Show("Unable to connect to server.", "Error", MessageBoxButtons.OK, MessageBoxIcon.Error); return; }
The above code is self-explanatory as I am just connecting to Raspberry PI.
In the form load event, I have to initialize chart values and add 3 line series to my CartesianChart
for X, Y and Z axis respectively. In my case the name of the Cartesian Chart is ADXLViz
.
Values_X = new ChartValues<ObservableValue>(); Values_Y = new ChartValues<ObservableValue>(); Values_Z = new ChartValues<ObservableValue>(); ADXLViz.Series.Add(new LineSeries { Values = Values_X, Title = "X", StrokeThickness = 4, PointGeometrySize = 0, DataLabels = true }); ADXLViz.Series.Add(new LineSeries { Values = Values_Y, Title = "Y", StrokeThickness = 4, PointGeometrySize = 0, DataLabels = true }); ADXLViz.Series.Add(new LineSeries { Values = Values_Z, Title = "Z", StrokeThickness = 4, PointGeometrySize = 0, DataLabels = true });
Play around with different properties in the LineSeries
class and set the output that suits your need or your eye. Notice the Values properties in the LineSeries
class which holds the value which is received from Raspberry PI.
I am requesting the readings from Raspberry PI every 500ms and to do this I am using a Timer
class. This is easy to use and configure. Just drag and drop the Timer
control from the toolbox. In the properties change the Interval
property to 500
and Enabled
to True
. After this I set the Tick
event which will request the new readings every 500ms.
string stringData; server.Send(Encoding.ASCII.GetBytes("adxl")); data = new byte[1024]; int recv = server.Receive(data); stringData = Encoding.ASCII.GetString(data, 0, recv); string[] adxl = stringData.Replace(" ", "").Split('|'); Values_X.Add(new ObservableValue(Convert.ToDouble(adxl[0].Split(':')[1]))); Values_Y.Add(new ObservableValue(Convert.ToDouble(adxl[1].Split(':')[1]))); Values_Z.Add(new ObservableValue(Convert.ToDouble(adxl[2].Split(':')[1]))); if (Values_X.Count > 10) Values_X.RemoveAt(0); if (Values_Y.Count > 10) Values_Y.RemoveAt(0); if (Values_Z.Count > 10) Values_Z.RemoveAt(0); X_Label.Text = Convert.ToString(adxl[0].Split(':')[1]); Y_Label.Text = Convert.ToString(adxl[1].Split(':')[1]); Z_Label.Text = Convert.ToString(adxl[2].Split(':')[1]);
The stringData
variable holds the response or reading which is received from Raspberry PI. If you check the Python code above you will see that the response is being sent in a single string called data
. I am splitting the string here and extracting the values and setting it to ChartValues<ObservableValue>
object. This will render all the 3 line series chart and update it with the readings received from PI. But the problem here will be that in few minutes the chart will be hard to see due to lot of data congestion in chart. In order to overcome this problem, I have removed the first value from all the 3 line series when the chart displays more than 10 values. You can change the value from 10 to whatever suits you.
The overall idea of building this application is to see whether it is possible or easy to communicate from Raspberry PI apart from using frameworks like WebioPI or Flask. The complete source code for Raspberry PI and Windows Forms application is available on Github along with Fritzing sketch file and additional instructions to install the dependencies.