Andy Moore
Published © GPL3+

Personal Thermostat

Senses and displays temperature and humidity, and controls power to fans, heaters, etc. based on flexible temperature trip points.

BeginnerShowcase (no instructions)1 hour2,530
Personal Thermostat

Things used in this project

Hardware components

Modulo Base
Modulo Base
×1
Modulo Controller
Modulo Controller
×1
Modulo Display
Modulo Display
×2
Modulo Knob
Modulo Knob
×1
IoT Power Relay
×1
DHT22 Temperature Sensor
DHT22 Temperature Sensor
×1

Software apps and online services

Arduino IDE
Arduino IDE
Required Libraries: Adafruit DHT Unified, Adafruit Unified Sensor, DHT sensor library, LinkedList (https://github.com/ivanseidel/LinkedList), Modulo.

Story

Read more

Code

PersonalThermostat.ino

Arduino
/*
 PersonalThermostat.ino - Personal Thermostat project
 Copyright (C) 2016 Andy Moore.  All rights reserved.

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
*/

#include "Modulo.h"
#include "Wire.h"

//#include "Mode.C"
#include "Sensor.C"
#include "Relay.C"
#include "UI.C"
#include "UiItem.C"
#include "UiColor.C"

const int SENSOR_PIN = 0;
const int RELAY_PIN = 4;
const unsigned long SENSOR_UPDATE_INTERVAL_MILLIS = 2000;
const unsigned long DISPLAY_UPDATE_INTERVAL_MILLIS = 50;
const float DEFAULT_TARGET_TEMP = 72.0;
const float DEFAULT_HYSTERESIS = 1.0;

const UiColor COLOR_TEMP  = UiColor(1.0, 0.9, 0.5);
const UiColor COLOR_HUMID = UiColor(0.7, 1.0, 0.9);
const UiColor COLOR_PARAM = UiColor(0.5, 0.5, 0.7);
const UiColor COLOR_FOCUS = UiColor(0.9, 0.7, 0.2);

//const Mode::Enum DEFAULT_MODE = Mode::Enum::COOL;
//Mode::Enum mode;
enum Mode { OFF, COOL, HEAT, ON };
const Mode DEFAULT_MODE = Mode::COOL;
Mode mode;

enum ParameterFocus { MODE, TRIP_ON, TRIP_OFF };
const ParameterFocus DEFAULT_PARAMETER_FOCUS = ParameterFocus::TRIP_ON;
ParameterFocus parameterFocus = DEFAULT_PARAMETER_FOCUS;

float targetTemp = DEFAULT_TARGET_TEMP;
float hysteresis = DEFAULT_HYSTERESIS;

Sensor sensor(SENSOR_PIN);
Relay relay(RELAY_PIN);
UI ui;
UiItem* tempItem;
UiItem* humidItem;
UiItem* tripOnItem;
UiItem* tripOnSignItem;
UiItem* tripOffItem;
UiItem* tripOffSignItem;
UiItem* modeItem;

int knobPositionPrevious;

unsigned long last_sensor_update_millis;
long time_since_last_sensor_update;

float getTripOnTemp()
  {
  return targetTemp;
  }

float getTripOffTemp()
  {
  float result = targetTemp - hysteresis;
  if (mode == Mode::HEAT)
    {
    result = targetTemp + hysteresis;
    }
  return result;
  }

void updateRelay()
  {
  switch (mode)
    {
    case Mode::OFF:
      if (relay.isOn())
        {
        relay.set(false);
        }
      break;

    case Mode::COOL:
      if (relay.isOn())
        {
        if (sensor.getTemperatureF() < getTripOffTemp())
          {
          relay.set(false);
          }
        }
      else // relay is off
        {
        if (sensor.getTemperatureF() >= getTripOnTemp())
          {
          relay.set(true);
          }
        }
      break;

    case Mode::HEAT:
      if (relay.isOn())
        {
        if (sensor.getTemperatureF() > getTripOffTemp())
          {
          relay.set(false);
          }
        }
      else // relay is off
        {
        if (sensor.getTemperatureF() <= getTripOnTemp())
          {
          relay.set(true);
          }
        }
      break;

    case Mode::ON:
      if (!relay.isOn())
        {
        relay.set(true);
        }
      break;
    }
    
  ui.setIndicator(2, relay.isOn());
  }

String modeToString(Mode mode_)
  {
  String result;
  switch (mode_)
    {
    case Mode::OFF:  result = String("Off"); break;
    case Mode::COOL: result = String("Cool"); break;
    case Mode::HEAT: result = String("Heat"); break;
    case Mode::ON:   result = String("On"); break;
    }
  return result;
  }

Mode nextMode(Mode mode_)
  {
  Mode result;
  switch (mode_)
    {
    case Mode::OFF:  result = Mode::COOL; break;
    case Mode::COOL: result = Mode::HEAT; break;
    case Mode::HEAT: result = Mode::ON; break;
    case Mode::ON:   result = Mode::OFF; break;
    }
  return result;
  }

Mode previousMode(Mode mode_)
  {
  Mode result;
  switch (mode_)
    {
    case Mode::OFF:  result = Mode::ON; break;
    case Mode::COOL: result = Mode::OFF; break;
    case Mode::HEAT: result = Mode::COOL; break;
    case Mode::ON:   result = Mode::HEAT; break;
    }
  return result;
  }

ParameterFocus nextParameterFocus(ParameterFocus parameterFocus_)
  {
  ParameterFocus result;
  switch(parameterFocus_)
    {
    case ParameterFocus::MODE:     result = ParameterFocus::TRIP_ON; break;
    case ParameterFocus::TRIP_ON:  result = ParameterFocus::TRIP_OFF; break;
    case ParameterFocus::TRIP_OFF: result = ParameterFocus::MODE; break;
    }
  return result;
  }

void updateUIforMode()
  {
  modeItem->setText(modeToString(mode));
  switch (mode)
    {
    case Mode::OFF:
      ui.setKnobColor(UiColor::BLACK);
      tripOnSignItem->setVisible(false);
      tripOnItem->setVisible(false);
      tripOffSignItem->setVisible(false);
      tripOffItem->setVisible(false);
      updateTripItems();
      break;

    case Mode::COOL:
      ui.setKnobColor(UiColor::BLUE);
      tripOnSignItem->setVisible(true);
      tripOnSignItem->setText(String(">= "));
      tripOnItem->setVisible(true);
      tripOffSignItem->setVisible(true);
      tripOffSignItem->setText(String("< "));
      tripOffItem->setVisible(true);
      updateTripItems();
      break;

    case Mode::HEAT:
      ui.setKnobColor(UiColor::RED);
      tripOnSignItem->setVisible(true);
      tripOnSignItem->setText(String("<= "));
      tripOnItem->setVisible(true);
      tripOffSignItem->setVisible(true);
      tripOffSignItem->setText(String("> "));
      tripOffItem->setVisible(true);
      updateTripItems();
      break;

    case Mode::ON:
      ui.setKnobColor(UiColor::WHITE);
      tripOnSignItem->setVisible(false);
      tripOnItem->setVisible(false);
      tripOffSignItem->setVisible(false);
      tripOffItem->setVisible(false);
      updateTripItems();
      break;
    }
  }

void setMode(Mode mode_)
  {
  mode = mode_;
  updateUIforMode();
  }

void onKnobButtonRelease(KnobModulo& knob_)
  {
  parameterFocus = nextParameterFocus(parameterFocus);
  }

void updateTripItems()
  {
  tripOnItem->setText(String(getTripOnTemp(), 1));
  tripOffItem->setText(String(getTripOffTemp(), 1));
  }

void onKnobPositionChange(KnobModulo& knob_)
  {
  int knobPositionCurrent = knob_.getPosition();
  int knobPositionDelta = knobPositionCurrent - knobPositionPrevious;
  knobPositionPrevious = knobPositionCurrent;
  switch (parameterFocus)
    {
    case ParameterFocus::MODE:
      if (knobPositionDelta < 0)
        {
        setMode(previousMode(mode));
        }
      else
        {
        setMode(nextMode(mode));
        }
      break;
    
    case ParameterFocus::TRIP_ON:
      if (mode == Mode::OFF || mode == Mode::ON) return;
      targetTemp += (knobPositionDelta / 10.0);
      updateTripItems();
      break;

    case ParameterFocus::TRIP_OFF:
      if (mode == Mode::OFF || mode == Mode::ON) return;
      if (mode == Mode::COOL)
        {
        hysteresis -= (knobPositionDelta / 10.0);
        }
      else if (mode == Mode::HEAT)
        {
        hysteresis += (knobPositionDelta / 10.0);
        }
      if (hysteresis < 0.1) hysteresis = 0.1;
      updateTripItems();
      break;
    }
  }

void initUI()
  {
  ui.initialize();

             ui.item(1)->text("Temperature ")->position(0, 0)  ->color(COLOR_TEMP);
  tempItem = ui.item(1)->text("(temp)")      ->position(20, 13)->textSize(2);
             ui.item(1)->text("F");
  
              ui.item(1)->text("Humidity ")->position(0, 32) ->color(COLOR_HUMID);
  humidItem = ui.item(1)->text("(humid)")  ->position(20, 45)->textSize(2);
              ui.item(1)->text("%");

             ui.item(2)->text("Mode ") ->position(0,  0)->color(COLOR_PARAM);
  modeItem = ui.item(2)->text("(mode)")->textSize(2);

                   ui.item(2)->text("On ")->position(0, 20)->color(COLOR_PARAM);
  tripOnSignItem = ui.item(2)->text("(onSign)");
      tripOnItem = ui.item(2)->text("(onTemp)")->textSize(2);
                   ui.item(2)->text("F");
  
                    ui.item(2)->text("Off ")     ->position(0, 40)->color(COLOR_PARAM);
  tripOffSignItem = ui.item(2)->text("(offSign)");
      tripOffItem = ui.item(2)->text("(offTemp)")->textSize(2);
                    ui.item(2)->text("F");
  
  tempItem->setText(String(sensor.getTemperatureF(), 1));
  humidItem->setText(String(sensor.getRHumidity(), 1));
  tripOnItem->setText(String(getTripOnTemp(), 1));
  tripOffItem->setText(String(getTripOffTemp(), 1));
  updateUIforMode();

  ui.setKnobColor(COLOR_FOCUS);
  ui.setKnobButtonReleaseCallback(onKnobButtonRelease);
  ui.setKnobPositionChangeCallback(onKnobPositionChange);
  }

void updateUI()
  {
  UiColor color;
  
  color = COLOR_PARAM;
  if (parameterFocus == ParameterFocus::MODE) color = COLOR_FOCUS;
  modeItem->setColor(color);
  
  color = COLOR_PARAM;
  if (parameterFocus == ParameterFocus::TRIP_ON) color = COLOR_FOCUS;
  tripOnItem->setColor(color);
  
  color = COLOR_PARAM;
  if (parameterFocus == ParameterFocus::TRIP_OFF) color = COLOR_FOCUS;
  tripOffItem->setColor(color);
  
  ui.update();
  }

void updateSensor()
  {
  ui.setIndicator(1, true);
  sensor.update();
  last_sensor_update_millis = millis();
  ui.setIndicator(1, false);
  tempItem->setText(String(sensor.getTemperatureF(), 1));
  humidItem->setText(String(sensor.getRHumidity(), 1));
  }

void setup()
  {
  delay(1000);  // give bootloader a chance!
  sensor.initialize();
  relay.initialize();
  initUI();
  setMode(DEFAULT_MODE);
  updateSensor();
  updateRelay();
  updateUI();
  }

void loop()
  {
  time_since_last_sensor_update = millis() - last_sensor_update_millis;
  if (time_since_last_sensor_update >= SENSOR_UPDATE_INTERVAL_MILLIS)
    {
    updateSensor();
    updateRelay();
    }
  updateUI();
  ui.loop();
  delay(DISPLAY_UPDATE_INTERVAL_MILLIS);
  }

Relay.C

C/C++
/*
 Relay.C - Personal Thermostat project
 Copyright (C) 2016 Andy Moore.  All rights reserved.

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
*/

#pragma once

#include "Wire.h"

class Relay
  {
 public:

  Relay(int pin_)
    {
    _pin = pin_;
    _on = false;
    }

  void initialize()
    {
    pinMode(_pin, OUTPUT);
    }

  bool isOn()
    {
    return _on;
    }

  void set(bool on_)
    {
    if (on_)
      {
      digitalWrite(_pin, HIGH);
      _on = true;
      }
    else
      {
      digitalWrite(_pin, LOW);
      _on = false;
      }
    }

 private:
  int _pin;
  bool _on;

  }; // class Relay

Sensor.C

C/C++
/*
 Sensor.C - Personal Thermostat project
 Copyright (C) 2016 Andy Moore.  All rights reserved.

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
*/

#pragma once

#include <Adafruit_Sensor.h>
#include <DHT.h>
#include <DHT_U.h>

const uint8_t DHT_TYPE = DHT22;

class Sensor
  {
 public:

  Sensor(int pin_)
    :
    _dht(pin_, DHT_TYPE)
    {
    }

  float getRHumidity()
    {
    return _humid;
    }

  float getTemperatureF()
    {
    return _tempF;
    }

  void initialize()
    {
    _dht.begin();
    }

  void update()
    {
    sensors_event_t event;
    _dht.temperature().getEvent(&event);
    float tempC = event.temperature;
    if (isnan(tempC))
      {
      _tempF = tempC;
      }
    else
      {
      _tempF = (event.temperature * 1.8) + 32;
      }
    _dht.humidity().getEvent(&event);
    _humid = event.relative_humidity;
    }

 private:

  DHT_Unified _dht;
  float _tempF;
  float _humid;

  }; // class Sensor

UI.C

C/C++
/*
 UI.C - Personal Thermostat project
 Copyright (C) 2016 Andy Moore.  All rights reserved.

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
*/

#pragma once

#include "Modulo.h"
#include "Wire.h"
#include <LinkedList.h>
#include "UiItem.C"
#include "UiColor.C"
#include "UiPosition.C"

class UI
  {
 public:

  UI()
    :
    _display1(),
    _display2(),
    _knob()
    {
    }

  UiItem* item(int n_)
    {
    UiItem* newItem = new UiItem();
    if (n_ == 1)
      {
      _items1.add(newItem);
      }
    else if (n_ == 2)
      {
      _items2.add(newItem);
      }
    return newItem;
    }

  void setIndicator(int n_, bool on_)
    {
    if (n_ <= 0 || n_ > 3) return;
    uint16_t deviceID;
    switch(n_)
      {
      case 1: deviceID = _display1.getDeviceID(); break;
      case 2: deviceID = _display2.getDeviceID(); break;
      case 3: deviceID = _knob.getDeviceID(); break;
      }
    ModuloStatus status = ModuloStatus::ModuloStatusOff;
    if (on_) status = ModuloStatus::ModuloStatusOn;
    Modulo.setStatus(deviceID, status);
    }

  void setKnobColor(const UiColor& color)
    {
    _knob.setColor(color.getRed(), color.getGreen(), color.getBlue());
    }

  void setKnobPositionChangeCallback(void (*callback_)(KnobModulo&))
    {
    _knob.setPositionChangeCallback(callback_);
    }

  void setKnobButtonReleaseCallback(void (*callback_)(KnobModulo&))
    {
    _knob.setButtonReleaseCallback(callback_);
    }

  void drawItem(DisplayModulo& display_, UiItem* item_)
    {
    if (!item_->isVisible()) return;
    UiPosition* pPosition = item_->getPosition();
    if (pPosition->isSet())
      {
      display_.setCursor(pPosition->getX(), pPosition->getY());
      }
    UiColor* pColor = item_->getColor();
    if (pColor->isSet())
      {
      display_.setTextColor(pColor->getRed(),
                            pColor->getGreen(),
                            pColor->getBlue());
      }
    display_.setTextSize(item_->getTextSize());
    display_.print(item_->getText());
    }

  void initialize()
    {
    Modulo.setup();
    for (int n = 1; n <= 3; n++)
      {
      for (int i = 1; i <= 3; i++)
        {
        setIndicator(i, true);
        delay(100);
        setIndicator(i, false);
        }
      }
    }

  void update()
    {
    updateDisplay(_display1, _items1);
    updateDisplay(_display2, _items2);
    }

  void updateDisplay(DisplayModulo& display_, LinkedList<UiItem*>& items_)
    {
    display_.clear();
    for (int i = 0; i < items_.size(); i++)
      {
      UiItem* e = items_.get(i);
      drawItem(display_, e);
      }
    display_.refresh();
    }

  void loop()
    {
    Modulo.loop();
    }

 private:
  DisplayModulo _display1;
  DisplayModulo _display2;
  KnobModulo _knob;
  LinkedList<UiItem*> _items1;
  LinkedList<UiItem*> _items2;

  }; // end class UI

UiColor.C

C/C++
/*
 UiColor.C - Personal Thermostat project
 Copyright (C) 2016 Andy Moore.  All rights reserved.

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
*/

#pragma once

class UiColor
  {
 public:
  
  UiColor(float red_, float green_, float blue_)
    {
    _set = true;
    _red = red_;
    _green = green_;
    _blue = blue_;
    }

  UiColor()
    {
    _set = false;
    _red = NAN;
    _green = NAN;
    _blue = NAN;
    }

  UiColor(const UiColor& color_)
    {
    _set = color_.isSet();
    _red = color_.getRed();
    _green = color_.getGreen();
    _blue = color_.getBlue();
    }

  UiColor(UiColor* pColor_)
    {
    _set = pColor_->isSet();
    _red = pColor_->getRed();
    _green = pColor_->getGreen();
    _blue = pColor_->getBlue();
    }

  float getRed() const { return _red; }
  float getGreen() const { return _green; }
  float getBlue() const { return _blue; }
  bool isSet() const { return _set; }

  static const UiColor NOT_SET;
  static const UiColor BLACK;
  static const UiColor WHITE;
  static const UiColor RED;
  static const UiColor GREEN;
  static const UiColor BLUE;

 private:
 
  bool _set;
  float _red;
  float _green;
  float _blue;

  }; // end class UiColor
  
const UiColor UiColor::NOT_SET  = new UiColor();
const UiColor UiColor::BLACK = new UiColor(0.0, 0.0, 0.0);
const UiColor UiColor::WHITE = new UiColor(1.0, 1.0, 1.0);
const UiColor UiColor::RED   = new UiColor(1.0, 0.0, 0.0);
const UiColor UiColor::GREEN = new UiColor(0.0, 1.0, 0.0);
const UiColor UiColor::BLUE  = new UiColor(0.0, 0.0, 1.0);

UiItem.C

C/C++
/*
 UiItem.C - Personal Thermostat project
 Copyright (C) 2016 Andy Moore.  All rights reserved.

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
*/

#pragma once

#include "UiColor.C"
#include "UiPosition.C"

class UiItem
  {
 public:

  UiItem(const UiPosition& position_, const UiColor& color_, int textSize_, const String& text_)
    {
    _pPosition = new UiPosition(position_);
    _pColor = new UiColor(color_);
    _textSize = textSize_;
    _pText = new String(text_);
    _visible = true;
    }

  UiItem(const UiPosition& position_, const UiColor& color_, int textSize_, const char* charString_)
    {
    _pPosition = new UiPosition(position_);
    _pColor = new UiColor(color_);
    _textSize = textSize_;
    _pText = new String(charString_);
    _visible = true;
    }

  UiItem(const UiItem& other_)
    {
    _pPosition = new UiPosition(other_.getPosition());
    _pColor = new UiColor(other_.getColor());
    _textSize = other_.getTextSize();
    _pText = new String(other_.getText());
    _visible = other_.isVisible();
    }

  UiItem()
    {
    _pPosition = new UiPosition(DEFAULT_POSITION);
    _pColor = new UiColor(DEFAULT_COLOR);
    _textSize = DEFAULT_TEXTSIZE;
    _pText = new String(DEFAULT_TEXT);
    _visible = DEFAULT_VISIBLE;
    }

  UiPosition* getPosition() const { return _pPosition; }
  UiItem* position(const UiPosition& position_)
    {
    if (_pPosition) delete _pPosition;
    _pPosition = new UiPosition(position_);
    return this;
    }
  UiItem* position(int x_, int y_)
    {
    if (_pPosition) delete _pPosition;
    _pPosition = new UiPosition(x_, y_);
    return this;
    }
  void setPosition(const UiPosition& position_)
    {
    position(position_);
    }
  void setPosition(int x_, int y_)
    {
    position(x_, y_);
    }
  
  UiColor* getColor() const { return _pColor; }
  UiItem* color(const UiColor& color_)
    {
    if (_pColor) delete _pColor;
    _pColor = new UiColor(color_);
    return this;
    }
  void setColor(const UiColor& color_)
    {
    color(color_);
    }

  int getTextSize() const { return _textSize; }
  UiItem* textSize(int textSize_)
    {
    _textSize = textSize_;
    return this;
    }
  void setTextSize(int textSize_)
    {
    textSize(textSize_);
    }

  String getText() const { return *_pText; }
  UiItem* text(const String& text_)
    {
    if (_pText) delete _pText;
    _pText = new String(text_);
    return this;
    }
  void setText(const String& text_)
    {
    text(text_);
    }

  boolean isVisible() const { return _visible; }
  UiItem* setVisible(bool visible_)
    {
    _visible = visible_;
    return this;
    }

 private:

  const UiPosition DEFAULT_POSITION = UiPosition::NOT_SET;
  const UiColor DEFAULT_COLOR = UiColor::NOT_SET;
  const int DEFAULT_TEXTSIZE = 1;
  const String DEFAULT_TEXT = String("?");
  const bool DEFAULT_VISIBLE = true;

  UiPosition* _pPosition;
  UiColor* _pColor;
  int _textSize;
  String* _pText;
  bool _visible;

  }; // end class UiItem

UiPosition.C

C/C++
/*
 UiPosition.C - Personal Thermostat project
 Copyright (C) 2016 Andy Moore.  All rights reserved.

 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.
*/

#pragma once

class UiPosition
  {
 public:
  
  UiPosition(int x_, int y_)
    {
    _set = true;
    _x = x_;
    _y = y_;
    }

  UiPosition()
    {
    _set = false;
    }

  UiPosition(const UiPosition& position_)
    {
    _set = position_.isSet();
    _x = position_.getX();
    _y = position_.getY();
    }

  UiPosition(UiPosition* pPosition_)
    {
    _set = pPosition_->isSet();
    _x = pPosition_->getX();
    _y = pPosition_->getY();
    }

  int getX() const { return _x; }
  int getY() const { return _y; }
  bool isSet() const { return _set; }

  static const UiPosition NOT_SET;

 private:
 
  bool _set;
  int _x;
  int _y;

  }; // end class UiPosition
  
const UiPosition UiPosition::NOT_SET = new UiPosition();

Credits

Andy Moore

Andy Moore

1 project • 3 followers

Comments