diff --git a/include/main.h b/include/main.h new file mode 100644 index 0000000..8365cc2 --- /dev/null +++ b/include/main.h @@ -0,0 +1,33 @@ +#include + +void initPins(); + +void initWifi(); + +void initHA(); + +void onCoverLeftCommand(HACover::CoverCommand cmd); + +void onCoverRightCommand(HACover::CoverCommand cmd); + +void onCoverLeftSetPositionCommand(uint8_t pos); + +void onCoverRightSetPositionCommand(uint8_t pos); + +void processStateLeft(); + +void processStateRight(); + +void sendCoverLeftOpen(); + +void sendCoverLeftStop(); + +void sendCoverLeftClose(); + +void sendCoverRightOpen(); + +void sendCoverRightStop(); + +void sendCoverRightClose(); + +void sendRemoteCommand(); \ No newline at end of file diff --git a/src/main.cpp b/src/main.cpp new file mode 100644 index 0000000..e96b534 --- /dev/null +++ b/src/main.cpp @@ -0,0 +1,333 @@ +#include +#include +#include + +#define BROKER_ADDR IPAddress(192,168,1,46) +#define WIFI_SSID "Heimathafen" +#define WIFI_PASSWORD "43762579905371198122" +#define COVER_CLOSING_TIME_TOTAL_MILLIS 27500 +#define REMOTE_BUTTON_PRESS_LENGTH_MILLIS 1000 +#define REMOTE_BUTTON_PRESS_COOLDOWN_MILLIS 500 +#define MAX_REMOTE_COMMAND_QUEUE_LENGTH 20 +#define PIN_LEFT_OPEN D5 +#define PIN_LEFT_CLOSE D6 +#define PIN_RIGHT_OPEN D7 +#define PIN_RIGHT_CLOSE D8 + +byte mac[] = {0x00, 0x10, 0xFA, 0x6E, 0x38, 0x4A}; + +enum CoverState { + Stopped, + Opening, + Closing +}; + +enum RemoteCommands { + None, + LeftOpen, + LeftClose, + RightOpen, + RightClose +}; + +enum RemoteState { + Idle, + Busy, + Cooldown +}; + +int remoteCommandQueue[MAX_REMOTE_COMMAND_QUEUE_LENGTH] = { RemoteCommands::None }; +int remoteCommandQueueLength = 0; + +WiFiClient client; +HADevice device(mac, sizeof(mac)); +HAMqtt mqtt(client, device); +HACover coverLeft("rolladen-wohnzimmer-links", false, false); +HACover coverRight("rolladen-wohnzimmer-rechts", false, false); +String lastCommandLeft = ""; +String lastCommandRight = ""; +int currentPositionLeft = 0; +int currentPositionRight = 0; +int targetPositionLeft = 0; +int targetPositionRight = 0; +unsigned long startMovingLeftMillis = 0; +unsigned long startMovingRightMillis = 0; +CoverState currentStateLeft = CoverState::Stopped; +CoverState currentStateRight = CoverState::Stopped; +unsigned long startSendRemoteCommandMillis = 0; +int remoteState = RemoteState::Idle; + +void setup() { + Serial.begin(9600); + Serial.println("Starting..."); + initPins(); + initWifi(); + initHA(); +} + +void loop() { + mqtt.loop(); + processStateLeft(); + processStateRight(); + sendRemoteCommand(); +} + +void initPins() { + pinMode(PIN_LEFT_OPEN, OUTPUT); + pinMode(PIN_LEFT_CLOSE, OUTPUT); + pinMode(PIN_RIGHT_OPEN, OUTPUT); + pinMode(PIN_RIGHT_CLOSE, OUTPUT); + digitalWrite(PIN_LEFT_OPEN, LOW); + digitalWrite(PIN_LEFT_CLOSE, LOW); + digitalWrite(PIN_RIGHT_OPEN, LOW); + digitalWrite(PIN_RIGHT_CLOSE, LOW); +} + +void initWifi() { + // connect to wifi + WiFi.begin(WIFI_SSID, WIFI_PASSWORD); + while (WiFi.status() != WL_CONNECTED) { + Serial.print("."); + delay(500); // waiting for the connection + } + Serial.println(); + Serial.println("Connected to the network"); +} + +void initHA() { + coverLeft.onCommand(onCoverLeftCommand); + coverRight.onCommand(onCoverRightCommand); + coverLeft.onSetPositionCommand(onCoverLeftSetPositionCommand); + coverRight.onSetPositionCommand(onCoverRightSetPositionCommand); + + // set device's details (optional) + device.setName("NodeMCU_Rollladen_Wohnzimmer"); + device.setSoftwareVersion("1.0.0"); + + mqtt.begin(BROKER_ADDR); +} + +void onCoverLeftCommand(HACover::CoverCommand cmd) { + if (cmd == HACover::CommandOpen) { + Serial.println("Received Command: Open"); + if(targetPositionLeft != 100) { + sendCoverLeftStop(); + targetPositionLeft = 100; + } + } else if (cmd == HACover::CommandClose) { + Serial.println("Received Command: Close"); + if(targetPositionLeft != 0) { + sendCoverLeftStop(); + targetPositionLeft = 0; + } + } else if (cmd == HACover::CommandStop) { + Serial.println("Received Command: Stop"); + sendCoverLeftStop(); + } +} + +void onCoverRightCommand(HACover::CoverCommand cmd) { + if (cmd == HACover::CommandOpen) { + Serial.println("Received Command: Open"); + if(targetPositionRight != 100) { + sendCoverRightStop(); + targetPositionRight = 100; + } + } else if (cmd == HACover::CommandClose) { + Serial.println("Received Command: Close"); + if(targetPositionRight != 0) { + sendCoverRightStop(); + targetPositionRight = 0; + } + } else if (cmd == HACover::CommandStop) { + Serial.println("Received Command: Stop"); + sendCoverRightStop(); + } +} + +void onCoverLeftSetPositionCommand(uint8_t pos) { + Serial.println("Received Set Position Command: " + String(pos)); + sendCoverLeftStop(); + targetPositionLeft = pos; +} + +void onCoverRightSetPositionCommand(uint8_t pos) { + Serial.println("Received Set Position Command: " + String(pos)); + sendCoverRightStop(); + targetPositionRight = pos; +} + +void processStateLeft() { + if(currentStateLeft == CoverState::Stopped) { + if(targetPositionLeft < currentPositionLeft) { + sendCoverLeftClose(); + } + if(targetPositionLeft > currentPositionLeft) { + sendCoverLeftOpen(); + } + } + if(currentStateLeft == CoverState::Closing || currentStateLeft == CoverState::Opening) { + unsigned long targetMovementTime = abs(currentPositionLeft - targetPositionLeft) * COVER_CLOSING_TIME_TOTAL_MILLIS / 100; + unsigned long currentMovementTime = millis() - startMovingLeftMillis; + if(currentMovementTime > targetMovementTime) { + sendCoverLeftStop(); + } + } +} + +void processStateRight() { + if(currentStateRight == CoverState::Stopped) { + if(targetPositionRight < currentPositionRight) { + sendCoverRightClose(); + } + if(targetPositionRight > currentPositionRight) { + sendCoverRightOpen(); + } + } + if(currentStateRight == CoverState::Closing || currentStateRight == CoverState::Opening) { + unsigned long targetMovementTime = abs(currentPositionRight - targetPositionRight) * COVER_CLOSING_TIME_TOTAL_MILLIS / 100; + unsigned long currentMovementTime = millis() - startMovingRightMillis; + if(currentMovementTime > targetMovementTime) { + sendCoverRightStop(); + } + } +} + +void sendCoverLeftOpen() { + coverLeft.setState(HACover::StateOpening); + Serial.println("Send Cover Left: OPEN."); + remoteCommandQueue[remoteCommandQueueLength] = RemoteCommands::LeftOpen; + remoteCommandQueueLength++; + currentStateLeft = CoverState::Opening; + startMovingLeftMillis = millis(); +} + +void sendCoverLeftStop() { + int movementDiff = (millis() - startMovingLeftMillis) * 100 / COVER_CLOSING_TIME_TOTAL_MILLIS; + if(currentStateLeft == CoverState::Opening) { + Serial.println("Send Cover Left: CLOSE TO STOP."); + remoteCommandQueue[remoteCommandQueueLength] = RemoteCommands::LeftClose; + remoteCommandQueueLength++; + currentPositionLeft = currentPositionLeft + movementDiff; + } + if(currentStateLeft == CoverState::Closing) { + Serial.println("Send Cover Left: OPEN TO STOP."); + remoteCommandQueue[remoteCommandQueueLength] = RemoteCommands::LeftOpen; + remoteCommandQueueLength++; + currentPositionLeft = currentPositionLeft - movementDiff; + } + + currentStateLeft = CoverState::Stopped; + targetPositionLeft = currentPositionLeft; + + coverLeft.setState(HACover::StateStopped); + coverLeft.setPosition(currentPositionLeft); + // Serial.println("Current Position: " + String(currentPositionLeft)); +} + +void sendCoverLeftClose() { + coverLeft.setState(HACover::StateClosing); + Serial.println("Send Cover Left: CLOSE."); + remoteCommandQueue[remoteCommandQueueLength] = RemoteCommands::LeftClose; + remoteCommandQueueLength++; + currentStateLeft = CoverState::Closing; + startMovingLeftMillis = millis(); +} + +void sendCoverRightOpen() { + coverRight.setState(HACover::StateOpening); + Serial.println("Send Cover Right: OPEN."); + remoteCommandQueue[remoteCommandQueueLength] = RemoteCommands::RightOpen; + remoteCommandQueueLength++; + currentStateRight = CoverState::Opening; + startMovingRightMillis = millis(); +} + +void sendCoverRightStop() { + int movementDiff = (millis() - startMovingRightMillis) * 100 / COVER_CLOSING_TIME_TOTAL_MILLIS; + if(currentStateRight == CoverState::Opening) { + Serial.println("Send Cover Right: CLOSE TO STOP."); + remoteCommandQueue[remoteCommandQueueLength] = RemoteCommands::RightClose; + remoteCommandQueueLength++; + currentPositionRight = currentPositionRight + movementDiff; + } + if(currentStateRight == CoverState::Closing) { + Serial.println("Send Cover Right: OPEN TO STOP."); + remoteCommandQueue[remoteCommandQueueLength] = RemoteCommands::RightOpen; + remoteCommandQueueLength++; + currentPositionRight = currentPositionRight - movementDiff; + } + + currentStateRight = CoverState::Stopped; + targetPositionRight = currentPositionRight; + + coverRight.setState(HACover::StateStopped); + coverRight.setPosition(currentPositionRight); + // Serial.println("Current Position: " + String(currentPositionRight)); +} + +void sendCoverRightClose() { + coverRight.setState(HACover::StateClosing); + Serial.println("Send Cover Right: CLOSE."); + remoteCommandQueue[remoteCommandQueueLength] = RemoteCommands::RightClose; + remoteCommandQueueLength++; + currentStateRight = CoverState::Closing; + startMovingRightMillis = millis(); +} + +void sendRemoteCommand() { + // Stop sending remote command + if(remoteState == RemoteState::Busy && millis() - REMOTE_BUTTON_PRESS_LENGTH_MILLIS > startSendRemoteCommandMillis) { + Serial.println("RemoteState::Cooldown"); + remoteState = RemoteState::Cooldown; + digitalWrite(PIN_LEFT_OPEN, LOW); + digitalWrite(PIN_LEFT_CLOSE, LOW); + digitalWrite(PIN_RIGHT_OPEN, LOW); + digitalWrite(PIN_RIGHT_CLOSE, LOW); + } + + // Wait Cooldown before sending next button press + if(remoteState == RemoteState::Cooldown && millis() - REMOTE_BUTTON_PRESS_LENGTH_MILLIS - REMOTE_BUTTON_PRESS_COOLDOWN_MILLIS > startSendRemoteCommandMillis) { + Serial.println("RemoteState::Idle"); + remoteState = RemoteState::Idle; + } + + // Send next command + if (remoteState == RemoteState::Idle && remoteCommandQueueLength > 0) { + // Serial.println("remoteCommandQueueLength: " + String(remoteCommandQueueLength)); + int nextCommand = remoteCommandQueue[0]; + remoteCommandQueueLength--; + + // Move all commands in Queue; + for(int i = 0; i < MAX_REMOTE_COMMAND_QUEUE_LENGTH - 1; i++) { + remoteCommandQueue[i] = remoteCommandQueue[i+1]; + } + + switch (nextCommand) + { + case RemoteCommands::LeftOpen: + Serial.println("Remote: Press Button Left Open"); + digitalWrite(PIN_LEFT_OPEN, HIGH); + break; + case RemoteCommands::LeftClose: + Serial.println("Remote: Press Button Left Close"); + digitalWrite(PIN_LEFT_CLOSE, HIGH); + break; + case RemoteCommands::RightOpen: + Serial.println("Remote: Press Button Right Open"); + digitalWrite(PIN_RIGHT_OPEN, HIGH); + break; + case RemoteCommands::RightClose: + Serial.println("Remote: Press Button Right Close"); + digitalWrite(PIN_RIGHT_CLOSE, HIGH); + break; + + default: + break; + } + + Serial.println("RemoteState::Busy"); + remoteState = RemoteState::Busy; + startSendRemoteCommandMillis = millis(); + } +} \ No newline at end of file