GroupStateStore.cpp 3.1 KB

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