#include #include #include #include "button.h" #include "relay.h" #include "temperature_sensor.h" #include "queue.h" #define AIR_TEMP_SENSOR_PIN A1 #define RELAY_PIN 6 #define SPEAKER_PIN 7 #define BUTTON_RIGHT_PIN 8 #define BUTTON_LEFT_PIN 9 #define BUTTON_DOWN_PIN 10 #define BUTTON_UP_PIN 11 #define MAX_STATE 4 // Amount of display states #define SCREEN_WIDTH 128 // OLED display width, in pixels #define SCREEN_HEIGHT 64 // OLED display height, in pixels #define TEMP_DELTA 4 // Minimum temperature difference before relay is toggled #define ALARM_TEMP_DELTA 15 // Minimum temperature difference before the alarm wil sound #define TEMP_PLOT_INTERVAL 60000 // Amount of milliseconds between temperature measuring points in the plot byte state = 0; int targetTemp = 70; int alarmState = 0; long lastTempQueue = -1000000; Button buttonUp(BUTTON_UP_PIN); Button buttonDown(BUTTON_DOWN_PIN); Button buttonLeft(BUTTON_LEFT_PIN); Button buttonRight(BUTTON_RIGHT_PIN); Relay relay(RELAY_PIN); // Pass pin, reference voltage, and a,b,c coefficients TemperatureSensor airTempSensor(AIR_TEMP_SENSOR_PIN, 10000, 0.0010626977757858514, 0.00025567427237838396, -8.706543235296982e-8); // Declaration for an SSD1306 display connected to I2C (SDA, SCL pins) Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, -1); Queue tempQueue; void setup() { pinMode(SPEAKER_PIN, OUTPUT); digitalWrite(SPEAKER_PIN, LOW); //Serial.begin(9600); if (!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { //Serial.println(F("SSD1306 allocation failed")); for (;;); } display.setRotation(2); display.clearDisplay(); display.setTextColor(WHITE); airTempSensor.preload(); } void loop() { updateAirTemp(); byte bUp = buttonUp.getState(); byte bDown = buttonDown.getState(); byte bLeft = buttonLeft.getState(); byte bRight = buttonRight.getState(); if (bRight >= 1) { if (state >= MAX_STATE) state = 0; else state += 1; } if (bLeft >= 1) { if (state <= 0) state = MAX_STATE; else state -= 1; } display.clearDisplay(); displayMenuBar(); switch (state) { case 0: targetTempState(bUp, bDown); break; case 1: manualState(bUp, bDown); break; case 2: uptimeState(bUp, bDown); break; case 3: tempPlotState(bUp, bDown); break; case 4: alarmSettingState(bUp, bDown); break; } display.display(); } void updateAirTemp() { airTempSensor.update(); if (millis() - lastTempQueue > TEMP_PLOT_INTERVAL) { tempQueue.push(airTempSensor.getTemperature()); lastTempQueue = millis(); } } void updateRelay() { float temperature = airTempSensor.getTemperature(); if (temperature - targetTemp >= TEMP_DELTA) { //Temp too high relay.off(); } else if (targetTemp - temperature >= TEMP_DELTA) { //Temp too low relay.on(); } if (temperature - targetTemp >= ALARM_TEMP_DELTA) { int second = millis() % 1000; if (alarmState == 0 and second < 100) { alarmState = 1; digitalWrite(SPEAKER_PIN, HIGH); } else if (alarmState == 1 and second > 500 and second < 600) { alarmState = 0; digitalWrite(SPEAKER_PIN, LOW); } else if (alarmState == -1) { digitalWrite(SPEAKER_PIN, LOW); } } else { digitalWrite(SPEAKER_PIN, LOW); } } void targetTempState(byte bUp, byte bDown) { updateRelay(); switch (bUp) { case 1: targetTemp += 1; break; case 2: targetTemp += 1; break; case 3: targetTemp += 3; break; } switch (bDown) { case 1: targetTemp -= 1; break; case 2: targetTemp -= 1; break; case 3: targetTemp -= 3; break; } displayCurrentTemp(); // Target Temp display.setTextSize(1); display.setCursor(0, 40); display.print("Target: "); display.setTextSize(2); display.setCursor(0, 50); display.print(targetTemp); display.print(" "); display.setTextSize(1); display.cp437(true); display.write(167); display.setTextSize(2); display.print("C"); //display.drawRect(0, 0, display.width(), display.height(), SSD1306_WHITE); } void manualState(byte bUp, byte bDown) { if (bUp == 1) { relay.on(); } if (bDown == 1) { relay.off(); } displayCurrentTemp(); display.setTextSize(1); display.setCursor(0, 40); display.print("Manual Mode"); display.setTextSize(2); display.setCursor(0, 50); if (relay.getState()) { display.print("Heater ON"); } else { display.print("Heater OFF"); } } void uptimeState(byte bUp, byte bDown) { updateRelay(); unsigned int seconds = millis() / 1000; //convect milliseconds to seconds unsigned int minutes = seconds / 60; //convert seconds to minutes unsigned int hours = minutes / 60; //convert minutes to hours seconds = seconds - (minutes * 60); //subtract the coverted seconds to minutes in order to display 59 secs max minutes = minutes - (hours * 60); //subtract the coverted minutes to hours in order to display 59 minutes max displayCurrentTemp(); display.setTextSize(1); display.setCursor(0, 40); display.print("Uptime:"); display.setTextSize(2); display.setCursor(0, 50); if (hours < 10) display.print(0); display.print(hours); display.print(":"); if (minutes < 10) display.print(0); display.print(minutes); display.print(":"); if (seconds < 10) display.print(0); display.print(seconds); } void displayMenuBar() { byte space = display.width() / (MAX_STATE + 1); for (byte i = 0; i < MAX_STATE + 1; i++) { if (i == state) display.fillCircle(space * i + space / 2, 3, 3, WHITE); else display.drawCircle(space * i + space / 2, 3, 3, WHITE); } } void tempPlotState(byte bUp, byte bDown) { updateRelay(); byte maxValue = tempQueue.getMax(); byte minValue = tempQueue.getMin(); if (minValue > 99) minValue = 99; display.setTextSize(1); if (maxValue > 99)display.setCursor(110, 8); else display.setCursor(116, 8); display.print(maxValue); display.setCursor(116, 57); display.print(minValue); if (maxValue - minValue < 10) { minValue -= 1; maxValue += 1; } for (int i = 0; i < TEMP_QUEUE_LENGTH; i++) { byte barHeight = tempQueue.lookup(i); if (barHeight < minValue) barHeight = minValue; barHeight = map(barHeight, minValue, maxValue, 2, 58); display.fillRect(i * 2, SCREEN_HEIGHT - barHeight, 1, barHeight, WHITE); } } void alarmSettingState(byte bUp, byte bDown) { updateRelay(); if (bUp == 1) { alarmState = 0; } if (bDown == 1) { alarmState = -1; } displayCurrentTemp(); display.setTextSize(1); display.setCursor(0, 40); display.print("Alarm temp: "); display.print(targetTemp + ALARM_TEMP_DELTA); display.print(" "); display.cp437(true); display.write(167); display.setTextSize(1); display.print("C"); display.setTextSize(2); display.setCursor(0, 50); if (alarmState == -1) { display.print("Alarm OFF"); } else { display.print("Alarm ON"); } } void displayCurrentTemp() { display.setTextSize(1); display.setCursor(0, 10); display.print("Current: "); display.setTextSize(2); display.setCursor(0, 20); display.print(airTempSensor.getTemperature()); display.print(" "); display.setTextSize(1); display.cp437(true); display.write(167); display.setTextSize(2); display.print("C"); }