Add Adjust topic and improve state handling

Add adjusting topic to allow for tweaking the open/close endpoints.
Improved the state handling/transitions so that it will only change
states when IDLE.
This commit is contained in:
Cameron
2021-09-20 21:57:10 -04:00
parent e2f186c399
commit 4a2d216279

View File

@@ -6,9 +6,16 @@ WiFiClient net;
MQTTClient client; MQTTClient client;
AccelStepper stepper(AccelStepper::HALF4WIRE, D0, D2, D1, D3); AccelStepper stepper(AccelStepper::HALF4WIRE, D0, D2, D1, D3);
// Config
const char ssid[] = ""; const char ssid[] = "";
const char pw[] = ""; const char wifi_pw[] = "";
const char mqtt_addr[] = "192.168.10.30"; const char mqtt_user[] = "";
const char mqtt_pw[] = "";
const char mqtt_addr[] = "";
const char client_name[] = "";
// End Config
unsigned long lastMillis = 0; unsigned long lastMillis = 0;
@@ -18,69 +25,103 @@ const int SLACK = 1;
const int OPENING_BLINDS = 2; const int OPENING_BLINDS = 2;
const int CLOSING_BLINDS = 3; const int CLOSING_BLINDS = 3;
const int IDLE = 4; const int IDLE = 4;
const int ADJUSTING = 5;
int state = SETUP; int state = SETUP;
int previousState = SETUP; int previousState = SETUP;
bool blindsOpen = false; bool blindsOpen = false;
long fullyOpenPosition = -14000;
long fullyClosedPosition = 0;
void connect() { void connect() {
Serial.print("checking wifi..."); Serial.println("checking wifi...");
while (WiFi.status() != WL_CONNECTED) { while (WiFi.status() != WL_CONNECTED) {
Serial.print("."); Serial.print(".");
delay(1000); delay(1000);
} }
Serial.print("\nconnecting..."); Serial.println("\nconnecting...");
while (!client.connect("bedroom-blinds-1", "cameron", pw)) { while (!client.connect(client_name, mqtt_user, mqtt_pw)) {
Serial.print("."); Serial.print(".");
delay(1000); delay(1000);
} }
Serial.println("\nconnected!"); Serial.println("\nconnected!");
client.subscribe("/blinds/bedroom/1"); client.subscribe("/bedroom/blinds/2");
client.subscribe("/bedroom/blinds/2/adjust");
} }
void messageReceived(String &topic, String &payload) { void messageReceived(String &topic, String &payload) {
Serial.println("incoming: " + topic + " - " + payload); Serial.println("incoming: " + topic + " - " + payload);
// Note: Do not use the client in the callback to publish, subscribe or if (topic.endsWith("adjust")) {
// unsubscribe as it may cause deadlocks when other things arrive while int adjustment;
// sending and receiving acknowledgments. Instead, change a global variable, sscanf(payload.c_str(), "%d", &adjustment);
// or push to a queue and handle it in the loop after calling `client.loop()`. adjustClosedPosition(adjustment);
if (payload.indexOf("open") != -1) {
openBlinds();
} else if (payload.indexOf("close") != -1) {
closeBlinds();
} else { } else {
Serial.println(payload); if (payload.indexOf("open") != -1) {
openBlinds();
} else if (payload.indexOf("close") != -1) {
closeBlinds();
} else if (payload.indexOf("reset") != -1) {
Serial.println("Resetting current position and setting blinds state to closed");
stepper.setCurrentPosition(0);
blindsOpen = false;
} else {
Serial.println(payload);
}
}
}
void updateState(int newState) {
previousState = state;
state = newState;
if(newState == IDLE) {
Serial.println("Transitioning to idle");
} else {
Serial.print("Moving ");
Serial.print(previousState);
Serial.print(" -> ");
Serial.println(newState);
} }
} }
void openBlinds() { void openBlinds() {
if (!blindsOpen) { if (!blindsOpen && state == IDLE) {
Serial.println("Opening Blinds"); Serial.println("Opening Blinds");
previousState = state; updateState(OPENING_BLINDS);
state = OPENING_BLINDS;
stepper.enableOutputs(); stepper.enableOutputs();
stepper.moveTo(-14000); stepper.moveTo(fullyOpenPosition);
} }
} }
void closeBlinds() { void closeBlinds() {
if (blindsOpen) { if (blindsOpen && state == IDLE) {
Serial.println("Closing Blinds"); Serial.println("Closing Blinds");
previousState = state; updateState(CLOSING_BLINDS);
state = CLOSING_BLINDS;
stepper.enableOutputs(); stepper.enableOutputs();
stepper.moveTo(0); stepper.moveTo(fullyClosedPosition);
} }
} }
void adjustClosedPosition(int offset) {
if(offset == 0 || state != IDLE) return;
Serial.print("Adjust by: ");
Serial.println(offset);
updateState(ADJUSTING);
stepper.enableOutputs();
stepper.move(offset);
}
void setup() { void setup() {
Serial.begin(115200); Serial.begin(115200);
WiFi.begin(ssid, pw); WiFi.begin(ssid, wifi_pw);
client.begin(mqtt_addr, 1883, net); client.begin(mqtt_addr, 1883, net);
client.onMessage(messageReceived); client.onMessage(messageReceived);
@@ -112,15 +153,14 @@ void loop() {
} else if (previousState == CLOSING_BLINDS) { } else if (previousState == CLOSING_BLINDS) {
stepper.move(-3000); stepper.move(-3000);
} else if (stepper.distanceToGo() == 0) { } else if (stepper.distanceToGo() == 0) {
state = IDLE; updateState(IDLE);
stepper.disableOutputs(); stepper.disableOutputs();
Serial.println("Transitioning to IDLE");
return; return;
} else {
stepper.run();
} }
// Update previous to SLACK until we take up the slack stepper.run();
// Update previous to SLACK until we take up the slack to prevent the stepper from moving forever
previousState = state; previousState = state;
break; break;
case OPENING_BLINDS: case OPENING_BLINDS:
@@ -139,19 +179,46 @@ void loop() {
bool open = state == OPENING_BLINDS; bool open = state == OPENING_BLINDS;
blindsOpen = open; blindsOpen = open;
sendBlindsUpdate(open); sendBlindsUpdate(open);
previousState = state; updateState(SLACK);
state = SLACK;
} }
break;
case ADJUSTING:
if (millis() - lastMillis > 1000) {
Serial.println("Adjusting...");
lastMillis = millis();
}
stepper.run();
if (stepper.distanceToGo() == 0) {
Serial.print("Finished adjusting to: ");
Serial.println(stepper.currentPosition());
updateState(IDLE);
stepper.disableOutputs();
if(blindsOpen) {
fullyOpenPosition = stepper.currentPosition();
Serial.print("New open position: ");
Serial.println(fullyOpenPosition);
} else {
fullyClosedPosition = stepper.currentPosition();
Serial.print("New closed position: ");
Serial.println(fullyClosedPosition);
}
}
break; break;
} }
} }
void setup_stepper() { void setup_stepper() {
previousState = state; updateState(IDLE);
state = IDLE;
stepper.setCurrentPosition(-3000); stepper.setCurrentPosition(-3000);
} }
void sendBlindsUpdate(bool isOpen) { void sendBlindsUpdate(bool isOpen) {
client.publish("/blinds/bedroom/1/status", isOpen ? "true" : "false", true); client.publish("/bedroom/blinds/2/status", isOpen ? "true" : "false", true);
} }