IoT Thermometer

Authors
  • Augustine Ho
  • Ryan Huff
  • Kartik Prabhu
  • Angel Sanchez
Description

This is an IoT thermostat using MQTT to communicate between a slave device, a web application and windows application and an on board mbed through a server. The slave device only publishes/sends current temperature readings. The web and windows applications publish target temperatures, scheduled temperatures, and on/off thermostat switch to the server. The on board mbed mechanically controls the thermostat.

When the onboard mbed receives a a target temperature from either the on board push buttons, the web application, or the windows application, it will turn heating or cooling on full blast until the target temperature is fulfilled. If the target temperature is met the thermostat will be turned off and then wait until the current temperature deviates a few degrees away from the target temperature.

The web application and windows application also have scheduling features that takes in four start times and four target temperatures, one for each start time. From startTime1 to startTime2 it will set the temperature to the first given target temperature and so on.

Parts List
  1. LPC1768 mbed
  2. Push Buttons
  3. uLCD
  4. TMP36 sensor
  5. DC motors
  6. RJ45 Magjack
  7. TB6612FNG H-Bridges

This IoT thermometer has push buttons to change the target temperature. It also has a uLCD to display the current temperature read by the TMP36 sensor and the target temperature. The display's background indicates what mode it is in either heating or cooling or off. The mbed will control the thermometer with 3 DC motors using two TB6612FNG H-Bridges. One DC motor is used to flip the thermometer switch up to turn on the heating/cooling and one DC motor is used to flip the thermometer switch down to turn off the heating/cooling. The third DC motor is used to rotate the thermometer nob, which indicates how strong the heating or cooling will be. For our purposes this motor will always turn the nob all the way CCW to cool or all the way CW to heating. The mbed will be connected to the internet via MagJack and ethernet cord in order to receive messages from the online applications through MQTT.

Schematics

Mechanical Controls Schematic Mechanical Controls Schematic

Slave Device Schematic Slave Device Schematic

Source Code

ThermostatControllerMain.cpp

#include "mbed.h"
#include "uLCD_4DGL.h"
#include "easy-connect.h"
#include "MQTTNetwork.h"
#include "MQTTmbed.h"
#include "MQTTClient.h"
#include "credentials.h"
#include "Motor.h"

using namespace std;

int currentTemp = 0;
int targetTemp = 75;
int threshold = 2;
bool modeChange = false;

Motor m(p23, p5, p6); // pwm, fwd, rev - top motor
Motor m2(p24, p9, p8); // pwm, fwd, rev - bottom motor
Motor m3(p25, p12, p13); // pwm, fwd, rev - knob motor
DigitalIn pb1(p22); // Increase temp
DigitalIn pb2(p21); // Decrease temp

enum Modetype { MODE_OFF = 0, MODE_ON };
Modetype mode = MODE_OFF;
Modetype previousMode = MODE_OFF;
enum Statetype { HEAT_OFF = 0, HEAT_ON, COOL_OFF, COOL_ON };
Statetype state = HEAT_OFF;

uLCD_4DGL uLCD(p28, p27, p29); // create a global uLCD object

void messageArrived(MQTT::MessageData& md) // temperature: Current Temperature from Slave Device
{
    MQTT::Message &message = md.message;
    printf("Message arrived: qos %d, retained %d, dup %d, packetid %d\r\n", message.qos, message.retained, message.dup, message.id);
    printf("Payload %.*s\r\n", message.payloadlen, (char*)message.payload);

    // can't just use (char*)message.payload, some weird stuff gets printed at the end
    char buf[5];
    sprintf(buf, "%.*s", message.payloadlen, (char*)message.payload);

    currentTemp = atoi(buf);
    uLCD.locate(8,11);
    uLCD.text_height(2);
    printf("%d\r\n", currentTemp);
    uLCD.printf("%d     " , currentTemp);
    uLCD.text_height(1);
}

void messageArrived2(MQTT::MessageData& md) // ideal: Ideal Temperature for Override Mode
{
    MQTT::Message &message = md.message;
    printf("Message arrived: qos %d, retained %d, dup %d, packetid %d\r\n", message.qos, message.retained, message.dup, message.id);
    printf("Payload %.*s\r\n", message.payloadlen, (char*)message.payload);

    // can't just use (char*)message.payload, some weird stuff gets printed at the end
    char buf[5];
    sprintf(buf, "%.*s", message.payloadlen, (char*)message.payload);

    targetTemp = atoi(buf);
    uLCD.locate(8,4);
    uLCD.text_height(2);
    uLCD.printf("%d      " , targetTemp);
    uLCD.text_height(1);
}

void messageArrived3(MQTT::MessageData& md) // control: On or Off
{
    MQTT::Message &message = md.message;
    printf("Message arrived: qos %d, retained %d, dup %d, packetid %d\r\n", message.qos, message.retained, message.dup, message.id);
    printf("Payload %.*s\r\n", message.payloadlen, (char*)message.payload);

    // can't just use (char*)message.payload, some weird stuff gets printed at the end
    char buf[5];
    sprintf(buf, "%.*s", message.payloadlen, (char*)message.payload);
    previousMode = mode;
    mode = (Modetype)atoi(buf);
    if (mode != previousMode) {
        modeChange = true;
    }
}

void controlHeat()  // move knob to heat
{
    m3.speed(-1.0);
    wait(1);
    m3.speed(0);
}

void controlCool()  // move knob to cool
{
    m3.speed(1.0);
    wait(1);
    m3.speed(0);
}

void controlOn()  // turn switch on
{
    m.speed(-1.0);
    wait(.5);
    m.speed(1.0);
    wait(.5);
    m.speed(-1.0);
    wait(.5);
    m.speed(1.0);
    wait(.5);
    m.speed(-1.0);
    wait(1);
    m.speed(0.5);
    wait(.25);
    m.speed(0);
}

void controlOff()  // turn switch off
{
    m2.speed(1.0);
    wait(.5);
    m2.speed(-1.0);
    wait(.5);
    m2.speed(1.0);
    wait(.5);
    m2.speed(-1.0);
    wait(.5);
    m2.speed(1.0);
    wait(1);
    m2.speed(-0.5);
    wait(.25);
    m2.speed(0);
}


int main()
{
    pb1.mode(PullUp);
    pb2.mode(PullUp);
    wait(.001);

    uLCD.baudrate(BAUD_3000000);
    uLCD.cls();

    uLCD.locate(6,2);
    uLCD.printf("Target");
    uLCD.locate(6,9);
    uLCD.printf("Current");

    extern const char* hostname;
    extern const int port;
    extern char* username;
    extern char* password;

    NetworkInterface* network = easy_connect(true);
    MQTTNetwork mqttNetwork(network);

    MQTT::Client<MQTTNetwork, Countdown> client(mqttNetwork);

    printf("Connecting to %s:%d\r\n", hostname, port);
    int rc = mqttNetwork.connect(hostname, port);
    if (rc != 0)
        printf("rc from TCP connect is %d\r\n", rc);

    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
    data.MQTTVersion = 3;

    char clientID[100];
    strcpy(clientID, "mbed-");
    strcat(clientID, network->get_mac_address());

    data.clientID.cstring = clientID;
    data.username.cstring = username;
    data.password.cstring = password;
    if ((rc = client.connect(data)) != 0)
        printf("rc from MQTT connect is %d\r\n", rc);

    if ((rc = client.subscribe("temperature", MQTT::QOS2, messageArrived)) != 0)
        printf("rc from MQTT subscribe is %d\r\n", rc);
    if ((rc = client.subscribe("finalTargetTemp", MQTT::QOS2, messageArrived2)) != 0)
        printf("rc from MQTT subscribe is %d\r\n", rc);
    if ((rc = client.subscribe("control", MQTT::QOS2, messageArrived3)) != 0)
        printf("rc from MQTT subscribe is %d\r\n", rc);

    MQTT::Message messagePb;
    messagePb.qos = MQTT::QOS0;
    messagePb.retained = true;
    messagePb.dup = false;

    while(true) {
        //printf("start yield\r\n");
        client.yield(100);

        if (pb1 == 0) {
            char buf[100];
            sprintf(buf, "%d", targetTemp + 1);
            messagePb.payload = (void*)buf;
            messagePb.payloadlen = strlen(buf)+1;
            printf("Increase temp flag set.\r\n");
            client.publish("ideal", messagePb);
            wait(.5);
        }
        if (pb2 == 0) {
            char buf[100];
            sprintf(buf, "%d", targetTemp - 1);
            messagePb.payload = (void*)buf;
            messagePb.payloadlen = strlen(buf)+1;
            printf("Decrease temp flag set.\r\n");
            client.publish("ideal", messagePb);
            wait(.5);
        }

        printf("Mode: %d\r\n", mode);
        printf("State: %d\r\n", state);

        if(mode == MODE_OFF) { // don't do anything
            if (modeChange) {
                controlOff();
                modeChange = false;
            }
            continue;
        }


        if(targetTemp > currentTemp+threshold) { // need to heat
            printf("Need to heat!\r\n");
            switch(state) {
                case HEAT_OFF:
                    controlOn();
                    state = HEAT_ON;
                    break;
                case COOL_OFF:
                    controlHeat();
                    controlOn();
                    state = HEAT_ON;
                    break;
                case COOL_ON:
                    controlHeat();
                    state = HEAT_ON;
                    break;
            }
        } else if(targetTemp < currentTemp-threshold) { // need to cool
            printf("Need to cool!\r\n");
            switch(state) {
                case COOL_OFF:
                    controlOn();
                    state = COOL_ON;
                    break;
                case HEAT_OFF:
                    controlCool();
                    controlOn();
                    state = COOL_ON;
                    break;
                case HEAT_ON:
                    controlCool();
                    state = COOL_ON;
                    break;
            }
        } else { // in range, so turn off if anything is on
            printf("Do nothing!\r\n");
            switch(state) {
                case HEAT_ON:
                    controlOff();
                    state = HEAT_OFF;
                    break;
                case COOL_ON:
                    controlOff();
                    state = COOL_OFF;
                    break;
            }
        }
    }
    return 0;
}

SlaveDeviceMain.cpp

#include "mbed.h"
#include "easy-connect.h"
#include "MQTTNetwork.h"
#include "MQTTmbed.h"
#include "MQTTClient.h"
#include "credentials.h"

AnalogIn tempSensor1(p20);
AnalogIn tempSensor2(p18);

bool successSent = false;

float getTemp(float raw){
    return (9.0*(((raw*3.3)-0.500)*100.0))/5.0 + 32.0;
}

void messageArrived(MQTT::MessageData& md)
{
    MQTT::Message &message = md.message;
    printf("Message arrived: qos %d, retained %d, dup %d, packetid %d\r\n", message.qos, message.retained, message.dup, message.id);
    printf("Payload %.*s\r\n", message.payloadlen, (char*)message.payload);
    successSent = true;
}

int main(){
    extern const char* hostname;
    extern const int port;
    extern char* username;
    extern char* password;

    NetworkInterface* network = easy_connect(true); 
    MQTTNetwork mqttNetwork(network);

    MQTT::Client<MQTTNetwork, Countdown> client(mqttNetwork);
    printf("Connecting to %s:%d\r\n", hostname, port);
    int rc = mqttNetwork.connect(hostname, port);
    if (rc != 0)
        printf("rc from TCP connect is %d\r\n", rc);

    MQTTPacket_connectData data = MQTTPacket_connectData_initializer;
    data.MQTTVersion = 3;

    char clientID[100];
    strcpy(clientID, "mbed-");
    strcat(clientID, network->get_mac_address());

    data.clientID.cstring = clientID;
    data.username.cstring = username;
    data.password.cstring = password;
    if ((rc = client.connect(data)) != 0)
        printf("rc from MQTT connect is %d\r\n", rc);

    if ((rc = client.subscribe("temperature", MQTT::QOS2, messageArrived)) != 0)
        printf("rc from MQTT subscribe is %d\r\n", rc);

    MQTT::Message message;
    message.qos = MQTT::QOS0;
    message.retained = false;
    message.dup = false;
    
    while(true){
        // Take 10 readings
        float temperature = 0.0;
        for(int i = 0; i < 10; i++){
            temperature += getTemp(tempSensor1);
            temperature += getTemp(tempSensor2);
            Thread::wait(500);
        }
        int final_temperature = (temperature/20.0);
        printf("temperature: %d\r\n", final_temperature);
        char buf[100];
        sprintf(buf, "%d", final_temperature);
        message.payload = (void*)buf;
        message.payloadlen = strlen(buf)+1;
        client.publish("temperature", message);
        
        int tries = 0;
        while(!successSent && tries < 10){
            client.yield();
            tries++;
        }
        successSent = false;

    }

    return 0;
}
Github Code
  1. Thermostat Controller
  2. Slave Device
  3. Web Application
  4. Windows Application
Video Demo

Link to Video

Pictures

/media/uploads/angeldsanchez/thermostat.png Thermostat

/media/uploads/angeldsanchez/setupzoomout.jpg mbed set up with mechanical controls

/media/uploads/angeldsanchez/setupzoomin.jpg mbed set up

/media/uploads/angeldsanchez/slavedevice.jpg slave device set up


Please log in to post comments.