|
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