├── .gitmodules ├── CMakeLists.txt ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── command_center_node ├── .gitignore ├── bower.json ├── config.json ├── package.json ├── public │ └── index.html └── server.js ├── img ├── rpi2_command_center.png └── rpi2_remote_monitoring.png └── samples ├── CMakeLists.txt ├── build.sh ├── platform_specific ├── CMakeLists.txt ├── inc │ ├── bme280.h │ └── locking.h └── src │ ├── bme280.c │ └── locking.c ├── remote_monitoring ├── CMakeLists.txt ├── remote_monitoring.c └── remote_monitoring.h └── simplesample_amqp ├── CMakeLists.txt ├── linux └── main.c ├── simplesample_amqp.c └── simplesample_amqp.h /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "azure-iot-sdks"] 2 | path = azure-iot-sdks 3 | url = https://github.com/Azure/azure-iot-sdks.git 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #Copyright (c) Microsoft. All rights reserved. 2 | #Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | cmake_minimum_required(VERSION 2.8.11) 5 | 6 | project(iot-hub-c-raspberrypi-getstartedkit) 7 | 8 | option(use_amqp_kit "use samples provided in the kit" ON) 9 | 10 | add_subdirectory(azure-iot-sdks/c) 11 | 12 | add_subdirectory(samples) 13 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Azure samples 2 | 3 | Thank you for your interest in contributing to Azure samples! 4 | 5 | ## Ways to contribute 6 | 7 | You can contribute to [Azure samples](https://azure.microsoft.com/documentation/samples/) in a few different ways: 8 | 9 | - Submit feedback on [this sample page](https://azure.microsoft.com/documentation/samples/iot-hub-c-raspberrypi-getstartedkit/) whether it was helpful or not. 10 | - Submit issues through [issue tracker](https://github.com/Azure-Samples/iot-hub-c-raspberrypi-getstartedkit/issues) on GitHub. We are actively monitoring the issues and improving our samples. 11 | - If you wish to make code changes to samples, or contribute something new, please follow the [GitHub Forks / Pull requests model](https://help.github.com/articles/fork-a-repo/): Fork the sample repo, make the change and propose it back by submitting a pull request. -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 Microsoft Corporation 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | --- 2 | services: iot-hub, stream-analytics, event-hubs, web-apps, documentdb, storage-accounts 3 | platforms: c ,raspberry-pi 4 | author: hegate 5 | --- 6 | 7 | # Get Started with Microsoft Azure IoT Starter Kit - Raspberry Pi2 and Pi3 8 | 9 | This page contains technical information to help you get familiar with Azure IoT using the Azure IoT Starter Kit - Raspberry Pi2 and Pi3. You will find two tutorials that will walk you through different scenarios: the first tutorial will show you how to connect your Azure IoT Starter kit to our Remote Monitoring preconfigured solution from Azure IoT Suite. In the second tutorial, you will leverage Azure IoT services to create your own IoT architecture. 10 | 11 | You can choose to start with whichever tutorial you want to. If you've never worked with Azure IoT services before, we encourage you to start with the Remote Monitoring solution tutorial, because all of the Azure services will be provisioned for you in a built-in preconfigured solution. Then you can explore how each of the services work by going through the second tutorial. 12 | 13 | We hope you enjoy the process. Please provide feedback if there's anything that we can improve. 14 | 15 | *** 16 | **Don't have a kit yet?:** Click [here](http://azure.com/iotstarterkits) 17 | *** 18 | 19 | - [Connecting your Raspberry Pi2 or Pi3 to the Azure IoT Suite Remote Monitoring Solution](#connecting-your-raspberry-pi) 20 | - [Using Microsoft Azure IoT Services to Identify Temperature Anomalies](#identify-temperature-anomalies) 21 | 22 | 23 | # Connecting your Raspberry Pi2 or Pi3 to the Azure IoT Suite Remote Monitoring Solution 24 | 25 | This tutorial describes the process of taking your Microsoft Azure IoT Starter Kit for Raspberry Pi2 and Pi3, and using it to develop a temperature and humidity reader that can communicate with the cloud using the Raspbian OS and Microsoft Azure IoT SDK. For Windows 10 IoT Core samples, please visit [windowsondevices.com](http://www.windowsondevices.com/). 26 | 27 | ## Table of Contents 28 | 29 | - [1.1 Tutorial Overview](#section1.1) 30 | - [1.2 Before Starting](#section1.2) 31 | - [1.2.1 Required Software](#section1.2.1) 32 | - [1.2.2 Required Hardware](#section1.2.2) 33 | - [1.3 Create a New Azure IoT Suite Remote Monitoring solution and Add Device](#section1.3) 34 | - [1.4 Prepare the Device](#section1.4) 35 | - [1.4.1 Log in and Access the Terminal](#section1.4.1) 36 | - [1.4.2 Log in Using PuTTY](#section1.4.2) 37 | - [1.4.2.1 Log in using Linux or Mac OS](#section1.4.2.1) 38 | - [1.5 Configure the Remote Monitoring device sample](#section1.5) 39 | - [1.5.1 Clone repositories](#section1.5.1) 40 | - [1.5.2 Update the Connection String](#section1.5.2) 41 | - [1.6 Build the Modified Sample](#section1.6) 42 | - [1.7 View the Sensor Data from the IoT Suite Portal](#section1.7) 43 | - [1.8 Next steps](#section1.8) 44 | 45 | 46 | ## 1.1 Tutorial Overview 47 | 48 | In this tutorial, you'll be doing the following: 49 | 50 | - Setting up your environment on Azure using the Microsoft Azure IoT Suite Remote Monitoring preconfigured solution, getting a large portion of the set-up that would be required done in one step. 51 | - Setting your device and sensors up so that it can communicate with both your computer, and Azure IoT. 52 | - Updating the device code sample to include our connection data and send it to Azure IoT to be viewed remotely. 53 | 54 | 55 | ## 1.2 Before Starting 56 | 57 | 58 | ### 1.2.1 Required Software 59 | 60 | - An SSH client – This makes it so you can remotely access the Raspberry Pi’s command line remotely from your computer 61 | - Windows doesn’t have a built-in SSH client. We recommend using [PuTTY](http://www.putty.org/) 62 | - Many Linux distributions and Mac OS has SSH built into their terminal. If yours does not, we recommend OpenSSH 63 | - See also: [SSH Using Linux or Mac OS](https://www.raspberrypi.org/documentation/remote-access/ssh/unix.md) 64 | 65 | 66 | ### 1.2.2 Required Hardware 67 | 68 | - Microsoft Azure IoT Starter Kit 69 | - 8GB MicroSD Card (Comes with the kit, flashed with Windows 10 IoT Core) 70 | - A USB Mini cable 71 | - An Ethernet cable or Wi-Fi dongle 72 | 73 | 74 | ## 1.3 Create a New Azure IoT Suite Remote Monitoring solution and Add Device 75 | 76 | - Log in to [Azure IoT Suite](https://www.azureiotsuite.com/) with your Microsoft account and click **Create a New Preconfigured Solution** 77 | 78 | *** 79 | **Note:** Creating an account is free. Click here to get your [Azure free trial](https://azure.microsoft.com/en-us/pricing/free-trial/) 80 | *** 81 | 82 | - Click select in the **Remote Monitoring** option 83 | - Type in a solution name. For this tutorial we’ll be using “PiSuite” 84 | 85 | *** 86 | **Note:** Make sure to copy down the names and connection strings mentioned into a text document for reference later. 87 | *** 88 | 89 | - Choose your subscription plan and geographic region, then click **Create Solution** 90 | - Wait for Azure to finish provisioning your IoT suite (this process may take up to 10 minutes), and then click **Launch** 91 | 92 | *** 93 | **Note:** You may be asked to log back in. This is to ensure your solution has proper permissions associated with your account. 94 | *** 95 | 96 | - Open the link to your IoT Suite’s “Solution Dashboard.” You may have been redirected there already. 97 | - This opens your personal remote monitoring site at the URL <Your IoT Hub suite name>.azurewebsites.net (e.g. PiSuite.azurewebsites.net) 98 | - Click **Add a Device** at the lower left hand corner of your screen 99 | - Add a new **custom device** 100 | - Enter your desired device ID. In this case we’ll use “RaspPi”, and then click **Create** 101 | - Make note of your device ID, Device Key, and IoT Hub Hostname to enter into the code you’ll run on your device later 102 | 103 | *** 104 | **Warning:** The Remote Monitoring solution provisions a set of Azure IoT Services in your Azure account. It is meant to reflect a real enterprise architecture and thus its Azure consumption is quite heavy. To avoid unnecessary Azure consumption, we recommend you delete the preconfigured solution in azureiotsuite.com once you are done with your work (since it is easy to recreate). Alternatively, if you want to keep it up and running you can do several things to reduce consumption: 105 | 106 | 1) Visit this [guide](https://github.com/Azure/azure-iot-remote-monitoring/blob/master/Docs/configure-preconfigured-demo.md) to run the solution in demo mode and reduce the Azure consumption. 107 | 108 | 2) Disable the simulated devices created with the solution (Go to Devices>>Select the device>> on the device details menu on the right, clich on Disable Device. Repeat with all the simulated devices). 109 | 110 | 3) **Stop** your remote monitoring solution while you are working on the next steps. (See: [Troubleshooting](#troubleshooting)) 111 | *** 112 | 113 | 114 | ## 1.4 Prepare the Device 115 | 116 | If this is the first time you are using Raspberry Pi, now is the time to set it up. If you’ll be using Windows, please use [windowsondevices.com](http://www.windowsondevices.com/) for detailed 117 | guidelines on how to get started with the Raspberry Pi. If you’re using Linux, Raspberry Pi and Adafruit have a set of tutorials and videos to help you get started. 118 | 119 | Please visit the following links: 120 | 121 | - [Raspberry Pi NOOBS setup page](https://www.raspberrypi.org/help/noobs-setup/) 122 | - Using [this image](https://github.com/Azure-Samples/iot-hub-c-raspberrypi-getstartedkit/blob/master/img/rpi2_remote_monitoring.png?raw=true) as a reference, connect your BME280 to the breadboard and to the Raspberry Pi 123 | 124 | *** 125 | **Note:** Column on the left corresponds to the sensor and on the right to the board. On the image, the BME280 is connected between pins 15A(VIN) and 21A(CS). 126 | *** 127 | 128 | | Pi Pin | End | Cable Color | 129 | | ----------------------- | ---------------------- | ------------: | 130 | | SPI_CE0 (Pin 24) | CS (Pin 21A) | Blue cable | 131 | | SPI_SCLK (Pin 23) | SCK (18A) | Yellow cable | 132 | | SPI_MISO (Pin 21) | SDO (19A ) | White cable | 133 | | SPI_MOSI (Pin 19) | SDI (Pin 20A) | Green cable | 134 | | GND (Pin 6) | GND (Pin 17A) | Black cable | 135 | | 3.3V (Pin 1) | 3Vo (Pin 16A) | Red cable | 136 | 137 | **At the end of your work, your Raspberry Pi should be connected with a working sensor.** 138 | 139 | 140 | ### 1.4.1 Log in and Access the Terminal 141 | 142 | The default login for Raspbian is username `pi` with password `raspberry`. If you use the Raspbian interface directly, in the task bar up top, you can launch the Terminal using the 3rd icon from the left – The one that looks like a monitor. 143 | 144 | 145 | ### 1.4.2 Log in Using PuTTY 146 | 147 | - You need to discover the IP address of your Raspberry Pi before you can connect using PuTTY. Type `hostname -I` in a command prompt to discover your IP. For more information see: [https://www.raspberrypi.org/documentation/remote-access/ip-address.md](https://www.raspberrypi.org/documentation/remote-access/ip-address.md) 148 | - With the Raspberry Pi on and running, open an SSH terminal program such as [PuTTY](http://www.putty.org/) on your desktop machine. 149 | - Use the IP address from previous step as the Host Name, Port=22, and Connection type=SSH to complete the connection. 150 | - When prompted, log in with username `pi`, and password `raspberry`. 151 | 152 | 153 | #### 1.4.2.1 Log in using Linux or Mac OS 154 | 155 | - See: [SSH Using Linux of Mac OS](https://www.raspberrypi.org/documentation/remote-access/ssh/unix.md) 156 | 157 | 158 | ## 1.5 Configure the Remote Monitoring device sample 159 | 160 | Now we can download the Remote Monitoring device sample, input your device credentials (i.e. your "Connection String") and start sending data from the Pi to our Azure Remote Monitoring solution. 161 | 162 | 163 | ### 1.5.1 Clone repositories 164 | 165 | Clone the following repositories and combine them by entering the following commands on your Pi: 166 | 167 | ``` 168 | cd ~ 169 | git clone --recursive https://github.com/Azure-Samples/iot-hub-c-raspberrypi-getstartedkit.git 170 | git clone --recursive https://github.com/WiringPi/WiringPi.git 171 | ``` 172 | 173 | Now, we need to update device connection string 174 | 175 | 176 | ### 1.5.2 Update the Connection String 177 | 178 | - Edit the file by entering the following command: 179 | 180 | ``` 181 | nano ~/iot-hub-c-raspberrypi-getstartedkit/samples/remote_monitoring/remote_monitoring.c 182 | ``` 183 | 184 | - Use the arrow keys to navigate to the following lines: 185 | 186 | ``` 187 | static const char* deviceId = "[Device Id]"; 188 | static const char* deviceKey = "[Device Key]"; 189 | static const char* hubName = "[IoTHub Name]"; 190 | static const char* hubSuffix = "[IoTHub Suffix, i.e. azure-devices.net]"; 191 | ``` 192 | - Replace the placeholder with your device and IoT Hub information you created and saved at the beginning of this tutorial. In our example: 193 | - Device Id --> `RaspPi` 194 | - Device Key --> <Azure device key ended with `==`> 195 | - IoTHub Name --> `PiSuite` 196 | - IoTHub Suffix, i.e. azure-devices.net --> `azure-devices.net` 197 | - Save and exit with `Control-o, Enter, Control-x` 198 | 199 | 200 | ## 1.6 Build the Modified Sample 201 | 202 | Now that you’re exited out of Nano, install the prerequisite packages for the Microsoft Azure IoT Device SDK for C by issuing the following commands using the terminal (either on the device or through an SSH client like PuTTY): 203 | 204 | ``` 205 | sudo apt-get update 206 | sudo apt-get install curl libcurl4-openssl-dev uuid-dev uuid g++ make cmake git unzip openjdk-7-jre libssl-dev libncurses-dev subversion gawk 207 | ``` 208 | 209 | - Now go ahead and build the updated sample solution by entering the following: 210 | 211 | ``` 212 | cd ~/iot-hub-c-raspberrypi-getstartedkit/ 213 | sudo ~/iot-hub-c-raspberrypi-getstartedkit/azure-iot-sdks/c/build_all/linux/setup.sh 214 | chmod +x ~/iot-hub-c-raspberrypi-getstartedkit/samples/build.sh 215 | ~/iot-hub-c-raspberrypi-getstartedkit/samples/build.sh 216 | ``` 217 | 218 | - Before running the program we need to enable the SPI drive to install by default at boot. 219 | 220 | ``` 221 | sudo nano /boot/config.txt 222 | ``` 223 | 224 | - Scroll down and find the line: 225 | 226 | ``` 227 | #dtparam=spi=on 228 | ``` 229 | 230 | - Delete the `#` at the beginning of the line to uncomment it. 231 | - Save and exit with `Control-o`, `Enter`, `Control-x`. 232 | - Reboot the Raspberry Pi to enable the spi, it will disconnect the terminal, you will need to login again. Run the command: 233 | 234 | ``` 235 | sudo reboot 236 | ``` 237 | 238 | - Now that everything is compiled, it’s time to run the program. Enter the command: 239 | 240 | ``` 241 | sudo ~/cmake/samples/remote_monitoring/remote_monitoring 242 | ``` 243 | 244 | If all goes well, you will begin to see data streaming! 245 | Press `ctrl-c` to exit at any time. Below is a sample of the expected command prompt output: 246 | 247 | ``` 248 | Humidity = 48.4% Temperature = 23.9*C 249 | Sending sensor value Temperature = 23.9*C, Humidity = 48.4% 250 | IoTHubClient accepted the message for delivery 251 | ``` 252 | 253 | 254 | ## 1.7 View the Sensor Data from the IoT Suite Portal 255 | 256 | - Once you have the sample running, visit your dashboard by visiting azureiotsuite.com and clicking “Launch” on your solution 257 | - Make sure the “Device to View” in the upper right is set to your device 258 | - If the demo is running, you should see the graph change as your data updates in real time! 259 | 260 | *** 261 | **Note:** Make sure you delete or **stop** your remote monitoring solution once you have completed this to avoid unnecessary Azure consumption! (See: [Troubleshooting](#troubleshooting)) 262 | *** 263 | 264 | 265 | ## 1.8 Next steps 266 | 267 | Please visit our [Azure IoT Dev Center](https://azure.microsoft.com/en-us/develop/iot/) for more samples and documentation on Azure IoT. 268 | 269 | 270 | # Using Microsoft Azure IoT Services to Identify Temperature Anomalies 271 | 272 | This tutorial describes the process of taking your Microsoft Azure IoT Starter Kit for Raspberry Pi 2 and Pi 3, and using it to develop a temperature and humidity reader that can communicate with Microsoft Azure IoT Services, process the data, detects abnormal data, and sends that back to the Pi for use. We will be using 273 | the Raspbian OS and Microsoft Azure IoT SDK. For Windows 10 IoT Core samples, 274 | please visit [windowsondevices.com](http://www.windowsondevices.com/). 275 | 276 | ## Table of Contents 277 | 278 | - [2.1 Tutorial Overview](#section2.1) 279 | - [2.2 Requirements](#section2.2) 280 | - [2.2.1 Required Software](#section2.2.1) 281 | - [2.2.2 Required Hardware](#section2.2.2) 282 | - [2.3 Create a New Microsoft Azure IoT Hub and Add Device](#section2.3) 283 | - [2.4 Prepare the Device](#section2.4) 284 | - [2.4.1 Log in and Access the Terminal](#section2.4.1) 285 | - [2.4.2 Log in Using PuTTY](#section2.4.2) 286 | - [2.5 Create an Event Hub](#section2.5) 287 | - [2.6 Create a Storage Account for Table Storage](#section2.6) 288 | - [2.7 Create a Stream Analytics job to Save Sensor Data in Table Storage and Raise Alerts](#section2.7) 289 | - [2.8 Node Application Setup](#section2.8) 290 | - [2.9 Configure the Command Center device sample](#section2.9) 291 | - [2.9.1 Update the Connection Data](#section2.9.1) 292 | - [2.10 Build the Modified Sample](#section2.10) 293 | - [2.11 Next steps](#section2.11) 294 | 295 | 296 | ## 2.1 Tutorial Overview 297 | 298 | This tutorial has the following steps: 299 | - Provision an IoT Hub instance on Microsoft Azure and adding your device. 300 | - Prepare the device, get connected to the device, and set it up so that it can read sensor data. 301 | - Configure your Microsoft Azure IoT services by adding Event Hub, Storage Account, and Stream Analytics resources. 302 | - Prepare your local web solution for monitoring and sending commands to your device. 303 | - Update the sample code to respond to commands and include the data from our sensors, sending it to Microsoft Azure to be viewed remotely. 304 | 305 | Here is a breakdown of the data flow: 306 | - The application running on the Raspberry Pi will get temperature data from the temperature sensor and it will send them to the IoT Hub 307 | - A Stream Analytics job will read the data from IoT Hub and write them to an Azure Storage Table. Also, if an anomaly is detected, then this job will write data to an Event Hub 308 | - The Node.js application that is running on your computers will read the data from the Azure Storage Table and the Event Hub and will present them to the user 309 | 310 | The end result will be a functional command center where you can view the history of your device's sensor data, a history of alerts, and send commands back to the device. 311 | 312 | 313 | ## 2.2 Requirements 314 | 315 | 316 | ### 2.2.1 Required Software 317 | 318 | - [Git](https://git-scm.com/downloads) - For cloning the required repositories 319 | - Node.js - For the Node application, we will go over this later. 320 | - An SSH client – This makes it so you can remotely access the Raspberry Pi’s command line remotely from your computer 321 | - Windows doesn’t have a built-in SSH client. We recommend using [PuTTY](http://www.putty.org/) 322 | - Many Linux distributions and Mac OS has SSH built into their terminal. If yours does not, we recommend OpenSSH 323 | - See also: [SSH Using Linux on Mac OS](https://www.raspberrypi.org/documentation/remote-access/ssh/unix.md) 324 | 325 | 326 | ### 2.2.2 Required Hardware 327 | 328 | - Microsoft Azure IoT Starter Kit 329 | - 8GB MicroSD Card (comes with the kit, flashed with Windows 10 IoT Core) 330 | - A USB Mini cable 331 | - An Ethernet cable or Wi-Fi dongle 332 | 333 | 334 | ## 2.3 Create a New Microsoft Azure IoT Hub and Add Device 335 | 336 | - To create your Microsoft Azure IoT Hub and add a device, follow the instructions outlined in the [Setup IoT Hub Microsoft Azure Iot SDK page](https://github.com/Azure/azure-iot-sdks/blob/master/doc/setup_iothub.md). 337 | - We named our IoT Hub `raspPiIoT` 338 | 339 | *** 340 | **Note:** Make sure to copy down the names and connection strings mentioned into a text document for reference later. 341 | *** 342 | 343 | - After creating your device, make note of your connection string to enter into the code you’ll run on your device later 344 | 345 | 346 | ## 2.4 Prepare the Device 347 | 348 | If this is the first time you are using Raspberry Pi, now it’s the time to set it up. If you’ll be using Windows, please use [windowsondevices.com](http://www.windowsondevices.com/) for detail 349 | guidelines on how to get started with the Raspberry Pi. If you’re using Linux, Raspberry Pi and Adafruit have a set of tutorials and videos to help you get started. 350 | 351 | Please visit the following links: 352 | 353 | - [Raspberry Pi NOOBS setup page](https://www.raspberrypi.org/help/noobs-setup/) 354 | - Using [this image](https://github.com/Azure-Samples/iot-hub-c-raspberrypi-getstartedkit/blob/master/img/rpi2_command_center.png?raw=true) as a reference, connect your LEDs and your BME280 to the breadboard and the Raspberry Pi. 355 | 356 | *** 357 | **Note:** Column on the left corresponds to the sensor and on the right to the board. On the image, the sensor is place between 15E(VIN) and 21E(CS). The - symbol refers to the blue row on the board, with the pins counting from the left starting at 15. See the diagram above for more reference. 358 | 359 | **Note:** The resistor can change a little from one kit to another, e.g. it can be 330 Ohm (orange, orange, brown) or 560 Ohm (green, blue, brown). Both will work with success. 360 | *** 361 | 362 | | Raspberry Pi Pins | Breadboard ends | Cable Color | 363 | | ----------------------- | ---------------------- | ------------: | 364 | | SPI_CE0 (Pin 24) | CS (Pin 21A) | Blue cable | 365 | | SPI_SCLK (Pin 23) | SCK (18A) | Yellow cable | 366 | | SPI_MISO (Pin 21) | SDO (19A ) | White cable | 367 | | SPI_MOSI (Pin 19) | SDI (Pin 20A) | Green cable | 368 | | GND (Pin 6) | Pin 3- | Black cable | 369 | | 3.3V (Pin 1) | 3Vo (Pin 16A) | Red cable | 370 | | GPIO 24 (Pin 18) | Pin 10D | Green cable | 371 | | GPIO 23 (Pin 16) | Pin 7D | Red cable | 372 | | Pin 13- | GND (Pin 17A) | Black cable | 373 | 374 | | Start | End | Connector | 375 | | ----------------------- | ---------------------- | ------------: | 376 | | Pin 4- | Pin 6B | Resistor | 377 | | Pin 6- | Pin 9B | Resistor | 378 | | Pin 6E | Pin 7E | Red LED (long leg) | 379 | | Pin 9E | Pin 10E | Green LED (long leg) | 380 | 381 | **At the end of your work, your Raspberry Pi should be connected with a working sensor.** 382 | 383 | 384 | ### 2.4.1 Log in and Access the Terminal 385 | 386 | The default login for Raspbian is username `pi` with password `raspberry`. If you use the Raspbian interface directly, in the task bar up top, you can launch the Terminal using the 3rd icon from the left – The one that looks like a monitor. 387 | 388 | 389 | ### 2.4.2 Log in Using PuTTY 390 | 391 | - You need to discover the IP address of your Raspberry Pi before you can connect using PuTTY. Type `hostname -I` in a command prompt to discover your IP.For more information see: [https://www.raspberrypi.org/documentation/remote-access/ip-address.md](https://www.raspberrypi.org/documentation/remote-access/ip-address.md) 392 | - With the Raspberry Pi on and running, open an SSH terminal program such as [PuTTY](http://www.putty.org/) on your desktop machine. 393 | - Use the IP address from previous step as the Host Name, Port=22, and Connection type=SSH to complete the connection. 394 | - When prompted, log in with username `pi`, and password `raspberry`. 395 | 396 | 397 | ## 2.5 Create an Event Hub 398 | Event Hub is an Azure IoT publish-subscribe service that can ingest millions of events per second and stream them into multiple applications, services or devices. 399 | 400 | - Log on to the [Microsoft Azure Portal](https://portal.azure.com/) 401 | - Click on **New** -> **Internet of Things**-> **Event Hub** 402 | - Enter the following settings for the Event Hub Namespace (use a name of your choice for the event hub and the namespace): 403 | - Name: `Your choice` (we chose `PiSuite`) 404 | - Pricing Tier: `Basic` 405 | - Subscription: `Your choice` 406 | - Resource Group: `Your choice` 407 | - Location: `Your choice` 408 | - Click on **Create** 409 | - Wait until the Event Hub Namespace is created, and then create an Event Hub using the following steps: 410 | - Click on your `PiSuite` Event Hub Namespace (or pick any other name that you used) 411 | - Click the **Add Event Hub** 412 | - Name: `piEventHub` 413 | - Click on **Create** 414 | - Wait until the new Event Bus is created 415 | - Click on the **Event Hubs** arrow in the **Overview** tab (might require a few clicks, until the UI is updated) 416 | - Select the `piEventHub` eventhub and go in the **Configure** tab in the **Shared Access Policies** section, add a new policy: 417 | - Name = `readwrite` 418 | - Permissions = `Send, Listen` 419 | - Click **Save** at the bottom of the page, then click the **Dashboard** tab near the top and click on **Connection Information** at the bottom 420 | - _Copy down the connection string for the `readwrite` policy you created._ 421 | - From the your IoT Hub Settings (The Resource that has connected dots) on the [Microsoft Azure Portal](https://portal.azure.com/), click the **Messaging blade** (found in your settings), write down the _Event Hub-compatible name_ 422 | - Look at the _Event-hub-compatible Endpoint_, and write down this part: sb://**thispart**.servicebus.windows.net/ we will call this one the _IoTHub EventHub-compatible namespace_ 423 | 424 | 425 | ## 2.6 Create a Storage Account for Table Storage 426 | Now we will create a service to store our data in the cloud. 427 | - Log on to the [Microsoft Azure Portal](https://portal.azure.com/) 428 | - In the menu, click **New** and select **Data + Storage** then **Storage Account** 429 | - Name: `Your choice` (we chose `pistorage`) 430 | - Deployment model: `Classic` 431 | - Performance: `Standard` 432 | - Replication: `Read-access geo-redundant storage (RA-GRS)` 433 | - Subscription: `Your choice` 434 | - Resource Group: `Your choice` 435 | - Location: `Your choice` 436 | - Once the account is created, find it in the **resources blade** or click on the **pinned tile**, go to **Settings**, **Keys**, and write down the _primary connection string_. 437 | 438 | 439 | ## 2.7 Create a Stream Analytics job to Save Sensor Data in Table Storage and Raise Alerts 440 | Stream Analytics is an Azure IoT service that streams and analyzes data in the cloud. We'll use it to process data coming from your device. 441 | 442 | - Log on to the [Microsoft Azure Portal](https://portal.azure.com/) 443 | - In the menu, click **New**, then click **Internet of Things**, and then click **Stream Analytics Job** 444 | - Enter a name for the job (We chose “PiStorageJob”), a preferred region, then choose your subscription. At this stage you are also offered to create a new or to use an existing resource group. Choose the resource group you created earlier. 445 | - Once the job is created, open your **Job’s blade** or click on the **pinned tile**, and find the section titled _“Job Topology”_ and click the **Inputs** tile. In the Inputs blade, click on **Add** 446 | - Enter the following settings: 447 | - Input Alias = _`TempSensors`_ 448 | - Source Type = _`Data Stream`_ 449 | - Source = _`IoT Hub`_ 450 | - IoT Hub = _`PiSuite`_ (use the name for the IoT Hub you create before) 451 | - Shared Access Policy Name = _`iothubowner`_ 452 | - Shared Access Policy Key = _The `iothubowner` primary key can be found in your IoT Hub Settings -> Shared access policies_ 453 | - IoT Hub Consumer Group = "" (leave it to the default empty value) 454 | - Event serialization format = _`JSON`_ 455 | - Encoding = _`UTF-8`_ 456 | 457 | - Back to the **Stream Analytics Job blade**, click on the **Query tile** (next to the Inputs tile). In the Query settings blade, type in the below query and click **Save**: 458 | 459 | ``` 460 | SELECT 461 |     DeviceId, 462 |     EventTime, 463 |     MTemperature as TemperatureReading 464 | INTO 465 |     TemperatureTableStorage 466 | from TempSensors 467 | WHERE 468 |    DeviceId is not null 469 |    and EventTime is not null 470 | 471 | SELECT 472 |     DeviceId, 473 |     EventTime, 474 |     MTemperature as TemperatureReading 475 | INTO    476 |     TemperatureAlertToEventHub 477 | FROM 478 |     TempSensors 479 | WHERE MTemperature>25 480 | ``` 481 | 482 | *** 483 | **Note:** You can change the `25` to `0` when you're ready to generate alerts to look at. This number represents the temperature in degrees celsius to check for when creating alerts. 25 degrees celsius is 77 degrees fahrenheit. 484 | *** 485 | 486 | - Back to the **Stream Analytics Job blade**, click on the **Outputs** tile and in the **Outputs blade**, click on **Add** 487 | - Enter the following settings then click on **Create**: 488 | - Output Alias = _`TemperatureTableStorage`_ 489 | - Sink = _`Table Storage`_ 490 | - Subscription = _`Provide table settings storage manually`_ 491 | - Storage account = _`pistorage`_ (The storage account you created earlier) 492 | - Storage account key = _(The primary key for the storage account made earlier, can be found in Settings -> Keys -> Primary Access Key)_ 493 | - Table Name = _`TemperatureRecords`_ (Your choice - If the table doesn’t already exist, Local Storage will create it) 494 | - Partition Key = _`DeviceId`_ 495 | - Row Key = _`EventTime`_ 496 | - Batch size = _`1`_ 497 | - Back to the **Stream Analytics Job blade**, click on the **Outputs tile**, and in the **Outputs blade**, click on **Add** 498 | - Enter the following settings then click on **Create**: 499 | - Output Alias = _`TemperatureAlertToEventHub`_ 500 | - Sink = _`Event Hub`_ 501 | - Subscription = _`Provide table settings storage manually`_ 502 | - Service Bus Namespace = _`PiSuite`_ 503 | - Event Hub Name = _`piEventHub`_ (The Event Hub you made earlier) 504 | - Event Hub Policy Name = _`readwrite`_ 505 | - Event Hub Policy Key = _`Primary Key for readwrite Policy name`_ (That's the one you wrote down after creating the event hub) 506 | - Partition Key Column = _`0`_ 507 | - Event Serialization format = _`JSON`_ 508 | - Encoding = _`UTF-8`_ 509 | - Format = _`Line separated`_ 510 | - Back in the** Stream Analytics blade**, start the job by clicking on the **Start **button at the top 511 | 512 | *** 513 | **Note:** Make sure to **stop** your Command Center jobs once you have when you take a break or finish to avoid unnecessary Azure consumption! (See: [Troubleshooting](#troubleshooting)) 514 | *** 515 | 516 | 517 | ## 2.8 Node Application Setup 518 | 519 | - If you do not have it already, install Node.js and NPM. 520 | - Windows and Mac installers can be found here: https://nodejs.org/en/download/ 521 | - Ensure that you select the options to install NPM and add to your PATH. 522 | - Linux users can use the commands: 523 | 524 | ``` 525 | sudo apt-get update 526 | sudo apt-get install nodejs 527 | sudo apt-get install npm 528 | ``` 529 | 530 | - Additionally, make sure you have cloned the project repository locally by issuing the following command in your desired directory: 531 | 532 | ``` 533 | git clone --recursive https://github.com/Azure-Samples/iot-hub-c-raspberrypi-getstartedkit.git 534 | ``` 535 | 536 | - Open the `command_center_node` folder in your command prompt (`cd path/to/command_center_node`) and install the required modules by running the following: 537 | 538 | ``` 539 | sudo npm install -g bower 540 | sudo npm install 541 | bower install 542 | ``` 543 | 544 | - Open the `config.json` file and replace the information with your project. See the following for instructions on how to retrieve those values. 545 | 546 | - eventhubName: 547 | - Open the [Classic Azure Management Portal](https://manage.windowsazure.com) 548 | - Open the Service Bus namespace you created earlier 549 | - Switch to the **EVENT HUBS** page 550 | - You can see and copy the name of your event hub from that page 551 | - ehConnString: 552 | - Click on the name of the event hub from above to open it 553 | - Click on the "CONNECTION INFORMATION" button along the bottom. 554 | - From there, click the button to copy the readwrite shared access policy connection string. 555 | - deviceConnString: 556 | - Use the information on the [Manage IoT Hub](https://github.com/Azure/azure-iot-sdks/blob/master/doc/manage_iot_hub.md) to retrieve your device connection string using either the Device Explorer or iothub-explorer tools. 557 | - iotHubConnString: 558 | - In the [Azure Portal](https://portal.azure.com) 559 | - Open the IoT Hub you created previously. 560 | - Open the "Settings" blade 561 | - Click on the "Shared access policies" setting 562 | - Click on the "service" policy 563 | - Copy the primary connection string for the policy 564 | - storageAccountName: 565 | - In the [Azure Portal](https://portal.azure.com) 566 | - Open the classic Storage Account you created previously to copy its name 567 | - storageAccountKey: 568 | - Click on the name of the storage account above to open it 569 | - Click the "Settings" button to open the Settings blade 570 | - Click on the "Keys" setting 571 | - Click the button next to the "PRIMARY ACCESS KEY" top copy it 572 | - storageTableName: 573 | - This must match the name of the table that was used in the Stream Analytics table storage output above. 574 | - If you used the instructions above, you would have named it ***`TemperatureRecords`*** 575 | - If you named it something else, enter the name you used instead. 576 | 577 | ``` 578 | { 579 | "port": "3000", 580 | "eventHubName": "event-hub-name", 581 | "ehConnString": "Endpoint=sb://name.servicebus.windows.net/;SharedAccessKeyName=readwrite;SharedAccessKey=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=", 582 | "deviceId": "iot-hub-device-name", 583 | "iotHubConnString": "HostName=iot-hub-name.azure-devices.net;SharedAccessKeyName=service;SharedAccessKey=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=", 584 | "storageAcountName": "aaaaaaaaaaa", 585 | "storageAccountKey": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa==", 586 | "storageTable": "TemperatureRecords" 587 | } 588 | ``` 589 | 590 | - Now it is time to run it! Enter the following command: 591 | 592 | ``` 593 | node server.js 594 | ``` 595 | 596 | - You should then see something similar to: 597 | 598 | ``` 599 | app running on http://localhost:3000 600 | client connected 601 | ``` 602 | 603 | - Visit the url in your browser and you will see the Node app running! 604 | 605 | To deploy this project to the cloud using Azure, you can reference [Creating a Node.js web app in Azure App Service](https://azure.microsoft.com/en-us/documentation/articles/web-sites-nodejs-develop-deploy-mac/). 606 | 607 | Next, we will update your device so that it can interact with all the things you just created. 608 | 609 | 610 | ## 2.9 Configure the Command Center device sample 611 | 612 | Now we can download the sample solution repos and incorporate the data from the sensors and send it up to our Microsoft Azure Command Center solution. 613 | 614 | Clone the repositories by entering the following commands on your Pi: 615 | 616 | ``` 617 | cd ~ 618 | git clone --recursive https://github.com/Azure-Samples/iot-hub-c-raspberrypi-getstartedkit.git 619 | git clone --recursive https://github.com/WiringPi/WiringPi.git 620 | ``` 621 | 622 | Now, we need to update three things: 623 | 624 | - Include the required libraries (included in the git repository) 625 | - Include the Device ID 626 | - Update the connection string to use the string we saved above 627 | 628 | 629 | ### 2.9.1 Update the Connection Data 630 | 631 | To update the connection data, we need to update the source file. You can edit the file by entering the following command: 632 | 633 | ``` 634 | nano ~/iot-hub-c-raspberrypi-getstartedkit/samples/simplesample_amqp/simplesample_amqp.c 635 | ``` 636 | 637 | - Use the arrow keys to navigate to the following lines: 638 | 639 | ``` 640 | static const char* connectionString = "[device connection string]"; 641 | static char* deviceId = "[Device Name]"; 642 | ``` 643 | 644 | - Replace the placeholder with your device connection information you gathered at the beginning of this tutorial. It must looks like `HostName=.azure-devices.net;DeviceId=;SharedAccessKey=`. 645 | - Save and exit with `Control-o, Enter, Control-x` 646 | 647 | 648 | ## 2.10 Build the Modified Sample 649 | 650 | Now that you’re exited out of Nano, install the prerequisite packages for the Microsoft Azure IoT Device SDK for C by issuing the following commands using the terminal (either on the device or through an SSH client like PuTTY): 651 | 652 | ``` 653 | sudo apt-get update 654 | sudo apt-get install curl libcurl4-openssl-dev uuid-dev uuid g++ make cmake git unzip openjdk-7-jre libssl-dev libncurses-dev subversion gawk 655 | ``` 656 | 657 | - Now go ahead and build the updated sample solution by entering the following: 658 | 659 | ``` 660 | cd ~/iot-hub-c-raspberrypi-getstartedkit/ 661 | sudo ~/iot-hub-c-raspberrypi-getstartedkit/azure-iot-sdks/c/build_all/linux/setup.sh 662 | chmod +x ~/iot-hub-c-raspberrypi-getstartedkit/samples/build.sh 663 | ~/iot-hub-c-raspberrypi-getstartedkit/samples/build.sh 664 | ``` 665 | 666 | - Before running the program we need to enable the SPI drive to install by default at boot. 667 | 668 | ``` 669 | sudo nano /boot/config.txt 670 | ``` 671 | 672 | - Scroll down and find the line: 673 | 674 | ``` 675 | #dtparam=spi=on 676 | ``` 677 | 678 | - Delete the `#` at the beginning of the line to uncomment it. 679 | - Save and exit with `Control-o`, `Enter`, `Control-x`. 680 | - Reboot the Raspberry Pi to enable the spi, it will disconnect the terminal, you will need to login again. Run the command: 681 | 682 | ``` 683 | sudo reboot 684 | ``` 685 | 686 | - Now that everything is compiled, it’s time to run the program. Enter the command: 687 | 688 | ``` 689 | sudo ~/cmake/samples/simplesample_amqp/simplesample_amqp 690 | ``` 691 | 692 | You will now see data being sent off at regular intervals to 693 | Microsoft Azure. An alert has also been set to go off when it detects the temperature is above 25 degrees celsius (77'F). You can cup your hand around the sensor and blow warm air to raise the temperature and when the alert goes off, you will see the LED you’ve set up turn red! 694 | 695 | *** 696 | **Note:** If you're in a particularly hot or cold room, you may need to adjust the alert temperature specified in [Create a Stream Analytics job to Save Sensor Data in Table Storage and Raise Alerts](#create-a-stream-analytics-job-to-save-iot-data-in-table-storage-and-raise-alerts). 697 | *** 698 | 699 | Head back to your Node application and you will have a fully functional command center, complete with a history of sensor data, alerts that display when the temperature got outside a certain range, and commands that you can send to your device remotely. 700 | 701 | *** 702 | **Note:** Make sure to **stop** your Command Center jobs once you have when you finish to avoid unnecessary Azure consumption! (See: [Troubleshooting](#troubleshooting)) 703 | *** 704 | 705 | 706 | ## 2.11 Next steps 707 | 708 | Please visit our [Azure IoT Dev Center](https://azure.microsoft.com/en-us/develop/iot/) for more samples and documentation on Azure IoT. 709 | 710 | 711 | # Troubleshooting 712 | 713 | ## Stopping Provisioned Services 714 | 715 | - In the [Microsoft Azure Portal](https://portal.azure.com/) 716 | - Click on "All Resources" 717 | - For each Stream Analytics and Web App resource: 718 | - Click on the resource and click the "Stop" button in the new blade that appears 719 | - For each IoT Hub resource: 720 | - Click on the resource and click the "Devices" button in the new blade that appears 721 | - Click on each device in the list and click the "Disable" button that appears in the new blade at the bottom 722 | 723 | ## Data is not showing up in the Node.js application 724 | 725 | In this section we will explain how to see the data flowing from the Arduino application to the Node.js application: 726 | - Arduino application: In the Arduino IDE go to Tools -> Serial Monitor 727 | - IoT Hub: Use [Device Explorer](https://github.com/Azure/azure-iot-sdks/blob/master/tools/DeviceExplorer/doc/how_to_use_device_explorer.md) 728 | - Azure Storage Table: Use [Azure Storage Explorer](http://storageexplorer.com/) 729 | -------------------------------------------------------------------------------- /command_center_node/.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules 2 | /bower_components 3 | /.vscode 4 | -------------------------------------------------------------------------------- /command_center_node/bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "controller", 3 | "description": "", 4 | "main": "server.js", 5 | "license": "ISC", 6 | "moduleType": [], 7 | "homepage": "", 8 | "ignore": [ 9 | "**/.*", 10 | "node_modules", 11 | "bower_components", 12 | "test", 13 | "tests" 14 | ], 15 | "dependencies": { 16 | "angular": "^1.5.2", 17 | "bootstrap": "^3.3.6" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /command_center_node/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "port": "3000", 3 | "eventHubName": "event-hub-name", 4 | "ehConnString": "Endpoint=sb://name.servicebus.windows.net/;SharedAccessKeyName=readwrite;SharedAccessKey=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=", 5 | "deviceConnString": "HostName=name.azure-devices.net;DeviceId=device-id;SharedAccessKey=aaaaaaaaaaaaaaaaaaaaaa==", 6 | "iotHubConnString": "HostName=name.azure-devices.net;SharedAccessKeyName=device;SharedAccessKey=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa=", 7 | "storageAcountName": "aaaaaaaaaaa", 8 | "storageAccountKey": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa==", 9 | "storageTable": "storage-table-name" 10 | } -------------------------------------------------------------------------------- /command_center_node/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "controller", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "keywords": [], 10 | "author": "", 11 | "license": "ISC", 12 | "dependencies": { 13 | "azure-iot-common": "^1.0.1", 14 | "azure-event-hubs": "0.0.1", 15 | "azure-iot-device": "^1.0.1", 16 | "azure-iothub": "^1.0.2", 17 | "azure-storage": "^0.9.0", 18 | "body-parser": "^1.15.0", 19 | "express": "^4.13.4", 20 | "nconf": "^0.8.4" 21 | }, 22 | "devDependencies": { 23 | "gulp": "^3.9.1" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /command_center_node/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Azure IoT Hub 6 | 7 | 8 | 9 | 10 | 27 | 28 | 29 | 30 | 31 | 50 | 51 | 52 | 53 | 54 | 55 |
56 |
57 |

Current Temperature

The last recorded reading on device {{ latest_reading.deviceid }} was: 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 |
TemperatureTime
{{ latest_reading.temperature | number }}°C{{ latest_reading.eventtime | date : 'medium' }}
71 |
72 |
73 |

Alerts

74 | 75 |
{{ alert | json }}
76 |
77 | 78 |
79 |
80 |

Temperature History

81 |
82 |

Most recent {{ temperatures.length }} readings

83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 |
TemperatureTime
{{ t.temperature | number }}°C{{ t.eventtime | date : 'medium' }}
96 |
97 | No temperature history found 98 |
99 |
100 |
101 | 102 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /command_center_node/server.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | var express = require('express'); 4 | var bodyParser = require('body-parser'); 5 | 6 | var ServiceClient = require('azure-iothub').Client; 7 | var Message = require('azure-iot-common').Message; 8 | var EventHubClient = require('azure-event-hubs').Client; 9 | var DeviceConnectionString = require('azure-iot-device').ConnectionString; 10 | var azure = require('azure-storage'); 11 | var nconf = require('nconf'); 12 | 13 | nconf.argv().env().file('./config.json'); 14 | var eventHubName = nconf.get('eventHubName'); 15 | var ehConnString = nconf.get('ehConnString'); 16 | var deviceConnString = nconf.get('deviceConnString'); 17 | var storageAcountName = nconf.get('storageAcountName'); 18 | var storageAccountKey = nconf.get('storageAccountKey'); 19 | var storageTable = nconf.get('storageTable'); 20 | var iotHubConnString = nconf.get('iotHubConnString'); 21 | 22 | var deviceId = DeviceConnectionString.parse(deviceConnString).DeviceId; 23 | var iotHubClient = ServiceClient.fromConnectionString(iotHubConnString); 24 | 25 | // event hub alerts 26 | var alerts = []; 27 | var ehclient = EventHubClient.fromConnectionString(ehConnString, eventHubName) 28 | ehclient.createReceiver('$Default', '0', { startAfterTime: Date.now() }) 29 | .then(function(rx) { 30 | rx.on('errorReceived', function(err) { console.log(err); }); 31 | rx.on('message', function(message) { 32 | alerts.push(message.body); 33 | alerts = alerts.slice(-5); // keep last 5 34 | }); 35 | }); 36 | 37 | // table storage 38 | var tableSvc = azure.createTableService(storageAcountName, storageAccountKey); 39 | tableSvc.createTableIfNotExists(storageTable, function(err, result, response) { 40 | if (err) { 41 | console.log('error looking up table'); 42 | console.log(err) 43 | } 44 | }); 45 | 46 | // website setup 47 | var app = express(); 48 | var port = nconf.get('port'); 49 | app.use(express.static('public')); 50 | app.use(express.static('bower_components')); 51 | app.use(bodyParser.json()); 52 | 53 | // app api 54 | app.get('/api/alerts', function(req, res) { 55 | res.json(alerts); 56 | }); 57 | 58 | app.get('/api/temperatures', function(req, res) { 59 | var query = new azure.TableQuery() 60 | .select(['eventtime', 'temperaturereading', 'deviceid']) 61 | .where('PartitionKey eq ?', deviceId); 62 | tableSvc.queryEntities(storageTable, query, null, function(err, result, response) { 63 | res.json(result.entries.slice(-10)); 64 | }) 65 | }) 66 | 67 | var completedCallback = function(err, res) { 68 | if (err) { console.log(err); } 69 | else { console.log(res); } 70 | }; 71 | 72 | app.post('/api/command', function(req, res) { 73 | console.log('command received: ' + req.body.command); 74 | 75 | var command = "TurnFanOff"; 76 | if (req.body.command === 1) { 77 | command = "TurnFanOn"; 78 | } 79 | 80 | iotHubClient.open(function(err) { 81 | if (err) { 82 | console.error('Could not connect: ' + err.message); 83 | } else { // {"Name":"TurnFanOn","Parameters":""} 84 | var data = JSON.stringify({ "Name":command,"Parameters":"" }); 85 | console.log('Sending message: ' + data); 86 | iotHubClient.send(deviceId, data, printResultFor('send')); 87 | } 88 | }); 89 | 90 | // Helper function to print results in the console 91 | function printResultFor(op) { 92 | return function printResult(err, res) { 93 | if (err) { 94 | console.log(op + ' error: ' + err.toString()); 95 | } else { 96 | console.log(op + ' status: ' + res.constructor.name); 97 | } 98 | }; 99 | } 100 | 101 | res.end(); 102 | }); 103 | 104 | app.listen(port, function() { 105 | console.log('app running on http://localhost:' + port); 106 | }); 107 | -------------------------------------------------------------------------------- /img/rpi2_command_center.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure-Samples/iot-hub-c-raspberrypi-getstartedkit/0158a948b440e5b322a4477116e9fcf6d1b29ed6/img/rpi2_command_center.png -------------------------------------------------------------------------------- /img/rpi2_remote_monitoring.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Azure-Samples/iot-hub-c-raspberrypi-getstartedkit/0158a948b440e5b322a4477116e9fcf6d1b29ed6/img/rpi2_remote_monitoring.png -------------------------------------------------------------------------------- /samples/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #Copyright (c) Microsoft. All rights reserved. 2 | #Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #this is CMakeLists.txt for serializer samples. There's nothing here, except redirections to 5 | #individual samples 6 | 7 | set(PLATFORM_INC_FOLDER ${CMAKE_CURRENT_LIST_DIR}/platform_specific/inc CACHE INTERNAL "this is what needs to be included if using bme280 sensor and locked file lib" FORCE) 8 | 9 | include_directories(${SERIALIZER_INC_FOLDER} ${SHARED_UTIL_INC_FOLDER} ${PLATFORM_INC_FOLDER}) 10 | 11 | function(add_sample_directory whatIsBuilding) 12 | add_subdirectory(${whatIsBuilding}) 13 | 14 | set_target_properties(${whatIsBuilding} 15 | PROPERTIES 16 | FOLDER "Serializer_Samples") 17 | endfunction() 18 | 19 | add_subdirectory(platform_specific) 20 | 21 | if(${use_amqp_kit}) 22 | add_sample_directory(remote_monitoring) 23 | add_sample_directory(simplesample_amqp) 24 | endif() 25 | 26 | if(${use_http_kit}) 27 | message(SEND_ERROR "The kit for Raspberrypi do not support http yet") 28 | endif() 29 | 30 | if(${use_mqtt_kit}) 31 | message(SEND_ERROR "The kit for Raspberrypi do not support mqtt yet") 32 | endif() 33 | 34 | -------------------------------------------------------------------------------- /samples/build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | #set -o pipefail 3 | # 4 | 5 | set -e 6 | 7 | script_dir=$(cd "$(dirname "$0")" && pwd) 8 | build_root=$(cd "${script_dir}/.." && pwd) 9 | log_dir=$build_root 10 | run_e2e_tests=OFF 11 | run_longhaul_tests=OFF 12 | build_amqp=ON 13 | build_http=ON 14 | build_mqtt=OFF 15 | skip_unittests=ON 16 | 17 | echo "Building Remote Monitoring for Raspberry Pi." 18 | echo " Script directory: "$script_dir 19 | echo " Build root: "$build_root 20 | echo "" 21 | 22 | usage () 23 | { 24 | echo "build.sh [options]" 25 | echo "options" 26 | echo " -cl, --compileoption specify a compile option to be passed to gcc" 27 | echo " Example: -cl -O1 -cl ..." 28 | echo " --skip-e2e-tests skip the running of end-to-end tests (e2e tests are run by default)" 29 | echo " --skip-unittests skip the running of unit tests (unit tests are run by default)" 30 | echo " --run-longhaul-tests run long haul tests (long haul tests are not run by default)" 31 | echo "" 32 | echo " --no-amqp do no build AMQP transport and samples" 33 | echo " --no-http do no build HTTP transport and samples" 34 | echo " --no-mqtt do no build MQTT transport and samples" 35 | exit 1 36 | } 37 | 38 | process_args () 39 | { 40 | save_next_arg=0 41 | extracloptions="-I\"~/wiringPi/wiringPi/\" -pthread -o $TARGET $TARGET.c -lwiringPi -lrt " 42 | 43 | for arg in $* 44 | do 45 | if [ $save_next_arg == 1 ] 46 | then 47 | # save arg to pass to gcc 48 | extracloptions="$arg $extracloption" 49 | save_next_arg=0 50 | else 51 | case "$arg" in 52 | "-cl" | "--compileoption" ) save_next_arg=1;; 53 | "--skip-e2e-tests" ) run_e2e_tests=OFF;; 54 | "--skip-unittests" ) skip_unittests=ON;; 55 | "--run-longhaul-tests" ) run_longhaul_tests=ON;; 56 | "--no-amqp" ) build_amqp=OFF;; 57 | "--no-http" ) build_http=OFF;; 58 | "--no-mqtt" ) build_mqtt=OFF;; 59 | * ) usage;; 60 | esac 61 | fi 62 | done 63 | } 64 | 65 | process_args $* 66 | 67 | rm -r -f ~/cmake 68 | mkdir ~/cmake 69 | pushd ~/cmake 70 | cmake -DcompileOption_C:STRING="$extracloptions" -Drun_e2e_tests:BOOL=$run_e2e_tests -Drun_longhaul_tests=$run_longhaul_tests -Duse_amqp:BOOL=$build_amqp -Duse_http:BOOL=$build_http -Duse_mqtt:BOOL=$build_mqtt -Dskip_unittests:BOOL=$skip_unittests $build_root 71 | make --jobs=$(nproc) 72 | ctest -C "Debug" -V 73 | popd 74 | -------------------------------------------------------------------------------- /samples/platform_specific/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #Copyright (c) Microsoft. All rights reserved. 2 | #Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | cmake_minimum_required(VERSION 2.8.11) 5 | #this is CMakeLists.txt for the BME280 and a protected file access for Raspberry PI. 6 | 7 | compileAsC99() 8 | 9 | set(platform_c_files 10 | ./src/bme280.c 11 | ./src/locking.c 12 | ) 13 | 14 | set(platform_h_files 15 | ./inc/bme280.h 16 | ./inc/locking.h 17 | ) 18 | 19 | set(PLATFORM_INC_FOLDER ${CMAKE_CURRENT_LIST_DIR}/inc CACHE INTERNAL "this is what needs to be included if using serializer lib" FORCE) 20 | include_directories(${PLATFORM_INC_FOLDER}) 21 | 22 | add_library( 23 | aziotplatform ${platform_c_files} ${platform_h_files} 24 | ) 25 | 26 | if(WIN32) 27 | else() 28 | install (TARGETS aziotplatform DESTINATION lib) 29 | install (FILES ${platform_h_files} DESTINATION include/azureiot/platform_specific) 30 | endif (WIN32) 31 | -------------------------------------------------------------------------------- /samples/platform_specific/inc/bme280.h: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // bme280.h: 4 | // SPI based interface to read temperature, pressure and humidity samples from 5 | // a BME280 module. 6 | // 7 | /////////////////////////////////////////////////////////////////////////////// 8 | 9 | #ifndef __BME280_H 10 | #define __BME280_H 11 | 12 | 13 | /////////////////////////////////////////////////////////////////////////////// 14 | // Call this after setting the chip select (or SPI Enable) pin (via 15 | // bme280_set_cs_pin()), and before calling the bmp280_read function. 16 | // Return: 0 if the module was not found. 17 | // 1 if the module was readable, and verified to be a BMP280, and the 18 | // calibration data was read. 19 | int bme280_init(int Chip_enable_to_use__i); 20 | 21 | /////////////////////////////////////////////////////////////////////////////// 22 | // Prerequisite: 23 | // You must call wiringPiSetup before calling this function. For example: 24 | // int Result__i = wiringPiSetup(); 25 | // if (Result__i != 0) exit(Result__i); 26 | // You must call wiringPiSPISetup before calling this function. For example: 27 | // int Spi_fd__i = wiringPiSPISetup(Spi_channel__i, Spi_clock__i); 28 | // if (Spi_fd__i < 0) 29 | // { 30 | // printf("Can't setup SPI, error %i calling wiringPiSPISetup(%i, %i) %s\n", 31 | // Spi_fd__i, Spi_channel__i, Spi_clock__i, strerror(Spi_fd__i)); 32 | // exit(Spi_fd__i); 33 | // } 34 | // 35 | // Param: Temp_C__fp Pointer to a float to receive the current temperature in 36 | // degrees Celcius. Only set if read is successful. 37 | // Param: Pres_Pa__fp Pointer to a float to receive the current pressure 38 | // as hPa. Only set if read is successful. 39 | // Param: Hum_pct__fp Pointer to a float to receive the current humidity 40 | // as a percentage. Only set if read is successful. 41 | // Return: If wiringPi gets an error, this will be < 0 42 | // If the read attempts fail, this will be 1 43 | // If the read succeeds within the available retries, returns 0 44 | int bme280_read_sensors(float * Temp_C__fp, float * Pres_Pa__fp, 45 | float * Hum_pct__fp); 46 | 47 | #endif//__BME280_H 48 | 49 | -------------------------------------------------------------------------------- /samples/platform_specific/inc/locking.h: -------------------------------------------------------------------------------- 1 | /* 2 | * locking.c: 3 | * Prevents rapid use of application by implementing a file lock 4 | * technion@lolware.net 5 | */ 6 | 7 | #define LOCKFILE "/var/run/dht.lock" 8 | 9 | int open_lockfile(const char *filename); 10 | void close_lockfile(int fd); 11 | 12 | -------------------------------------------------------------------------------- /samples/platform_specific/src/bme280.c: -------------------------------------------------------------------------------- 1 | /////////////////////////////////////////////////////////////////////////////// 2 | // 3 | // bme280.c: 4 | // SPI based interface to read temperature, pressure and humidity samples from 5 | // a BME280 module. 6 | // 7 | /////////////////////////////////////////////////////////////////////////////// 8 | 9 | #include "bme280.h" 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | 17 | #define SENSOR_MODULE_MAX_XFER_LEN (128) 18 | static int Num_allowed_retries__i = 3; 19 | static int Chip_enable_selected__i = -1; 20 | 21 | #define SHOW_DEBUG_OUTPUT 22 | 23 | 24 | /////////////////////////////////////////////////////////////////////////////// 25 | // Device registers 26 | enum 27 | { 28 | eBME280reg_DIG_T1 = 0x88 29 | , eBME280reg_DIG_T2 = 0x8A 30 | , eBME280reg_DIG_T3 = 0x8C 31 | 32 | , eBME280reg_DIG_P1 = 0x8E 33 | , eBME280reg_DIG_P2 = 0x90 34 | , eBME280reg_DIG_P3 = 0x92 35 | , eBME280reg_DIG_P4 = 0x94 36 | , eBME280reg_DIG_P5 = 0x96 37 | , eBME280reg_DIG_P6 = 0x98 38 | , eBME280reg_DIG_P7 = 0x9A 39 | , eBME280reg_DIG_P8 = 0x9C 40 | , eBME280reg_DIG_P9 = 0x9E 41 | 42 | , eBME280reg_DIG_H1 = 0xA1 43 | , eBME280reg_DIG_H2 = 0xE1 44 | , eBME280reg_DIG_H3 = 0xE3 45 | , eBME280reg_DIG_H4 = 0xE4 46 | , eBME280reg_DIG_H5 = 0xE5 47 | , eBME280reg_DIG_H6 = 0xE7 48 | 49 | , eBME280reg_CHIPID = 0xD0 50 | , eBME280reg_VERSION = 0xD1 51 | , eBME280reg_SWRESET = 0xE0 52 | 53 | , eBME280reg_STATUS = 0xF3 54 | , eBME280reg_CONTROL = 0xF4 55 | , eBME280reg_CONFIG = 0xF5 56 | , eBME280reg_PRESDATA = 0xF7 57 | , eBME280reg_TEMPDATA = 0xFA 58 | }; 59 | 60 | 61 | // Calibration data as read from the device. 62 | typedef struct 63 | { 64 | uint16_t dig_T1; 65 | int16_t dig_T2; 66 | int16_t dig_T3; 67 | 68 | uint16_t dig_P1; 69 | int16_t dig_P2; 70 | int16_t dig_P3; 71 | int16_t dig_P4; 72 | int16_t dig_P5; 73 | int16_t dig_P6; 74 | int16_t dig_P7; 75 | int16_t dig_P8; 76 | int16_t dig_P9; 77 | 78 | uint8_t dig_H1; 79 | int16_t dig_H2; 80 | uint16_t dig_H3; 81 | int16_t dig_H4; 82 | int16_t dig_H5; 83 | int8_t dig_H6; 84 | } bme280_calib_data_t; 85 | bme280_calib_data_t Calib_data; 86 | 87 | 88 | /////////////////////////////////////////////////////////////////////////////// 89 | int bme280_read(const uint8_t Register__u8, uint8_t * Data__u8p, uint8_t Num_bytes__u8) 90 | { 91 | if (Chip_enable_selected__i == -1) { return 0; } 92 | if (Num_bytes__u8 >= SENSOR_MODULE_MAX_XFER_LEN) { return 0; } 93 | 94 | uint8_t Buffer__u8a[SENSOR_MODULE_MAX_XFER_LEN]; 95 | memset(Buffer__u8a, 0, SENSOR_MODULE_MAX_XFER_LEN); 96 | 97 | // Set bit 7 high to tell it to read. 98 | Buffer__u8a[0] = (0x80 | Register__u8); 99 | int Result__i = 100 | wiringPiSPIDataRW(Chip_enable_selected__i, Buffer__u8a, Num_bytes__u8 + 1); 101 | int Out_idx__i = 0; 102 | while (Out_idx__i < (Result__i - 1)) 103 | { 104 | Data__u8p[Out_idx__i] = Buffer__u8a[Out_idx__i + 1]; 105 | Out_idx__i++; 106 | } 107 | 108 | return Result__i - 1; 109 | } 110 | 111 | /////////////////////////////////////////////////////////////////////////////// 112 | int bme280_write(const uint8_t Register__u8, const uint8_t * Data__u8p, uint8_t Num_bytes__u8) 113 | { 114 | if (Chip_enable_selected__i == -1) { return 0; } 115 | if (Num_bytes__u8 > SENSOR_MODULE_MAX_XFER_LEN) { return 0; } 116 | 117 | uint8_t Buffer__u8a[SENSOR_MODULE_MAX_XFER_LEN]; 118 | 119 | uint8_t Write_idx__u8 = 0; 120 | while (Write_idx__u8 < Num_bytes__u8) 121 | { 122 | // Set bit 7 low to tell it to write. 123 | Buffer__u8a[Write_idx__u8 * 2] = (0x7F & (Register__u8 + Write_idx__u8)); 124 | Buffer__u8a[Write_idx__u8 * 2 + 1] = *Data__u8p; 125 | 126 | Write_idx__u8++; 127 | Data__u8p++; 128 | } 129 | 130 | int Result__i = wiringPiSPIDataRW(Chip_enable_selected__i, 131 | Buffer__u8a, Num_bytes__u8 * 2); 132 | 133 | return Result__i / 2; 134 | } 135 | 136 | /////////////////////////////////////////////////////////////////////////////// 137 | int bme280_init(int Chip_enable_to_use__i) 138 | { 139 | #ifdef SHOW_DEBUG_OUTPUT 140 | printf("bme280_init(%i)\n", Chip_enable_to_use__i); 141 | #endif 142 | 143 | if ((Chip_enable_to_use__i < 0) || (Chip_enable_to_use__i > 1)) 144 | { 145 | return 0; 146 | } 147 | Chip_enable_selected__i = Chip_enable_to_use__i; 148 | 149 | // Verify that the chip is really a BME280. 150 | uint8_t ID_value__u8 = 0; 151 | int Bytes_read__i = bme280_read(eBME280reg_CHIPID, &ID_value__u8, 1); 152 | if (Bytes_read__i != 1) 153 | { 154 | return 0; 155 | } 156 | #ifdef SHOW_DEBUG_OUTPUT 157 | printf("Read 0x%02x from register 0x%02x\n", ID_value__u8, eBME280reg_CHIPID); 158 | #endif 159 | 160 | if (ID_value__u8 != 0x60) 161 | { 162 | #ifdef SHOW_DEBUG_OUTPUT 163 | printf("This is not a BME280. Expecting an ID register value of 0x%02x\n", 164 | 0x60); 165 | #endif 166 | return 0; 167 | } 168 | 169 | #define T_P_CALIB_NUM_BYTES (24) 170 | Bytes_read__i = bme280_read(eBME280reg_DIG_T1, (uint8_t *)&Calib_data, 171 | T_P_CALIB_NUM_BYTES); 172 | if (Bytes_read__i != T_P_CALIB_NUM_BYTES) 173 | { 174 | #ifdef SHOW_DEBUG_OUTPUT 175 | printf("Err: Only read %i out of %i calibration data bytes.\n", 176 | Bytes_read__i, T_P_CALIB_NUM_BYTES); 177 | #endif 178 | return 0; 179 | } 180 | uint8_t Hum_calib_buf__u8a[9]; 181 | Bytes_read__i += bme280_read(eBME280reg_DIG_H1, &Hum_calib_buf__u8a[0], 1); 182 | if (Bytes_read__i != T_P_CALIB_NUM_BYTES + 1) 183 | { 184 | #ifdef SHOW_DEBUG_OUTPUT 185 | printf("Err: Only read %i out of %i calibration data bytes.\n", 186 | Bytes_read__i, T_P_CALIB_NUM_BYTES + 1); 187 | #endif 188 | return 0; 189 | } 190 | Bytes_read__i += bme280_read(eBME280reg_DIG_H2, &Hum_calib_buf__u8a[1], 7); 191 | if (Bytes_read__i != T_P_CALIB_NUM_BYTES + 8) 192 | { 193 | #ifdef SHOW_DEBUG_OUTPUT 194 | printf("Err: Only read %i out of %i calibration data bytes.\n", 195 | Bytes_read__i, T_P_CALIB_NUM_BYTES + 8); 196 | #endif 197 | return 0; 198 | } 199 | #ifdef SHOW_DEBUG_OUTPUT 200 | printf("Read %i calibration data bytes starting at 0x%02x.\n", 201 | Bytes_read__i, eBME280reg_DIG_T1); 202 | #endif 203 | 204 | // Decode the humidity compensation constants. 205 | Calib_data.dig_H1 = Hum_calib_buf__u8a[0]; 206 | Calib_data.dig_H2 = (int16_t)(((uint16_t)Hum_calib_buf__u8a[1]) 207 | + (((uint16_t)Hum_calib_buf__u8a[2]) << 8)); 208 | Calib_data.dig_H3 = Hum_calib_buf__u8a[3]; 209 | Calib_data.dig_H4 = (int16_t)((((uint16_t)Hum_calib_buf__u8a[4]) << 4) 210 | + (((uint16_t)Hum_calib_buf__u8a[5]) & 0x0F)); 211 | Calib_data.dig_H5 = (int16_t)((((uint16_t)Hum_calib_buf__u8a[5]) >> 4) 212 | + (((uint16_t)Hum_calib_buf__u8a[6]) << 4)); 213 | Calib_data.dig_H6 = (int8_t)Hum_calib_buf__u8a[7]; 214 | 215 | // bits 7~5 = 001 = temperature oversampling * 1 216 | // bits 4~2 = 111 = pressure oversampling * 16 217 | // bits 1~0 = 11 = normal power mode 218 | const uint8_t Control_setting__u8 = 0x3F; 219 | uint8_t Bytes_written__u8 = bme280_write(eBME280reg_CONTROL, 220 | &Control_setting__u8, 1); 221 | if (Bytes_written__u8 != 1) 222 | { 223 | #ifdef SHOW_DEBUG_OUTPUT 224 | printf("Err: Could not write 0x%02x to register 0x%02x.\n", 225 | Control_setting__u8, eBME280reg_CONTROL); 226 | #endif 227 | return 0; 228 | } 229 | #ifdef SHOW_DEBUG_OUTPUT 230 | printf("Wrote 0x%02x to configuration register 0x%02x.\n", 231 | Control_setting__u8, eBME280reg_CONTROL); 232 | #endif 233 | 234 | return 1; 235 | } 236 | 237 | /////////////////////////////////////////////////////////////////////////////// 238 | // Returns temperature in DegC, resolution is 0.01 DegC. 239 | // For example: Output value of “5123” equals 51.23 DegC. 240 | // t_fine is stored globally since it is also used by the pressure comp calc. 241 | // Note: Must call this before calling compensate_P or compensate_H because of 242 | // the global t_fine variable. 243 | int32_t t_fine = 0; 244 | int32_t bme280_compensate_T_int32(int32_t adc_T) 245 | { 246 | int32_t var1, var2, T; 247 | var1 = ((((adc_T >> 3) - ((int32_t)Calib_data.dig_T1 << 1))) 248 | * ((int32_t)Calib_data.dig_T2)) >> 11; 249 | var2 = (((((adc_T >> 4) - ((int32_t)Calib_data.dig_T1)) 250 | * ((adc_T >> 4) - ((int32_t)Calib_data.dig_T1))) >> 12) 251 | * ((int32_t)Calib_data.dig_T3)) >> 14; 252 | t_fine = var1 + var2; 253 | T = (t_fine * 5 + 128) >> 8; 254 | return T; 255 | } 256 | 257 | /////////////////////////////////////////////////////////////////////////////// 258 | // Returns pressure in Pa as unsigned 32 bit integer in Q24.8 format (24 259 | // integer bits and 8 fractional bits). 260 | // For example: Output value of “24674867” represents 24674867/256 = 96386.2 Pa 261 | // = 963.862 hPa 262 | // Note: Must call compensate_T before calling this because of 263 | // the global t_fine variable. 264 | uint32_t bme280_compensate_P_int64(int32_t adc_P) 265 | { 266 | int64_t var1, var2, p; 267 | var1 = ((int64_t)t_fine) - 128000LL; 268 | var2 = var1 * var1 * (int64_t)Calib_data.dig_P6; 269 | var2 = var2 + ((var1*(int64_t)Calib_data.dig_P5) << 17); 270 | var2 = var2 + (((int64_t)Calib_data.dig_P4) << 35); 271 | var1 = ((var1 * var1 * (int64_t)Calib_data.dig_P3)>>8) + ((var1 * (int64_t)Calib_data.dig_P2) << 12); 272 | var1 = (((((int64_t)1) << 47) + var1)) * ((int64_t)Calib_data.dig_P1) >> 33; 273 | if (var1 == 0) 274 | { 275 | // Avoid divide by zero exception. 276 | return 0; 277 | } 278 | p = 1048576 - adc_P; 279 | p = (((p << 31) - var2) * 3125) / var1; 280 | var1 = (((int64_t)Calib_data.dig_P9) * (p >> 13) * (p >> 13)) >> 25; 281 | var2 = (((int64_t)Calib_data.dig_P8) * p) >> 19; 282 | p = ((p + var1 + var2) >> 8) + (((int64_t)Calib_data.dig_P7) << 4); 283 | return (uint32_t)p; 284 | } 285 | 286 | /////////////////////////////////////////////////////////////////////////////// 287 | // Returns humidity as a relative percentage. 288 | // Encoded as Q22.10 format (22 integer bits and 10 fractional bits). 289 | // For example: Output value of “47445” represents 47445/1024 = 46.333 %RH 290 | // Note: Must call compensate_T before calling this because of 291 | // the global t_fine variable. 292 | uint32_t bme280_compensate_H_int32(int32_t adc_H) 293 | { 294 | int32_t v_x1_u32r; 295 | v_x1_u32r = (t_fine - ((int32_t)76800L)); 296 | v_x1_u32r = (((((adc_H << 14) - (((int32_t)Calib_data.dig_H4) << 20) 297 | - (((int32_t)Calib_data.dig_H5) * v_x1_u32r)) + ((int32_t)16384)) >> 15) 298 | * (((((((v_x1_u32r * ((int32_t)Calib_data.dig_H6)) >> 10) 299 | * (((v_x1_u32r * ((int32_t)Calib_data.dig_H3)) >> 11) 300 | + ((int32_t)32768))) >> 10) + ((int32_t)2097152)) 301 | * ((int32_t)Calib_data.dig_H2) + 8192) >> 14)); 302 | v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) 303 | * ((int32_t)Calib_data.dig_H1)) >> 4)); 304 | v_x1_u32r = (v_x1_u32r < 0 ? 0 : v_x1_u32r); 305 | v_x1_u32r = (v_x1_u32r > 419430400 ? 419430400 : v_x1_u32r); 306 | return (uint32_t)(v_x1_u32r >> 12); 307 | } 308 | 309 | /////////////////////////////////////////////////////////////////////////////// 310 | int bme280_read_sensors(float * Temp_c__fp, float * Pres_Pa__fp, 311 | float * Hum_pct__fp) 312 | { 313 | int Return_status__i = 0; 314 | 315 | // Make sure the sensor isn't busy updating values. 316 | uint8_t Status__u8 = 0x01; 317 | while ((Status__u8 & 0x01) != 0) 318 | { 319 | uint8_t Num_bytes_read__u8 = bme280_read(eBME280reg_STATUS, &Status__u8, 1); 320 | if (Num_bytes_read__u8 != 1) 321 | { 322 | return Return_status__i; 323 | } 324 | } 325 | 326 | const uint8_t Num_bytes_to_read__u8 = 8; 327 | uint8_t Buffer__u8a[Num_bytes_to_read__u8]; 328 | int Num_retries__i = 0; 329 | while (Num_retries__i <= Num_allowed_retries__i) 330 | { 331 | uint8_t Register__u8 = eBME280reg_PRESDATA; 332 | int Num_bytes_read__i = bme280_read(Register__u8, Buffer__u8a, 333 | Num_bytes_to_read__u8); 334 | if (Num_bytes_read__i == (int)Num_bytes_to_read__u8) 335 | { 336 | // Decode the fields. 337 | 338 | // Pressure is in registers 0xf7 ~ 0xf9. 339 | // Most Significant Bits [19:12] of Pressure ADC value. 340 | int32_t Pressure_raw_adc__i32 = ((int32_t)Buffer__u8a[0]) << 12; 341 | // Mid/lower Significant Bits [11:4] of Pressure ADC value. 342 | Pressure_raw_adc__i32 += ((int32_t)Buffer__u8a[1]) << 4; 343 | // Least Significant Bits [3]|[3:2]|[3:1]|[3:0], depending on the 344 | // resolution as determined by the oversampling setting. 345 | Pressure_raw_adc__i32 += ((int32_t)Buffer__u8a[2]) & 0x04; 346 | 347 | // Temperature is in registers 0xfa ~ 0xfc. 348 | // Most Significant Bits [19:12] of Temperature ADC value. 349 | int32_t Temperature_raw_adc__i32 = ((int32_t)Buffer__u8a[3]) << 12; 350 | // Mid/lower Significant Bits [11:4] of Temperature ADC value. 351 | Temperature_raw_adc__i32 += ((int32_t)Buffer__u8a[4]) << 4; 352 | // Least Significant Bits [3]|[3:2]|[3:1]|[3:0], depending on the 353 | // resolution as determined by the oversampling setting. 354 | Temperature_raw_adc__i32 += ((int32_t)Buffer__u8a[5]) & 0x04; 355 | 356 | // Humidity is in registers 0xfd ~ 0xfe. 357 | // Most Significant Bits [15:8] of Humidity ADC value. 358 | int32_t Humidity_raw_adc__i32 = (((int32_t)Buffer__u8a[6]) << 8); 359 | // Least Significant Bits [7:0] of Humidity ADC value. 360 | Humidity_raw_adc__i32 += ((int32_t)Buffer__u8a[7]); 361 | printf("raw H = 0x%08x\n", Humidity_raw_adc__i32); 362 | 363 | *Temp_c__fp = bme280_compensate_T_int32(Temperature_raw_adc__i32) / 100.0; 364 | *Pres_Pa__fp = bme280_compensate_P_int64(Pressure_raw_adc__i32) / 256.0; 365 | *Hum_pct__fp = bme280_compensate_H_int32(Humidity_raw_adc__i32) / 1024.0; 366 | 367 | Return_status__i = 1; 368 | break; 369 | } 370 | 371 | Num_retries__i++; 372 | delay(1); 373 | } 374 | 375 | return Return_status__i; 376 | } 377 | 378 | -------------------------------------------------------------------------------- /samples/platform_specific/src/locking.c: -------------------------------------------------------------------------------- 1 | /* 2 | * locking.c: 3 | * Prevents rapid use of application by implementing a file lock 4 | * technion@lolware.net 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | int open_lockfile(const char *filename) 16 | { 17 | int fd; 18 | fd = open(filename, O_CREAT | O_RDONLY, 0600); 19 | 20 | if (fd < 0) 21 | { 22 | printf("Failed to access lock file: %s\nerror: %s (did you use sudo?)\n", 23 | filename, strerror(errno)); 24 | exit(EXIT_FAILURE); 25 | } 26 | 27 | while(flock(fd, LOCK_EX | LOCK_NB) == -1) 28 | { 29 | if(errno == EWOULDBLOCK) 30 | { 31 | printf("Lock file is in use, exiting...\n"); 32 | /* If the lockfile is in use, we COULD sleep and try again. 33 | * However, a lockfile would more likely indicate an already runaway 34 | * process. 35 | */ 36 | exit(EXIT_FAILURE); 37 | } 38 | perror("Flock failed"); 39 | exit(EXIT_FAILURE); 40 | } 41 | return fd; 42 | } 43 | 44 | void close_lockfile(int fd) 45 | { 46 | if(flock(fd, LOCK_UN) == -1) 47 | { 48 | perror("Failed to unlock file"); 49 | exit(EXIT_FAILURE); 50 | } 51 | if(close(fd) == -1) 52 | { 53 | perror("Closing descriptor on lock file failed"); 54 | exit(EXIT_FAILURE); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /samples/remote_monitoring/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #Copyright (c) Microsoft. All rights reserved. 2 | #Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #this is CMakeLists.txt for remote_monitoring sample 5 | 6 | compileAsC99() 7 | 8 | if(NOT ${use_amqp_kit}) 9 | message(FATAL_ERROR "remote_monitoring being generated without amqp support") 10 | endif() 11 | 12 | set(remote_monitoring_c_files 13 | remote_monitoring.c 14 | ) 15 | 16 | if(WIN32) 17 | set(remote_monitoring_c_files ${remote_monitoring_c_files}) 18 | else() 19 | set(remote_monitoring_c_files ${remote_monitoring_c_files}) 20 | endif() 21 | 22 | set(remote_monitoring_h_files 23 | remote_monitoring.h 24 | ) 25 | 26 | IF(WIN32) 27 | #windows needs this define 28 | add_definitions(-D_CRT_SECURE_NO_WARNINGS) 29 | ENDIF(WIN32) 30 | 31 | include_directories(. ${IOTHUB_CLIENT_INC_FOLDER}) 32 | 33 | link_directories(${whatIsBuilding}_dll ${SHARED_UTIL_LIB_DIR}) 34 | 35 | add_executable(remote_monitoring ${remote_monitoring_c_files} ${remote_monitoring_h_files}) 36 | target_link_libraries(remote_monitoring serializer iothub_client iothub_client_amqp_transport aziotplatform wiringPi) 37 | 38 | linkSharedUtil(remote_monitoring) 39 | linkUAMQP(remote_monitoring) 40 | -------------------------------------------------------------------------------- /samples/remote_monitoring/remote_monitoring.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #ifndef WINCE 5 | #include "iothubtransportamqp.h" 6 | #else 7 | #include "iothubtransporthttp.h" 8 | #endif 9 | #include "schemalib.h" 10 | #include "iothub_client.h" 11 | #include "serializer.h" 12 | #include "schemaserializer.h" 13 | 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | #include 23 | #include 24 | 25 | #include "bme280.h" 26 | #include "locking.h" 27 | 28 | #include "azure_c_shared_utility/threadapi.h" 29 | #include "azure_c_shared_utility/platform.h" 30 | 31 | #ifdef MBED_BUILD_TIMESTAMP 32 | #include "certs.h" 33 | #endif // MBED_BUILD_TIMESTAMP 34 | 35 | 36 | static const char* deviceId = "[Device Id]"; 37 | static const char* deviceKey = "[Device Key]"; 38 | static const char* hubName = "[IoTHub Name]"; 39 | static const char* hubSuffix = "[IoTHub Suffix, i.e. azure-devices.net]"; 40 | 41 | static const int Spi_channel = 0; 42 | static const int Spi_clock = 1000000L; 43 | 44 | static const int Red_led_pin = 4; 45 | static const int Grn_led_pin = 5; 46 | 47 | static int Lock_fd; 48 | 49 | // Define the Model 50 | BEGIN_NAMESPACE(Contoso); 51 | 52 | DECLARE_STRUCT(SystemProperties, 53 | ascii_char_ptr, DeviceID, 54 | _Bool, Enabled 55 | ); 56 | 57 | DECLARE_STRUCT(DeviceProperties, 58 | ascii_char_ptr, DeviceID, 59 | _Bool, HubEnabledState 60 | ); 61 | 62 | DECLARE_MODEL(Thermostat, 63 | 64 | /* Event data (temperature, external temperature and humidity) */ 65 | WITH_DATA(float, Temperature), 66 | WITH_DATA(float, ExternalTemperature), 67 | WITH_DATA(float, Humidity), 68 | WITH_DATA(ascii_char_ptr, DeviceId), 69 | 70 | /* Device Info - This is command metadata + some extra fields */ 71 | WITH_DATA(ascii_char_ptr, ObjectType), 72 | WITH_DATA(_Bool, IsSimulatedDevice), 73 | WITH_DATA(ascii_char_ptr, Version), 74 | WITH_DATA(DeviceProperties, DeviceProperties), 75 | WITH_DATA(ascii_char_ptr_no_quotes, Commands), 76 | 77 | /* Commands implemented by the device */ 78 | WITH_ACTION(SetTemperature, int, temperature), 79 | WITH_ACTION(SetHumidity, int, humidity) 80 | ); 81 | 82 | END_NAMESPACE(Contoso); 83 | 84 | EXECUTE_COMMAND_RESULT SetTemperature(Thermostat* thermostat, int temperature) 85 | { 86 | (void)printf("Received temperature %d\r\n", temperature); 87 | thermostat->Temperature = temperature; 88 | return EXECUTE_COMMAND_SUCCESS; 89 | } 90 | 91 | EXECUTE_COMMAND_RESULT SetHumidity(Thermostat* thermostat, int humidity) 92 | { 93 | (void)printf("Received humidity %d\r\n", humidity); 94 | thermostat->Humidity = humidity; 95 | return EXECUTE_COMMAND_SUCCESS; 96 | } 97 | 98 | static void sendMessage(IOTHUB_CLIENT_HANDLE iotHubClientHandle, const unsigned char* buffer, size_t size) 99 | { 100 | IOTHUB_MESSAGE_HANDLE messageHandle = IoTHubMessage_CreateFromByteArray(buffer, size); 101 | if (messageHandle == NULL) 102 | { 103 | (void)printf("unable to create a new IoTHubMessage\r\n"); 104 | } 105 | else 106 | { 107 | if (IoTHubClient_SendEventAsync(iotHubClientHandle, messageHandle, NULL, NULL) != IOTHUB_CLIENT_OK) 108 | { 109 | (void)printf("failed to hand over the message to IoTHubClient\r\n"); 110 | } 111 | else 112 | { 113 | (void)printf("IoTHubClient accepted the message for delivery\r\n"); 114 | } 115 | 116 | IoTHubMessage_Destroy(messageHandle); 117 | } 118 | free((void*)buffer); 119 | } 120 | 121 | /*this function "links" IoTHub to the serialization library*/ 122 | static IOTHUBMESSAGE_DISPOSITION_RESULT IoTHubMessage(IOTHUB_MESSAGE_HANDLE message, void* userContextCallback) 123 | { 124 | IOTHUBMESSAGE_DISPOSITION_RESULT result; 125 | const unsigned char* buffer; 126 | size_t size; 127 | if (IoTHubMessage_GetByteArray(message, &buffer, &size) != IOTHUB_MESSAGE_OK) 128 | { 129 | printf("unable to IoTHubMessage_GetByteArray\r\n"); 130 | result = EXECUTE_COMMAND_ERROR; 131 | } 132 | else 133 | { 134 | /*buffer is not zero terminated*/ 135 | char* temp = malloc(size + 1); 136 | if (temp == NULL) 137 | { 138 | printf("failed to malloc\r\n"); 139 | result = EXECUTE_COMMAND_ERROR; 140 | } 141 | else 142 | { 143 | EXECUTE_COMMAND_RESULT executeCommandResult; 144 | 145 | memcpy(temp, buffer, size); 146 | temp[size] = '\0'; 147 | executeCommandResult = EXECUTE_COMMAND(userContextCallback, temp); 148 | result = 149 | (executeCommandResult == EXECUTE_COMMAND_ERROR) ? IOTHUBMESSAGE_ABANDONED : 150 | (executeCommandResult == EXECUTE_COMMAND_SUCCESS) ? IOTHUBMESSAGE_ACCEPTED : 151 | IOTHUBMESSAGE_REJECTED; 152 | free(temp); 153 | } 154 | } 155 | return result; 156 | } 157 | 158 | static int remote_monitoring_init(void) 159 | { 160 | int result; 161 | 162 | Lock_fd = open_lockfile(LOCKFILE); 163 | 164 | if (setuid(getuid()) < 0) 165 | { 166 | perror("Dropping privileges failed. (did you use sudo?)n"); 167 | result = EXIT_FAILURE; 168 | } 169 | else 170 | { 171 | result = wiringPiSetup(); 172 | if (result != 0) 173 | { 174 | perror("Wiring Pi setup failed."); 175 | } 176 | else 177 | { 178 | result = wiringPiSPISetup(Spi_channel, Spi_clock); 179 | if (result < 0) 180 | { 181 | printf("Can't setup SPI, error %i calling wiringPiSPISetup(%i, %i) %sn", 182 | result, Spi_channel, Spi_clock, strerror(result)); 183 | } 184 | else 185 | { 186 | int sensorResult = bme280_init(Spi_channel); 187 | if (sensorResult != 1) 188 | { 189 | printf("It appears that no BMP280 module on Chip Enable %i is attached. Aborting.\n", Spi_channel); 190 | result = 1; 191 | } 192 | else 193 | { 194 | // Read the Temp & Pressure module. 195 | float tempC = -300.0; 196 | float pressurePa = -300; 197 | float humidityPct = -300; 198 | sensorResult = bme280_read_sensors(&tempC, &pressurePa, &humidityPct); 199 | if (sensorResult == 1) 200 | { 201 | printf("Temperature = %.1f *C Pressure = %.1f Pa Humidity = %1f %%\n", 202 | tempC, pressurePa, humidityPct); 203 | result = 0; 204 | } 205 | else 206 | { 207 | printf("Unable to read BME280 on pin %i. Aborting.\n", Spi_channel); 208 | result = 1; 209 | } 210 | } 211 | } 212 | } 213 | } 214 | return result; 215 | } 216 | 217 | static void remote_monitoring_run(void) 218 | { 219 | if (platform_init() != 0) 220 | { 221 | printf("Failed to initialize the platform.\r\n"); 222 | } 223 | else 224 | { 225 | if (serializer_init(NULL) != SERIALIZER_OK) 226 | { 227 | printf("Failed on serializer_init\r\n"); 228 | } 229 | else 230 | { 231 | IOTHUB_CLIENT_CONFIG config; 232 | IOTHUB_CLIENT_HANDLE iotHubClientHandle; 233 | 234 | config.deviceSasToken = NULL; 235 | config.deviceId = deviceId; 236 | config.deviceKey = deviceKey; 237 | config.iotHubName = hubName; 238 | config.iotHubSuffix = hubSuffix; 239 | #ifndef WINCE 240 | config.protocol = AMQP_Protocol; 241 | #else 242 | config.protocol = HTTP_Protocol; 243 | #endif 244 | iotHubClientHandle = IoTHubClient_Create(&config); 245 | if (iotHubClientHandle == NULL) 246 | { 247 | (void)printf("Failed on IoTHubClient_CreateFromConnectionString\r\n"); 248 | } 249 | else 250 | { 251 | #ifdef MBED_BUILD_TIMESTAMP 252 | // For mbed add the certificate information 253 | if (IoTHubClient_SetOption(iotHubClientHandle, "TrustedCerts", certificates) != IOTHUB_CLIENT_OK) 254 | { 255 | printf("failure to set option \"TrustedCerts\"\r\n"); 256 | } 257 | #endif // MBED_BUILD_TIMESTAMP 258 | 259 | Thermostat* thermostat = CREATE_MODEL_INSTANCE(Contoso, Thermostat); 260 | if (thermostat == NULL) 261 | { 262 | (void)printf("Failed on CREATE_MODEL_INSTANCE\r\n"); 263 | } 264 | else 265 | { 266 | STRING_HANDLE commandsMetadata; 267 | 268 | if (IoTHubClient_SetMessageCallback(iotHubClientHandle, IoTHubMessage, thermostat) != IOTHUB_CLIENT_OK) 269 | { 270 | printf("unable to IoTHubClient_SetMessageCallback\r\n"); 271 | } 272 | else 273 | { 274 | 275 | /* send the device info upon startup so that the cloud app knows 276 | what commands are available and the fact that the device is up */ 277 | thermostat->ObjectType = "DeviceInfo"; 278 | thermostat->IsSimulatedDevice = false; 279 | thermostat->Version = "1.0"; 280 | thermostat->DeviceProperties.HubEnabledState = true; 281 | thermostat->DeviceProperties.DeviceID = (char*)deviceId; 282 | 283 | commandsMetadata = STRING_new(); 284 | if (commandsMetadata == NULL) 285 | { 286 | (void)printf("Failed on creating string for commands metadata\r\n"); 287 | } 288 | else 289 | { 290 | /* Serialize the commands metadata as a JSON string before sending */ 291 | if (SchemaSerializer_SerializeCommandMetadata(GET_MODEL_HANDLE(Contoso, Thermostat), commandsMetadata) != SCHEMA_SERIALIZER_OK) 292 | { 293 | (void)printf("Failed serializing commands metadata\r\n"); 294 | } 295 | else 296 | { 297 | unsigned char* buffer; 298 | size_t bufferSize; 299 | thermostat->Commands = (char*)STRING_c_str(commandsMetadata); 300 | 301 | /* Here is the actual send of the Device Info */ 302 | if (SERIALIZE(&buffer, &bufferSize, thermostat->ObjectType, thermostat->Version, thermostat->IsSimulatedDevice, thermostat->DeviceProperties, thermostat->Commands) != IOT_AGENT_OK) 303 | { 304 | (void)printf("Failed serializing\r\n"); 305 | } 306 | else 307 | { 308 | sendMessage(iotHubClientHandle, buffer, bufferSize); 309 | } 310 | 311 | } 312 | 313 | STRING_delete(commandsMetadata); 314 | } 315 | 316 | thermostat->Temperature = 50; 317 | thermostat->ExternalTemperature = 55; 318 | thermostat->Humidity = 50; 319 | thermostat->DeviceId = (char*)deviceId; 320 | 321 | while (1) 322 | { 323 | unsigned char*buffer; 324 | size_t bufferSize; 325 | 326 | float tempC = -300.0; 327 | float pressurePa = -300; 328 | float humidityPct = -300; 329 | 330 | int sensorResult = bme280_read_sensors(&tempC, &pressurePa, &humidityPct); 331 | 332 | if (sensorResult == 1) 333 | { 334 | thermostat->Temperature = tempC; 335 | thermostat->Humidity = humidityPct; 336 | printf("Humidity = %.1f%% Temperature = %.1f*C \n", 337 | humidityPct, tempC); 338 | pinMode(Grn_led_pin, OUTPUT); 339 | } 340 | else 341 | { 342 | thermostat->Temperature = 404.0; 343 | thermostat->Humidity = 404.0; 344 | printf("Unable to read BME280 on pin %i\n", Spi_channel); 345 | pinMode(Red_led_pin, OUTPUT); 346 | } 347 | 348 | (void)printf("Sending sensor value Temperature = %.1f*C, Humidity = %.1f%%\r\n", thermostat->Temperature, thermostat->Humidity); 349 | 350 | if (SERIALIZE(&buffer, &bufferSize, thermostat->DeviceId, thermostat->Temperature, thermostat->Humidity, thermostat->ExternalTemperature) != IOT_AGENT_OK) 351 | { 352 | (void)printf("Failed sending sensor value\r\n"); 353 | } 354 | else 355 | { 356 | sendMessage(iotHubClientHandle, buffer, bufferSize); 357 | } 358 | 359 | ThreadAPI_Sleep(1000); 360 | } 361 | } 362 | close_lockfile(Lock_fd); 363 | DESTROY_MODEL_INSTANCE(thermostat); 364 | } 365 | IoTHubClient_Destroy(iotHubClientHandle); 366 | } 367 | serializer_deinit(); 368 | } 369 | platform_deinit(); 370 | } 371 | } 372 | 373 | int main(void) 374 | { 375 | int result = remote_monitoring_init(); 376 | if(result == 0) 377 | { 378 | remote_monitoring_run(); 379 | } 380 | return result; 381 | } 382 | 383 | -------------------------------------------------------------------------------- /samples/remote_monitoring/remote_monitoring.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #ifndef REMOTE_MONITORING_H 5 | #define REMOTE_MONITORING_H 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | void remote_monitoring_run(void); 12 | 13 | #ifdef __cplusplus 14 | } 15 | #endif 16 | 17 | #endif /* REMOTE_MONITORING_H */ 18 | -------------------------------------------------------------------------------- /samples/simplesample_amqp/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | #Copyright (c) Microsoft. All rights reserved. 2 | #Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #this is CMakeLists.txt for simplesample_amqp sample 5 | 6 | compileAsC99() 7 | 8 | if(NOT ${use_amqp_kit}) 9 | message(FATAL_ERROR "simplesample_amqp being generated without amqp support") 10 | endif() 11 | 12 | set(simplesample_amqp_c_files 13 | simplesample_amqp.c 14 | ) 15 | 16 | if(WIN32) 17 | set(simplesample_amqp_c_files ${simplesample_amqp_c_files} ./windows/main.c) 18 | else() 19 | set(simplesample_amqp_c_files ${simplesample_amqp_c_files} ./linux/main.c) 20 | endif() 21 | 22 | set(simplesample_amqp_h_files 23 | simplesample_amqp.h 24 | ) 25 | 26 | IF(WIN32) 27 | #windows needs this define 28 | add_definitions(-D_CRT_SECURE_NO_WARNINGS) 29 | ENDIF(WIN32) 30 | 31 | include_directories(. ${SHARED_UTIL_INC_FOLDER} ${IOTHUB_CLIENT_INC_FOLDER}) 32 | link_directories(${whatIsBuilding}_dll ${SHARED_UTIL_LIB_DIR}) 33 | 34 | add_executable(simplesample_amqp ${simplesample_amqp_c_files} ${simplesample_amqp_h_files}) 35 | 36 | target_link_libraries(simplesample_amqp serializer iothub_client iothub_client_amqp_transport aziotplatform wiringPi) 37 | 38 | linkSharedUtil(simplesample_amqp) 39 | linkUAMQP(simplesample_amqp) 40 | -------------------------------------------------------------------------------- /samples/simplesample_amqp/linux/main.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #include "simplesample_amqp.h" 5 | 6 | int main(void) 7 | { 8 | simplesample_amqp_run(); 9 | 10 | return 0; 11 | } 12 | 13 | -------------------------------------------------------------------------------- /samples/simplesample_amqp/simplesample_amqp.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "serializer.h" 14 | #include "azure_c_shared_utility/threadapi.h" 15 | #include "azure_c_shared_utility/sastoken.h" 16 | #include "azure_c_shared_utility/platform.h" 17 | #include "iothub_client.h" 18 | #include "iothubtransportamqp.h" 19 | #include "iothub_client_ll.h" 20 | 21 | // Sensor and Device Includes 22 | #include 23 | #include 24 | #include "bme280.h" 25 | #include "locking.h" 26 | 27 | #ifdef MBED_BUILD_TIMESTAMP 28 | #include "certs.h" 29 | #endif // MBED_BUILD_TIMESTAMP 30 | 31 | const int Spi_channel = 0; 32 | const int Spi_clock = 1000000L; 33 | int mcp3008Read(int Analog_in_channel); 34 | 35 | const int Red_led_pin = 4; 36 | const int Grn_led_pin = 5; 37 | 38 | /*String containing Hostname, Device Id & Device Key in the format: */ 39 | /* "HostName=;DeviceId=;SharedAccessKey=" */ 40 | static const char* connectionString = "[device connection string]"; 41 | static char* deviceId = "[Device Name]"; 42 | 43 | // Define the Model 44 | BEGIN_NAMESPACE(WeatherStation); 45 | 46 | DECLARE_MODEL(ContosoAnemometer, 47 | WITH_DATA(ascii_char_ptr, DeviceId), 48 | WITH_DATA(ascii_char_ptr, EventTime), 49 | WITH_DATA(float, MTemperature), 50 | WITH_ACTION(TurnFanOn), 51 | WITH_ACTION(TurnFanOff), 52 | WITH_ACTION(SetAirResistance, int, Position) 53 | ); 54 | 55 | END_NAMESPACE(WeatherStation); 56 | 57 | EXECUTE_COMMAND_RESULT TurnFanOn(ContosoAnemometer* device) 58 | { 59 | (void)device; 60 | (void)printf("Turning Green LED on.\r\n"); 61 | digitalWrite(Red_led_pin, LOW); 62 | digitalWrite(Grn_led_pin, HIGH); 63 | return EXECUTE_COMMAND_SUCCESS; 64 | } 65 | 66 | EXECUTE_COMMAND_RESULT TurnFanOff(ContosoAnemometer* device) 67 | { 68 | (void)device; 69 | (void)printf("Turning red LED on.\r\n"); 70 | digitalWrite(Red_led_pin, HIGH); 71 | digitalWrite(Grn_led_pin, LOW); 72 | return EXECUTE_COMMAND_SUCCESS; 73 | } 74 | 75 | EXECUTE_COMMAND_RESULT SetAirResistance(ContosoAnemometer* device, int Position) 76 | { 77 | (void)device; 78 | (void)printf("Setting Air Resistance Position to %d.\r\n", Position); 79 | return EXECUTE_COMMAND_SUCCESS; 80 | } 81 | 82 | void sendCallback(IOTHUB_CLIENT_CONFIRMATION_RESULT result, void* userContextCallback) 83 | { 84 | unsigned int messageTrackingId = (unsigned int)(uintptr_t)userContextCallback; 85 | 86 | (void)printf("Message Id: %u Received.\r\n", messageTrackingId); 87 | 88 | (void)printf("Result Call Back Called! Result is: %s \r\n", ENUM_TO_STRING(IOTHUB_CLIENT_CONFIRMATION_RESULT, result)); 89 | } 90 | 91 | 92 | static void sendMessage(IOTHUB_CLIENT_HANDLE iotHubClientHandle, const unsigned char* buffer, size_t size) 93 | { 94 | static unsigned int messageTrackingId; 95 | IOTHUB_MESSAGE_HANDLE messageHandle = IoTHubMessage_CreateFromByteArray(buffer, size); 96 | if (messageHandle == NULL) 97 | { 98 | printf("unable to create a new IoTHubMessage\r\n"); 99 | } 100 | else 101 | { 102 | if (IoTHubClient_SendEventAsync(iotHubClientHandle, messageHandle, sendCallback, (void*)(uintptr_t)messageTrackingId) != IOTHUB_CLIENT_OK) 103 | { 104 | printf("failed to hand over the message to IoTHubClient"); 105 | } 106 | else 107 | { 108 | printf("IoTHubClient accepted the message for delivery\r\n"); 109 | } 110 | 111 | IoTHubMessage_Destroy(messageHandle); 112 | } 113 | free((void*)buffer); 114 | messageTrackingId++; 115 | } 116 | 117 | static IOTHUBMESSAGE_DISPOSITION_RESULT IoTHubMessage(IOTHUB_MESSAGE_HANDLE message, void* userContextCallback) 118 | { 119 | IOTHUBMESSAGE_DISPOSITION_RESULT result; 120 | const unsigned char* buffer; 121 | size_t size; 122 | 123 | printf("Action Detected...\r\n"); 124 | 125 | if (IoTHubMessage_GetByteArray(message, &buffer, &size) != IOTHUB_MESSAGE_OK) 126 | { 127 | printf("unable to IoTHubMessage_GetByteArray\r\n"); 128 | result = EXECUTE_COMMAND_ERROR; 129 | } 130 | else 131 | { 132 | /*buffer is not zero terminated*/ 133 | char* temp = malloc(size + 1); 134 | if (temp == NULL) 135 | { 136 | printf("failed to malloc\r\n"); 137 | result = EXECUTE_COMMAND_ERROR; 138 | } 139 | else 140 | { 141 | memcpy(temp, buffer, size); 142 | temp[size] = '\0'; 143 | EXECUTE_COMMAND_RESULT executeCommandResult = EXECUTE_COMMAND(userContextCallback, temp); 144 | result = 145 | (executeCommandResult == EXECUTE_COMMAND_ERROR) ? IOTHUBMESSAGE_ABANDONED : 146 | (executeCommandResult == EXECUTE_COMMAND_SUCCESS) ? IOTHUBMESSAGE_ACCEPTED : 147 | IOTHUBMESSAGE_REJECTED; 148 | free(temp); 149 | } 150 | } 151 | return result; 152 | } 153 | 154 | 155 | void simplesample_amqp_run(void) 156 | { 157 | if (platform_init() != 0) 158 | { 159 | (void)printf("Failed to initialize the platform.\r\n"); 160 | } 161 | else 162 | { 163 | if (serializer_init(NULL) != SERIALIZER_OK) 164 | { 165 | (void)printf("Failed on serializer_init\r\n"); 166 | } 167 | else 168 | { 169 | /* Setup IoTHub client configuration */ 170 | IOTHUB_CLIENT_HANDLE iotHubClientHandle = IoTHubClient_CreateFromConnectionString(connectionString, AMQP_Protocol); 171 | srand((unsigned int)time(NULL)); 172 | int avgWindSpeed = 10; 173 | 174 | if (iotHubClientHandle == NULL) 175 | { 176 | (void)printf("Failed on IoTHubClient_Create\r\n"); 177 | } 178 | else 179 | { 180 | #ifdef MBED_BUILD_TIMESTAMP 181 | // For mbed add the certificate information 182 | if (IoTHubClient_SetOption(iotHubClientHandle, "TrustedCerts", certificates) != IOTHUB_CLIENT_OK) 183 | { 184 | (void)printf("failure to set option \"TrustedCerts\"\r\n"); 185 | } 186 | #endif // MBED_BUILD_TIMESTAMP 187 | 188 | ContosoAnemometer* myWeather = CREATE_MODEL_INSTANCE(WeatherStation, ContosoAnemometer); 189 | if (myWeather == NULL) 190 | { 191 | (void)printf("Failed on CREATE_MODEL_INSTANCE\r\n"); 192 | } 193 | else 194 | { 195 | unsigned char* destination; 196 | size_t destinationSize; 197 | 198 | if (IoTHubClient_SetMessageCallback(iotHubClientHandle, IoTHubMessage, myWeather) != IOTHUB_CLIENT_OK) 199 | { 200 | printf("unable to IoTHubClient_SetMessageCallback\r\n"); 201 | } 202 | else 203 | { 204 | int Lock_fd = open_lockfile(LOCKFILE); 205 | if (setuid(getuid()) < 0) 206 | { 207 | perror("Dropping privileges failed. (did you use sudo?)\n"); 208 | exit(EXIT_FAILURE); 209 | } 210 | 211 | int result = wiringPiSetup(); 212 | if (result != 0) exit(result); 213 | 214 | int Spi_fd = wiringPiSPISetup(Spi_channel, Spi_clock); 215 | if (Spi_fd < 0) 216 | { 217 | printf("Can't setup SPI, error %i calling wiringPiSPISetup(%i, %i) %s\n", 218 | Spi_fd, Spi_channel, Spi_clock, strerror(Spi_fd)); 219 | exit(Spi_fd); 220 | } 221 | 222 | int Init_result = bme280_init(Spi_channel); 223 | if (Init_result != 1) 224 | { 225 | printf("It appears that no BMP280 module on Chip Enable %i is attached. Aborting.\n", Spi_channel); 226 | exit(1); 227 | } 228 | 229 | pinMode(Red_led_pin, OUTPUT); 230 | pinMode(Grn_led_pin, OUTPUT); 231 | 232 | //////////////// 233 | 234 | 235 | // Read the Temp & Pressure module. 236 | float tempC = -300.0; 237 | float pressurePa = -300; 238 | float humidityPct = -300; 239 | result = bme280_read_sensors(&tempC, &pressurePa, &humidityPct); 240 | 241 | if (result == 1) 242 | { 243 | printf("Temperature = %.1f *C Pressure = %.1f Pa Humidity = %1f %%\n", 244 | tempC, pressurePa, humidityPct); 245 | } 246 | else 247 | { 248 | printf("Unable to read BME280 on pin %i\n", Spi_channel); 249 | } 250 | 251 | char buff[11]; 252 | int timeNow = 0; 253 | 254 | int c; 255 | while (1) 256 | { 257 | timeNow = (int)time(NULL); 258 | 259 | sprintf(buff, "%d", timeNow); 260 | 261 | myWeather->DeviceId = deviceId; 262 | myWeather->EventTime = buff; 263 | 264 | if (result == 1) 265 | { 266 | myWeather->MTemperature = tempC; 267 | printf("Humidity = %.1f%% Temperature = %.1f*C \n", humidityPct, tempC); 268 | } 269 | else 270 | { 271 | myWeather->MTemperature = 404.0; 272 | printf("Unable to read BME280 on pin %i\n", Spi_channel); 273 | pinMode(Red_led_pin, OUTPUT); 274 | } 275 | 276 | 277 | if (SERIALIZE(&destination, &destinationSize, myWeather->DeviceId, myWeather->EventTime, myWeather->MTemperature) != IOT_AGENT_OK) 278 | { 279 | (void)printf("Failed to serialize\r\n"); 280 | } 281 | else 282 | { 283 | sendMessage(iotHubClientHandle, destination, destinationSize); 284 | } 285 | 286 | delay(5000); 287 | } 288 | /* wait for commands */ 289 | // (void)getchar(); 290 | 291 | close_lockfile(Lock_fd); 292 | 293 | } 294 | DESTROY_MODEL_INSTANCE(myWeather); 295 | } 296 | IoTHubClient_Destroy(iotHubClientHandle); 297 | } 298 | serializer_deinit(); 299 | } 300 | } 301 | } 302 | 303 | int mcp3008Read(int analog_in_channel) 304 | { 305 | int result; 306 | 307 | if ((analog_in_channel > 7) || (analog_in_channel < 0)) 308 | { 309 | result = -1; 310 | } 311 | else 312 | { 313 | // Send the convert command and channel to the chip. 314 | // Simultaneously read back two bytes from the chip. 315 | unsigned char buf[3]; 316 | // Start bit. 317 | buf[0] = 0x01; 318 | // Bit 7 = single-ended, Bits 6-4 = channel. 319 | buf[1] = (0x80 + (analog_in_channel << 4)); 320 | buf[2] = 0; 321 | result = wiringPiSPIDataRW(Spi_channel, buf, 3); 322 | if (result >= 0) 323 | { 324 | // Extract the relevant 10 bits. 325 | result = ((buf[1] & 3) << 8) + buf[2]; 326 | } 327 | } 328 | return result; 329 | } 330 | 331 | -------------------------------------------------------------------------------- /samples/simplesample_amqp/simplesample_amqp.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) Microsoft. All rights reserved. 2 | // Licensed under the MIT license. See LICENSE file in the project root for full license information. 3 | 4 | #ifndef SIMPLESAMPLEAMQP_H 5 | #define SIMPLESAMPLEAMQP_H 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | void simplesample_amqp_run(void); 12 | 13 | #ifdef __cplusplus 14 | } 15 | #endif 16 | 17 | #endif /* SIMPLESAMPLEAMQP_H */ 18 | --------------------------------------------------------------------------------