GroupStateStore.cpp 3.4 KB

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