24 changed files with 672 additions and 6 deletions
@ -0,0 +1,26 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2025 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.service.cf.ctx.state.aggregation.single; |
||||
|
|
||||
|
import lombok.Data; |
||||
|
|
||||
|
@Data |
||||
|
public class AggIntervalEntry { |
||||
|
|
||||
|
public Long startTs; |
||||
|
public Long endTs; |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,116 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2025 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.service.cf.ctx.state.aggregation.single; |
||||
|
|
||||
|
import com.fasterxml.jackson.databind.node.ObjectNode; |
||||
|
import com.google.common.util.concurrent.Futures; |
||||
|
import com.google.common.util.concurrent.ListenableFuture; |
||||
|
import lombok.Setter; |
||||
|
import org.thingsboard.common.util.JacksonUtil; |
||||
|
import org.thingsboard.server.actors.TbActorRef; |
||||
|
import org.thingsboard.server.common.data.cf.CalculatedFieldType; |
||||
|
import org.thingsboard.server.common.data.cf.configuration.Output; |
||||
|
import org.thingsboard.server.common.data.cf.configuration.aggregation.single.EntityAggregationCalculatedFieldConfiguration; |
||||
|
import org.thingsboard.server.common.data.id.EntityId; |
||||
|
import org.thingsboard.server.service.cf.CalculatedFieldProcessingService; |
||||
|
import org.thingsboard.server.service.cf.CalculatedFieldResult; |
||||
|
import org.thingsboard.server.service.cf.TelemetryCalculatedFieldResult; |
||||
|
import org.thingsboard.server.service.cf.ctx.state.ArgumentEntry; |
||||
|
import org.thingsboard.server.service.cf.ctx.state.BaseCalculatedFieldState; |
||||
|
import org.thingsboard.server.service.cf.ctx.state.CalculatedFieldCtx; |
||||
|
|
||||
|
import java.util.HashMap; |
||||
|
import java.util.Map; |
||||
|
|
||||
|
import static java.util.concurrent.TimeUnit.SECONDS; |
||||
|
|
||||
|
public class EntityAggregationCalculatedFieldState extends BaseCalculatedFieldState { |
||||
|
|
||||
|
private Map<AggIntervalEntry, Boolean> aggIntervals = new HashMap<>(); |
||||
|
|
||||
|
@Setter |
||||
|
private long lastArgsRefreshTs = -1; |
||||
|
@Setter |
||||
|
private long lastMetricsEvalTs = -1; |
||||
|
|
||||
|
private long deduplicationIntervalMs = -1; |
||||
|
|
||||
|
CalculatedFieldProcessingService cfProcessingService; |
||||
|
|
||||
|
public EntityAggregationCalculatedFieldState(EntityId entityId) { |
||||
|
super(entityId); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void setCtx(CalculatedFieldCtx ctx, TbActorRef actorCtx) { |
||||
|
super.setCtx(ctx, actorCtx); |
||||
|
this.cfProcessingService = ctx.getCfProcessingService(); |
||||
|
var configuration = (EntityAggregationCalculatedFieldConfiguration) ctx.getCalculatedField().getConfiguration(); |
||||
|
deduplicationIntervalMs = SECONDS.toMillis(configuration.getDeduplicationIntervalInSec()); |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public CalculatedFieldType getType() { |
||||
|
return CalculatedFieldType.ENTITY_AGGREGATION; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public ListenableFuture<CalculatedFieldResult> performCalculation(Map<String, ArgumentEntry> updatedArgs, CalculatedFieldCtx ctx) throws Exception { |
||||
|
long endTs = System.currentTimeMillis(); |
||||
|
long startTs = endTs - 1000; |
||||
|
AggIntervalEntry interval = new AggIntervalEntry(); |
||||
|
|
||||
|
Map<String, ArgumentEntry> metrics = cfProcessingService.fetchArgumentValuesDuringInterval(entityId, interval, ctx); |
||||
|
|
||||
|
Output output = ctx.getOutput(); |
||||
|
lastMetricsEvalTs = System.currentTimeMillis(); |
||||
|
ctx.scheduleReevaluation(deduplicationIntervalMs, actorCtx); |
||||
|
ObjectNode result = toResult(endTs, metrics); |
||||
|
if (result != null) { |
||||
|
return Futures.immediateFuture(TelemetryCalculatedFieldResult.builder() |
||||
|
.type(output.getType()) |
||||
|
.scope(output.getScope()) |
||||
|
.result(result) |
||||
|
.build()); |
||||
|
} |
||||
|
return Futures.immediateFuture(TelemetryCalculatedFieldResult.EMPTY); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
protected ObjectNode toResult(long endTs, Map<String, ArgumentEntry> metrics) { |
||||
|
ObjectNode metricsNode = JacksonUtil.newObjectNode(); |
||||
|
for (Map.Entry<String, ArgumentEntry> entry : metrics.entrySet()) { |
||||
|
String metricName = entry.getKey(); |
||||
|
ArgumentEntry argumentEntry = entry.getValue(); |
||||
|
if (!argumentEntry.isEmpty()) { |
||||
|
metricsNode.put(metricName, JacksonUtil.toString(argumentEntry.getValue())); |
||||
|
} |
||||
|
} |
||||
|
ObjectNode resultNode = JacksonUtil.newObjectNode(); |
||||
|
if (!metricsNode.isEmpty()) { |
||||
|
resultNode.put("ts", endTs); |
||||
|
resultNode.set("values", metricsNode); |
||||
|
} |
||||
|
return resultNode; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
@Override |
||||
|
public boolean isReady() { |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,59 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2025 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.common.data.cf.configuration.aggregation.single; |
||||
|
|
||||
|
import jakarta.validation.Valid; |
||||
|
import jakarta.validation.constraints.NotEmpty; |
||||
|
import lombok.Data; |
||||
|
import org.thingsboard.server.common.data.cf.CalculatedFieldType; |
||||
|
import org.thingsboard.server.common.data.cf.configuration.Argument; |
||||
|
import org.thingsboard.server.common.data.cf.configuration.ArgumentsBasedCalculatedFieldConfiguration; |
||||
|
import org.thingsboard.server.common.data.cf.configuration.Output; |
||||
|
import org.thingsboard.server.common.data.cf.configuration.aggregation.AggMetric; |
||||
|
import org.thingsboard.server.common.data.cf.configuration.aggregation.single.interval.AggInterval; |
||||
|
|
||||
|
import java.util.Map; |
||||
|
|
||||
|
@Data |
||||
|
public class EntityAggregationCalculatedFieldConfiguration implements ArgumentsBasedCalculatedFieldConfiguration { |
||||
|
|
||||
|
private Map<String, Argument> arguments; |
||||
|
@Valid |
||||
|
@NotEmpty |
||||
|
private Map<String, AggMetric> metrics; |
||||
|
|
||||
|
private AggInterval interval; |
||||
|
private long deduplicationIntervalInSec; |
||||
|
private long watermark; |
||||
|
|
||||
|
private Output output; |
||||
|
|
||||
|
@Override |
||||
|
public CalculatedFieldType getType() { |
||||
|
return CalculatedFieldType.ENTITY_AGGREGATION; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public void validate() { |
||||
|
if (arguments.containsKey("ctx")) { |
||||
|
throw new IllegalArgumentException("Argument name 'ctx' is reserved and cannot be used."); |
||||
|
} |
||||
|
if (arguments.values().stream().anyMatch(Argument::hasTsRollingArgument)) { |
||||
|
throw new IllegalArgumentException("Calculated field with type: '" + getType() + "' doesn't support TS_ROLLING arguments."); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,44 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2025 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.common.data.cf.configuration.aggregation.single.interval; |
||||
|
|
||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; |
||||
|
import com.fasterxml.jackson.annotation.JsonSubTypes; |
||||
|
import com.fasterxml.jackson.annotation.JsonTypeInfo; |
||||
|
|
||||
|
@JsonTypeInfo( |
||||
|
use = JsonTypeInfo.Id.NAME, |
||||
|
include = JsonTypeInfo.As.PROPERTY, |
||||
|
property = "type" |
||||
|
) |
||||
|
@JsonSubTypes({ |
||||
|
@JsonSubTypes.Type(value = HourInterval.class, name = "HOUR"), |
||||
|
@JsonSubTypes.Type(value = DayInterval.class, name = "DAY"), |
||||
|
@JsonSubTypes.Type(value = WeekInterval.class, name = "WEEK"), |
||||
|
@JsonSubTypes.Type(value = WeekSunSatInterval.class, name = "WEEK_SUN_SAT"), |
||||
|
@JsonSubTypes.Type(value = MonthInterval.class, name = "MONTH"), |
||||
|
@JsonSubTypes.Type(value = YearInterval.class, name = "YEAR"), |
||||
|
@JsonSubTypes.Type(value = CustomInterval.class, name = "CUSTOM"), |
||||
|
@JsonSubTypes.Type(value = SpecificTimeInterval.class, name = "SPECIFIC_TIME"), |
||||
|
}) |
||||
|
@JsonIgnoreProperties(ignoreUnknown = true) |
||||
|
public interface AggInterval { |
||||
|
|
||||
|
AggIntervalType getType(); |
||||
|
|
||||
|
long getDelayUntilIntervalEnd(); |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,29 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2025 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.common.data.cf.configuration.aggregation.single.interval; |
||||
|
|
||||
|
public enum AggIntervalType { |
||||
|
|
||||
|
HOUR, |
||||
|
DAY, |
||||
|
WEEK, |
||||
|
WEEK_SUN_SAT, |
||||
|
MONTH, |
||||
|
YEAR, |
||||
|
CUSTOM, |
||||
|
SPECIFIC_TIME |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,54 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2025 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.common.data.cf.configuration.aggregation.single.interval; |
||||
|
|
||||
|
import java.time.DayOfWeek; |
||||
|
import java.time.Duration; |
||||
|
import java.time.ZonedDateTime; |
||||
|
import java.time.temporal.ChronoUnit; |
||||
|
|
||||
|
public abstract class BaseAggInterval implements AggInterval { |
||||
|
|
||||
|
protected long offsetMillis; // delay millis since start of interval
|
||||
|
|
||||
|
@Override |
||||
|
public long getDelayUntilIntervalEnd() { |
||||
|
return getDelayUntilIntervalEnd(getType(), 1); |
||||
|
} |
||||
|
|
||||
|
protected long getDelayUntilIntervalEnd(AggIntervalType type, long multiplier) { |
||||
|
ZonedDateTime now = ZonedDateTime.now(); |
||||
|
ZonedDateTime next; |
||||
|
|
||||
|
switch (getType()) { |
||||
|
case HOUR -> next = now.plusHours(multiplier).truncatedTo(ChronoUnit.HOURS); |
||||
|
case DAY -> next = now.plusDays(multiplier).truncatedTo(ChronoUnit.DAYS); |
||||
|
case WEEK -> next = now.plusWeeks(multiplier).with(DayOfWeek.MONDAY).truncatedTo(ChronoUnit.DAYS); |
||||
|
case WEEK_SUN_SAT -> next = now.plusWeeks(multiplier).with(DayOfWeek.SUNDAY).truncatedTo(ChronoUnit.DAYS); |
||||
|
case MONTH -> next = now.plusMonths(multiplier).withDayOfMonth(1).truncatedTo(ChronoUnit.DAYS); |
||||
|
case YEAR -> next = now.plusYears(multiplier).withDayOfYear(1).truncatedTo(ChronoUnit.DAYS); |
||||
|
default -> throw new IllegalArgumentException("Unsupported type: " + getType()); |
||||
|
} |
||||
|
|
||||
|
long delayMillis = Duration.between(now, next).toMillis(); |
||||
|
if (offsetMillis > 0) { |
||||
|
delayMillis += offsetMillis; |
||||
|
} |
||||
|
|
||||
|
return Math.max(delayMillis, 0); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,33 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2025 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.common.data.cf.configuration.aggregation.single.interval; |
||||
|
|
||||
|
public class CustomInterval extends BaseAggInterval { |
||||
|
|
||||
|
private int multiplier; // number of base units (e.g. 2 hours, 5 days)
|
||||
|
private AggIntervalType internalIntervalType; |
||||
|
|
||||
|
@Override |
||||
|
public AggIntervalType getType() { |
||||
|
return AggIntervalType.CUSTOM; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public long getDelayUntilIntervalEnd() { |
||||
|
return super.getDelayUntilIntervalEnd(internalIntervalType, multiplier); |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2025 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.common.data.cf.configuration.aggregation.single.interval; |
||||
|
|
||||
|
public class DayInterval extends BaseAggInterval { |
||||
|
|
||||
|
@Override |
||||
|
public AggIntervalType getType() { |
||||
|
return AggIntervalType.DAY; |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2025 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.common.data.cf.configuration.aggregation.single.interval; |
||||
|
|
||||
|
public class HourInterval extends BaseAggInterval { |
||||
|
|
||||
|
@Override |
||||
|
public AggIntervalType getType() { |
||||
|
return AggIntervalType.HOUR; |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,26 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2025 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.common.data.cf.configuration.aggregation.single.interval; |
||||
|
|
||||
|
public class MonthInterval extends BaseAggInterval { |
||||
|
|
||||
|
@Override |
||||
|
public AggIntervalType getType() { |
||||
|
return AggIntervalType.MONTH; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
} |
||||
@ -0,0 +1,42 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2025 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.common.data.cf.configuration.aggregation.single.interval; |
||||
|
|
||||
|
import java.time.LocalTime; |
||||
|
|
||||
|
public class SpecificTimeInterval implements AggInterval { |
||||
|
|
||||
|
public Long startMillis; // start millis since start of day
|
||||
|
public Long endMillis; // end millis since start of day
|
||||
|
|
||||
|
@Override |
||||
|
public AggIntervalType getType() { |
||||
|
return AggIntervalType.SPECIFIC_TIME; |
||||
|
} |
||||
|
|
||||
|
@Override |
||||
|
public long getDelayUntilIntervalEnd() { |
||||
|
long nowMillis = LocalTime.now().toNanoOfDay() / 1_000_000L; |
||||
|
long delayMillis; |
||||
|
if (nowMillis < endMillis) { |
||||
|
delayMillis = endMillis - nowMillis; // later today
|
||||
|
} else { |
||||
|
delayMillis = (24 * 60 * 60 * 1000L - nowMillis) + endMillis; // next day
|
||||
|
} |
||||
|
return delayMillis; |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2025 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.common.data.cf.configuration.aggregation.single.interval; |
||||
|
|
||||
|
public class WeekInterval extends BaseAggInterval { |
||||
|
|
||||
|
@Override |
||||
|
public AggIntervalType getType() { |
||||
|
return AggIntervalType.WEEK; |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2025 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.common.data.cf.configuration.aggregation.single.interval; |
||||
|
|
||||
|
public class WeekSunSatInterval extends BaseAggInterval { |
||||
|
|
||||
|
@Override |
||||
|
public AggIntervalType getType() { |
||||
|
return AggIntervalType.WEEK_SUN_SAT; |
||||
|
} |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,25 @@ |
|||||
|
/** |
||||
|
* Copyright © 2016-2025 The Thingsboard Authors |
||||
|
* |
||||
|
* Licensed under the Apache License, Version 2.0 (the "License"); |
||||
|
* you may not use this file except in compliance with the License. |
||||
|
* You may obtain a copy of the License at |
||||
|
* |
||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
* |
||||
|
* Unless required by applicable law or agreed to in writing, software |
||||
|
* distributed under the License is distributed on an "AS IS" BASIS, |
||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
||||
|
* See the License for the specific language governing permissions and |
||||
|
* limitations under the License. |
||||
|
*/ |
||||
|
package org.thingsboard.server.common.data.cf.configuration.aggregation.single.interval; |
||||
|
|
||||
|
public class YearInterval extends BaseAggInterval { |
||||
|
|
||||
|
@Override |
||||
|
public AggIntervalType getType() { |
||||
|
return AggIntervalType.YEAR; |
||||
|
} |
||||
|
|
||||
|
} |
||||
Loading…
Reference in new issue