@ -33,14 +33,15 @@ import org.thingsboard.server.common.data.cf.CalculatedField;
import org.thingsboard.server.common.data.cf.CalculatedFieldType ;
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.Argument ;
import org.thingsboard.server.common.data.cf.configuration.ArgumentType ;
import org.thingsboard.server.common.data.cf.configuration.ArgumentType ;
import org.thingsboard.server.common.data.cf.configuration.AttributesOutput ;
import org.thingsboard.server.common.data.cf.configuration.CalculatedFieldConfiguration ;
import org.thingsboard.server.common.data.cf.configuration.CalculatedFieldConfiguration ;
import org.thingsboard.server.common.data.cf.configuration.Output ;
import org.thingsboard.server.common.data.cf.configuration.OutputType ;
import org.thingsboard.server.common.data.cf.configuration.PropagationCalculatedFieldConfiguration ;
import org.thingsboard.server.common.data.cf.configuration.PropagationCalculatedFieldConfiguration ;
import org.thingsboard.server.common.data.cf.configuration.ReferencedEntityKey ;
import org.thingsboard.server.common.data.cf.configuration.ReferencedEntityKey ;
import org.thingsboard.server.common.data.cf.configuration.RelationPathQueryDynamicSourceConfiguration ;
import org.thingsboard.server.common.data.cf.configuration.RelationPathQueryDynamicSourceConfiguration ;
import org.thingsboard.server.common.data.cf.configuration.ScriptCalculatedFieldConfiguration ;
import org.thingsboard.server.common.data.cf.configuration.ScriptCalculatedFieldConfiguration ;
import org.thingsboard.server.common.data.cf.configuration.SimpleCalculatedFieldConfiguration ;
import org.thingsboard.server.common.data.cf.configuration.SimpleCalculatedFieldConfiguration ;
import org.thingsboard.server.common.data.cf.configuration.TimeSeriesImmediateOutputStrategy ;
import org.thingsboard.server.common.data.cf.configuration.TimeSeriesOutput ;
import org.thingsboard.server.common.data.cf.configuration.geofencing.EntityCoordinates ;
import org.thingsboard.server.common.data.cf.configuration.geofencing.EntityCoordinates ;
import org.thingsboard.server.common.data.cf.configuration.geofencing.GeofencingCalculatedFieldConfiguration ;
import org.thingsboard.server.common.data.cf.configuration.geofencing.GeofencingCalculatedFieldConfiguration ;
import org.thingsboard.server.common.data.cf.configuration.geofencing.ZoneGroupConfiguration ;
import org.thingsboard.server.common.data.cf.configuration.geofencing.ZoneGroupConfiguration ;
@ -93,13 +94,11 @@ public class CalculatedFieldIntegrationTest extends CalculatedFieldControllerTes
config . setArguments ( Map . of ( "T" , argument ) ) ;
config . setArguments ( Map . of ( "T" , argument ) ) ;
config . setExpression ( "(T * 9/5) + 32" ) ;
config . setExpression ( "(T * 9/5) + 32" ) ;
Output output = new Output ( ) ;
TimeSeries Output output = new TimeSeries Output( ) ;
output . setName ( "fahrenheitTemp" ) ;
output . setName ( "fahrenheitTemp" ) ;
output . setType ( OutputType . TIME_SERIES ) ;
config . setOutput ( output ) ;
config . setOutput ( output ) ;
calculatedField . setConfiguration ( config ) ;
calculatedField . setConfiguration ( config ) ;
calculatedField . setVersion ( 1L ) ;
CalculatedField savedCalculatedField = doPost ( "/api/calculatedField" , calculatedField , CalculatedField . class ) ;
CalculatedField savedCalculatedField = doPost ( "/api/calculatedField" , calculatedField , CalculatedField . class ) ;
@ -121,10 +120,12 @@ public class CalculatedFieldIntegrationTest extends CalculatedFieldControllerTes
assertThat ( fahrenheitTemp . get ( "fahrenheitTemp" ) . get ( 0 ) . get ( "value" ) . asText ( ) ) . isEqualTo ( "86.0" ) ;
assertThat ( fahrenheitTemp . get ( "fahrenheitTemp" ) . get ( 0 ) . get ( "value" ) . asText ( ) ) . isEqualTo ( "86.0" ) ;
} ) ;
} ) ;
Output savedOutput = savedCalculatedField . getConfiguration ( ) . getOutput ( ) ;
AttributesOutput newOutput = new AttributesOutput ( ) ;
savedOutput . setType ( OutputType . ATTRIBUTES ) ;
newOutput . setScope ( AttributeScope . SERVER_SCOPE ) ;
savedOutput . setScope ( AttributeScope . SERVER_SCOPE ) ;
newOutput . setName ( "temperatureF" ) ;
savedOutput . setName ( "temperatureF" ) ;
config . setOutput ( newOutput ) ;
savedCalculatedField . setConfiguration ( config ) ;
savedCalculatedField = doPost ( "/api/calculatedField" , savedCalculatedField , CalculatedField . class ) ;
savedCalculatedField = doPost ( "/api/calculatedField" , savedCalculatedField , CalculatedField . class ) ;
await ( ) . alias ( "update CF output -> perform calculation with updated output" ) . atMost ( TIMEOUT , TimeUnit . SECONDS )
await ( ) . alias ( "update CF output -> perform calculation with updated output" ) . atMost ( TIMEOUT , TimeUnit . SECONDS )
@ -179,9 +180,8 @@ public class CalculatedFieldIntegrationTest extends CalculatedFieldControllerTes
config . setArguments ( Map . of ( "T" , argument ) ) ;
config . setArguments ( Map . of ( "T" , argument ) ) ;
config . setExpression ( "(T * 9/5) + 32" ) ;
config . setExpression ( "(T * 9/5) + 32" ) ;
Output output = new Output ( ) ;
TimeSeries Output output = new TimeSeries Output( ) ;
output . setName ( "fahrenheitTemp" ) ;
output . setName ( "fahrenheitTemp" ) ;
output . setType ( OutputType . TIME_SERIES ) ;
config . setOutput ( output ) ;
config . setOutput ( output ) ;
calculatedField . setConfiguration ( config ) ;
calculatedField . setConfiguration ( config ) ;
@ -228,9 +228,8 @@ public class CalculatedFieldIntegrationTest extends CalculatedFieldControllerTes
config . setArguments ( Map . of ( "T" , argument ) ) ;
config . setArguments ( Map . of ( "T" , argument ) ) ;
config . setExpression ( "(T * 9/5) + 32" ) ;
config . setExpression ( "(T * 9/5) + 32" ) ;
Output output = new Output ( ) ;
TimeSeries Output output = new TimeSeries Output( ) ;
output . setName ( "fahrenheitTemp" ) ;
output . setName ( "fahrenheitTemp" ) ;
output . setType ( OutputType . TIME_SERIES ) ;
config . setOutput ( output ) ;
config . setOutput ( output ) ;
calculatedField . setConfiguration ( config ) ;
calculatedField . setConfiguration ( config ) ;
@ -292,9 +291,8 @@ public class CalculatedFieldIntegrationTest extends CalculatedFieldControllerTes
config . setExpression ( "x + y" ) ;
config . setExpression ( "x + y" ) ;
Output output = new Output ( ) ;
Attributes Output output = new Attributes Output( ) ;
output . setName ( "z" ) ;
output . setName ( "z" ) ;
output . setType ( OutputType . ATTRIBUTES ) ;
output . setScope ( AttributeScope . SERVER_SCOPE ) ;
output . setScope ( AttributeScope . SERVER_SCOPE ) ;
config . setOutput ( output ) ;
config . setOutput ( output ) ;
@ -449,9 +447,8 @@ public class CalculatedFieldIntegrationTest extends CalculatedFieldControllerTes
config . setArguments ( Map . of ( "T" , argument ) ) ;
config . setArguments ( Map . of ( "T" , argument ) ) ;
config . setExpression ( "(T * 9/0) + 32" ) ;
config . setExpression ( "(T * 9/0) + 32" ) ;
Output output = new Output ( ) ;
TimeSeries Output output = new TimeSeries Output( ) ;
output . setName ( "fahrenheitTemp" ) ;
output . setName ( "fahrenheitTemp" ) ;
output . setType ( OutputType . TIME_SERIES ) ;
config . setOutput ( output ) ;
config . setOutput ( output ) ;
calculatedField . setConfiguration ( config ) ;
calculatedField . setConfiguration ( config ) ;
@ -499,9 +496,8 @@ public class CalculatedFieldIntegrationTest extends CalculatedFieldControllerTes
config . setArguments ( Map . of ( "T" , argument ) ) ;
config . setArguments ( Map . of ( "T" , argument ) ) ;
config . setExpression ( "(T * 9/5) + 32" ) ;
config . setExpression ( "(T * 9/5) + 32" ) ;
Output output = new Output ( ) ;
TimeSeries Output output = new TimeSeries Output( ) ;
output . setName ( "fahrenheitTemp" ) ;
output . setName ( "fahrenheitTemp" ) ;
output . setType ( OutputType . TIME_SERIES ) ;
config . setOutput ( output ) ;
config . setOutput ( output ) ;
config . setUseLatestTs ( true ) ;
config . setUseLatestTs ( true ) ;
@ -549,9 +545,8 @@ public class CalculatedFieldIntegrationTest extends CalculatedFieldControllerTes
config . setArguments ( Map . of ( "a" , argument1 , "b" , argument2 ) ) ;
config . setArguments ( Map . of ( "a" , argument1 , "b" , argument2 ) ) ;
config . setExpression ( "a + b" ) ;
config . setExpression ( "a + b" ) ;
Output output = new Output ( ) ;
TimeSeries Output output = new TimeSeries Output( ) ;
output . setName ( "c" ) ;
output . setName ( "c" ) ;
output . setType ( OutputType . TIME_SERIES ) ;
config . setOutput ( output ) ;
config . setOutput ( output ) ;
config . setUseLatestTs ( true ) ;
config . setUseLatestTs ( true ) ;
@ -603,9 +598,7 @@ public class CalculatedFieldIntegrationTest extends CalculatedFieldControllerTes
config . setArguments ( Map . of ( "T" , argument ) ) ;
config . setArguments ( Map . of ( "T" , argument ) ) ;
config . setExpression ( "return {\"ts\": ctx.latestTs, \"values\": {\"fahrenheitTemp\": (T * 1.8) + 32}};" ) ;
config . setExpression ( "return {\"ts\": ctx.latestTs, \"values\": {\"fahrenheitTemp\": (T * 1.8) + 32}};" ) ;
Output output = new Output ( ) ;
config . setOutput ( new TimeSeriesOutput ( ) ) ;
output . setType ( OutputType . TIME_SERIES ) ;
config . setOutput ( output ) ;
calculatedField . setConfiguration ( config ) ;
calculatedField . setConfiguration ( config ) ;
@ -639,9 +632,8 @@ public class CalculatedFieldIntegrationTest extends CalculatedFieldControllerTes
config . setArguments ( Map . of ( "m" , argument ) ) ;
config . setArguments ( Map . of ( "m" , argument ) ) ;
config . setExpression ( "m + 1" ) ;
config . setExpression ( "m + 1" ) ;
Output output = new Output ( ) ;
TimeSeries Output output = new TimeSeries Output( ) ;
output . setName ( "m1" ) ;
output . setName ( "m1" ) ;
output . setType ( OutputType . TIME_SERIES ) ;
output . setDecimalsByDefault ( 0 ) ;
output . setDecimalsByDefault ( 0 ) ;
config . setOutput ( output ) ;
config . setOutput ( output ) ;
@ -714,8 +706,7 @@ public class CalculatedFieldIntegrationTest extends CalculatedFieldControllerTes
cfg . setZoneGroups ( Map . of ( "allowedZones" , allowedZonesGroup , "restrictedZones" , restrictedZonesGroup ) ) ;
cfg . setZoneGroups ( Map . of ( "allowedZones" , allowedZonesGroup , "restrictedZones" , restrictedZonesGroup ) ) ;
// Output to server attributes
// Output to server attributes
Output out = new Output ( ) ;
AttributesOutput out = new AttributesOutput ( ) ;
out . setType ( OutputType . ATTRIBUTES ) ;
out . setScope ( AttributeScope . SERVER_SCOPE ) ;
out . setScope ( AttributeScope . SERVER_SCOPE ) ;
cfg . setOutput ( out ) ;
cfg . setOutput ( out ) ;
@ -825,8 +816,7 @@ public class CalculatedFieldIntegrationTest extends CalculatedFieldControllerTes
cfg . setZoneGroups ( Map . of ( "allowedZones" , allowedZonesGroup , "restrictedZones" , restrictedZonesGroup ) ) ;
cfg . setZoneGroups ( Map . of ( "allowedZones" , allowedZonesGroup , "restrictedZones" , restrictedZonesGroup ) ) ;
// Output to server attributes
// Output to server attributes
Output out = new Output ( ) ;
AttributesOutput out = new AttributesOutput ( ) ;
out . setType ( OutputType . ATTRIBUTES ) ;
out . setScope ( AttributeScope . SERVER_SCOPE ) ;
out . setScope ( AttributeScope . SERVER_SCOPE ) ;
cfg . setOutput ( out ) ;
cfg . setOutput ( out ) ;
@ -923,8 +913,7 @@ public class CalculatedFieldIntegrationTest extends CalculatedFieldControllerTes
cfg . setZoneGroups ( Map . of ( "allowedZones" , allowedZonesGroup ) ) ;
cfg . setZoneGroups ( Map . of ( "allowedZones" , allowedZonesGroup ) ) ;
// Server attributes output
// Server attributes output
Output out = new Output ( ) ;
AttributesOutput out = new AttributesOutput ( ) ;
out . setType ( OutputType . ATTRIBUTES ) ;
out . setScope ( AttributeScope . SERVER_SCOPE ) ;
out . setScope ( AttributeScope . SERVER_SCOPE ) ;
cfg . setOutput ( out ) ;
cfg . setOutput ( out ) ;
@ -1034,8 +1023,7 @@ public class CalculatedFieldIntegrationTest extends CalculatedFieldControllerTes
cfg . setExpression ( "{\"testResult\": t * 2}" ) ;
cfg . setExpression ( "{\"testResult\": t * 2}" ) ;
Output output = new Output ( ) ;
AttributesOutput output = new AttributesOutput ( ) ;
output . setType ( OutputType . ATTRIBUTES ) ;
output . setScope ( AttributeScope . SERVER_SCOPE ) ;
output . setScope ( AttributeScope . SERVER_SCOPE ) ;
cfg . setOutput ( output ) ;
cfg . setOutput ( output ) ;
@ -1111,9 +1099,7 @@ public class CalculatedFieldIntegrationTest extends CalculatedFieldControllerTes
arg . setRefEntityKey ( new ReferencedEntityKey ( "temperature" , ArgumentType . TS_LATEST , null ) ) ;
arg . setRefEntityKey ( new ReferencedEntityKey ( "temperature" , ArgumentType . TS_LATEST , null ) ) ;
cfg . setArguments ( Map . of ( "temperatureComputed" , arg ) ) ;
cfg . setArguments ( Map . of ( "temperatureComputed" , arg ) ) ;
Output output = new Output ( ) ;
cfg . setOutput ( new TimeSeriesOutput ( ) ) ;
output . setType ( OutputType . TIME_SERIES ) ;
cfg . setOutput ( output ) ;
cf . setConfiguration ( cfg ) ;
cf . setConfiguration ( cfg ) ;
@ -1181,9 +1167,8 @@ public class CalculatedFieldIntegrationTest extends CalculatedFieldControllerTes
config . setArguments ( Map . of ( "a" , argumentA , "b" , argumentB ) ) ;
config . setArguments ( Map . of ( "a" , argumentA , "b" , argumentB ) ) ;
config . setExpression ( "a + b" ) ;
config . setExpression ( "a + b" ) ;
Output output = new Output ( ) ;
TimeSeries Output output = new TimeSeries Output( ) ;
output . setName ( "c" ) ;
output . setName ( "c" ) ;
output . setType ( OutputType . TIME_SERIES ) ;
output . setDecimalsByDefault ( 0 ) ;
output . setDecimalsByDefault ( 0 ) ;
config . setOutput ( output ) ;
config . setOutput ( output ) ;
@ -1210,6 +1195,48 @@ public class CalculatedFieldIntegrationTest extends CalculatedFieldControllerTes
} ) ;
} ) ;
}
}
@Test
public void testSimpleCalculatedFieldWhenSkipRuleEngineOutputProcessing ( ) throws Exception {
Device testDevice = createDevice ( "Test device" , "1234567890" ) ;
postTelemetry ( testDevice . getId ( ) , "{\"temperature\":24.5}" ) ;
CalculatedField calculatedField = new CalculatedField ( ) ;
calculatedField . setEntityId ( testDevice . getId ( ) ) ;
calculatedField . setType ( CalculatedFieldType . SIMPLE ) ;
calculatedField . setName ( "C to F" ) ;
calculatedField . setDebugSettings ( DebugSettings . all ( ) ) ;
SimpleCalculatedFieldConfiguration config = new SimpleCalculatedFieldConfiguration ( ) ;
Argument argument = new Argument ( ) ;
ReferencedEntityKey refEntityKey = new ReferencedEntityKey ( "temperature" , ArgumentType . TS_LATEST , null ) ;
argument . setRefEntityKey ( refEntityKey ) ;
config . setArguments ( Map . of ( "T" , argument ) ) ;
config . setExpression ( "(T * 9/5) + 32" ) ;
TimeSeriesOutput output = new TimeSeriesOutput ( ) ;
output . setName ( "fahrenheitTemp" ) ;
output . setDecimalsByDefault ( 1 ) ;
output . setStrategy ( new TimeSeriesImmediateOutputStrategy ( 1000L , true , true , true , true ) ) ;
config . setOutput ( output ) ;
config . setUseLatestTs ( true ) ;
calculatedField . setConfiguration ( config ) ;
CalculatedField savedCalculatedField = doPost ( "/api/calculatedField" , calculatedField , CalculatedField . class ) ;
await ( ) . alias ( "create CF -> perform initial calculation" ) . atMost ( TIMEOUT , TimeUnit . SECONDS )
. pollInterval ( POLL_INTERVAL , TimeUnit . SECONDS )
. untilAsserted ( ( ) - > {
ObjectNode fahrenheitTemp = getLatestTelemetry ( testDevice . getId ( ) , "fahrenheitTemp" ) ;
assertThat ( fahrenheitTemp ) . isNotNull ( ) ;
assertThat ( fahrenheitTemp . get ( "fahrenheitTemp" ) . get ( 0 ) . get ( "value" ) . asText ( ) ) . isEqualTo ( "76.1" ) ;
} ) ;
}
private ObjectNode getLatestTelemetry ( EntityId entityId , String . . . keys ) throws Exception {
private ObjectNode getLatestTelemetry ( EntityId entityId , String . . . keys ) throws Exception {
return doGetAsync ( "/api/plugins/telemetry/" + entityId . getEntityType ( ) + "/" + entityId . getId ( ) + "/values/timeseries?keys=" + String . join ( "," , keys ) , ObjectNode . class ) ;
return doGetAsync ( "/api/plugins/telemetry/" + entityId . getEntityType ( ) + "/" + entityId . getId ( ) + "/values/timeseries?keys=" + String . join ( "," , keys ) , ObjectNode . class ) ;
}
}