GroupStateStore.cpp 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120
  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. // Always force re-initialization of group 0 state
  11. if (id.groupId == 0 || state == NULL) {
  12. trackEviction();
  13. GroupState loadedState = GroupState::defaultState(id.deviceType);
  14. // For device types with groups, group 0 is a "virtual" group. All devices paired with the same ID will respond
  15. // to group 0. So it doesn't make sense to store group 0 state by itself.
  16. //
  17. // For devices that don't have groups, we made the unfortunate decision to represent state using the fake group
  18. // ID 0, so we can't always ignore group 0.
  19. const MiLightRemoteConfig* remoteConfig = MiLightRemoteConfig::fromType(id.deviceType);
  20. if (remoteConfig == NULL) {
  21. return NULL;
  22. }
  23. if (id.groupId != 0 || remoteConfig->numGroups == 0) {
  24. persistence.get(id, loadedState);
  25. }
  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. If id.groupId == 0, will iterate across all groups
  35. // and individually save each group (recursively)
  36. GroupState* GroupStateStore::set(const BulbId &id, const GroupState& state) {
  37. GroupState* storedState = get(id);
  38. *storedState = state;
  39. if (id.groupId == 0) {
  40. const MiLightRemoteConfig* remote = MiLightRemoteConfig::fromType(id.deviceType);
  41. BulbId individualBulb(id);
  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. individualBulb.groupId = i;
  48. GroupState* individualState = get(individualBulb);
  49. individualState->patch(state);
  50. }
  51. }
  52. return storedState;
  53. }
  54. GroupState* GroupStateStore::set(const uint16_t deviceId, const uint8_t groupId, const MiLightRemoteType deviceType, const GroupState& state) {
  55. BulbId bulbId(deviceId, groupId, deviceType);
  56. return set(bulbId, state);
  57. }
  58. void GroupStateStore::trackEviction() {
  59. if (cache.isFull()) {
  60. evictedIds.add(cache.getLru());
  61. }
  62. }
  63. bool GroupStateStore::flush() {
  64. ListNode<GroupCacheNode*>* curr = cache.getHead();
  65. bool anythingFlushed = false;
  66. while (curr != NULL && curr->data->state.isDirty() && !anythingFlushed) {
  67. persistence.set(curr->data->id, curr->data->state);
  68. curr->data->state.clearDirty();
  69. #ifdef STATE_DEBUG
  70. BulbId bulbId = curr->data->id;
  71. printf(
  72. "Flushing dirty state for 0x%04X / %d / %s\n",
  73. bulbId.deviceId,
  74. bulbId.groupId,
  75. MiLightRemoteConfig::fromType(bulbId.deviceType)->name.c_str()
  76. );
  77. #endif
  78. curr = curr->next;
  79. anythingFlushed = true;
  80. }
  81. while (evictedIds.size() > 0 && !anythingFlushed) {
  82. persistence.clear(evictedIds.shift());
  83. anythingFlushed = true;
  84. }
  85. return anythingFlushed;
  86. }
  87. void GroupStateStore::limitedFlush() {
  88. unsigned long now = millis();
  89. if ((lastFlush + flushRate) < now) {
  90. if (flush()) {
  91. lastFlush = now;
  92. }
  93. }
  94. }