|
9 | 9 | #define _SINRICDEVICE_H_ |
10 | 10 |
|
11 | 11 | #include "SinricProDeviceInterface.h" |
12 | | -#include <map> |
13 | | - |
14 | | -#define BUCKET_SIZE 20 |
15 | | -#define DROP_WAIT_TIME 30000 |
16 | | -#define DROP_ADD_FACTOR 100 |
| 12 | +#include "LeakyBucket.h" |
17 | 13 |
|
18 | | -struct leackyBucket_t { |
19 | | - int dropsInBucket=0; |
20 | | - unsigned long lastDrop; |
21 | | -}; |
| 14 | +#include <map> |
22 | 15 |
|
23 | 16 | class SinricProDevice : public SinricProDeviceInterface { |
24 | 17 | public: |
@@ -46,7 +39,7 @@ class SinricProDevice : public SinricProDeviceInterface { |
46 | 39 | private: |
47 | 40 | SinricProInterface* eventSender; |
48 | 41 | unsigned long eventWaitTime; |
49 | | - std::map<String, leackyBucket_t> eventFilter; |
| 42 | + std::map<String, LeakyBucket_t> eventFilter; |
50 | 43 | }; |
51 | 44 |
|
52 | 45 | SinricProDevice::SinricProDevice(const char* newDeviceId, unsigned long eventWaitTime) : |
@@ -90,52 +83,30 @@ DynamicJsonDocument SinricProDevice::prepareEvent(const char* deviceId, const ch |
90 | 83 | return DynamicJsonDocument(1024); |
91 | 84 | } |
92 | 85 |
|
| 86 | + |
93 | 87 | bool SinricProDevice::sendEvent(JsonDocument& event) { |
94 | | - unsigned long actualMillis = millis(); |
95 | 88 | String eventName = event["payload"]["action"] | ""; // get event name |
96 | 89 |
|
97 | | - leackyBucket_t bucket; |
| 90 | + LeakyBucket_t bucket; // leaky bucket algorithm is used to prevent flooding the server |
98 | 91 |
|
99 | | -// get Bucket for eventName |
100 | | - |
101 | | - if (eventFilter.find(eventName) == eventFilter.end()) { // if eventFilter is not initialized |
102 | | -// eventFilter[eventName] = -eventWaitTime; // initialize eventFilter |
103 | | - bucket.dropsInBucket = 0; |
104 | | - bucket.lastDrop = -eventWaitTime; |
105 | | - eventFilter[eventName] = bucket; |
106 | | - } else { // if eventFilter is initialized, get bucket |
107 | | - bucket = eventFilter[eventName]; |
108 | | - } |
109 | | - DEBUG_SINRIC("Bucket dropsInBucket: %d\r\n", bucket.dropsInBucket); |
110 | | -// leack bucket... |
111 | | - int drops_to_leak = (actualMillis - bucket.lastDrop) / DROP_WAIT_TIME; |
112 | | - DEBUG_SINRIC("Bucket leaking: %d\r\n", drops_to_leak); |
113 | | - if (drops_to_leak > 0) { |
114 | | - if (bucket.dropsInBucket <= drops_to_leak) { |
115 | | - bucket.dropsInBucket = 0; |
116 | | - } else { |
117 | | - bucket.dropsInBucket -= drops_to_leak; |
118 | | - } |
| 92 | + // get leaky bucket for event from eventFilter |
| 93 | + if (eventFilter.find(eventName) == eventFilter.end()) { // if there is no bucket ... |
| 94 | + eventFilter[eventName] = bucket; // ...add a new bucket |
| 95 | + } else { |
| 96 | + bucket = eventFilter[eventName]; // else get bucket |
119 | 97 | } |
120 | 98 |
|
121 | | -// unsigned long lastEventMillis = eventFilter[eventName] | 0; // get the last timestamp for event |
122 | | -// if (actualMillis - lastEventMillis < eventWaitTime) return false; // if last event was before waitTime return... |
123 | | -// if (actualMillis - bucket.lastDrop < eventWaitTime) return false; |
124 | | - if (bucket.dropsInBucket < BUCKET_SIZE && actualMillis-bucket.lastDrop > bucket.dropsInBucket * DROP_ADD_FACTOR) { // new drop can be placed into bucket? |
125 | | - Serial.printf("SinricProDevice::sendMessage(): %d event's left before limiting to 1 event per %d seconds. %lu ms until next event\r\n", BUCKET_SIZE-bucket.dropsInBucket-1, DROP_WAIT_TIME / 1000, ((bucket.dropsInBucket+1) * DROP_ADD_FACTOR)); |
126 | | - bucket.dropsInBucket++; // place drop in bucket |
127 | | - bucket.lastDrop = actualMillis; // store last drop time |
128 | | - eventFilter[eventName] = bucket; // save bucket back to map |
129 | | - if (eventSender) eventSender->sendMessage(event); // send event |
| 99 | + if (bucket.addDrop()) { // if we can add a new drop |
| 100 | + if (eventSender) eventSender->sendMessage(event); // send event |
| 101 | + eventFilter[eventName] = bucket; // update bucket on eventFilter |
130 | 102 | return true; |
131 | 103 | } |
132 | 104 |
|
133 | | - if (bucket.dropsInBucket >= BUCKET_SIZE) { |
134 | | - Serial.printf("- WARNING: EVENTS ARE BLOCKED FOR %lu SECONDS (%lu seconds left)\r", DROP_WAIT_TIME/1000, (DROP_WAIT_TIME-(actualMillis-bucket.lastDrop))/1000); |
135 | | - } |
| 105 | + eventFilter[eventName] = bucket; // update bucket on eventFilter |
136 | 106 | return false; |
137 | 107 | } |
138 | 108 |
|
| 109 | + |
139 | 110 | bool SinricProDevice::sendPowerStateEvent(bool state, String cause) { |
140 | 111 | DynamicJsonDocument eventMessage = prepareEvent(deviceId, "setPowerState", cause.c_str()); |
141 | 112 | JsonObject event_value = eventMessage["payload"]["value"]; |
|
0 commit comments