Project tutorial
Project KOOL: Temperature and Humidity Remote Monitoring

Project KOOL: Temperature and Humidity Remote Monitoring © GPL3+

This KOOL project is a proof-of-concept implementation of temperature and humidity remote monitoring for a cold water delivery company.

  • 5,810 views
  • 1 comment
  • 17 respects

Components and supplies

Apps and online services

About this project

Company ABC is a building maintenance company which provides air-conditioning facility to keep the temperature of office building cool in the area of Cyberjaya, Malaysia. Cold water is delivered to buildings to keep the buildings in cool and comfortable level. Under the SLA (service level agreement), Company ABC will pay certain penalty if the company does not fulfill its responsibility to keep the buildings below certain level of temperature.

Company ABC has identify two of the important metrics to monitor namely the temperature and humidity. Of course, there are other factors which have am impact to the cold water delivery efficiency. With sensors deployed to the remote building, Company ABC hopes to receive alerts before the level of temperature of buildings breaching the SLA.

The distance between the cold water delivery center of the Company ABC and those buildings are an important factor as longer distance means that the temperature of the cold water will be higher arriving those buildings. And humidity has a minor impact compared to temperature. The temperature and humidity alert thresholds are set based on Company ABC's collected historical data and distance of the building. Whenever an alert threshold is hit, an alarm will be issued and shown on the Alarm History panel on the dashboard. At the same time, the location pin of the respective building on the map will change its color to indicate the alert. Table below shows the location (latitude and longitude) of the sensors at the buildings.

  • DHL_Cyberjaya @ 2.922188, 101.656551
  • LHDN_Cyberjaya @ 2.910881, 101.650145
  • MMU_Cyberjaya @ 2.927704, 101.642050
  • MPEC @ 2.922412, 101.659017
  • MaGIC @ 2.909192, 101.654814
  • NTT_MSC @ 2.925622, 101.658963

This is the table of thresholds.

Azure IOT Suite Remote Monitoring Solution

The project is built based on the Azure IOT suite remote monitoring solution. A remote monitoring solution for this project is made using this tutorial. The above sensors are add to the remote monitoring solution, as shown in the map below.

Sensors at the following locations are simulated devices:

  • MMU_Cyberjaya
  • MPEC
  • MaGIC
  • NTT_MSC

And the following are custom devices:.

  • DHL_Cyberjaya (a simulator C program running on a Windows 10 device)
  • LHDN_Cyberjaya (live device running on Genuino MKR1000)

Note that the thresholds of the temperature and humidity are estimated based on empirical data with the consideration of the distance between the chiller center and buildings.

Connecting the DHL_Cyberjaya sensor

This is a simulator written in C language which can be run on any Windows 10 devices. I use my DELL notebook and Advantech ARK-1123 to test this simulator. ARK-1123H is an embedded IoT Gateway which is Azure certified.

.

For detail instruction, follow this "Connect your device to the remote monitoring preconfigured solution (Windows) " guide to get the sensor connected to the Azure IOT preconfigured solution. I have added some random data generation code to make more realistic data. You can get the code (RMDevice.c) from the code section in this project.

void GetNextRawValue(struct RandomGeneratorParam *param) { 
	double val = (double)rand() / RAND_MAX; 
	double adjustment = ((2.0 * (*param).deltaValue) * val) - (*param).deltaValue; 
	(*param).nextValue += adjustment; 
	if ((*param).nextValue < (*param).minValueToGenerate || (*param).nextValue >(*param).maxNonPeakValueToGenerate) { 
		(*param).nextValue -= adjustment; 
		if ((*param).nextValue < (*param).minValueToGenerate || (*param).nextValue >(*param).maxNonPeakValueToGenerate) { 
			(*param).nextValue = (*param).startValue; 
		} 
	} 
} 
double GetNextValue(struct RandomGeneratorParam *param) { 
	GetNextRawValue(param); 
	bool determinePeak = (*param).generatePeaks && ((*param).tickCounter % (*param).peakInterval) == 0; 
	++((*param).tickCounter); 
	if (determinePeak) { 
		return (*param).nextValue + (*param).thresholdWidth; 
	} 
	return (*param).nextValue; 
} 

Create a custom device and add to the preconfigured solution.

.

Running the custom device simulator.

Connecting the LHDN_Cyberjaya sensor

I am using Genuino MKR1000 and DHT11 for this custom device. Follow the "ADD A CUSTOM DEVICE TO THE AZURE IOT SUITE REMOTE MONITORING SOLUTION" guide to set this up. I have changed the code to use the DHT11 sensor. All the code are in the code section of this project. You will need to change the WiFi setting and the device ID and key.

Setup the SSL certificate for the remote monitoring solution. The URL will be like [web-app-name].azurewebsites.net. Follow this link if you need more details on how to set it up.

Upload and run the code from the Arduino IDE: select Tools -> Serial Monitor. You can check the log from here.

Video Demo

Code

remote_monitoring.inoC/C++
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

// Use Arduino IDE 1.6.8 or later.

#include <stdlib.h>
#include <stdio.h>
#include <stdint.h>
#include <time.h>
#include <sys/time.h>
#include <WiFi101.h>
#include "remote_monitoring.h"
#include "NTPClient.h"
#include "AzureIoTHubClient.h"

WiFiSSLClient sslClient;
AzureIoTHubClient iotHubClient(sslClient);

static const char ssid[] = "[Your WiFi network SSID or name]";
static const char pass[] = "[Your WiFi network WPA password or WEP key]";

int status = WL_IDLE_STATUS;

void setup() {
    // The Feather M0 loses it's COMn connection with every reset.
    // This 10 s delay allows you to reselect the COM port and open the serial monitor window.
    delay(10000);
    
    initSerial();

    initWifi();
    
    initTime();
}

void loop() {
    // Run the Remote Monitoring from the Azure IoT Hub C SDK
    // You must set the device id, device key, IoT Hub name and IotHub suffix in
    // remote_monitoring.c
    remote_monitoring_run();
}

void initSerial() {
    // Start serial and initialize stdout
    Serial.begin(115200);
    //Serial.setDebugOutput(true);
}

void initWifi() {
    // Attempt to connect to Wifi network:
    Serial.print("Attempting to connect to SSID: ");
    Serial.println(ssid);

    // Connect to WPA/WPA2 network. Change this line if using open or WEP network:
    status = WiFi.begin(ssid, pass);

    while (WiFi.status() != WL_CONNECTED) {
        delay(500);
        Serial.print(".");
    }

    Serial.println("Connected to wifi");
}

///////////////////////////////////////////////////////////////////////////////////////////////////
void initTime() {
#ifdef ARDUINO_SAMD_FEATHER_M0
    Adafruit_WINC1500UDP     _udp;
#elif defined(ARDUINO_SAMD_ZERO) || defined(ARDUINO_SAMD_MKR1000)
    WiFiUDP     _udp;
#endif

    time_t epochTime = (time_t)-1;

    NTPClient ntpClient;
    ntpClient.begin();

    while (true) {
        epochTime = ntpClient.getEpochTime("0.pool.ntp.org");

        if (epochTime == (time_t)-1) {
            Serial.println("Fetching NTP epoch time failed! Waiting 5 seconds to retry.");
            delay(5000);
        } else {
            Serial.print("Fetched NTP epoch time is: ");
            Serial.println(epochTime);
            break;
        }
    }
    
    ntpClient.end();

    struct timeval tv;
    tv.tv_sec = epochTime;
    tv.tv_usec = 0;

    settimeofday(&tv, NULL);
}
remote_monitoring.hC/C++
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#ifndef REMOTE_MONITORING_H
#define REMOTE_MONITORING_H

#ifdef __cplusplus
extern "C" {
#endif

void remote_monitoring_run(void);

#ifdef __cplusplus
}
#endif

#endif /* REMOTE_MONITORING_H */
remote_monitoring.cC/C++
// Copyright (c) Microsoft. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#include "AzureIoTHub.h"
#include "sdk/schemaserializer.h"
#include "dht11.h"


static const char* deviceId = "[device-id]";
static const char* deviceKey = "[device-key]";
static const char* hubName = "[hub-name]";
static const char* hubSuffix = "azure-devices.net";

// Define the Model
BEGIN_NAMESPACE(Contoso);

DECLARE_STRUCT(SystemProperties,
    ascii_char_ptr, DeviceID,
    _Bool, Enabled
);

DECLARE_STRUCT(DeviceProperties,
ascii_char_ptr, DeviceID,
_Bool, HubEnabledState
);

DECLARE_MODEL(Thermostat,

    /* Event data (temperature, external temperature and humidity) */
    WITH_DATA(int, Temperature),
    WITH_DATA(int, ExternalTemperature),
    WITH_DATA(int, Humidity),
    WITH_DATA(ascii_char_ptr, DeviceId),

    /* Device Info - This is command metadata + some extra fields */
    WITH_DATA(ascii_char_ptr, ObjectType),
    WITH_DATA(_Bool, IsSimulatedDevice),
    WITH_DATA(ascii_char_ptr, Version),
    WITH_DATA(DeviceProperties, DeviceProperties),
    WITH_DATA(ascii_char_ptr_no_quotes, Commands),

    /* Commands implemented by the device */
    WITH_ACTION(SetTemperature, int, temperature),
    WITH_ACTION(SetHumidity, int, humidity)
);

END_NAMESPACE(Contoso);

EXECUTE_COMMAND_RESULT SetTemperature(Thermostat* thermostat, int temperature)
{
    LogInfo("Received temperature %d\r\n", temperature);
    thermostat->Temperature = temperature;
    return EXECUTE_COMMAND_SUCCESS;
}

EXECUTE_COMMAND_RESULT SetHumidity(Thermostat* thermostat, int humidity)
{
    LogInfo("Received humidity %d\r\n", humidity);
    thermostat->Humidity = humidity;
    return EXECUTE_COMMAND_SUCCESS;
}

static void sendMessage(IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle, const unsigned char* buffer, size_t size)
{
    IOTHUB_MESSAGE_HANDLE messageHandle = IoTHubMessage_CreateFromByteArray(buffer, size);
    if (messageHandle == NULL)
    {
        LogInfo("unable to create a new IoTHubMessage\r\n");
    }
    else
    {
        if (IoTHubClient_LL_SendEventAsync(iotHubClientHandle, messageHandle, NULL, NULL) != IOTHUB_CLIENT_OK)
        {
            LogInfo("failed to hand over the message to IoTHubClient");
        }
        else
        {
            LogInfo("IoTHubClient accepted the message for delivery\r\n");
        }

        IoTHubMessage_Destroy(messageHandle);
    }
    free((void*)buffer);
}

/*this function "links" IoTHub to the serialization library*/
static IOTHUBMESSAGE_DISPOSITION_RESULT IoTHubMessage(IOTHUB_MESSAGE_HANDLE message, void* userContextCallback)
{
    IOTHUBMESSAGE_DISPOSITION_RESULT result;
    const unsigned char* buffer;
    size_t size;
    if (IoTHubMessage_GetByteArray(message, &buffer, &size) != IOTHUB_MESSAGE_OK)
    {
        LogInfo("unable to IoTHubMessage_GetByteArray\r\n");
        result = EXECUTE_COMMAND_ERROR;
    }
    else
    {
        /*buffer is not zero terminated*/
        char* temp = malloc(size + 1);
        if (temp == NULL)
        {
            LogInfo("failed to malloc\r\n");
            result = EXECUTE_COMMAND_ERROR;
        }
        else
        {
            EXECUTE_COMMAND_RESULT executeCommandResult;

            memcpy(temp, buffer, size);
            temp[size] = '\0';
            executeCommandResult = EXECUTE_COMMAND(userContextCallback, temp);
            result =
                (executeCommandResult == EXECUTE_COMMAND_ERROR) ? IOTHUBMESSAGE_ABANDONED :
                (executeCommandResult == EXECUTE_COMMAND_SUCCESS) ? IOTHUBMESSAGE_ACCEPTED :
                IOTHUBMESSAGE_REJECTED;
            free(temp);
        }
    }
    return result;
}

void remote_monitoring_run(void)
{
        initDHT();

        srand((unsigned int)time(NULL));
        if (serializer_init(NULL) != SERIALIZER_OK)
        {
            LogInfo("Failed on serializer_init\r\n");
        }
        else
        {
            IOTHUB_CLIENT_CONFIG config;
            IOTHUB_CLIENT_LL_HANDLE iotHubClientHandle;

            config.deviceId = deviceId;
            config.deviceKey = deviceKey;
            config.iotHubName = hubName;
            config.iotHubSuffix = hubSuffix;
            config.protocol = HTTP_Protocol;

            iotHubClientHandle = IoTHubClient_LL_Create(&config);
            if (iotHubClientHandle == NULL)
            {
                LogInfo("Failed on IoTHubClient_CreateFromConnectionString\r\n");
            }
            else
            {
#ifdef MBED_BUILD_TIMESTAMP
                // For mbed add the certificate information
                if (IoTHubClient_LL_SetOption(iotHubClientHandle, "TrustedCerts", certificates) != IOTHUB_CLIENT_OK)
                {
                    LogInfo("failure to set option \"TrustedCerts\"\r\n");
                }
#endif // MBED_BUILD_TIMESTAMP

                Thermostat* thermostat = CREATE_MODEL_INSTANCE(Contoso, Thermostat);
                if (thermostat == NULL)
                {
                    LogInfo("Failed on CREATE_MODEL_INSTANCE\r\n");
                }
                else
                {
                    STRING_HANDLE commandsMetadata;

                    if (IoTHubClient_LL_SetMessageCallback(iotHubClientHandle, IoTHubMessage, thermostat) != IOTHUB_CLIENT_OK)
                    {
                        LogInfo("unable to IoTHubClient_SetMessageCallback\r\n");
                    }
                    else
                    {

                        /* send the device info upon startup so that the cloud app knows
                        what commands are available and the fact that the device is up */
                        thermostat->ObjectType = "DeviceInfo";
                        thermostat->IsSimulatedDevice = false;
                        thermostat->Version = "1.0";
                        thermostat->DeviceProperties.HubEnabledState = true;
                        thermostat->DeviceProperties.DeviceID = (char*)deviceId;

                        commandsMetadata = STRING_new();
                        if (commandsMetadata == NULL)
                        {
                            LogInfo("Failed on creating string for commands metadata\r\n");
                        }
                        else
                        {
                            /* Serialize the commands metadata as a JSON string before sending */
                            if (SchemaSerializer_SerializeCommandMetadata(GET_MODEL_HANDLE(Contoso, Thermostat), commandsMetadata) != SCHEMA_SERIALIZER_OK)
                            {
                                LogInfo("Failed serializing commands metadata\r\n");
                            }
                            else
                            {
                                unsigned char* buffer;
                                size_t bufferSize;
                                thermostat->Commands = (char*)STRING_c_str(commandsMetadata);

                                /* Here is the actual send of the Device Info */
                                if (SERIALIZE(&buffer, &bufferSize, thermostat->ObjectType, thermostat->Version, thermostat->IsSimulatedDevice, thermostat->DeviceProperties, thermostat->Commands) != IOT_AGENT_OK)
                                {
                                    LogInfo("Failed serializing\r\n");
                                }
                                else
                                {
                                    sendMessage(iotHubClientHandle, buffer, bufferSize);
                                }

                            }

                            STRING_delete(commandsMetadata);
                        }

                        thermostat->DeviceId = (char*)deviceId;
                        int sendCycle = 10;
                        int currentCycle = 0;
                        while (1)
                        {
                            if(currentCycle >= sendCycle) {
                                float Temp;
                                float Humi;
                                getNextSample(&Temp, &Humi);
                                thermostat->Temperature = (int)round(Temp);
                                thermostat->ExternalTemperature = 55 + (rand() % 5 + 2);
                                thermostat->Humidity = (int)round(Humi);
                                currentCycle = 0;
                                unsigned char*buffer;
                                size_t bufferSize;

                                LogInfo("Sending sensor value Temperature = %d, Humidity = %d\r\n", thermostat->Temperature, thermostat->Humidity);

                                if (SERIALIZE(&buffer, &bufferSize, thermostat->DeviceId, thermostat->Temperature, thermostat->Humidity, thermostat->ExternalTemperature) != IOT_AGENT_OK)
                                {
                                    LogInfo("Failed sending sensor value\r\n");
                                }
                                else
                                {
                                    sendMessage(iotHubClientHandle, buffer, bufferSize);
                                }
                            }

                            IoTHubClient_LL_DoWork(iotHubClientHandle);
                            ThreadAPI_Sleep(100);
                            currentCycle++;
                        }
                    }

                    DESTROY_MODEL_INSTANCE(thermostat);
                }
                IoTHubClient_LL_Destroy(iotHubClientHandle);
            }
            serializer_deinit();

    }
}
NTPClient.hC/C++
// Copyright (c) Arduino. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#ifdef ARDUINO_SAMD_FEATHER_M0
#include <Adafruit_WINC1500.h>
#include <Adafruit_WINC1500Udp.h>
#elif defined(ARDUINO_SAMD_ZERO) || defined(ARDUINO_SAMD_MKR1000)
#include <WiFi101.h>
#include <WiFiUdp.h>
#endif

#ifndef NTPCLIENT_H
#define NTPCLIENT_H

#define NTP_PACKET_SIZE     48
#define NTP_PORT            123

#define DEFAULT_NTP_TIMEOUT 10000

class NTPClient
{
    public:
        NTPClient();
        int begin();
        uint32_t getEpochTime(const char* host, int port = NTP_PORT, unsigned long timeout = DEFAULT_NTP_TIMEOUT);
        void end();

    private:
        void prepareRequest();
        void sendRequest(const char* host, int port);
        int receiveResponse(unsigned long timeout);
        uint32_t parseResponse();

        char        _buffer[NTP_PACKET_SIZE];
#ifdef ARDUINO_SAMD_FEATHER_M0
        Adafruit_WINC1500UDP     _udp;
#elif defined(ARDUINO_SAMD_ZERO) || defined(ARDUINO_SAMD_MKR1000)
        WiFiUDP     _udp;
#endif

};

#endif
NTPClient.cppC/C++
// Copyright (c) Arduino. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

#if defined(ARDUINO_ARCH_SAMD)
#include "NTPClient.h"

#define LOCAL_UDP_PORT 2390

NTPClient::NTPClient() :
    _udp()
{
}

int NTPClient::begin()
{
    return _udp.begin(LOCAL_UDP_PORT);
}

uint32_t NTPClient::getEpochTime(const char* host, int port, unsigned long timeout)
{
    if (host == NULL || port < 1) {
        return (uint32_t)-1;
    }

    prepareRequest();
    sendRequest(host, port);

    if (!receiveResponse(timeout)) {
        return (uint32_t)-1;
    }

    return parseResponse();
}

void NTPClient::end()
{
    _udp.stop();
}

void NTPClient::prepareRequest()
{
    memset(_buffer, 0, NTP_PACKET_SIZE);

    // Initialize values needed to form NTP request
    _buffer[0] = 0b11100011;   // LI, Version, Mode
    _buffer[1] = 0;     // Stratum, or type of clock
    _buffer[2] = 6;     // Polling Interval
    _buffer[3] = 0xEC;  // Peer Clock Precision

    // 8 bytes of zero for Root Delay & Root Dispersion

    _buffer[12] = 49;
    _buffer[13] = 0x4E;
    _buffer[14] = 49;
    _buffer[15] = 52;
}

void NTPClient::sendRequest(const char* host, int port)
{
    _udp.beginPacket(host, port);
    _udp.write(_buffer, NTP_PACKET_SIZE);
    _udp.endPacket();
}

int NTPClient::receiveResponse(unsigned long timeout)
{
    long start = millis();
    int size = 0;

    while(size == 0 && (millis() - start) < timeout) {
        size = _udp.parsePacket();
    }

    if (size != NTP_PACKET_SIZE) {
        return 0;
    }

    _udp.read(_buffer, NTP_PACKET_SIZE);

    return 1;
}

uint32_t NTPClient::parseResponse()
{
    uint16_t high = word(_buffer[40], _buffer[41]);
    uint16_t low = word(_buffer[42], _buffer[43]);
    uint32_t ntpTime = high << 16 | low; // since 1900
    uint32_t epoch = ntpTime - 2208988800UL; // since 1970

    return epoch;
}
#endif
dht11.hC/C++
#ifndef __DHT11_H
#define __DHT11_H


#ifdef __cplusplus
extern "C" {
#endif

///////////////////////////////////////////////////////////////////////////////////////////////////
void initDHT(void);

///////////////////////////////////////////////////////////////////////////////////////////////////
void getNextSample(float* Temperature, float* Humidity);

#ifdef __cplusplus
}
#endif


#endif//__DHT11_H
dht11.cppC/C++
#include <Arduino.h>
#include "DHT.h"
#include "dht11.h"

#define DHTPIN 2     // what digital pin we're connected to
#define DHTTYPE DHT11   // DHT 11

DHT dht(DHTPIN, DHTTYPE);

bool DHT_init_result = false;


///////////////////////////////////////////////////////////////////////////////////////////////////
void initDHT(void)
{
dht.begin();
}

///////////////////////////////////////////////////////////////////////////////////////////////////
void getNextSample(float* Temperature, float* Humidity)
{
  // Wait a few seconds between measurements.
  delay(2000);

  // Reading temperature or humidity takes about 250 milliseconds!
  // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor)
  *Humidity = dht.readHumidity();
  // Read temperature as Celsius (the default)
  *Temperature = dht.readTemperature();
  // Read temperature as Fahrenheit (isFahrenheit = true)
  // float f = dht.readTemperature(true);

  //printf("Temp=%.2f, Pres=%.2f, Humi=%.2f\n", Temp_c__f, Pres_hPa__f, Humi_pct__f);
  printf("Temp=%.2f, Humi=%.2f\n", *Temperature, *Humidity);
}
RMDevice.cC/C++
// RMDevice.cpp : Defines the entry point for the console application.
//

#include "iothubtransporthttp.h"
#include "schemalib.h"
#include "iothub_client.h"
#include "serializer.h"
#include "schemaserializer.h"
#include "azure_c_shared_utility/threadapi.h"
#include "azure_c_shared_utility/platform.h"
#include "stdlib.h"
#include <math.h>



static const char* deviceId = "DHL_Cyberjaya";
static const char* deviceKey = "devicekey";
static const char* hubName = "hubname";
static const char* hubSuffix = "azure-devices.net";

struct RandomGeneratorParam {
	double maximumFractionToChangePerTick;
	double minValueToGenerate;
	double maxNonPeakValueToGenerate;
	double minPeakValueToGenerate;
	bool generatePeaks;
	int peakInterval;
	double startValue;
	double nextValue;
	double deltaValue;
	double thresholdWidth;
	long tickCounter;
};

struct RandomGeneratorParam temperatureParam, humidityParam;

void CheckParams(struct RandomGeneratorParam *param) {
	(*param).maximumFractionToChangePerTick = 0.10;

	if ((*param).minValueToGenerate >= (*param).maxNonPeakValueToGenerate) {
		exit(1);
	}
	
	if ((*param).minPeakValueToGenerate != 0 && ((*param).maxNonPeakValueToGenerate >= (*param).minPeakValueToGenerate)) {
		exit(1);
	}

	(*param).generatePeaks = (*param).minPeakValueToGenerate != 0 ? true : false;

	if ((*param).generatePeaks && (*param).peakInterval == 0) {
		exit(1);
	}

	(*param).minPeakValueToGenerate = (*param).minPeakValueToGenerate * 1.01;

	(*param).startValue = (((*param).maxNonPeakValueToGenerate - (*param).minValueToGenerate) / 2.0) + (*param).minValueToGenerate;
	(*param).nextValue = (*param).startValue;

	(*param).deltaValue = ((*param).maxNonPeakValueToGenerate - (*param).minValueToGenerate) * (*param).maximumFractionToChangePerTick;
	(*param).thresholdWidth = (*param).minPeakValueToGenerate - (*param).minValueToGenerate;
	
	(*param).tickCounter = 1;

}

void GetNextRawValue(struct RandomGeneratorParam *param) {
	double val = (double)rand() / RAND_MAX;
	double adjustment = ((2.0 * (*param).deltaValue) * val) - (*param).deltaValue;
	(*param).nextValue += adjustment;

	if ((*param).nextValue < (*param).minValueToGenerate || (*param).nextValue >(*param).maxNonPeakValueToGenerate) {
		(*param).nextValue -= adjustment;

		if ((*param).nextValue < (*param).minValueToGenerate || (*param).nextValue >(*param).maxNonPeakValueToGenerate) {
			(*param).nextValue = (*param).startValue;
		}
	}
}

double GetNextValue(struct RandomGeneratorParam *param) {
	GetNextRawValue(param);
	bool determinePeak = (*param).generatePeaks && ((*param).tickCounter % (*param).peakInterval) == 0;
	++((*param).tickCounter);
	if (determinePeak) {
		return (*param).nextValue + (*param).thresholdWidth;
	}
	return (*param).nextValue;
}


// Define the Model
BEGIN_NAMESPACE(Contoso);

DECLARE_STRUCT(SystemProperties,
ascii_char_ptr, DeviceID,
_Bool, Enabled
);

DECLARE_STRUCT(DeviceProperties,
ascii_char_ptr, DeviceID,
_Bool, HubEnabledState
);

DECLARE_MODEL(Thermostat,

/* Event data (temperature, external temperature and humidity) */
WITH_DATA(double, Temperature),
//WITH_DATA(int, ExternalTemperature),
WITH_DATA(double, Humidity),
WITH_DATA(ascii_char_ptr, DeviceId),

/* Device Info - This is command metadata + some extra fields */
WITH_DATA(ascii_char_ptr, ObjectType),
WITH_DATA(_Bool, IsSimulatedDevice),
WITH_DATA(ascii_char_ptr, Version),
WITH_DATA(DeviceProperties, DeviceProperties),
WITH_DATA(ascii_char_ptr_no_quotes, Commands),

/* Commands implemented by the device */
WITH_ACTION(SetTemperature, int, temperature),
WITH_ACTION(SetHumidity, int, humidity)
);

END_NAMESPACE(Contoso);


EXECUTE_COMMAND_RESULT SetTemperature(Thermostat* thermostat, int temperature)
{
	(void)printf("Received temperature %d\r\n", temperature);
	thermostat->Temperature = temperature;
	return EXECUTE_COMMAND_SUCCESS;
}

EXECUTE_COMMAND_RESULT SetHumidity(Thermostat* thermostat, int humidity)
{
	(void)printf("Received humidity %d\r\n", humidity);
	thermostat->Humidity = humidity;
	return EXECUTE_COMMAND_SUCCESS;
}


static void sendMessage(IOTHUB_CLIENT_HANDLE iotHubClientHandle, const unsigned char* buffer, size_t size)
{
	IOTHUB_MESSAGE_HANDLE messageHandle = IoTHubMessage_CreateFromByteArray(buffer, size);
	if (messageHandle == NULL)
	{
		printf("unable to create a new IoTHubMessage\r\n");
	}
	else
	{
		if (IoTHubClient_SendEventAsync(iotHubClientHandle, messageHandle, NULL, NULL) != IOTHUB_CLIENT_OK)
		{
			printf("failed to hand over the message to IoTHubClient");
		}
		else
		{
			printf("IoTHubClient accepted the message for delivery\r\n");
		}

		IoTHubMessage_Destroy(messageHandle);
	}
	free((void*)buffer);
}



static IOTHUBMESSAGE_DISPOSITION_RESULT IoTHubMessage(IOTHUB_MESSAGE_HANDLE message, void* userContextCallback)
{
	IOTHUBMESSAGE_DISPOSITION_RESULT result;
	const unsigned char* buffer;
	size_t size;
	if (IoTHubMessage_GetByteArray(message, &buffer, &size) != IOTHUB_MESSAGE_OK)
	{
		printf("unable to IoTHubMessage_GetByteArray\r\n");
		result = EXECUTE_COMMAND_ERROR;
	}
	else
	{
		/*buffer is not zero terminated*/
		char* temp = malloc(size + 1);
		if (temp == NULL)
		{
			printf("failed to malloc\r\n");
			result = EXECUTE_COMMAND_ERROR;
		}
		else
		{
			memcpy(temp, buffer, size);
			temp[size] = '\0';
			EXECUTE_COMMAND_RESULT executeCommandResult = EXECUTE_COMMAND(userContextCallback, temp);
			result =
				(executeCommandResult == EXECUTE_COMMAND_ERROR) ? IOTHUBMESSAGE_ABANDONED :
				(executeCommandResult == EXECUTE_COMMAND_SUCCESS) ? IOTHUBMESSAGE_ACCEPTED :
				IOTHUBMESSAGE_REJECTED;
			free(temp);
		}
	}
	return result;
}


void remote_monitoring_run(void)
{
	if (serializer_init(NULL) != SERIALIZER_OK)
	{
		printf("Failed on serializer_init\r\n");
	}
	else
	{
		IOTHUB_CLIENT_CONFIG config;
		IOTHUB_CLIENT_HANDLE iotHubClientHandle;

		config.deviceId = deviceId;
		config.deviceKey = deviceKey;
		config.iotHubName = hubName;
		config.iotHubSuffix = hubSuffix;
		config.protocol = HTTP_Protocol;
		config.deviceSasToken = NULL;
		config.protocolGatewayHostName = NULL;
		iotHubClientHandle = IoTHubClient_Create(&config);
		if (iotHubClientHandle == NULL)
		{
			(void)printf("Failed on IoTHubClient_CreateFromConnectionString\r\n");
		}
		else
		{
			Thermostat* thermostat = CREATE_MODEL_INSTANCE(Contoso, Thermostat);
			if (thermostat == NULL)
			{
				(void)printf("Failed on CREATE_MODEL_INSTANCE\r\n");
			}
			else
			{
				STRING_HANDLE commandsMetadata;

				if (IoTHubClient_SetMessageCallback(iotHubClientHandle, IoTHubMessage, thermostat) != IOTHUB_CLIENT_OK)
				{
					printf("unable to IoTHubClient_SetMessageCallback\r\n");
				}
				else
				{

					/* send the device info upon startup so that the cloud app knows
					what commands are available and the fact that the device is up */
					thermostat->ObjectType = "DeviceInfo";
					thermostat->IsSimulatedDevice = false;
					thermostat->Version = "1.0";
					thermostat->DeviceProperties.HubEnabledState = true;
					thermostat->DeviceProperties.DeviceID = (char*)deviceId;

					commandsMetadata = STRING_new();
					if (commandsMetadata == NULL)
					{
						(void)printf("Failed on creating string for commands metadata\r\n");
					}
					else
					{
						/* Serialize the commands metadata as a JSON string before sending */
						if (SchemaSerializer_SerializeCommandMetadata(GET_MODEL_HANDLE(Contoso, Thermostat), commandsMetadata) != SCHEMA_SERIALIZER_OK)
						{
							(void)printf("Failed serializing commands metadata\r\n");
						}
						else
						{
							unsigned char* buffer;
							size_t bufferSize;
							thermostat->Commands = (char*)STRING_c_str(commandsMetadata);

							/* Here is the actual send of the Device Info */
							if (SERIALIZE(&buffer, &bufferSize, thermostat->ObjectType, thermostat->Version, thermostat->IsSimulatedDevice, thermostat->DeviceProperties, thermostat->Commands) != IOT_AGENT_OK)
							{
								(void)printf("Failed serializing\r\n");
							}
							else
							{
								sendMessage(iotHubClientHandle, buffer, bufferSize);
							}

						}

						STRING_delete(commandsMetadata);
					}



					const int REPORT_FREQUENCY_IN_SECONDS = 5;
					const int PEAK_FREQUENCY_IN_SECONDS = 90;

					int peakFrequencyInTicks = ceil((double)PEAK_FREQUENCY_IN_SECONDS / REPORT_FREQUENCY_IN_SECONDS);

					humidityParam.minValueToGenerate = 20;
					humidityParam.maxNonPeakValueToGenerate = 50;
					humidityParam.minPeakValueToGenerate = 0;
					humidityParam.peakInterval = 0;

					CheckParams(&humidityParam);

					temperatureParam.minValueToGenerate = 33;
					temperatureParam.maxNonPeakValueToGenerate = 36;
					temperatureParam.minPeakValueToGenerate = 42;
					temperatureParam.peakInterval = peakFrequencyInTicks;

					CheckParams(&temperatureParam);

					while (1)
					{
						unsigned char*buffer;
						size_t bufferSize;


						//thermostat->ExternalTemperature = 35;

						thermostat->Temperature = GetNextValue(&temperatureParam);
						thermostat->Humidity = GetNextValue(&humidityParam);

						thermostat->DeviceId = (char*)deviceId;

						(void)printf("Sending sensor value Temperature = %lf, Humidity = %lf\r\n", thermostat->Temperature, thermostat->Humidity);

						if (SERIALIZE(&buffer, &bufferSize, thermostat->DeviceId, thermostat->Temperature, thermostat->Humidity) != IOT_AGENT_OK)
						{
							(void)printf("Failed sending sensor value\r\n");
						}
						else
						{
							sendMessage(iotHubClientHandle, buffer, bufferSize);
						}

						ThreadAPI_Sleep(2000);
					}
				}

				DESTROY_MODEL_INSTANCE(thermostat);
			}
			IoTHubClient_Destroy(iotHubClientHandle);
		}
		serializer_deinit();
	}
}



int main()
{
	time_t t;

	/* Intializes random number generator */
	srand((unsigned)time(&t));

	remote_monitoring_run();
	return 0;
}

Comments

Similar projects you might like

MKR1000 Temp and Humidity Sensor

Project tutorial by Don Coleman

  • 18,134 views
  • 11 comments
  • 31 respects

Humidity and Temperature Monitoring System

Project tutorial by Vinayak Shantaram Joshi

  • 4,799 views
  • 2 comments
  • 16 respects

How to read temperature and humidity on Blynk with DHT11

Project tutorial by Tech with Matthew

  • 10,686 views
  • 3 comments
  • 14 respects

Temperature and humidity meter (iot)

Project showcase by 윤원호 and gledel

  • 5,689 views
  • 1 comment
  • 15 respects

Temperature and Humidity Data Logger

Project tutorial by Wimpie van den Berg

  • 23,409 views
  • 2 comments
  • 22 respects
Add projectSign up / Login