Kaynağa Gözat

Merge pull request #141 from sidoh/auto_throttle_repeats

Auto throttle repeats
Chris Mullins 8 yıl önce
ebeveyn
işleme
47f4f80607

Dosya farkı çok büyük olduğundan ihmal edildi
+ 2 - 2
dist/index.html.gz.h


+ 29 - 12
lib/MiLight/MiLightClient.cpp

@@ -4,13 +4,23 @@
 #include <RGBConverter.h>
 #include <Units.h>
 
-MiLightClient::MiLightClient(MiLightRadioFactory* radioFactory, GroupStateStore& stateStore)
-  : resendCount(MILIGHT_DEFAULT_RESEND_COUNT),
+MiLightClient::MiLightClient(
+  MiLightRadioFactory* radioFactory,
+  GroupStateStore& stateStore,
+  size_t throttleThreshold,
+  size_t throttleSensitivity,
+  size_t packetRepeatMinimum
+)
+  : baseResendCount(MILIGHT_DEFAULT_RESEND_COUNT),
     currentRadio(NULL),
     currentRemote(NULL),
     numRadios(MiLightRadioConfig::NUM_CONFIGS),
     packetSentHandler(NULL),
-    stateStore(stateStore)
+    stateStore(stateStore),
+    lastSend(0),
+    throttleThreshold(throttleThreshold),
+    throttleSensitivity(throttleSensitivity),
+    packetRepeatMinimum(packetRepeatMinimum)
 {
   radios = new MiLightRadio*[numRadios];
 
@@ -66,6 +76,7 @@ void MiLightClient::prepare(const MiLightRemoteConfig* config,
   const uint8_t groupId
 ) {
   switchRadio(config);
+
   this->currentRemote = config;
 
   if (deviceId >= 0 && groupId >= 0) {
@@ -81,7 +92,9 @@ void MiLightClient::prepare(const MiLightRemoteType type,
 }
 
 void MiLightClient::setResendCount(const unsigned int resendCount) {
-  this->resendCount = resendCount;
+  this->baseResendCount = resendCount;
+  this->currentResendCount = resendCount;
+  this->throttleMultiplier = ceil((throttleSensitivity / 1000.0) * this->baseResendCount);
 }
 
 bool MiLightClient::available() {
@@ -117,7 +130,7 @@ void MiLightClient::write(uint8_t packet[]) {
   int iStart = millis();
 #endif
 
-  for (int i = 0; i < this->resendCount; i++) {
+  for (int i = 0; i < this->currentResendCount; i++) {
     currentRadio->write(packet, currentRemote->packetFormatter->getPacketLength());
   }
 
@@ -377,14 +390,19 @@ uint8_t MiLightClient::parseStatus(const JsonObject& object) {
   return (strStatus.equalsIgnoreCase("on") || strStatus.equalsIgnoreCase("true")) ? ON : OFF;
 }
 
+void MiLightClient::updateResendCount() {
+  unsigned long now = millis();
+  long millisSinceLastSend = now - lastSend;
+  long x = (millisSinceLastSend - throttleThreshold);
+  long delta = x * throttleMultiplier;
+
+  this->currentResendCount = constrain(this->currentResendCount + delta, packetRepeatMinimum, this->baseResendCount);
+  this->lastSend = now;
+}
+
 void MiLightClient::flushPacket() {
   PacketStream& stream = currentRemote->packetFormatter->buildPackets();
-  const size_t prevNumRepeats = this->resendCount;
-
-  // When sending multiple packets, normalize the number of repeats
-  if (stream.numPackets > 1) {
-    setResendCount(MILIGHT_DEFAULT_RESEND_COUNT);
-  }
+  updateResendCount();
 
   while (stream.hasNext()) {
     write(stream.next());
@@ -394,7 +412,6 @@ void MiLightClient::flushPacket() {
     }
   }
 
-  setResendCount(prevNumRepeats);
   currentRemote->packetFormatter->reset();
 }
 

+ 34 - 2
lib/MiLight/MiLightClient.h

@@ -17,7 +17,13 @@
 
 class MiLightClient {
 public:
-  MiLightClient(MiLightRadioFactory* radioFactory, GroupStateStore& stateStore);
+  MiLightClient(
+    MiLightRadioFactory* radioFactory,
+    GroupStateStore& stateStore,
+    size_t throttleThreshold,
+    size_t throttleSensitivity,
+    size_t packetRepeatMinimum
+  );
 
   ~MiLightClient() {
     delete[] radios;
@@ -80,10 +86,36 @@ protected:
   MiLightRadio* currentRadio;
   const MiLightRemoteConfig* currentRemote;
   const size_t numRadios;
-  unsigned int resendCount;
   PacketSentHandler packetSentHandler;
   GroupStateStore& stateStore;
 
+  // Used to track auto repeat limiting
+  unsigned long lastSend;
+  int currentResendCount;
+  unsigned int baseResendCount;
+  int packetRepeatMinimum;
+  size_t throttleThreshold;
+  size_t throttleSensitivity;
+
+  // This will be pre-computed, but is simply:
+  //
+  //    (sensitivity / 1000.0) * R
+  //
+  // Where R is the base number of repeats.
+  size_t throttleMultiplier;
+
+  /*
+   * Calculates the number of resend packets based on when the last packet
+   * was sent using this function:
+   *
+   *    lastRepeatsValue + (millisSinceLastSend - THRESHOLD) * throttleMultiplier
+   *
+   * When the last send was more recent than THRESHOLD, the number of repeats
+   * will be decreased to a minimum of zero.  When less recent, it will be
+   * increased up to a maximum of the default resend count.
+   */
+  void updateResendCount();
+
   MiLightRadio* switchRadio(const MiLightRemoteConfig* remoteConfig);
   uint8_t parseStatus(const JsonObject& object);
 

+ 6 - 0
lib/Settings/Settings.cpp

@@ -82,6 +82,9 @@ void Settings::patch(JsonObject& parsedSettings) {
     this->setIfPresent(parsedSettings, "listen_repeats", listenRepeats);
     this->setIfPresent(parsedSettings, "state_flush_interval", stateFlushInterval);
     this->setIfPresent(parsedSettings, "mqtt_state_rate_limit", mqttStateRateLimit);
+    this->setIfPresent(parsedSettings, "packet_repeat_throttle_threshold", packetRepeatThrottleThreshold);
+    this->setIfPresent(parsedSettings, "packet_repeat_throttle_sensitivity", packetRepeatThrottleSensitivity);
+    this->setIfPresent(parsedSettings, "packet_repeat_minimum", packetRepeatMinimum);
 
     if (parsedSettings.containsKey("radio_interface_type")) {
       this->radioInterfaceType = Settings::typeFromString(parsedSettings["radio_interface_type"]);
@@ -151,6 +154,9 @@ void Settings::serialize(Stream& stream, const bool prettyPrint) {
   root["listen_repeats"] = this->listenRepeats;
   root["state_flush_interval"] = this->stateFlushInterval;
   root["mqtt_state_rate_limit"] = this->mqttStateRateLimit;
+  root["packet_repeat_throttle_sensitivity"] = this->packetRepeatThrottleSensitivity;
+  root["packet_repeat_throttle_threshold"] = this->packetRepeatThrottleThreshold;
+  root["packet_repeat_minimum"] = this->packetRepeatMinimum;
 
   if (this->deviceIds) {
     JsonArray& arr = jsonBuffer.createArray();

+ 7 - 1
lib/Settings/Settings.h

@@ -74,7 +74,10 @@ public:
     _autoRestartPeriod(0),
     discoveryPort(48899),
     stateFlushInterval(1000),
-    mqttStateRateLimit(500)
+    mqttStateRateLimit(500),
+    packetRepeatThrottleThreshold(200),
+    packetRepeatThrottleSensitivity(0),
+    packetRepeatMinimum(3)
   { }
 
   ~Settings() {
@@ -124,6 +127,9 @@ public:
   uint8_t listenRepeats;
   size_t stateFlushInterval;
   size_t mqttStateRateLimit;
+  size_t packetRepeatThrottleSensitivity;
+  size_t packetRepeatThrottleThreshold;
+  size_t packetRepeatMinimum;
 
 protected:
   size_t _autoRestartPeriod;

+ 7 - 1
src/main.cpp

@@ -169,7 +169,13 @@ void applySettings() {
 
   stateStore = new GroupStateStore(MILIGHT_MAX_STATE_ITEMS, settings.stateFlushInterval);
 
-  milightClient = new MiLightClient(radioFactory, *stateStore);
+  milightClient = new MiLightClient(
+    radioFactory,
+    *stateStore,
+    settings.packetRepeatThrottleThreshold,
+    settings.packetRepeatThrottleSensitivity,
+    settings.packetRepeatMinimum
+  );
   milightClient->begin();
   milightClient->onPacketSent(onPacketSentHandler);
   milightClient->setResendCount(settings.packetRepeats);

+ 12 - 2
web/src/js/script.js

@@ -9,7 +9,8 @@ var FORM_SETTINGS = [
   "http_repeat_factor", "auto_restart_period", "discovery_port", "mqtt_server",
   "mqtt_topic_pattern", "mqtt_update_topic_pattern", "mqtt_state_topic_pattern",
   "mqtt_username", "mqtt_password", "radio_interface_type", "listen_repeats",
-  "state_flush_interval", "mqtt_state_rate_limit"
+  "state_flush_interval", "mqtt_state_rate_limit", "packet_repeat_throttle_threshold",
+  "packet_repeat_throttle_sensitivity", "packet_repeat_minimum"
 ];
 
 var FORM_SETTINGS_HELP = {
@@ -39,7 +40,16 @@ var FORM_SETTINGS_HELP = {
   state_flush_interval : "Minimum number of milliseconds between flushing state to flash. " +
     "Set to 0 to disable delay and immediately persist state to flash.",
   mqtt_state_rate_limit : "Minimum number of milliseconds between MQTT updates of bulb state. " +
-    "Defaults to 500."
+    "Defaults to 500.",
+  packet_repeat_throttle_threshold : "Controls how packet repeats are throttled.  Packets sent " +
+    "with less time between them than this value (in milliseconds) will cause " +
+    "packet repeats to be throttled down.  More than this value will unthrottle " +
+    "up.  Defaults to 200ms",
+  packet_repeat_throttle_sensitivity : "Controls how packet repeats are throttled. " +
+    "Higher values cause packets to be throttled up and down faster.  Set to 0 " +
+    "to disable throttling.  Defaults to 1.  Maximum value 1000.",
+  packet_repeat_minimum : "Controls how far throttling can decrease the number " +
+    "of repeated packets.  Defaults to 3."
 }
 
 var UDP_PROTOCOL_VERSIONS = [ 5, 6 ];