Hackster is hosting Hackster Holidays, Ep. 6: Livestream & Giveaway Drawing. Watch previous episodes or stream live on Monday!Stream Hackster Holidays, Ep. 6 on Monday!
Zhongyi Chen
Published © GPL3+

Lane Tech HS - PCL - IOT Thermostat Controller + MP3 Player

This project was part of the Lane Tech HS Physical Computing Lab course. I created this project as part of the Home Automation/IoT project.

IntermediateFull instructions provided10 hours1,341
Lane Tech HS - PCL - IOT Thermostat Controller + MP3 Player

Things used in this project

Hardware components

Photon
Particle Photon
×1
DFPlayer Micro SD TF U-disk for Arduino US
×1
Adafruit High Torque Micro Servo
×1
Adafruit Breadboard Trim Potentiometer - 10K
×1
Adafruit Tactile Button Switch (6mm)
×1
Temperature Sensor
Temperature Sensor
×1
Speaker: 3W, 4 ohms
Speaker: 3W, 4 ohms
You can always reuse speakers from old/broken devices
×1

Software apps and online services

Particle Build Web IDE
Particle Build Web IDE
Blynk
Blynk

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)
Hot glue gun (generic)
Hot glue gun (generic)

Story

Read more

Schematics

Fritzing Diagram

Here is the general hardware placements and wiring of this project. The path of the wiring for the button/potentiometer is the same as in the demo.

Code

Thermostat Control

Arduino
Contains all featured functionalities. Instructions to how to add blynk functionality and how to add your own songs are also included.
//For Blynk
/*
 *  Although blynk.h is included through this file, to actually include it, follow these instructions from particle.io:
 *  https://docs.particle.io/guide/getting-started/build/photon/#using-libraries
 *  
 */
# include <blynk.h>
# define BLYNK_PRINT Serial

//For MP3
# define Start_Byte 0x7E
# define Version_Byte 0xFF
# define Command_Length 0x06
# define End_Byte 0xEF
# define Acknowledge 0x00
# define ACTIVATED LOW


//For Blynk
char auth[] = "(your auth token)";
WidgetTerminal terminal(V4);
String terminalMSG;
int tempTemp = 50;
bool modeSelection = false;
int modeIndex = 1;
int tempModeIndex = 1;
String modeLabels[4] = {"Mode Selector", "Temperature Mode", "MP3 Mode", "MP3 Volume Mode"};
String modeSelectLabels[3] = {"Set Mode", "Choose Mode: ", "Selected Mode: "};
String tempLabels[3] = {"Set Temp", "Choose Temperature", "Selected Temp(F): "};
String MP3Labels[3] = {"Set Song", "Choose Song: ", "Selected Song: "};
String MP3VolLabels[3] = {"Set Volume", "Choose Volume", "Selected Volume: "};

//For Thermostat
Servo turner;
int Potenti = A1;
int Button = A0;
int TMP36_SENSOR = A3;
int currentTemp = 50;
int currentPos = 147;

//For MP3 Player
int currentVolume = 20;
int songIndex = 0;
/*
 *  Here is where you will list out the names of your songs
 *  Follow the following format:
 *  String songs[(array length)] = {"(None Selected)", "Song1", "Song2"};
 *  If you add more songs here, change value in line 137 to the array length.
 *  
 *  For files in your SDCard:
 *  Create and open folder called "01"
 *  The names of your songs in the folder should be "001", "002", "003", etc.
 *  The names map to the index of your songs in the array below.
 *  
 */
String songs[1] = {"(None Selected)"};//Don't forget to change array length


void setup() {
    //Temp Control
    turner.attach(2);
    rotate(turner, currentPos, 0);
    pinMode(Button, INPUT_PULLUP);
    pinMode(TMP36_SENSOR, INPUT);
    
    //Blynk Control
    Serial.begin(9600);
    
    //MP3 Control
    Serial1.begin(9600);
    delay(3000);
    
    Blynk.begin(auth);
    initMP3();
}

void loop() {
    Blynk.run();
    int buttonRead = digitalRead(Button);
    if (potentiControl)
        handlePotentiEvent(Potenti);
    if(buttonRead == LOW)
        potentiControl = true;
    else potentiControl = false;
}


//Blynk Handlers
BLYNK_WRITE(V0) {
    if(param.asInt() == 1){
        if (modeSelection){
            modeIndex = tempModeIndex;
            Blynk.setProperty(V2, "label", modeSelectLabels[2]+modeLabels[modeIndex]);
            Blynk.virtualWrite(V2, modeIndex);
        }
        else if (modeIndex == 1){
            int posi = tempToPos(tempTemp);
            rotate(turner, posi, 10);
            Blynk.virtualWrite(V2, tempTemp);
        }
        else if (modeIndex == 2){
            play(1, songIndex);
            Blynk.setProperty(V2, "label", MP3Labels[2]+songs[songIndex]);
            Blynk.virtualWrite(V2, songIndex);
        }
        else if (modeIndex == 3){
            setVolume(currentVolume);
            Blynk.virtualWrite(V2, currentVolume);
        }
    }
}

BLYNK_WRITE(V1) {
    if (modeSelection){
        tempModeIndex = param.asInt();
        Blynk.setProperty(V1, "label", modeSelectLabels[1]+modeLabels[tempModeIndex]);
    }
    else if (modeIndex == 1)
        tempTemp = param.asInt();
    else if (modeIndex == 2){
        songIndex = param.asInt();
        Blynk.setProperty(V1, "label", MP3Labels[1]+songs[songIndex]);
    }
    else if (modeIndex == 3)
        currentVolume = param.asInt();
}

BLYNK_WRITE(V3) {
    if(param.asInt() == 0){
        modeSelection = false;
        Blynk.setProperty(V3, "offLabel", modeLabels[modeIndex]);
        if(modeIndex == 1){
            setLabelProperties(tempLabels);
            Blynk.setProperty(V1, "min", 50);
            Blynk.setProperty(V1, "max", 80);
            Blynk.virtualWrite(V1, 50);
            Blynk.virtualWrite(V2, 0);
        }
        else if(modeIndex == 2){
            setLabelProperties(MP3Labels);
            Blynk.setProperty(V1, "min", 0);
            Blynk.setProperty(V1, "max", 1);//Change third param when needed
            Blynk.virtualWrite(V1, 0);
            Blynk.virtualWrite(V2, 0);
        }
        else if(modeIndex == 3){
            setLabelProperties(MP3VolLabels);
            Blynk.setProperty(V1, "min", 0);
            Blynk.setProperty(V1, "max", 30);
            Blynk.virtualWrite(V1, 0);
            Blynk.virtualWrite(V2, 0);
        }
    }
    else if(param.asInt() == 1){
        modeSelection = true;
        setLabelProperties(modeSelectLabels);
        Blynk.setProperty(V1, "min", 1);
        Blynk.setProperty(V1, "max", 3);
        Blynk.virtualWrite(V1, 1);
        Blynk.virtualWrite(V2, 0);
    }
}

BLYNK_WRITE(V4) {
    terminalMSG = param.asStr();
    if(terminalMSG == "temp"){
        terminal.println("");
        terminal.print(getTempInFarenheit());
        terminal.println(" F");
    }
    terminal.flush();
}


void setLabelProperties(String labels[3]){
    Blynk.setProperty(V0, "label", labels[0]);
    Blynk.setProperty(V1, "label", labels[1]);
    Blynk.setProperty(V2, "label", labels[2]);
}

int tempToPos(int temper){
    return (37 + (80 - temper)*90/30);
}


//Thermostat Functions
void handlePotentiEvent(int potenti) {
    int val = analogRead(potenti);
    int temp = 80-val*30/4096;
    rotate(turner,tempToPos(temp),10);
}

void rotate(Servo serv, int position, int rate) {
    if (currentPos < position) {
        for(int i = currentPos; i <= position; i++){
            serv.write(i);
            delay(rate);
        }
        serv.write(position-3);
        currentPos = position-3;
    }
    else {
        for(int i = currentPos; i >= position; i--){
            serv.write(i);
            delay(rate);
        }
        serv.write(position+3);
        currentPos = position+3;
    }
}

double getTempInCelsius() {
  int tmp36Value = analogRead(TMP36_SENSOR);
  return (tmp36Value * 0.0008 - 0.5) / 0.010;
}

double getTempInFarenheit() {
  int tmp36Value = getTempInCelsius();
  return (tmp36Value *9/5) + 32;
}

//MP3 Functions
void initMP3(){
  execute_CMD(0x3F, 0, 0);
  delay(500);
  setVolume(currentVolume);
  delay(500);
}

void pause(){
  execute_CMD(0x0E,0,0);
  delay(500);
}

void play(int folder, int file){
  execute_CMD(0x0F,folder,file); 
  delay(500);
}

void setVolume(int volume){
  execute_CMD(0x06, 0, volume);
  delay(500);
}




void execute_CMD(byte CMD, byte Par1, byte Par2){
 // Calculate the checksum (2 bytes)
 int16_t checksum = -(Version_Byte + Command_Length + CMD + Acknowledge + Par1 + Par2);

 // Build the command line
 byte Command_line[10] = { Start_Byte, Version_Byte, Command_Length, CMD, Acknowledge, Par1, Par2, checksum >> 8, checksum & 0xFF, End_Byte};

 //Send the command line to the module
 for (byte k=0; k<10; k++)
 {
  Serial1.write( Command_line[k]);
 }
}

Credits

Zhongyi Chen

Zhongyi Chen

2 projects • 7 followers

Comments