GroupStateStore.cpp 3.9 KB

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