From 2ca65ec64334d70f20a04a236ff72cf7b4531f71 Mon Sep 17 00:00:00 2001 From: Siwat Sirichai Date: Wed, 10 Jan 2024 23:19:49 +0700 Subject: [PATCH] first prototype --- src/cud_display.cpp | 238 +++++++++++++++++++++++++++++++++++++++++++- src/cud_display.hpp | 80 ++++++++++++++- src/main.cpp | 36 ++++++- 3 files changed, 349 insertions(+), 5 deletions(-) diff --git a/src/cud_display.cpp b/src/cud_display.cpp index 81feeb7..651f093 100644 --- a/src/cud_display.cpp +++ b/src/cud_display.cpp @@ -1,4 +1,238 @@ #include -CUDDisplay::CUDDisplay() : ESPMegaDisplay(&Serial2) { -} \ No newline at end of file +CUDDisplay::CUDDisplay() : ESPMegaDisplay(&Serial2) +{ +} + +void CUDDisplay::begin(std::function getTime, HardwareSerial *serial, + DigitalInputCard *inputCard, DigitalOutputCard *outputCard, + ClimateCard *climateCard) +{ + ESPMegaDisplay::begin(); + this->getTime = getTime; + this->sendClock(); + this->inputCard = inputCard; + this->outputCard = outputCard; + this->climateCard = climateCard; + auto bindedHandlePWMChange = std::bind(&CUDDisplay::handlePWMChange, this, std::placeholders::_1, std::placeholders::_2); + auto bindedHandleACChange = std::bind(&CUDDisplay::handleACChange, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3); + this->outputCallbackHandle = this->outputCard->registerChangeCallback(bindedHandlePWMChange); + this->climateCallbackHandle = this->climateCard->registerChangeCallback(bindedHandleACChange); +} + +void CUDDisplay::handleTouch(uint8_t page, uint8_t component, uint8_t event) +{ + if (page != PAGE_DASHBOARD) + return; + switch (component) + { + case COMPONENT_LIGHT_TOGGLE_BUTTON: + if (event != TOUCH_TYPE_RELEASE) + break; + toggleLightGroupState(); + break; + case COMPONENT_FAN_TOGGLE_BUTTON: + if (event != TOUCH_TYPE_RELEASE) + break; + toggleFanGroupState(); + break; + case COMPONENT_AIR_PURIFIER_TOGGLE_BUTTON: + if (event != TOUCH_TYPE_RELEASE) + break; + this->outputCard->setState(7, !this->outputCard->getState(7)); + break; + case COMPONENT_AC_TEMP_UP_BUTTON: + if (event != TOUCH_TYPE_RELEASE) + break; + this->climateCard->setTemperature(this->climateCard->getTemperature() + 1); + break; + case COMPONENT_AC_TEMP_DOWN_BUTTON: + if (event != TOUCH_TYPE_RELEASE) + break; + this->climateCard->setTemperature(this->climateCard->getTemperature() - 1); + break; + case COMPONENT_AC_MODE_OFF_BUTTON: + if (event != TOUCH_TYPE_RELEASE) + break; + this->climateCard->setMode(0); + break; + case COMPONENT_AC_MODE_FAN_ONLY_BUTTON: + if (event != TOUCH_TYPE_RELEASE) + break; + this->climateCard->setMode(1); + break; + case COMPONENT_AC_MODE_COOL_BUTTON: + if (event != TOUCH_TYPE_RELEASE) + break; + this->climateCard->setMode(2); + break; + case COMPONENT_AC_FAN_MODE_AUTO_BUTTON: + if (event != TOUCH_TYPE_RELEASE) + break; + this->climateCard->setFanSpeed(0); + break; + case COMPONENT_AC_FAN_MODE_LOW_BUTTON: + if (event != TOUCH_TYPE_RELEASE) + break; + this->climateCard->setFanSpeed(1); + break; + case COMPONENT_AC_FAN_MODE_MEDIUM_BUTTON: + if (event != TOUCH_TYPE_RELEASE) + break; + this->climateCard->setFanSpeed(2); + break; + case COMPONENT_AC_FAN_MODE_HIGH_BUTTON: + if (event != TOUCH_TYPE_RELEASE) + break; + this->climateCard->setFanSpeed(3); + break; + default: + break; + } +} + +void CUDDisplay::handlePWMChange(uint8_t pin, uint8_t value) +{ + // Is the pin a light, fan, or air purifier? + if (pin >= 0 && pin <= 3) + { + // Light + updateLightGroupState(); + } + else if (pin >= 4 && pin <= 6) + { + // Fan + updateFanGroupState(); + + } + else if (pin == 7) + { + // Air Purifier + updateAirPurifierState(); + } +} + +void CUDDisplay::handleACChange(uint8_t mode, uint8_t fan_speed, uint8_t temperature) +{ + // Update AC Controls + updateACState(); +} + +void CUDDisplay::sendClock() +{ + // Get the time + rtctime_t time = this->getTime(); + // Send the time to the display + this->displayAdapter->print("clock.txt="); + // We use 24 hour format, HH:MM + this->displayAdapter->print(time.hours); + this->displayAdapter->print(":"); + this->displayAdapter->print(time.minutes); + this->sendStopBytes(); +} + +bool CUDDisplay::calculateLightGroupState() { + // Check if all lights are on + bool allLightsOn = true; + for (uint8_t i = 0; i < 4; i++) { + if (this->outputCard->getState(i) == 0) { + allLightsOn = false; + break; + } + } + return allLightsOn; +} +bool CUDDisplay::calculateFanGroupState() { + // Check if all fans are on + bool allFansOn = true; + for (uint8_t i = 4; i < 7; i++) { + if (this->outputCard->getState(i) == 0) { + allFansOn = false; + break; + } + } + return allFansOn; +} +void CUDDisplay::setLightGrouptState(bool state) { + // Set all lights to state + for (uint8_t i = 0; i < 4; i++) { + this->outputCard->setState(i, state); + } +} +void CUDDisplay::setFanGroupState(bool state) { + // Set all fans to state + for (uint8_t i = 4; i < 7; i++) { + this->outputCard->setState(i, state); + } +} +void CUDDisplay::toggleLightGroupState() { + // Get the current group state + bool state = calculateLightGroupState(); + // Toggle the state + state = !state; + // Set the state + setLightGrouptState(state); +} +void CUDDisplay::toggleFanGroupState() { + // Get the current group state + bool state = calculateFanGroupState(); + // Toggle the state + state = !state; + // Set the state + setFanGroupState(state); +} +void CUDDisplay::updateLightGroupState() { + // Calculate the state + bool state = calculateLightGroupState(); + // Send the state to the display + this->displayAdapter->print("LT_BT.pic="); + this->displayAdapter->println(state ? COMPONENT_LIGHT_TOGGLE_PIC_ON : COMPONENT_LIGHT_TOGGLE_PIC_OFF); + this->sendStopBytes(); +} +void CUDDisplay::updateFanGroupState() { + // Calculate the state + bool state = calculateFanGroupState(); + // Send the state to the display + this->displayAdapter->print("FAN_BT.pic="); + this->displayAdapter->println(state ? COMPONENT_FAN_TOGGLE_PIC_ON : COMPONENT_FAN_TOGGLE_PIC_OFF); + this->sendStopBytes(); +} +void CUDDisplay::updateAirPurifierState() { + // Get the state + bool state = this->outputCard->getState(7); + // Send the state to the display + this->displayAdapter->print("AIR_BT.pic="); + this->displayAdapter->println(state ? COMPONENT_AIR_PURIFIER_TOGGLE_PIC_ON : COMPONENT_AIR_PURIFIER_TOGGLE_PIC_OFF); + this->sendStopBytes(); +} +void CUDDisplay::updateACState() { + // Get the state + uint8_t mode = this->climateCard->getMode(); + uint8_t fan_speed = this->climateCard->getFanSpeed(); + uint8_t temperature = this->climateCard->getTemperature(); + // Send the state to the display + this->displayAdapter->print("AC_MODE_OFF.pic="); + this->displayAdapter->println(mode == 0 ? COMPONENT_AC_MODE_OFF_PIC_ACTIVE : COMPONENT_AC_MODE_OFF_PIC_INACTIVE); + this->sendStopBytes(); + this->displayAdapter->print("AC_MODE_FAN_ONLY.pic="); + this->displayAdapter->println(mode == 1 ? COMPONENT_AC_MODE_FAN_ONLY_PIC_ACTIVE : COMPONENT_AC_MODE_FAN_ONLY_PIC_INACTIVE); + this->sendStopBytes(); + this->displayAdapter->print("AC_MODE_COOL.pic="); + this->displayAdapter->println(mode == 2 ? COMPONENT_AC_MODE_COOL_PIC_ACTIVE : COMPONENT_AC_MODE_COOL_PIC_INACTIVE); + this->sendStopBytes(); + this->displayAdapter->print("AC_FAN_MODE_AUTO.pic="); + this->displayAdapter->println(fan_speed == 0 ? COMPONENT_AC_FAN_MODE_AUTO_PIC_ACTIVE : COMPONENT_AC_FAN_MODE_AUTO_PIC_INACTIVE); + this->sendStopBytes(); + this->displayAdapter->print("AC_FAN_MODE_HIGH.pic="); + this->displayAdapter->println(fan_speed == 1 ? COMPONENT_AC_FAN_MODE_HIGH_PIC_ACTIVE : COMPONENT_AC_FAN_MODE_HIGH_PIC_INACTIVE); + this->sendStopBytes(); + this->displayAdapter->print("AC_FAN_MODE_MEDIUM.pic="); + this->displayAdapter->println(fan_speed == 2 ? COMPONENT_AC_FAN_MODE_MEDIUM_PIC_ACTIVE : COMPONENT_AC_FAN_MODE_MEDIUM_PIC_INACTIVE); + this->sendStopBytes(); + this->displayAdapter->print("AC_FAN_MODE_LOW.pic="); + this->displayAdapter->println(fan_speed == 3 ? COMPONENT_AC_FAN_MODE_LOW_PIC_ACTIVE : COMPONENT_AC_FAN_MODE_LOW_PIC_INACTIVE); + this->sendStopBytes(); + this->displayAdapter->print("AC_TEMP.val="); + this->displayAdapter->println(temperature); + this->sendStopBytes(); +} diff --git a/src/cud_display.hpp b/src/cud_display.hpp index cc46116..c7a140c 100644 --- a/src/cud_display.hpp +++ b/src/cud_display.hpp @@ -1,11 +1,89 @@ #pragma once #include +#include +#include +#include +#include + +/* +Pin Mapping +0-3: Lights +4-6: Fans +7: Air Purifier +*/ + +// Touch Types +#define TOUCH_TYPE_PRESS 0 +#define TOUCH_TYPE_RELEASE 1 + +// Page IDs +#define PAGE_BOOT 0 +#define PAGE_DASHBOARD 1 + +// Dashboard Toggle Buttons +#define COMPONENT_LIGHT_TOGGLE_BUTTON 1 +#define COMPONENT_LIGHT_TOGGLE_PIC_ON 11 +#define COMPONENT_LIGHT_TOGGLE_PIC_OFF 12 +#define COMPONENT_FAN_TOGGLE_BUTTON 2 +#define COMPONENT_FAN_TOGGLE_PIC_ON 21 +#define COMPONENT_FAN_TOGGLE_PIC_OFF 22 +#define COMPONENT_AIR_PURIFIER_TOGGLE_BUTTON 3 +#define COMPONENT_AIR_PURIFIER_TOGGLE_PIC_ON 31 +#define COMPONENT_AIR_PURIFIER_TOGGLE_PIC_OFF 32 + +// Dashboard AC Controls +#define COMPONENT_AC_TEMP_UP_BUTTON 4 +#define COMPONENT_AC_TEMP_DOWN_BUTTON 5 +#define COMPONENT_AC_MODE_OFF_BUTTON 6 +#define COMPONENT_AC_MODE_OFF_PIC_ACTIVE 61 +#define COMPONENT_AC_MODE_OFF_PIC_INACTIVE 62 +#define COMPONENT_AC_MODE_FAN_ONLY_BUTTON 7 +#define COMPONENT_AC_MODE_FAN_ONLY_PIC_ACTIVE 71 +#define COMPONENT_AC_MODE_FAN_ONLY_PIC_INACTIVE 72 +#define COMPONENT_AC_MODE_COOL_BUTTON 8 +#define COMPONENT_AC_MODE_COOL_PIC_ACTIVE 81 +#define COMPONENT_AC_MODE_COOL_PIC_INACTIVE 82 +#define COMPONENT_AC_FAN_MODE_AUTO_BUTTON 9 +#define COMPONENT_AC_FAN_MODE_AUTO_PIC_ACTIVE 91 +#define COMPONENT_AC_FAN_MODE_AUTO_PIC_INACTIVE 92 +#define COMPONENT_AC_FAN_MODE_LOW_BUTTON 10 +#define COMPONENT_AC_FAN_MODE_LOW_PIC_ACTIVE 101 +#define COMPONENT_AC_FAN_MODE_LOW_PIC_INACTIVE 102 +#define COMPONENT_AC_FAN_MODE_MEDIUM_BUTTON 11 +#define COMPONENT_AC_FAN_MODE_MEDIUM_PIC_ACTIVE 111 +#define COMPONENT_AC_FAN_MODE_MEDIUM_PIC_INACTIVE 112 +#define COMPONENT_AC_FAN_MODE_HIGH_BUTTON 12 +#define COMPONENT_AC_FAN_MODE_HIGH_PIC_ACTIVE 121 +#define COMPONENT_AC_FAN_MODE_HIGH_PIC_INACTIVE 122 + +/** + * @brief A class for controlling the ESPMegaDisplay. + * + * Made for Chulalongkorn University Demonstration Seconary School. + */ class CUDDisplay : public ESPMegaDisplay { public: CUDDisplay(); - void begin(); + void begin(std::function getTime, HardwareSerial* serial, DigitalInputCard* inputCard, DigitalOutputCard* outputCard, ClimateCard* climateCard); void handleTouch(uint8_t page, uint8_t component, uint8_t event); void handlePWMChange(uint8_t pin, uint8_t value); void handleACChange(uint8_t mode, uint8_t fan_speed, uint8_t temperature); void sendClock(); + private: + std::function getTime; + DigitalInputCard* inputCard; + DigitalOutputCard* outputCard; + uint8_t outputCallbackHandle; + ClimateCard* climateCard; + uint8_t climateCallbackHandle; + bool calculateLightGroupState(); + bool calculateFanGroupState(); + void setLightGrouptState(bool state); + void setFanGroupState(bool state); + void toggleLightGroupState(); + void toggleFanGroupState(); + void updateLightGroupState(); + void updateFanGroupState(); + void updateAirPurifierState(); + void updateACState(); }; \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp index 6eb0292..019bff5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,9 +1,21 @@ #include #include -ESPMegaPRO espmega = ESPMegaPRO(); -CUDDisplay external_display = CUDDisplay(); +/*********************************************** +* Begin Configuration * +************************************************/ +// Display Configuration +#define cudDisplayAdapter Serial2 +#define CUD_DISPLAY_BAUD_RATE 115200 +#define CUD_DISPLAY_TX_PIN 16 +#define CUD_DISPLAY_RX_PIN 17 + +//Air Conditioner Configuration +#define AIR_CONDITIONER_SENSOR_TYPE AC_SENSOR_TYPE_DHT22 +#define AIR_CONDITIONER_SENSOR_PIN 4 +#define AIR_CONDITIONER_IR_PIN 5 +#define AIR_CONDITIONER_RMT_CHANNEL RMT_CHANNEL_0 const char *mode_names[] = {"off", "fan_only", "cool"}; const char *fan_speed_names[] = {"auto", "high", "medium", "low"}; @@ -18,6 +30,17 @@ AirConditioner ac = { .getInfraredCode = &getInfraredCode }; +/*********************************************** + * End Configuration * + ***********************************************/ + +ESPMegaPRO espmega = ESPMegaPRO(); +CUDDisplay cudDisplay = CUDDisplay(); + +ClimateCard climateCard = ClimateCard(AIR_CONDITIONER_IR_PIN, ac, + AIR_CONDITIONER_SENSOR_TYPE, AIR_CONDITIONER_SENSOR_PIN, + AIR_CONDITIONER_RMT_CHANNEL); + void setup() { espmega.begin(); espmega.enableIotModule(); @@ -30,6 +53,15 @@ void setup() { espmega.enableInternalDisplay(&Serial); espmega.enableWebServer(80); espmega.inputs.registerCallback(on_pin_change); + espmega.outputs.setAutoSaveToFRAM(true); + espmega.installCard(3, &climateCard); + climateCard.bindFRAM(&espmega.fram, 5000); + climateCard.loadStateFromFRAM(); + climateCard.setFRAMAutoSave(true); + espmega.iot->registerCard(3); + cudDisplayAdapter.begin(CUD_DISPLAY_BAUD_RATE, SERIAL_8N1, CUD_DISPLAY_RX_PIN, CUD_DISPLAY_TX_PIN); + auto bindedGetTime = std::bind(&ESPMegaPRO::getTime, &espmega); + cudDisplay.begin(bindedGetTime, &cudDisplayAdapter, &espmega.inputs, &espmega.outputs, &climateCard); } void loop() {