56 |
57 |
Current Temperature
The last recorded reading on device {{ latest_reading.deviceid }} was:
58 |
59 |
60 |
61 | Temperature |
62 | Time |
63 |
64 |
65 |
66 |
67 | {{ latest_reading.temperature | number }}°C | {{ latest_reading.eventtime | date : 'medium' }} |
68 |
69 |
70 |
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 | Temperature |
87 | Time |
88 |
89 |
90 |
91 |
92 | {{ t.temperature | number }}°C | {{ t.eventtime | date : 'medium' }} |
93 |
94 |
95 |
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 |
--------------------------------------------------------------------------------