GroupStateStore.cpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
  1. #include <GroupStateStore.h>
  2. #include <MiLightRemoteConfig.h>
  3. GroupStateStore::GroupStateStore(const size_t maxSize, const size_t flushRate)
  4. : cache(GroupStateCache(maxSize)),
  5. flushRate(flushRate),
  6. lastFlush(0)
  7. { }
  8. GroupState* GroupStateStore::get(const BulbId& id) {
  9. GroupState* state = cache.get(id);
  10. if (state == NULL) {
  11. #if STATE_DEBUG
  12. Serial.println(F("Couldn't fetch state from cache, getting it from persistence"));
  13. #endif
  14. trackEviction();
  15. GroupState loadedState = GroupState::defaultState(id.deviceType);
  16. const MiLightRemoteConfig* remoteConfig = MiLightRemoteConfig::fromType(id.deviceType);
  17. if (remoteConfig == NULL) {
  18. return NULL;
  19. }
  20. persistence.get(id, loadedState);
  21. state = cache.set(id, loadedState);
  22. }
  23. return state;
  24. }
  25. GroupState* GroupStateStore::get(const uint16_t deviceId, const uint8_t groupId, const MiLightRemoteType deviceType) {
  26. BulbId bulbId(deviceId, groupId, deviceType);
  27. return get(bulbId);
  28. }
  29. // Save state for a bulb.
  30. //
  31. // Notes:
  32. //
  33. // * For device types with groups, group 0 is a "virtual" group. All devices paired with the same ID will
  34. // respond to group 0. When state for an individual (i.e., != 0) group is changed, the state for
  35. // group 0 becomes out of sync and should be cleared.
  36. //
  37. // * If id.groupId == 0, will iterate across all groups and individually save each group (recursively)
  38. //
  39. GroupState* GroupStateStore::set(const BulbId &id, const GroupState& state) {
  40. BulbId otherId(id);
  41. GroupState* storedState = get(id);
  42. storedState->patch(state);
  43. if (id.groupId == 0) {
  44. const MiLightRemoteConfig* remote = MiLightRemoteConfig::fromType(id.deviceType);
  45. #ifdef STATE_DEBUG
  46. Serial.printf_P(PSTR("Fanning out group 0 state for device ID 0x%04X (%d groups in total)\n"), id.deviceId, remote->numGroups);
  47. state.debugState("group 0 state = ");
  48. #endif
  49. for (size_t i = 1; i <= remote->numGroups; i++) {
  50. otherId.groupId = i;
  51. GroupState* individualState = get(otherId);
  52. individualState->patch(state);
  53. }
  54. } else {
  55. otherId.groupId = 0;
  56. GroupState* group0State = get(otherId);
  57. group0State->clearNonMatchingFields(state);
  58. }
  59. return storedState;
  60. }
  61. GroupState* GroupStateStore::set(const uint16_t deviceId, const uint8_t groupId, const MiLightRemoteType deviceType, const GroupState& state) {
  62. BulbId bulbId(deviceId, groupId, deviceType);
  63. return set(bulbId, state);
  64. }
  65. void GroupStateStore::clear(const BulbId& bulbId) {
  66. GroupState* state = get(bulbId);
  67. if (state != NULL) {
  68. state->initFields();
  69. }
  70. }
  71. void GroupStateStore::trackEviction() {
  72. if (cache.isFull()) {
  73. evictedIds.add(cache.getLru());
  74. }
  75. }
  76. bool GroupStateStore::flush() {
  77. ListNode<GroupCacheNode*>* curr = cache.getHead();
  78. bool anythingFlushed = false;
  79. while (curr != NULL && curr->data->state.isDirty() && !anythingFlushed) {
  80. persistence.set(curr->data->id, curr->data->state);
  81. curr->data->state.clearDirty();
  82. #ifdef STATE_DEBUG
  83. BulbId bulbId = curr->data->id;
  84. printf(
  85. "Flushing dirty state for 0x%04X / %d / %s\n",
  86. bulbId.deviceId,
  87. bulbId.groupId,
  88. MiLightRemoteConfig::fromType(bulbId.deviceType)->name.c_str()
  89. );
  90. #endif
  91. curr = curr->next;
  92. anythingFlushed = true;
  93. }
  94. while (evictedIds.size() > 0 && !anythingFlushed) {
  95. persistence.clear(evictedIds.shift());
  96. anythingFlushed = true;
  97. }
  98. return anythingFlushed;
  99. }
  100. void GroupStateStore::limitedFlush() {
  101. unsigned long now = millis();
  102. if ((lastFlush + flushRate) < now) {
  103. if (flush()) {
  104. lastFlush = now;
  105. }
  106. }
  107. }