David Barbour
Published

Kool Diggs automatic dog bed

Heats up when it's cold, cools down when it's warm. What more could a dog want in this life?

BeginnerFull instructions provided8 hours87
Kool Diggs automatic dog bed

Things used in this project

Hardware components

LED Strip, NeoPixel Digital RGB
LED Strip, NeoPixel Digital RGB
Shows status of the bed
×1
Grove - mini PIR motion sensor
Seeed Studio Grove - mini PIR motion sensor
Detects motion to know when the dog is present
×1
SparkFun Atmospheric Sensor Breakout - BME280
SparkFun Atmospheric Sensor Breakout - BME280
Determines the temperature, so the bed know if it should heat up or cool down
×1
Grove - OLED Display 0.66" (SSD1306)- IIC - 3.3V/5V
Seeed Studio Grove - OLED Display 0.66" (SSD1306)- IIC - 3.3V/5V
Used for configuration menu and status display
×1
Analog joystick (Generic)
×1
Philips hue
Philips hue
×1
Amazon Alexa Wemo smart plug
×1
Photon 2
Particle Photon 2
×1
Amazon Alexa Heating pad
×1
Amazon Alexa 5V USB desk fan
×1

Software apps and online services

Visual Studio Code Extension for Arduino
Microsoft Visual Studio Code Extension for Arduino

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)
Drill / Driver, Cordless
Drill / Driver, Cordless

Story

Read more

Custom parts and enclosures

Enclosure for electrical components

Solidworks drawing of enclosure to hold electronics

Clip to hold up sign

Solidworks design for clip to hold up sign

Schematics

Configuration menu path

The configuration menu, indicating what each joystick direction does.

Operating workflow

Diagram indicating the operating workflow

Schematic

Schematic of components

Fritz diagram of circuit

Diagram of circuit and pin out configuration for componenets

Code

Main code

C/C++
Setup, Void loop and functions
/* 
 * Project DogBed
 * Author: David Barbour
 * Date: 3/1/24
 */

#include "Particle.h"
#include "IoTClassroom_CNM.h"
#include "neopixel.h"
#include "Colors.h"
#include "math.h"
#include "IoTTimer.h"
#include "Adafruit_GFX.h"
#include "Adafruit_SSD1306.h"
#include "Adafruit_BME280.h"
#include "Graphic.h"
#include "Button.h"
#include "wemo.h"

//CONSTANTS
    //joystick 
    const int joyHorz = A1;
    const int joyVert = A2;
    const int joySwitch = D6;

    //neo pixel
    const int PIXELCOUNT = 20;

    //temperature reading
    const int SENSORWAITTINE=10;

    //Motion detector
    const int DETECTPIN=D9;

    //hue light bulb
    const int BULB=3;

//Variables
    //joystick
    int newVer;int newHor;int oldVer;int oldHor;
    bool setVertDown = false;bool setVertUp = false;
    bool setHorRight = false;bool setHorLeft = false;
    Button joyButton(joySwitch,true);

    //Neo pixels
    Adafruit_NeoPixel pixel ( PIXELCOUNT , SPI1 , WS2812B );

    //temperature reading
    bool forceHeat = false;bool forceCool = false;
    float coolingTemp = 74;float heatingTemp = 73;
    float currentTemp;
    bool status;
    Adafruit_BME280 bme;

    //display setup
    Adafruit_SSD1306 display(-1);
    bool showDisplay=false;

    //timers
    IoTTimer waitTimer;
    int waitedTime=0;

    //Motion detector
    bool motionDetected=false;

    //wemo device numbers
    int wemoCool=4;int wemoHeat=2; 

    //hue light bulb
    bool sendCmdToHue = true;

    //debugging button
    Button debugButton(D4,false);

    //application and setup states
    int applicationState=0;int prevApplicationState;
    int setupState=0;int subSetupState=0;

    //functions
    void PixelFill(int startPixel, int endPixel, int theColor);
    void setPixelDisplay(int theState);
    void programLogic();

    
    SYSTEM_MODE(MANUAL);

void setup() {

    //start serial monitor
    Serial.begin(9600);
    waitFor (Serial.isConnected,10000);

    //turn on wi fi
    WiFi.on();
    WiFi.clearCredentials();
    WiFi.setCredentials("IoTNetwork");
    WiFi.connect();
    while(WiFi.connecting()) {
        delay(50);
        Serial.printf(".");}

    //start the display
    display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
    display.clearDisplay();
    display.display();
    showDisplay=true;

    //start the neo pixels
    pixel.begin();
    pixel.setBrightness(22);
    pixel.clear();
    pixel.show();

    //set up motion detector
    pinMode(DETECTPIN,INPUT);

    //start bme temp guage
    status=bme.begin (0x76);
    if (status==false ) {
        Serial.printf (" BME280 at address %c failed to start ", 0x76 );}

}

void loop() 
{
    programLogic();

 }

void programLogic()
{
    
    //There are multiple states the application can be in
    // 0 - off
    // 1 - setup mode
    // 2 - waiting to cool
    // 3 - cooling
    // 4 - waiting to heat
    // 5 - heating

    //read the temperature
    currentTemp = (bme.readTemperature ()*9/5)+32.0; // deg F

    //this is for debugging only
    if (debugButton.isClicked()==true){
        //Serial.printf("Start %i, Temp %0.1f%cF\n\n",0,currentTemp,248);
        Serial.printf("Application %i, SetupState %i \n",applicationState,setupState);
        Serial.printf("Forcecool %i, forceheat %i motion %i\n",forceCool,forceHeat,motionDetected);
        Serial.printf("Currenttemp %f, cooltemp %f heatingtemp %f\n",currentTemp,coolingTemp,heatingTemp);
        Serial.printf("\n");
        }

    //determine what state you should be in
    prevApplicationState = applicationState;
    if (forceCool==true){
        forceHeat=false;
        applicationState=3;
        setupState=0;
        }

    if (forceHeat==true){
        forceCool = false;
        applicationState = 5;
        setupState=0;
        }

    //when you're in running mode
    if(forceCool==false && forceHeat==false && applicationState>1){  
        //go throught the temperature and motion settings
        if(currentTemp>=coolingTemp){   
            if (motionDetected==true){
                applicationState=3;
                }
            else{
                applicationState=2;
            }
        }
        
        //if the temperature goes below the heating temp, turn on 
        if(currentTemp<heatingTemp)
        {
            if (motionDetected==true){
                applicationState=5;
            }
            else{
                applicationState=4;
            }
        }
    }


    //only update the display if something changes
    if(applicationState!=prevApplicationState){showDisplay=true;}

    switch (applicationState){
    case 0: 
        //this is off

        //turn off the neopixels
        setPixelDisplay(0);

        //turn off the display
        if(showDisplay){
            display.clearDisplay();
            display.display();
            showDisplay=false;

            //turn off the heater
            wemoWrite(wemoHeat,LOW);

            //turn off the fan
            wemoWrite(wemoCool,LOW);
        }
          
        //if user clicks on button, start  running process
        if (joyButton.isPressed()==true){
            Serial.print("Push joystick button");
            applicationState=1;
            showDisplay=true;
        }

        //set these back to default off
        forceHeat = false;
        forceCool = false;
        break;
    
    case 1:  
        //setup mode

        setPixelDisplay(1);
        newVer = analogRead(joyVert);
        newHor = analogRead(joyHorz);
        switch (setupState){
        case 0: //on off screen
            
            if(showDisplay){
                display.clearDisplay();
                display.drawBitmap(20, 0,graphic_onoff, 80,68, 1);
                display.display();
                showDisplay=false;

                //turn off the heater
                wemoWrite(wemoHeat,LOW);

                //turn off the fan
                wemoWrite(wemoCool,LOW);

            }

            //DOWN set the application state back to off
            if(newVer>3500){setVertDown=true;}
            if(newVer<3500 && setVertDown==true){
                applicationState = 0;
                setVertDown = false;
                showDisplay=true;
            }

            //UP turn it on
            if(newVer<1500){setVertUp=true;}
            if(newVer>1500 && setVertUp==true){
                applicationState = 2;
                setHorRight = false;setHorLeft= false;setVertDown=false;setVertUp=false;
                showDisplay=true;
            }


            //RIGHT, go to the cooling teperature screen
            if(newHor>3500){setHorRight=true;}
            if(newHor<3500 && setHorRight==true){
                setHorRight = false;setHorLeft= false;setVertDown=false;setVertUp=false;
                setupState = 1;
                showDisplay=true;
            }
            
            //set these back to default off
            forceHeat = false;
            forceCool = false;

            break;

        case 1:
            //set cooling termperature

            //up down arrow
            if (showDisplay){
                display.clearDisplay();
                display.drawBitmap(0, 9,graphic_updown,16,46, 1);
                display.setTextColor(WHITE);
                display.setTextSize(1);
                display.setCursor(20,0);
                display.printf("Set cooling temp");

                display.setTextSize(2);
                display.setCursor(60,25);
                display.printf("%.0f",coolingTemp);
                display.display();
                showDisplay=false;
            }
            
            //RIGHT, go to the heating teperature screen
            if(newHor>3500){setHorRight=true;}
            if(newHor<3500 && setHorRight==true){
                setHorRight = false;setHorLeft= false;setVertDown=false;setVertUp=false;
                setupState = 2;
                showDisplay=true;
            }

            //LEFT, go to on off screen
            if(newHor<1000){setHorLeft=true;}
            if(newHor>1000 && setHorLeft==true){
                setHorRight = false;setHorLeft= false;setVertDown=false;setVertUp=false;
                setupState = 0;
                showDisplay=true;
            }

            //UP, increase the cooling termperature
            if(newVer>3000){setVertUp=true;}
            if(newVer<3000 && setVertUp==true){
                setHorRight = false;setHorLeft= false;setVertDown=false;setVertUp=false;
                coolingTemp--;

                //keep the temps from overlapping
                if(heatingTemp>=coolingTemp){heatingTemp=coolingTemp-1.0;}

                showDisplay=true;
            }

            //DOWN, decrease the cooling termperature
            if(newVer<1000){setVertDown=true;}
            if(newVer>1000 && setVertDown==true){
                setHorRight = false;setHorLeft= false;setVertDown=false;setVertUp=false;
                coolingTemp++;

                //keep the temps from overlapping
                if(heatingTemp>=coolingTemp){heatingTemp=coolingTemp-1.0;}

                showDisplay=true;
            }

            break;
        
        case 2:
            //set heting termperature
            if(showDisplay){
                display.clearDisplay();
                display.drawBitmap(0, 9,graphic_updown,16,46, 1);
                display.setTextColor(WHITE);
                display.setTextSize(1);
                display.setCursor(20,0);
                display.printf("Set heating temp");

                display.setTextSize(2);
                display.setCursor(60,25);
                display.printf("%.0f",heatingTemp);
                display.display();
                showDisplay=false;
            }

            //LEFT, go to on off screen
            if(newHor<1000){setHorLeft=true;}
            if(newHor>1000 && setHorLeft==true){
                setHorRight = false;setHorLeft= false;setVertDown=false;setVertUp=false;
                setupState = 1;
                showDisplay=true;
            }

            //UP, increase the heating termperature
            if(newVer>3000){setVertUp=true;}
            if(newVer<3000 && setVertUp==true){
                setHorRight = false;setHorLeft= false;setVertDown=false;setVertUp=false;
                heatingTemp--;

                //keep the temps from overlapping
                if(heatingTemp>=coolingTemp){coolingTemp=heatingTemp+1.0;}

                showDisplay=true;
            }

            //DOWN, increase the heating termperature
            if(newVer<1000){setVertDown=true;}
            if(newVer>1000 && setVertDown==true){
                setHorRight = false;setHorLeft= false;setVertDown=false;setVertUp=false;
                heatingTemp++;

                //keep the temps from overlapping
                if(heatingTemp>=coolingTemp){coolingTemp=heatingTemp+1.0;}

                showDisplay=true;
            }

            //Right, go to manual screen
            if(newHor>3000){setHorRight=true;}
            if(newHor<3000 && setHorRight==true){
                setHorRight = false;setHorLeft= false;setVertDown=false;setVertUp=false;
                setupState = 3;
                showDisplay=true;
            }

            break;
        
        case 3:
            //manual heat or cool
            if(showDisplay){
                display.clearDisplay();
                display.drawBitmap(9, 5,graphic_hotcold,110,51, 1);
                display.setTextColor(WHITE);
                display.display();
                showDisplay=false;
            }

            //UP, start heat
            if(newVer<1000){setVertDown=true;}
            if(newVer>1000 && setVertDown==true){
                setHorRight = false;setHorLeft= false;setVertDown=false;setVertUp=false;
                forceHeat = true;
                showDisplay=true;
            }

            //DOWN, start cooling
            if(newVer>3000){setVertUp=true;}
            if(newVer<3000 && setVertUp==true){
                setHorRight = false;setHorLeft= false;setVertDown=false;setVertUp=false;
                forceCool = true;
                showDisplay=true;
            }

            //LEFT, to the heat temp screen
            if(newHor<1000){setHorLeft=true;}
            if(newHor>1000 && setHorLeft==true){
                setHorRight = false;setHorLeft= false;setVertDown=false;setVertUp=false;
                setupState = 2;
                showDisplay=true;
            }
            break;
        }
        break;
    
    case 2:  //wating to cool
        setPixelDisplay(2);
        
        //tell the user, it's waiting to cool
        if(showDisplay){
            waitedTime = 0;
            waitTimer.startTimer(1000);   
            motionDetected=0;

            display.clearDisplay();
            display.setTextColor(WHITE);
            display.setTextSize(1);
            display.setCursor(20,0);
            display.printf("Waiting to cool");
            display.display();
            showDisplay=false;
        }

        //do a countdown, so the motion sensor doesn't start reading
        //for 10 seconds
        if (waitedTime < SENSORWAITTINE){
            if (waitTimer.isTimerReady()==true){
                display.fillRect(50,20, 70,30,BLACK);
                display.setTextColor(WHITE);
                display.setTextSize(2);
                display.setCursor(50,20);
                display.printf("%i",SENSORWAITTINE-waitedTime);
                display.display();
                waitedTime++;
                waitTimer.startTimer(1000); 
                forceCool=false;forceHeat=false;
            }
        }
        else{
            //read the motion sensor
            display.fillRect(50,20, 70,30,BLACK);
            display.display();
            motionDetected = digitalRead(DETECTPIN);
        }

        //LEFT, go back to setup screen
        if(newHor<1000){setHorLeft=true;}
        if(newHor>1000 && setHorLeft==true){

            //Serial.print("Cooling left button");
            setHorRight = false;setHorLeft= false;setVertDown=false;setVertUp=false;
            applicationState = 1;
            setupState=0;
            waitedTime = 0;
            motionDetected=false;
            showDisplay=true;
            forceCool=false;forceHeat=false;
        }
        break;

    case 3:  //Cooling
        setPixelDisplay(3);
        newHor = analogRead(joyHorz);

        //tell the user, it's cooling
        if(showDisplay){
            display.clearDisplay();
            display.setTextColor(WHITE);
            display.setTextSize(2);
            display.setCursor(20,0);
            display.printf("Cooling");
            display.display();
            showDisplay=false;

            //turn on fan here
            wemoWrite(wemoCool,HIGH);
        }

        //LEFT, go back to setup screen
        if(newHor<1000){setHorLeft=true;}
        if(newHor>1000 && setHorLeft==true){
            setHorRight = false;setHorLeft= false;setVertDown=false;setVertUp=false;
            applicationState = 1;
            setupState=0;
            waitedTime = 0;
            motionDetected=false;
            showDisplay=true;
            forceCool=false;forceHeat=false;
        }

        break;

    case 4:  //Wating to heat
        setPixelDisplay(4);

        //tell the user, it's cooling
        if(showDisplay){   
            waitedTime = 0;
            waitTimer.startTimer(1000); 
            motionDetected=0;

            display.clearDisplay();
            display.setTextColor(WHITE);
            display.setTextSize(1);
            display.setCursor(20,0);
            display.printf("Wating to heat");
            display.display();
            showDisplay=false;
        }

        //do a countdown, so the motion sensor doesn't 
        //start reading for 10 seconds
        if (waitedTime < SENSORWAITTINE){
            if (waitTimer.isTimerReady()==true){
                display.fillRect(50,20, 70,30,BLACK);
                display.setTextColor(WHITE);
                display.setTextSize(2);
                display.setCursor(50,20);
                display.printf("%i",SENSORWAITTINE-waitedTime);
                display.display();
                waitedTime++;
                waitTimer.startTimer(1000); 
            }
        }
        else
        {
            //read the motion sensor
            display.fillRect(50,20, 70,30,BLACK);
            display.display();
            motionDetected = digitalRead(DETECTPIN);
        }

        //LEFT, go back to setup screen
        if(newHor<1000){setHorLeft=true;}
        if(newHor>1000 && setHorLeft==true){
            setHorRight = false;setHorLeft= false;setVertDown=false;setVertUp=false;
            applicationState = 1;
            setupState=0;
            waitedTime = 0;
            motionDetected=false;
            showDisplay=true;
            forceCool=false;forceHeat=false;
        }

        break;

    case 5:  //heating
        setPixelDisplay(5);
        newHor = analogRead(joyHorz);
        
        //tell the user, it's cooling
        if(showDisplay){
            display.clearDisplay();
            display.setTextColor(WHITE);
            display.setTextSize(2);
            display.setCursor(20,0);
            display.printf("Heating");
            display.display();
            showDisplay=false;

            //turn on heater here
            wemoWrite(wemoHeat,HIGH);
        }

        //LEFT, go back to setup screen
        if(newHor<1000){setHorLeft=true;}
        if(newHor>1000 && setHorLeft==true){
            Serial.print("Heating left button");
            setHorRight = false;setHorLeft= false;setVertDown=false;setVertUp=false;
            applicationState = 1;
            setupState=0;
            waitedTime = 0;
            motionDetected=false;
            forceHeat=false;
            showDisplay=true;
        }

        break;

    default:
        break;
    }


}


void setPixelDisplay(int theState)
{
    static int lastSwitch;
    static bool onOff;
    int brightNess;
    bool useHue = true;

    switch (theState)
    {
        case 0:
            //bed is off
            pixel.clear();
            pixel.show();
            if (useHue) {setHue(BULB,false,0,0,0);}
            break;

        case 1:  
            //setup mode  (blinking white every second)
            if(millis()-lastSwitch>500)
            {
                pixel.setBrightness(10);
                onOff = !onOff;
                if (onOff==true)
                {
                    PixelFill(0,PIXELCOUNT-1,white);
                    if (useHue) {setHue(BULB,true,HueOrange,75,10);}
                }
                else
                {
                    pixel.clear();
                    if (useHue) {setHue(BULB,false,0,0,0);}
                }
                pixel.show();
                lastSwitch = millis();
            }
            break;

        case 2: 
            // bed is ready to be cold (breath blue)
            PixelFill(0,PIXELCOUNT-1,blue);
            brightNess = 7 * sin(2.0*M_PI*(2.0/5.0)*millis()/1000.0)+ 10;
            pixel.setBrightness(brightNess);
            pixel.show();
            if (useHue) {setHue(BULB,true,HueBlue,brightNess,255);}
            break;

        case 3:
            //bed is in cold mode (steady blue)
            PixelFill(0,PIXELCOUNT-1,blue);
            pixel.setBrightness(40);
            pixel.show();
            if (useHue) {setHue(BULB,true,HueBlue,100,255);}
            break;

        case 4:
            // bed is ready to be hot (breathing yellow)
            PixelFill(0,PIXELCOUNT-1,yellow);
            brightNess = 7 * sin(2.0*M_PI*(2.0/5.0)*millis()/1000.0)+ 10;
            pixel.setBrightness(brightNess);
            pixel.show();
            if (useHue) {setHue(BULB,true,HueYellow,brightNess,255);}
            break;

        case 5:
            //bed is in heat mode (steady yellow)
            PixelFill(0,PIXELCOUNT-1,yellow);
            pixel.setBrightness(40);
            pixel.show();
            if (useHue) {setHue(BULB,true,HueYellow,100,255);}
            break;

        default:
            //bed is off
            pixel.clear();
            pixel.show();
            if (useHue) {setHue(BULB,false,0,0,0);}
            break;
    }

}

void PixelFill(int startPixel, int endPixel, int theColor)
{
  int theLoop;
  for (theLoop=startPixel;theLoop<=endPixel;theLoop++){
    pixel.setPixelColor(theLoop,theColor);
  }
}

Include (Button.h)

C/C++
Manages button clicks
#ifndef _BUTTON_H_
#define _BUTTON_H_

class Button {
  int _buttonPin;
  int _prevButtonState;
  bool _pullUp;

  public:
    Button(int buttonPin, bool pullUp=false) {
      _buttonPin = buttonPin;
      _pullUp = pullUp;

      if(pullUp) {
        pinMode(_buttonPin,INPUT_PULLUP);
      }
      else {
        pinMode(_buttonPin,INPUT_PULLDOWN);       
      }
    }

    bool isPressed() {
      bool _buttonState;

      _buttonState = digitalRead(_buttonPin);
      if(_pullUp) {
        _buttonState = !_buttonState;
      }
      return _buttonState;
    }

    bool isClicked() {
      bool _buttonState, _clicked;

      _buttonState = digitalRead(_buttonPin);
      if(_pullUp) {
        _buttonState = !_buttonState;
      }
      if(_buttonState != _prevButtonState) {
        _clicked = _buttonState;
      }
      else {
        _clicked = false;
      }
      _prevButtonState=_buttonState;
      return _clicked;
    }
};

#endif // _BUTTON_H_

Include (Colors.h)

C/C++
Library of colors for the neo pixels
/* 
 * Project: colors.h
 * Description: Header file for color mapping
 * Brian Rashap
 * 10-Feb-2020
 */

#ifndef _COLORS_H_
#define _COLORS_H_

const int black = 0x000000;
const int white = 0xFFFFFF;
const int red = 0xFF0000;
const int lime = 0x00FF00;
const int blue = 0x0000FF;
const int yellow = 0xFFFF00;
const int cyan = 0x00FFFF;
const int magenta = 0xFF00FF;
const int silver = 0xC0C0C0;
const int gray = 0x808080;
const int maroon = 0x800000;
const int olive = 0x808000;
const int green = 0x008000;
const int purple = 0x800080;
const int teal = 0x008080;
const int navy = 0x000080;
const int orange = 0xFFA500;
const int indigo = 0x4B0082;
const int violet = 0x9400D3;
const int maize = 0xF2C649;
const int pink = 0xFFC0CB;
const int turquoise = 0x40E0D0;
const int carrot = 0xED9121;
const int chocolate = 0xD2691E;
const int salmon = 0xC67171;
const int tomato = 0xFF6347;

const int rainbow[] = {red, orange, yellow, green, blue, indigo,violet};

#endif // _COLORS_H_

Include (Graphic.h)

C/C++
Graphics for the OLED display
#ifndef _GRAPHIC_H_
#define _GRAPHIC_H_

static const unsigned char graphic_updown[]={// 'UpDown, 16x46px
	0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0xfc, 0x3f, 0xf8, 0x1f, 0xf0, 0x0f, 0xe0, 0x07, 0xc0, 0x03, 
	0xf0, 0x0f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf0, 0x0f, 0xf8, 0x1f, 0xf8, 0x1f, 
	0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 
	0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 0xf8, 0x1f, 
	0xf0, 0x0f, 0xf8, 0x1f, 0xf0, 0x0f, 0xf0, 0x0f, 0xf8, 0x1f, 0xf0, 0x0f, 0xc0, 0x03, 0xe0, 0x07, 
	0xf0, 0x0f, 0xf8, 0x1f, 0xfc, 0x3f, 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff};

static const unsigned char graphic_off[] ={// 'Off, 65x61px
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0xff, 
	0xff, 0xff, 0x07, 0x06, 0x0f, 0xff, 0xff, 0x80, 0xff, 0xff, 0xfe, 0xf7, 0x3e, 0xff, 0xff, 0xff, 
	0x80, 0xff, 0xff, 0xfd, 0xfb, 0x7e, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xfd, 0xfb, 0x3e, 0x7f, 
	0xff, 0xff, 0x80, 0xff, 0xff, 0xfd, 0xfb, 0x06, 0x0f, 0xff, 0xff, 0x80, 0xff, 0xff, 0xfd, 0xfb, 
	0x3e, 0x7f, 0xff, 0xff, 0x80, 0xff, 0xff, 0xfd, 0xfb, 0x3e, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 
	0xfe, 0xf7, 0x3e, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x0f, 0x3e, 0xff, 0xff, 0xff, 0x80, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0x80, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 
	0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x00, 
	0x03, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 
	0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0x80, 
	0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 
	0xff, 0x80, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x00, 0x03, 
	0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 
	0x00, 0x03, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0x80, 0xff, 
	0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 
	0x80, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 
	0xff, 0xff, 0x80, 0xff, 0xff, 0xf0, 0x00, 0x00, 0x9f, 0xff, 0xff, 0x80, 0xff, 0xff, 0xc0, 0x00, 
	0x00, 0x0f, 0xff, 0xff, 0x80, 0xff, 0xff, 0xe0, 0x00, 0x00, 0x1f, 0xff, 0xff, 0x80, 0xff, 0xff, 
	0xf0, 0x00, 0x00, 0x3f, 0xff, 0xff, 0x80, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x7f, 0xff, 0xff, 0x80, 
	0xff, 0xff, 0xfc, 0x00, 0x00, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xfe, 0x00, 0x01, 0xff, 0xff, 
	0xff, 0x80, 0xff, 0xff, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0x80, 0x07, 
	0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 
	0xe0, 0x1f, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xff, 0x80, 0xff, 
	0xff, 0xff, 0xf8, 0x7f, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 
	0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0x80};


static const unsigned char graphic_onoff[] = {  //80 x 68
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xe1, 0xc3, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xde, 0xff, 0x7f, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xdf, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xdf, 0x43, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xdf, 0xff, 0x7f, 0xff, 0xff, 0xff, 
	0xfe, 0x3f, 0xff, 0xff, 0xde, 0xdf, 0x7f, 0xff, 0xff, 0xff, 0xfc, 0x1f, 0xff, 0xff, 0xed, 0xdf, 
	0x7f, 0xff, 0xff, 0xff, 0xf8, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf0, 0x07, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x03, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0x80, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x80, 0x00, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 
	0x00, 0x00, 0x3f, 0xff, 0x80, 0x03, 0xff, 0xff, 0xff, 0xfc, 0x00, 0x00, 0x1f, 0xff, 0x80, 0x03, 
	0xff, 0xff, 0xff, 0xf8, 0x00, 0x00, 0x0f, 0xff, 0x80, 0x03, 0xff, 0xff, 0xff, 0xf0, 0x00, 0x00, 
	0x07, 0xff, 0x80, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 
	0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 
	0x80, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0xff, 0xff, 
	0xc0, 0x01, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x03, 
	0xff, 0xff, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x01, 
	0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 
	0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 
	0x80, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0xff, 0xff, 
	0xc0, 0x01, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x03, 
	0xff, 0xff, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x01, 
	0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 
	0xff, 0xff, 0xc0, 0x01, 0xff, 0xe0, 0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xe0, 
	0x00, 0x00, 0x0f, 0xff, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xf8, 0x00, 0x00, 0x1f, 0xff, 0xff, 0xff, 
	0xc0, 0x01, 0xff, 0xf8, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xfe, 0x00, 0x00, 
	0x7f, 0xff, 0xff, 0xff, 0xc0, 0x01, 0xff, 0xfe, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x01, 
	0xff, 0xff, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xc8, 0x0b, 0xff, 0xff, 0x80, 0x03, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xe0, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xf0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x1f, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xf8, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xfc, 0x7b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfb, 0xb9, 0xdf, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xd9, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 
	0xde, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf7, 0xde, 0x5f, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xf7, 0xdf, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 0xbf, 0x9f, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf8, 0x7f, 0x9f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
};

// 'HeatCool', 110x51px
static const unsigned char graphic_hotcold[] = {  //110 x 51
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xfc, 0xff, 0xf8, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
	0x0f, 0xfc, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xfc, 
	0xff, 0xe0, 0x1f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xfc, 0xff, 0xc0, 
	0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xfc, 0xff, 0x80, 0x07, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xfc, 0xff, 0x00, 0x03, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xfc, 0xfe, 0x00, 0x01, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xc0, 0x0f, 0xfc, 0xfc, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xc0, 0x0f, 0xfc, 0xff, 0xc0, 0x07, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 
	0x0f, 0xfc, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xfc, 
	0xff, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xfc, 0xff, 0xc0, 
	0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xfc, 0xff, 0xc0, 0x0f, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xfc, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xc0, 0x0f, 0xfc, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xc0, 0x07, 0xfc, 0xff, 0xc0, 0x0f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf3, 
	0xfc, 0x00, 0x00, 0xfc, 0xff, 0xc0, 0x0f, 0xff, 0xc7, 0xc7, 0xff, 0xff, 0xff, 0xf3, 0xfe, 0x00, 
	0x00, 0xfc, 0xff, 0xc0, 0x0f, 0xff, 0xc7, 0x87, 0xff, 0xff, 0xff, 0xf3, 0xff, 0x00, 0x01, 0xfc, 
	0xff, 0xc0, 0x0f, 0xff, 0xc3, 0x86, 0x1d, 0x19, 0xd8, 0x73, 0xff, 0x80, 0x03, 0xfc, 0xff, 0xc0, 
	0x0f, 0xff, 0xd3, 0x26, 0x8c, 0x19, 0xd9, 0x33, 0xff, 0xc0, 0x07, 0xfc, 0xff, 0xc0, 0x0f, 0xff, 
	0xdb, 0x27, 0x0d, 0xc9, 0xdc, 0x33, 0xff, 0xe0, 0x0f, 0xfc, 0xff, 0xc0, 0x0f, 0xff, 0xd8, 0x66, 
	0x0d, 0xc9, 0xd8, 0x33, 0xff, 0xf0, 0x1f, 0xfc, 0xff, 0xc0, 0x0f, 0xff, 0xd8, 0x64, 0xcd, 0xc9, 
	0x99, 0xb3, 0xff, 0xf8, 0x7f, 0xfc, 0xff, 0xc0, 0x0f, 0xff, 0xdc, 0x64, 0x0d, 0xcc, 0x18, 0x33, 
	0xff, 0xfc, 0x7f, 0xfc, 0xff, 0xc0, 0x0f, 0xff, 0xdc, 0xe6, 0x0d, 0xcc, 0x5c, 0x33, 0xff, 0xff, 
	0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 
	0xfd, 0xdf, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x3f, 0xff, 0x7c, 0xf9, 0xdf, 
	0xff, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff, 0x7c, 0xf9, 0xd8, 0x63, 0x3f, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xf9, 0xf0, 0xc3, 0x7c, 0xf8, 0x13, 0x79, 0x3f, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xf9, 0xe6, 0xd9, 0x7c, 0xf9, 0x90, 0x61, 0x3f, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xf9, 0xe6, 0x99, 0x7c, 0xf9, 0x93, 0xc9, 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 
	0xf9, 0xe6, 0xdb, 0x7c, 0xf9, 0xd8, 0x61, 0x9f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0x30, 
	0xc3, 0x7c, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc, 0xff, 0xff, 0xff, 0xff, 
	0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfc
};



 #endif // _GRAPHIC_H_

Include (Hue.h)

C/C++
Controls hue external light bulbs
#ifndef _HUE_H_
#define _HUE_H_

/*
 *  Project: Hue IoT Library
 *  Description: Library for controlling Hue Lights at IOT Classroom
 *  Authors:  Brian Rashap
 *  Date:     1-MAY-2020
 */

#include "application.h"

/* Usage:
 * setHue(int lightNum, bool HueOn, int HueColor, int HueBright, int HueSat);
 * where:
 *    lightNum is the number of the light to be controlled
 *    HueOn is true to turn the light on, false to turn it off
 *    HueColor is a number between 0 and 65353 (see constants below)
 *    HueBright is the brightness between 0 and 255
 *    HueSat is the saturation between 0 and 255
 *
 * NOTE: In your main code, Ethernet.begin(mac) needs to be called
 */


// Hue Configuration
const char hueHubIP[] = "192.168.1.5";       // Hue hub IP
const char hueUsername[] = "MQlZziRO0Wai5MsMHll8xAUAQqw85Qrr8tM37F3T";
const int hueHubPort = 80;   // HTTP: 80, HTTPS: 443, HTTP-PROXY: 8080

//  Hue variables
bool hueOn;  // on/off
int hueBri;  // brightness value
long hueHue;  // hue value
String hueCmd;  // Hue command

// Hue colors
int HueRed = 0;
int HueOrange = 5000;
int HueYellow = 10000;
int HueGreen = 22500;
int HueBlue = 45000;
int HueIndigo = 47500;
int HueViolet = 50000;
int HueRainbow[] = {HueRed, HueOrange, HueYellow, HueGreen, HueBlue, HueIndigo, HueViolet};

TCPClient HueClient;

bool setHue(int lightNum, bool HueOn, int HueColor=HueBlue, int HueBright=255, int HueSat=255);
bool getHue(int lightNum);

bool setHue(int lightNum, bool HueOn, int HueColor, int HueBright, int HueSat) {

  static int PrevLightNum,PrevOn, PrevColor, PrevBright, PrevSat;

  String command = "";  

  if((lightNum==PrevLightNum)&&(HueOn==PrevOn)&&(HueColor==PrevColor)&&(HueBright==PrevBright)&&(HueSat==PrevSat)) {
    Serial.printf("No Change - Cancelling CMD\n");
    return false;
  }
  PrevLightNum = lightNum;
  PrevOn = HueOn;
  PrevColor=HueColor;
  PrevBright=HueBright;
  PrevSat=HueSat;

  if(HueOn == true) {
    /*
    command = "{\"on\":true,\"sat\":255,\"bri\":255,\"hue\":";
    command = command + String(HueColor) + "}";
    */
    
    command = "{\"on\":true,\"sat\":";
    command = command + String(HueSat) + ",\"bri\":";
    command = command + String(HueBright) + ",\"hue\":";
    command = command + String(HueColor) + "}";
  }
  else {
    command = "{\"on\":false}";
  }

  if (HueClient.connect(hueHubIP, hueHubPort)) {
    //while (HueClient.connected())
    //{
      // Serial.println("Sending Command to Hue");
      // Serial.println(command);
      Serial.printf("Sending Command to Hue: %s\n",command.c_str());
      HueClient.print("PUT /api/");
      HueClient.print(hueUsername);
      HueClient.print("/lights/");
      HueClient.print(lightNum);  // hueLight zero based, add 1
      //  HueClient.println("/state");
      HueClient.println("/state HTTP/1.1");
      HueClient.println("keep-alive");
      HueClient.print("Host: ");
      HueClient.println(hueHubIP);
      HueClient.print("Content-Length: ");
      HueClient.println(command.length());
      HueClient.println("Content-Type: text/plain;charset=UTF-8");
      HueClient.println();  // blank line before body
      HueClient.println(command);  // Hue command
      HueClient.readString();
      // Serial.println("From Hue");
      // Serial.println(HueClient.readString()); // To close connection
    HueClient.stop();
    return true;  // command executed
  }
  else
    return false;  // command failed
}


bool getHue(int lightNum) {
  if (HueClient.connect(hueHubIP, hueHubPort))
  {
    HueClient.print("GET /api/");
    HueClient.print(hueUsername);
    HueClient.print("/lights/");
    HueClient.print(lightNum);  
    HueClient.println(" HTTP/1.1");
    HueClient.print("Host: ");
    HueClient.println(hueHubIP);
    HueClient.println("Content-type: application/json");
    HueClient.println("keep-alive");
    HueClient.println();
    //while (HueClient.connected())
    //{
    //  if (HueClient.available()) {
        Serial.println();
        Serial.println(HueClient.readString());
        Serial.println();
        HueClient.findUntil("\"on\":", "\0");
        hueOn = (HueClient.readStringUntil(',') == "true");  // if light is on, set variable to true
        Serial.print("Hue Status: ");
        Serial.println(hueOn);
 
        HueClient.findUntil("\"bri\":", "\0");
        hueBri = HueClient.readStringUntil(',').toInt();  // set variable to brightness value
        Serial.println(hueBri);
        
        HueClient.findUntil("\"hue\":", "\0");
        hueHue = HueClient.readStringUntil(',').toInt();  // set variable to hue value
        Serial.printf("Hue is\n\n\n %i\n",hueHue);
        
        //break;  // not capturing other light attributes yet
    //  }
    //}
    HueClient.stop();
    return true;  // captured on,bri,hue
  }
 else
   return false;  // error reading on,bri,hue
}

#endif // _HUE_H_

Include (IoTTimer.h)

C#
Manages timer functionality
#ifndef _IOTTIMER_H_
#define _IOTTIMER_H_

class IoTTimer {

  unsigned int _timerStart, _timerTarget;

  public:
    //IoT Constructor with no parameters
    //IotTimer() {}
    
    void startTimer(unsigned int msec) {
      _timerStart = millis();
      _timerTarget = msec;       
    }

    bool isTimerReady() {
      return ((millis() - _timerStart) >= _timerTarget);
    }
};

#endif // _IOTTIMER_H_

Include (wemo.h)

C/C++
Manages WEMO internet plugs
#ifndef _WEMO_H_
#define _WEMO_H_

/*
 *  Project: Wemo IoT Library
 *  Description: Library for controlling Wemo Smart Outlets at IOT Classroom
 *  Authors:  Brian Rashap
 *  Date:     06-FEB-2022
 */

#include "application.h"

TCPClient WemoClient;

int wemoPort = 49153;
const char *wemoIP[6] = {"192.168.1.30","192.168.1.31","192.168.1.32","192.168.1.33","192.168.1.34","192.168.1.35"};

// Function Prototypes
void switchON(int wemo);
void switchOFF(int wemo);
void wemoWrite(int outlet, bool wemoState);

// Turn on/off wemo outlets similar to digitalWrite
void wemoWrite(int outlet, bool wemoState) {
  if(wemoState) {
    switchON(outlet);
  }
  else {
    switchOFF(outlet);
  }
}



// turn on specified wemo outlet
void switchON(int wemo) {
  
  String data1;
  
  Serial.printf("Switching On Wemo #%i\n",wemo);
  data1+="<?xml version=\"1.0\" encoding=\"utf-8\"?><s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><s:Body><u:SetBinaryState xmlns:u=\"urn:Belkin:service:basicevent:1\"><BinaryState>1</BinaryState></u:SetBinaryState></s:Body></s:Envelope>"; // Use HTML encoding for comma's
  if (WemoClient.connect(wemoIP[wemo],wemoPort)) {
        WemoClient.println("POST /upnp/control/basicevent1 HTTP/1.1");
        WemoClient.println("Content-Type: text/xml; charset=utf-8");
        WemoClient.println("SOAPACTION: \"urn:Belkin:service:basicevent:1#SetBinaryState\"");
        WemoClient.println("Connection: keep-alive");
        WemoClient.print("Content-Length: ");
        WemoClient.println(data1.length());
        WemoClient.println();
        WemoClient.print(data1);
        WemoClient.println();
    }

  if (WemoClient.connected()) {
     WemoClient.stop();
  }
}

// turn off wemo outlet specified
void switchOFF(int wemo){
  String data1;
  
  Serial.printf("Switching Off Wemo #%i \n",wemo);
  data1+="<?xml version=\"1.0\" encoding=\"utf-8\"?><s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><s:Body><u:SetBinaryState xmlns:u=\"urn:Belkin:service:basicevent:1\"><BinaryState>0</BinaryState></u:SetBinaryState></s:Body></s:Envelope>"; // Use HTML encoding for comma's
  if (WemoClient.connect(wemoIP[wemo],wemoPort)) {
        WemoClient.println("POST /upnp/control/basicevent1 HTTP/1.1");
        WemoClient.println("Content-Type: text/xml; charset=utf-8");
        WemoClient.println("SOAPACTION: \"urn:Belkin:service:basicevent:1#SetBinaryState\"");
        WemoClient.println("Connection: keep-alive");
        WemoClient.print("Content-Length: ");
        WemoClient.println(data1.length());
        WemoClient.println();
        WemoClient.print(data1);
        WemoClient.println();
    }
   
  if (WemoClient.connected()) {
     WemoClient.stop();
  }
}

#endif // _WEMO_H_

Credits

David Barbour
3 projects • 8 followers

Comments