rbed

Building services

An air conditioner's compressor power is measured every 10 s. Short cycling, starting again shortly after stopping, wears compressors out, so the Rules look for Runs that begin soon after the previous one and for many starts within an hour.

The live chart and its controls need JavaScript. The tables show the Events at the default parameters.

The site cannot run the default parameters: (JavaScript) TypeError: Cannot read properties of undefined (reading 'length')

import static io.github.romanhaendler.rbed.Conditions.*;

import io.github.romanhaendler.rbed.*;
import java.time.Duration;
import java.util.Map;

Channel power = Channel.named("power");

Rule run = Rule.named("Run")
    .when(power.above(500)).forDuration(Duration.ofSeconds(30))
    .endWhen(power.below(100)).forDuration(Duration.ofSeconds(30));
Rule quickRestart = Rule.named("QuickRestart")
    .when(after(run).within(Duration.ofMinutes(3)).and(power.above(500)))
    .forDuration(Duration.ofSeconds(30))
    .endWhen(power.below(100));
Rule frequentStarts = Rule.named("FrequentStarts")
    .when(count(run).within(Duration.ofHours(1)).above(2));
Detector detector = Detector.builder()
    .rules(run, quickRestart, frequentStarts)
    .listener(new EventListener() {
      @Override public void onEnded(Event e) {
        if (e.is(run) && shortCycle(e)) System.out.println("short cycle from " + e.start());
      }
    })
    .build();

for (int s = 0; s < 2_400; s += 10) {   // the power every 10 s
  boolean on = s >= 100 && s < 700 || s >= 800 && s < 920 || s >= 1_600 && s < 2_200;
  detector.push(s * 1_000L, Map.of(power, on ? 2_000.0 : 20.0));
}
detector.close();

// In the enclosing class:
// A plain method classifies the Ended Runs
static boolean shortCycle(Event run) {
  return run.end().getAsLong() - run.start() < Duration.ofMinutes(5).toMillis();
}

The Rules

  • Run: above 500 W for 30 s, over below 100 W for 30 s. A plain method, which the listener calls for each Ended Run, classifies a Run shorter than 5 minutes as a short cycle, shown as a note in the table.
  • QuickRestart: power above 500 W again for 30 s, within 3 minutes after the previous Run's end. It has no duration on its End Condition, so it is over at the first Sample below 100 W.
  • FrequentStarts: more than 2 Runs Confirmed within an hour.

At the defaults, the compressor runs from 100 s to 700 s, from 800 s to 920 s and from 1600 s to 2200 s, and each Run is Confirmed 30 s after its start, at 130, 830 and 1630 s. The second one starts 100 s after the first one's end, so it is a QuickRestart as well, and at 2 minutes it is a short cycle. QuickRestart Ends at once at the first Sample below 100 W (920 s). The Run has the same end, but it is over only once its End Condition has held for 30 s, at 950 s. With the third Run, three are Confirmed within an hour: FrequentStarts starts at 1630 s, and the window keeps all three until the data ends at 2390 s, so its end is Truncated.

Things to try

  • Lower Quick restart within to 2 minutes: the second Run begins 100 s after the first one's end, inside the window, but QuickRestart needs its 30 s above 500 W within it too. The window closes first, and the Pending QuickRestart is Discarded.

Reference

The example is HvacShortCyclingExample, a test with its expected Events, listed in the README's Examples.

Methods used: Channel.named, Rule.named, Rule.when, Expression.above, Rule.forDuration, Rule.endWhen, Expression.below, Conditions.after, After.within, Condition.and, Conditions.count, EventCount.within, Detector.builder, Detector.Builder.rules, Detector.Builder.listener, EventListener.onEnded, Event.is, Event.start, Detector.Builder.build, Detector.push, Detector.close, Event.end.

The concepts at work, each on a page of its own: After another Event, Counting Events, End Conditions and hysteresis.