Improve logic for fetching position while blind is moving or stopped

This commit is contained in:
2024-01-04 20:07:06 +11:00
parent dbed260fd1
commit 3c190897ee

View File

@@ -39,15 +39,20 @@ bool sendSetPosition(uint16_t destination, float percentage);
bool sendFetchPosition(uint16_t destination); bool sendFetchPosition(uint16_t destination);
bool sendPacket(Packet *packet); bool sendPacket(Packet *packet);
bool updatePosition(uint16_t shadeID); bool checkPosition(uint16_t shadeID);
void startFetchingPosition(uint16_t shadeID, int8_t targetPosition);
void publishPosition(const String& shadeName, const uint8_t position);
void publishState(const String& shadeName, const String& state);
struct Shade { struct Shade {
uint16_t ID; uint16_t ID;
String name; String name;
uint8_t lastTargetPosition; int8_t lastTargetPosition;
uint8_t lastPosition; int8_t lastPosition;
uint8_t lastPositionCount; uint8_t samePositionCount;
uint8_t positionFetchCount; uint8_t positionFetchCount;
void* timer;
}; };
std::vector<Shade> shades; std::vector<Shade> shades;
@@ -57,21 +62,21 @@ void setup() {
Serial.println("Starting up"); Serial.println("Starting up");
shades.push_back(Shade{0x4EF1, "study_blind"}); shades.push_back(Shade{0x4EF1, "study_blind", -1, -1, 0, 0, nullptr});
shades.push_back(Shade{0xA51F, "studio_blockout_left_blind"}); shades.push_back(Shade{0xA51F, "studio_blockout_left_blind", -1, -1, 0, 0, nullptr});
shades.push_back(Shade{0xDAEF, "studio_blockout_right_blind"}); shades.push_back(Shade{0xDAEF, "studio_blockout_right_blind", -1, -1, 0, 0, nullptr});
shades.push_back(Shade{0x7687, "studio_left_blind"}); shades.push_back(Shade{0x7687, "studio_left_blind", -1, -1, 0, 0, nullptr});
shades.push_back(Shade{0xB0DE, "studio_right_blind"}); shades.push_back(Shade{0xB0DE, "studio_right_blind", -1, -1, 0, 0, nullptr});
shades.push_back(Shade{0xB451, "bedroom_door_blockout_blind"}); shades.push_back(Shade{0xB451, "bedroom_door_blockout_blind", -1, -1, 0, 0, nullptr});
shades.push_back(Shade{0x48A6, "bedroom_window_blockout_blind"}); shades.push_back(Shade{0x48A6, "bedroom_window_blockout_blind", -1, -1, 0, 0, nullptr});
shades.push_back(Shade{0x9E14, "bedroom_door_blind"}); shades.push_back(Shade{0x9E14, "bedroom_door_blind", -1, -1, 0, 0, nullptr});
shades.push_back(Shade{0x061C, "bedroom_window_blind"}); shades.push_back(Shade{0x061C, "bedroom_window_blind", -1, -1, 0, 0, nullptr});
shades.push_back(Shade{0x2959, "bathroom_blind"}); shades.push_back(Shade{0x2959, "bathroom_blind", -1, -1, 0, 0, nullptr});
shades.push_back(Shade{0x6FAD, "kitchen_door_blind"}); shades.push_back(Shade{0x6FAD, "kitchen_door_blind", -1, -1, 0, 0, nullptr});
shades.push_back(Shade{0xFB21, "kitchen_window_blind"}); shades.push_back(Shade{0xFB21, "kitchen_window_blind", -1, -1, 0, 0, nullptr});
shades.push_back(Shade{0x8B10, "living_room_big_window_blind"}); shades.push_back(Shade{0x8B10, "living_room_big_window_blind", -1, -1, 0, 0, nullptr});
shades.push_back(Shade{0x3EB8, "living_room_door_blind"}); shades.push_back(Shade{0x3EB8, "living_room_door_blind", -1, -1, 0, 0, nullptr});
shades.push_back(Shade{0x5463, "living_room_window_blind"}); shades.push_back(Shade{0x5463, "living_room_window_blind", -1, -1, 0, 0, nullptr});
powerView.setPacketCallback(processPacket); powerView.setPacketCallback(processPacket);
if (!powerView.begin()) { if (!powerView.begin()) {
@@ -109,14 +114,15 @@ void processPacket(const Packet *packet) {
if (packet->source == shades[i].ID) { if (packet->source == shades[i].ID) {
uint16_t value = std::get<uint16_t>(field.value); uint16_t value = std::get<uint16_t>(field.value);
uint8_t position = (uint8_t)std::round(((float)value / 0xFFFF) * 100); uint8_t position = (uint8_t)std::round(((float)value / 0xFFFF) * 100);
if (shades[i].lastPosition == position) { if (shades[i].lastPosition == position) {
shades[i].lastPositionCount++; shades[i].samePositionCount++;
} else { } else {
shades[i].lastPositionCount = 0; shades[i].samePositionCount = 1;
} }
shades[i].lastPosition = position; shades[i].lastPosition = position;
String payload = String(position);
client.publish("hotdog/" + shades[i].name + "/position", payload, true); publishPosition(shades[i].name, position);
} }
} }
} }
@@ -212,46 +218,6 @@ bool sendPacket(Packet *packet) {
} }
} }
bool updatePosition(uint16_t shadeID) {
for (size_t i = 0; i < shades.size(); i++) {
if (shades[i].ID == shadeID) {
if (shades[i].lastTargetPosition != shades[i].lastPosition || shades[i].lastPosition == -1) {
if (shades[i].positionFetchCount >= MAX_FETCH_COUNT) {
// Give up waiting for the blind to reach the target position
if (shades[i].lastPosition > 0) {
client.publish("hotdog/" + shades[i].name + "/state", "open", true);
} else {
client.publish("hotdog/" + shades[i].name + "/state", "closed", true);
}
return false;
}
if (shades[i].lastPositionCount >= 2) {
// Blind hasn't moved after 3 fetches, so give up waiting
if (shades[i].lastPosition > 0) {
client.publish("hotdog/" + shades[i].name + "/state", "open", true);
} else {
client.publish("hotdog/" + shades[i].name + "/state", "closed", true);
}
return false;
}
shades[i].positionFetchCount++;
sendFetchPosition(shadeID);
return true;
} else {
if (shades[i].lastPosition > 0) {
client.publish("hotdog/" + shades[i].name + "/state", "open", true);
} else {
client.publish("hotdog/" + shades[i].name + "/state", "closed", true);
}
return false;
}
}
}
return false;
}
void processSetMessage(const String &topic, const String &payload) { void processSetMessage(const String &topic, const String &payload) {
int startIndex = topic.indexOf("/") + 1; int startIndex = topic.indexOf("/") + 1;
int endIndex = topic.indexOf("/", startIndex); int endIndex = topic.indexOf("/", startIndex);
@@ -262,31 +228,20 @@ void processSetMessage(const String &topic, const String &payload) {
if (payload == "OPEN") { if (payload == "OPEN") {
sendOpenPacket(shades[i].ID); sendOpenPacket(shades[i].ID);
shades[i].lastPosition = -1; startFetchingPosition(shades[i].ID, 100);
shades[i].lastTargetPosition = 100;
shades[i].positionFetchCount = 0;
shades[i].lastPositionCount = 0;
timer.every(2000, updatePosition, shades[i].ID);
client.publish("hotdog/" + shades[i].name + "/state", "opening", true); publishState(shades[i].name, "opening");
} else if (payload == "CLOSE") { } else if (payload == "CLOSE") {
sendClosePacket(shades[i].ID); sendClosePacket(shades[i].ID);
shades[i].lastPosition = -1; startFetchingPosition(shades[i].ID, 0);
shades[i].lastTargetPosition = 0;
shades[i].positionFetchCount = 0;
shades[i].lastPositionCount = 0;
timer.every(2000, updatePosition, shades[i].ID);
client.publish("hotdog/" + shades[i].name + "/state", "closing", true); publishState(shades[i].name, "closing");
} else if (payload == "STOP") { } else if (payload == "STOP") {
sendStopPacket(shades[i].ID); sendStopPacket(shades[i].ID);
shades[i].lastPosition = -1; startFetchingPosition(shades[i].ID, -1);
shades[i].lastTargetPosition = -1; timer.in(100, sendFetchPosition, shades[i].ID);
shades[i].positionFetchCount = 0;
shades[i].lastPositionCount = 0;
timer.every(2000, updatePosition, shades[i].ID);
} }
} }
} }
@@ -303,16 +258,61 @@ void processSetPositionMessage(const String& topic, const String &payload) {
sendSetPosition(shades[i].ID, percentage); sendSetPosition(shades[i].ID, percentage);
if (payload.toInt() > shades[i].lastPosition) { if (payload.toInt() > shades[i].lastPosition) {
client.publish("hotdog/" + shades[i].name + "/state", "opening", true); publishState(shades[i].name, "opening");
} else if (payload.toInt() < shades[i].lastPosition) { } else if (payload.toInt() < shades[i].lastPosition) {
client.publish("hotdog/" + shades[i].name + "/state", "closing", true); publishState(shades[i].name, "closing");
} }
shades[i].lastPosition = -1; startFetchingPosition(shades[i].ID, payload.toInt());
shades[i].lastTargetPosition = payload.toInt();
shades[i].positionFetchCount = 0;
shades[i].lastPositionCount = 0;
timer.every(2000, updatePosition, shades[i].ID);
} }
} }
} }
bool checkPosition(uint16_t shadeID) {
for (size_t i = 0; i < shades.size(); i++) {
if (shades[i].ID == shadeID) {
// Keep fetching position if:
// - the last reported position doesn't match the target position
// - a position hasn't been reported yet
// - there is no target position
if (shades[i].lastTargetPosition != shades[i].lastPosition || shades[i].lastPosition == -1 || shades[i].lastTargetPosition == -1) {
// Keep fetching position if the count limits have not been reached
if (shades[i].positionFetchCount < MAX_FETCH_COUNT && shades[i].samePositionCount < 2) {
shades[i].positionFetchCount++;
sendFetchPosition(shadeID);
return true;
}
}
publishState(shades[i].name, shades[i].lastPosition > 0 ? "open" : "closed");
return false;
}
}
return false;
}
void startFetchingPosition(uint16_t shadeID, int8_t targetPosition) {
for (size_t i = 0; i < shades.size(); i++) {
if (shades[i].ID == shadeID) {
// Cancel any existing timer
if (shades[i].timer != nullptr) {
timer.cancel(shades[i].timer);
shades[i].timer = nullptr;
}
shades[i].lastTargetPosition = targetPosition;
shades[i].positionFetchCount = 0;
shades[i].samePositionCount = 1;
shades[i].timer = timer.every(2000, checkPosition, shades[i].ID);
}
}
}
void publishState(const String& shadeName, const String& state) {
client.publish("hotdog/" + shadeName + "/state", state, true);
}
void publishPosition(const String& shadeName, const uint8_t position) {
client.publish("hotdog/" + shadeName + "/position", String(position), true);
}