diff --git a/core/sdk/src/main/java/com/viam/sdk/core/component/powersensor/PowerSensor.java b/core/sdk/src/main/java/com/viam/sdk/core/component/powersensor/PowerSensor.java new file mode 100644 index 000000000..30b1edeab --- /dev/null +++ b/core/sdk/src/main/java/com/viam/sdk/core/component/powersensor/PowerSensor.java @@ -0,0 +1,84 @@ +package com.viam.sdk.core.component.powersensor; + +import com.google.protobuf.Struct; +import com.viam.common.v1.Common; +import com.viam.sdk.core.component.Component; +import com.viam.sdk.core.resource.Resource; +import com.viam.sdk.core.resource.Subtype; +import com.viam.sdk.core.robot.RobotClient; + +import java.util.Map.Entry; + + +import java.util.Map; +import java.util.Optional; + +/** + * PowerSensor reports information about voltage, current and power. + */ +public abstract class PowerSensor extends Component { + public static final Subtype SUBTYPE = new Subtype( + Subtype.NAMESPACE_RDK, + Subtype.RESOURCE_TYPE_COMPONENT, + "power_sensor"); + + public PowerSensor(final String name) { + super(SUBTYPE, named(name)); + } + + /** + * Get the ResourceName of the component + * + * @param name the name of the component + * @return the component's ResourceName + */ + public static Common.ResourceName named(final String name) { + return Resource.named(SUBTYPE, name); + } + + /** + * Get the component with the provided name from the provided robot. + * + * @param robot the RobotClient + * @param name the name of the component + * @return the component + */ + public static PowerSensor fromRobot(final RobotClient robot, final String name) { + return robot.getResource(PowerSensor.class, named(name)); + } + + /** + * Return the voltage reading of a specified device and whether it is AC or DC. + * + * @return the pair where the first double representing the voltage reading in V, the second bool indicating whether the voltage is AC (`true`) or DC + * (`false`). + */ + public abstract Entry getVoltage(Optional extra); + + /** + * Return the current of a specified device and whether it is AC or DC. + * + * @return the pair where the first double representing the current reading in V, the second bool indicating whether the current is AC (`true`) or DC + * * (`false`). + */ + public abstract Entry getCurrent(Optional extra); + + /** + * Return the power reading in watts. + * + * @return the power reading in watts + */ + public abstract double getPower(Optional extra); + + + /** + * Get the measurements or readings that this power sensor provides. If a sensor is not configured correctly or fails to read a + * piece of data, it will not appear in the readings dictionary. + * + * @return The readings for the PowerSensor. Object should be of type Vector3, GeoPoint, Orientation, or any Value type. Includes voltage in volts (float), current in + * amperes (float), is_ac (bool), and power in watts (float). + */ + public abstract Map getReadings(Optional extra); + + +} \ No newline at end of file diff --git a/core/sdk/src/main/java/com/viam/sdk/core/component/powersensor/PowerSensorRPCClient.java b/core/sdk/src/main/java/com/viam/sdk/core/component/powersensor/PowerSensorRPCClient.java new file mode 100644 index 000000000..3d51fd6a7 --- /dev/null +++ b/core/sdk/src/main/java/com/viam/sdk/core/component/powersensor/PowerSensorRPCClient.java @@ -0,0 +1,66 @@ +package com.viam.sdk.core.component.powersensor; + +import com.google.protobuf.Struct; +import com.google.protobuf.Value; +import com.viam.common.v1.Common; +import com.viam.component.powersensor.v1.PowerSensorServiceGrpc; +import com.viam.component.powersensor.v1.Powersensor; +import com.viam.sdk.core.rpc.Channel; +import com.viam.sdk.core.util.Utils; + +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; + +public class PowerSensorRPCClient extends PowerSensor { + private final PowerSensorServiceGrpc.PowerSensorServiceBlockingStub client; + + public PowerSensorRPCClient(final String name, final Channel chan) { + super(name); + final PowerSensorServiceGrpc.PowerSensorServiceBlockingStub client = PowerSensorServiceGrpc.newBlockingStub(chan); + if (chan.getCallCredentials().isPresent()) { + this.client = client.withCallCredentials(chan.getCallCredentials().get()); + } else { + this.client = client; + } + } + + @Override + public Struct doCommand(final Map command) { + return client.doCommand(Common.DoCommandRequest.newBuilder(). + setName(getName().getName()). + setCommand(Struct.newBuilder().putAllFields(command).build()). + build()).getResult(); + } + + @Override + public Entry getVoltage(Optional extra) { + Powersensor.GetVoltageRequest.Builder builder = com.viam.component.powersensor.v1.Powersensor.GetVoltageRequest.newBuilder().setName(this.getName().getName()); + extra.ifPresent(builder::setExtra); + Powersensor.GetVoltageResponse response = client.getVoltage(builder.build()); + return Map.entry(response.getVolts(), response.getIsAc()); + } + + @Override + public Map.Entry getCurrent(Optional extra) { + Powersensor.GetCurrentRequest.Builder builder = com.viam.component.powersensor.v1.Powersensor.GetCurrentRequest.newBuilder().setName(this.getName().getName()); + extra.ifPresent(builder::setExtra); + Powersensor.GetCurrentResponse response = client.getCurrent(builder.build()); + return Map.entry(response.getAmperes(), response.getIsAc()); + } + + @Override + public double getPower(Optional extra) { + Powersensor.GetPowerRequest.Builder builder = com.viam.component.powersensor.v1.Powersensor.GetPowerRequest.newBuilder().setName(this.getName().getName()); + extra.ifPresent(builder::setExtra); + return client.getPower(builder.build()).getWatts(); + } + + @Override + public Map getReadings(Optional extra) { + Common.GetReadingsRequest.Builder builder = Common.GetReadingsRequest.newBuilder().setName(this.getName().getName()); + extra.ifPresent(builder::setExtra); + return Utils.sensorReadingsValueToNative(client.getReadings(builder.build()).getReadingsMap()); + + } +} diff --git a/core/sdk/src/main/java/com/viam/sdk/core/component/powersensor/PowerSensorRPCService.java b/core/sdk/src/main/java/com/viam/sdk/core/component/powersensor/PowerSensorRPCService.java new file mode 100644 index 000000000..abb506ec8 --- /dev/null +++ b/core/sdk/src/main/java/com/viam/sdk/core/component/powersensor/PowerSensorRPCService.java @@ -0,0 +1,78 @@ +package com.viam.sdk.core.component.powersensor; + +import com.google.protobuf.Struct; +import com.google.protobuf.Value; +import com.viam.common.v1.Common; +import com.viam.component.powersensor.v1.PowerSensorServiceGrpc; +import com.viam.component.powersensor.v1.Powersensor; +import com.viam.sdk.core.resource.ResourceManager; +import com.viam.sdk.core.resource.ResourceRPCService; +import com.viam.sdk.core.util.Utils; +import io.grpc.stub.StreamObserver; + +import java.util.Map; +import java.util.Map.Entry; +import java.util.Optional; + +public class PowerSensorRPCService extends PowerSensorServiceGrpc.PowerSensorServiceImplBase implements ResourceRPCService { + + private final ResourceManager manager; + + public PowerSensorRPCService(ResourceManager manager) { + this.manager = manager; + } + + @Override + public Class getResourceClass() { + return PowerSensor.class; + } + + @Override + public ResourceManager getManager() { + return manager; + } + + + @Override + public void getVoltage(Powersensor.GetVoltageRequest request, StreamObserver responseObserver) { + PowerSensor powerSensor = getResource(PowerSensor.named(request.getName())); + Entry voltage = powerSensor.getVoltage(Optional.of(request.getExtra())); + responseObserver.onNext(com.viam.component.powersensor.v1.Powersensor.GetVoltageResponse.newBuilder().setVolts(voltage.getKey()).setIsAc(voltage.getValue()).build()); + responseObserver.onCompleted(); + } + + @Override + public void getCurrent(Powersensor.GetCurrentRequest request, StreamObserver responseObserver) { + PowerSensor powerSensor = getResource(PowerSensor.named(request.getName())); + Entry current = powerSensor.getCurrent(Optional.of(request.getExtra())); + responseObserver.onNext(com.viam.component.powersensor.v1.Powersensor.GetCurrentResponse.newBuilder().setAmperes(current.getKey()).setIsAc(current.getValue()).build()); + responseObserver.onCompleted(); + } + + @Override + public void getPower(Powersensor.GetPowerRequest request, StreamObserver responseObserver) { + PowerSensor powerSensor = getResource(PowerSensor.named(request.getName())); + double power = powerSensor.getPower(Optional.of(request.getExtra())); + responseObserver.onNext(com.viam.component.powersensor.v1.Powersensor.GetPowerResponse.newBuilder().setWatts(power).build()); + responseObserver.onCompleted(); + } + + @Override + public void getReadings(Common.GetReadingsRequest request, StreamObserver responseObserver) { + PowerSensor powerSensor = getResource(PowerSensor.named(request.getName())); + Map readings = Utils.sensorReadingsNativeToValue(powerSensor.getReadings(Optional.of(request.getExtra()))); + responseObserver.onNext(Common.GetReadingsResponse.newBuilder().putAllReadings(readings).build()); + responseObserver.onCompleted(); + } + @Override + public void doCommand(Common.DoCommandRequest request, + StreamObserver responseObserver) { + + PowerSensor powerSensor = getResource(PowerSensor.named(request.getName())); + Struct result = powerSensor.doCommand(request.getCommand().getFieldsMap()); + responseObserver.onNext(Common.DoCommandResponse.newBuilder().setResult(result).build()); + responseObserver.onCompleted(); + } + +} + diff --git a/core/sdk/src/main/java/com/viam/sdk/core/component/sensor/Sensor.java b/core/sdk/src/main/java/com/viam/sdk/core/component/sensor/Sensor.java index 0ff1cf4fc..383dbd587 100644 --- a/core/sdk/src/main/java/com/viam/sdk/core/component/sensor/Sensor.java +++ b/core/sdk/src/main/java/com/viam/sdk/core/component/sensor/Sensor.java @@ -28,10 +28,6 @@ public Sensor(final String name) { super(SUBTYPE, named(name)); } - public Sensor(Subtype subtype, ResourceName name) { - super(subtype, name); - throw new UnsupportedOperationException(); - } /** * Get the ResourceName of the component diff --git a/core/sdk/src/main/java/com/viam/sdk/core/component/servo/Servo.java b/core/sdk/src/main/java/com/viam/sdk/core/component/servo/Servo.java new file mode 100644 index 000000000..1e0c489aa --- /dev/null +++ b/core/sdk/src/main/java/com/viam/sdk/core/component/servo/Servo.java @@ -0,0 +1,94 @@ +package com.viam.sdk.core.component.servo; + +import com.google.protobuf.Struct; +import com.viam.common.v1.Common; +import com.viam.sdk.core.component.Component; +import com.viam.sdk.core.resource.Resource; +import com.viam.sdk.core.resource.Subtype; +import com.viam.sdk.core.robot.RobotClient; + + +/** + * Servo represents a physical servo + */ +public abstract class Servo extends Component { + public static final Subtype SUBTYPE = new Subtype( + Subtype.NAMESPACE_RDK, + Subtype.RESOURCE_TYPE_COMPONENT, + "servo"); + + public Servo(final String name) { + super(SUBTYPE, named(name)); + } + + /** + * Get the ResourceName of the component + * + * @param name the name of the component + * @return the component's ResourceName + */ + public static Common.ResourceName named(final String name) { + return Resource.named(SUBTYPE, name); + } + + + /** + * Get the component with the provided name from the provided robot. + * @param robot the RobotClient + * @param name the name of the component + * @return the component + */ + public static Servo fromRobot(final RobotClient robot, final String name) { + return robot.getResource(Servo.class, named(name)); + } + + /** + * Move the servo to the provided angle. + * @param angle the desired angle of the servo in degrees + */ + public abstract void move(int angle, Struct extra); + + /** + * Move the servo to the provided angle. + * @param angle the desired angle of the servo in degrees + */ + public void move(int angle){ + move(angle, Struct.getDefaultInstance()); + } + + /** + * Get the current angle (degrees) of the servo. + * @return the current angle of the servo in degrees + */ + public abstract int getPosition(Struct extra); + + /** + * Get the current angle (degrees) of the servo. + * @return the current angle of the servo in degrees + */ + public int getPosition(){ + return getPosition(Struct.getDefaultInstance()); + } + + /** + * Stop the servo. It is assumed that the servo stops immediately. + */ + public abstract void stop(Struct extra); + + /** + * Stop the servo. It is assumed that the servo stops immediately. + */ + public void stop(){ + stop(Struct.getDefaultInstance()); + } + + + /** + * Get if the servo is currently moving. + * @return whether the servo is moving + */ + public abstract boolean isMoving(); + + +} + diff --git a/core/sdk/src/main/java/com/viam/sdk/core/component/servo/ServoRPCClient.java b/core/sdk/src/main/java/com/viam/sdk/core/component/servo/ServoRPCClient.java new file mode 100644 index 000000000..c9e2feb10 --- /dev/null +++ b/core/sdk/src/main/java/com/viam/sdk/core/component/servo/ServoRPCClient.java @@ -0,0 +1,68 @@ +package com.viam.sdk.core.component.servo; + +import com.google.protobuf.Struct; +import com.google.protobuf.Value; +import com.viam.common.v1.Common; +import com.viam.component.servo.v1.ServoServiceGrpc; + +import com.viam.sdk.core.rpc.Channel; + +import java.util.List; +import java.util.Map; +import java.util.Optional; + +public class ServoRPCClient extends Servo{ + private final ServoServiceGrpc.ServoServiceBlockingStub client; + + public ServoRPCClient(final String name, final Channel chan) { + super(name); + final ServoServiceGrpc.ServoServiceBlockingStub client = ServoServiceGrpc.newBlockingStub(chan); + if (chan.getCallCredentials().isPresent()) { + this.client = client.withCallCredentials(chan.getCallCredentials().get()); + } else { + this.client = client; + } + } + + @Override + public Struct doCommand(final Map command) { + return client.doCommand(Common.DoCommandRequest.newBuilder(). + setName(getName().getName()). + setCommand(Struct.newBuilder().putAllFields(command).build()). + build()).getResult(); + } + + @Override + public void move(int angle, Struct extra) { + com.viam.component.servo.v1.Servo.MoveRequest moveRequest = com.viam.component.servo.v1.Servo.MoveRequest.newBuilder().setName(this.getName().getName()).setAngleDeg(angle).setExtra(extra).build(); + client.move(moveRequest); + } + + @Override + public int getPosition(Struct extra) { + com.viam.component.servo.v1.Servo.GetPositionRequest getPositionRequest = com.viam.component.servo.v1.Servo.GetPositionRequest.newBuilder().setName(this.getName().getName()).setExtra(extra).build(); + return client.getPosition(getPositionRequest).getPositionDeg(); + } + + + @Override + public void stop(Struct extra) { + com.viam.component.servo.v1.Servo.StopRequest stopRequest = com.viam.component.servo.v1.Servo.StopRequest.newBuilder().setName(this.getName().getName()).setExtra(extra).build(); + client.stop(stopRequest); + } + + @Override + public boolean isMoving() { + com.viam.component.servo.v1.Servo.IsMovingRequest isMovingRequest = com.viam.component.servo.v1.Servo.IsMovingRequest.newBuilder().setName(this.getName().getName()).build(); + return client.isMoving(isMovingRequest).getIsMoving(); + } + + @Override + public List getGeometries(Optional extra){ + Common.GetGeometriesRequest.Builder builder = Common.GetGeometriesRequest.newBuilder().setName(this.getName().getName()); + extra.ifPresent(builder::setExtra); + return client.getGeometries(builder.build()).getGeometriesList(); + + } +} + diff --git a/core/sdk/src/main/java/com/viam/sdk/core/component/servo/ServoRPCService.java b/core/sdk/src/main/java/com/viam/sdk/core/component/servo/ServoRPCService.java new file mode 100644 index 000000000..5edbefb6c --- /dev/null +++ b/core/sdk/src/main/java/com/viam/sdk/core/component/servo/ServoRPCService.java @@ -0,0 +1,76 @@ +package com.viam.sdk.core.component.servo; + import com.google.protobuf.Struct; + import com.viam.common.v1.Common; + import com.viam.component.servo.v1.ServoServiceGrpc; + import com.viam.sdk.core.resource.ResourceRPCService; + import com.viam.sdk.core.resource.ResourceManager; + import io.grpc.stub.StreamObserver; + + import java.util.List; + import java.util.Optional; + + +public class ServoRPCService extends ServoServiceGrpc.ServoServiceImplBase implements ResourceRPCService { + + private final ResourceManager manager; + public ServoRPCService(ResourceManager manager) { this.manager = manager; } + @Override + public Class getResourceClass() { + return Servo.class; + } + + @Override + public ResourceManager getManager() { + return manager; + } + + @Override + public void move(com.viam.component.servo.v1.Servo.MoveRequest request, StreamObserver responseObserver) { + Servo servo = getResource(Servo.named(request.getName())); + servo.move(request.getAngleDeg(), request.getExtra()); + responseObserver.onNext(com.viam.component.servo.v1.Servo.MoveResponse.newBuilder().build()); + responseObserver.onCompleted(); + } + + @Override + public void stop(com.viam.component.servo.v1.Servo.StopRequest request, StreamObserver responseObserver) { + Servo servo = getResource(Servo.named(request.getName())); + servo.stop(); + responseObserver.onNext(com.viam.component.servo.v1.Servo.StopResponse.newBuilder().build()); + responseObserver.onCompleted(); + } + + @Override + public void getPosition(com.viam.component.servo.v1.Servo.GetPositionRequest request, StreamObserver responseObserver) { + Servo servo = getResource(Servo.named(request.getName())); + int position = servo.getPosition(request.getExtra()); + responseObserver.onNext(com.viam.component.servo.v1.Servo.GetPositionResponse.newBuilder().setPositionDeg(position).build()); + responseObserver.onCompleted(); + } + + @Override + public void isMoving(com.viam.component.servo.v1.Servo.IsMovingRequest request, StreamObserver responseObserver) { + Servo servo = getResource(Servo.named(request.getName())); + boolean isMoving = servo.isMoving(); + responseObserver.onNext(com.viam.component.servo.v1.Servo.IsMovingResponse.newBuilder().setIsMoving(isMoving).build()); + responseObserver.onCompleted(); + } + + @Override + public void getGeometries(com.viam.common.v1.Common.GetGeometriesRequest request, + StreamObserver responseObserver){ + Servo servo = getResource(Servo.named(request.getName())); + List geometries = servo.getGeometries(Optional.ofNullable(request.getExtra())); + responseObserver.onNext(Common.GetGeometriesResponse.newBuilder().addAllGeometries(geometries).build()); + responseObserver.onCompleted(); + } + @Override + public void doCommand(Common.DoCommandRequest request, + StreamObserver responseObserver) { + + Servo servo = getResource(Servo.named(request.getName())); + Struct result = servo.doCommand(request.getCommand().getFieldsMap()); + responseObserver.onNext(Common.DoCommandResponse.newBuilder().setResult(result).build()); + responseObserver.onCompleted(); + } +} diff --git a/core/sdk/src/main/java/com/viam/sdk/core/resource/ResourceManager.java b/core/sdk/src/main/java/com/viam/sdk/core/resource/ResourceManager.java index 396100b6f..353441346 100644 --- a/core/sdk/src/main/java/com/viam/sdk/core/resource/ResourceManager.java +++ b/core/sdk/src/main/java/com/viam/sdk/core/resource/ResourceManager.java @@ -5,11 +5,14 @@ import com.viam.component.board.v1.BoardServiceGrpc; import com.viam.component.camera.v1.CameraServiceGrpc; import com.viam.component.encoder.v1.EncoderServiceGrpc; +import com.viam.component.gantry.v1.GantryServiceGrpc; import com.viam.component.generic.v1.GenericServiceGrpc; import com.viam.component.gripper.v1.GripperServiceGrpc; import com.viam.component.motor.v1.MotorServiceGrpc; import com.viam.component.movementsensor.v1.MovementSensorServiceGrpc; +import com.viam.component.powersensor.v1.PowerSensorServiceGrpc; import com.viam.component.sensor.v1.SensorServiceGrpc; +import com.viam.component.servo.v1.ServoServiceGrpc; import com.viam.sdk.core.component.board.Board; import com.viam.sdk.core.component.board.BoardRPCClient; import com.viam.sdk.core.component.board.BoardRPCService; @@ -17,6 +20,9 @@ import com.viam.sdk.core.component.camera.CameraRPCClient; import com.viam.sdk.core.component.camera.CameraRPCService; import com.viam.sdk.core.component.encoder.*; +import com.viam.sdk.core.component.gantry.Gantry; +import com.viam.sdk.core.component.gantry.GantryRPCClient; +import com.viam.sdk.core.component.gantry.GantryRPCService; import com.viam.sdk.core.component.generic.Generic; import com.viam.sdk.core.component.generic.GenericRPCClient; import com.viam.sdk.core.component.generic.GenericRPCService; @@ -29,9 +35,15 @@ import com.viam.sdk.core.component.movementsensor.MovementSensor; import com.viam.sdk.core.component.movementsensor.MovementSensorRPCClient; import com.viam.sdk.core.component.movementsensor.MovementSensorRPCService; +import com.viam.sdk.core.component.powersensor.PowerSensor; +import com.viam.sdk.core.component.powersensor.PowerSensorRPCClient; +import com.viam.sdk.core.component.powersensor.PowerSensorRPCService; import com.viam.sdk.core.component.sensor.Sensor; import com.viam.sdk.core.component.sensor.SensorRPCClient; import com.viam.sdk.core.component.sensor.SensorRPCService; +import com.viam.sdk.core.component.servo.Servo; +import com.viam.sdk.core.component.servo.ServoRPCClient; +import com.viam.sdk.core.component.servo.ServoRPCService; import com.viam.sdk.core.exception.DuplicateResourceException; import com.viam.sdk.core.exception.ResourceNotFoundException; import com.viam.sdk.core.service.datamanager.DataManager; @@ -103,6 +115,25 @@ public class ResourceManager implements Closeable { EncoderRPCService::new, EncoderRPCClient::new )); + Registry.registerSubtype(new ResourceRegistration<>( + PowerSensor.SUBTYPE, + PowerSensorServiceGrpc.SERVICE_NAME, + PowerSensorRPCService::new, + PowerSensorRPCClient::new + )); + Registry.registerSubtype(new ResourceRegistration<>( + Servo.SUBTYPE, + ServoServiceGrpc.SERVICE_NAME, + ServoRPCService::new, + ServoRPCClient::new + )); + + Registry.registerSubtype(new ResourceRegistration<>( + Gantry.SUBTYPE, + GantryServiceGrpc.SERVICE_NAME, + GantryRPCService::new, + GantryRPCClient::new + )); // SERVICES Registry.registerSubtype(new ResourceRegistration<>( diff --git a/core/sdk/src/main/java/com/viam/sdk/core/util/Utils.java b/core/sdk/src/main/java/com/viam/sdk/core/util/Utils.java new file mode 100644 index 000000000..766e6b8af --- /dev/null +++ b/core/sdk/src/main/java/com/viam/sdk/core/util/Utils.java @@ -0,0 +1,131 @@ +package com.viam.sdk.core.util; + +import com.google.protobuf.*; +import com.viam.common.v1.Common; + +import java.util.*; + +public class Utils { + public static Object valueToNative(Value v) { + switch (v.getKindCase()) { + case STRUCT_VALUE: { + Map structMap = v.getStructValue().getFieldsMap(); + if (structMap.get("_type") != null) { + switch (structMap.get("_type").getStringValue()) { + case ("vector3"): { + return Common.Vector3.newBuilder().setX(structMap.get("x").getNumberValue()).setY(structMap.get("y").getNumberValue()).setZ(structMap.get("z").getNumberValue()).build(); + } + case ("geopoint"): { + return Common.GeoPoint.newBuilder().setLatitude(structMap.get("lat").getNumberValue()).setLongitude(structMap.get("lng").getNumberValue()).build(); + } + case ("orientation_vector_degrees"): { + return Common.Orientation.newBuilder().setOX(structMap.get("ox").getNumberValue()).setOY(structMap.get("oy").getNumberValue()).setOZ(structMap.get("oz").getNumberValue()).setTheta(structMap.get("theta").getNumberValue()).build(); + } + } + + } else { + Map nativeMap = new HashMap<>(); + for (Map.Entry entry : structMap.entrySet()) { + nativeMap.put(entry.getKey(), valueToNative(entry.getValue())); + } + return nativeMap; + + } + + + } + case LIST_VALUE: { + List list = new ArrayList<>(); + for (Value val : v.getListValue().getValuesList()) { + list.add(valueToNative(val)); + } + return list; + + } + case BOOL_VALUE: + return v.getBoolValue(); + case NUMBER_VALUE: + return v.getNumberValue(); + case STRING_VALUE: + return v.getStringValue(); + case NULL_VALUE: + return v.getNullValue(); + default: + return v; + } + + + } + + public static Value nativeToValue(Object obj) throws IllegalArgumentException { + if (obj instanceof Common.Vector3) { + Struct struct = Struct.newBuilder() + .putFields("x", Value.newBuilder().setNumberValue(((Common.Vector3) obj).getX()).build()) + .putFields("y", Value.newBuilder().setNumberValue(((Common.Vector3) obj).getY()).build()) + .putFields("z", Value.newBuilder().setNumberValue(((Common.Vector3) obj).getZ()).build()) + .putFields("_type", Value.newBuilder().setStringValue("vector3").build()) + .build(); + return Value.newBuilder().setStructValue(struct).build(); + + } else if (obj instanceof Common.GeoPoint) { + Struct struct = Struct.newBuilder() + .putFields("lat", Value.newBuilder().setNumberValue(((Common.GeoPoint) obj).getLatitude()).build()) + .putFields("lng", Value.newBuilder().setNumberValue(((Common.GeoPoint) obj).getLongitude()).build()) + .putFields("_type", Value.newBuilder().setStringValue("geopoint").build()) + .build(); + return Value.newBuilder().setStructValue(struct).build(); + } else if (obj instanceof Common.Orientation) { + Struct struct = Struct.newBuilder() + .putFields("ox", Value.newBuilder().setNumberValue(((Common.Orientation) obj).getOX()).build()) + .putFields("oy", Value.newBuilder().setNumberValue(((Common.Orientation) obj).getOY()).build()) + .putFields("oz", Value.newBuilder().setNumberValue(((Common.Orientation) obj).getOZ()).build()) + .putFields("theta", Value.newBuilder().setNumberValue(((Common.Orientation) obj).getTheta()).build()) + .putFields("_type", Value.newBuilder().setStringValue("orientation_vector_degrees").build()) + .build(); + return Value.newBuilder().setStructValue(struct).build(); + + } else if (obj instanceof Number) { + return Value.newBuilder().setNumberValue((double) obj).build(); + } else if (obj instanceof String) { + return Value.newBuilder().setStringValue((String) obj).build(); + } else if(obj instanceof byte[]){ + return Value.newBuilder().setStringValue(new String((byte[]) obj)).build(); + }else if (obj instanceof Boolean) { + return Value.newBuilder().setBoolValue((Boolean) obj).build(); + } else if (obj instanceof List) { + ListValue.Builder listBuilder = ListValue.newBuilder(); + for (Object o : (List) obj) { + listBuilder.addValues(nativeToValue(o)); + } + return Value.newBuilder().setListValue(listBuilder.build()).build(); + } else if (obj instanceof Map) { + Struct.Builder structBuilder = Struct.newBuilder(); + for (Map.Entry entry : ((Map) obj).entrySet()) { + if(!(entry.getKey() instanceof String)) throw new IllegalArgumentException(); + else structBuilder.putFields((String) entry.getKey(), nativeToValue(entry.getValue())); + } + return Value.newBuilder().setStructValue(structBuilder.build()).build(); + + } + else throw new IllegalArgumentException(); + } + + public static Map sensorReadingsNativeToValue(Map readings) { + Map valueMap = new HashMap<>(); + for (Map.Entry entry : readings.entrySet()) { + valueMap.put(entry.getKey(), nativeToValue(entry.getValue())); + } + return valueMap; + } + + public static Map sensorReadingsValueToNative(Map readings) { + Map map = new HashMap<>(); + for (Map.Entry entry : readings.entrySet()) { + map.put(entry.getKey(), valueToNative(entry.getValue())); + + } + return map; + } + + +} \ No newline at end of file diff --git a/core/sdk/src/main/kotlin/com/viam/sdk/core/component/encoder/Encoder.kt b/core/sdk/src/main/kotlin/com/viam/sdk/core/component/encoder/Encoder.kt index b55185917..533e36390 100644 --- a/core/sdk/src/main/kotlin/com/viam/sdk/core/component/encoder/Encoder.kt +++ b/core/sdk/src/main/kotlin/com/viam/sdk/core/component/encoder/Encoder.kt @@ -1,12 +1,14 @@ package com.viam.sdk.core.component.encoder import com.google.protobuf.Struct -import com.viam.component.encoder.v1.Encoder.* import com.viam.common.v1.Common.ResourceName +import com.viam.component.encoder.v1.Encoder.GetPropertiesResponse +import com.viam.component.encoder.v1.Encoder.PositionType import com.viam.sdk.core.component.Component import com.viam.sdk.core.resource.Resource import com.viam.sdk.core.resource.Subtype import com.viam.sdk.core.robot.RobotClient + typealias Properties = GetPropertiesResponse @@ -49,13 +51,13 @@ abstract class Encoder(name: String) : Component(SUBTYPE, named(name)) { /** * Set the current position to be the new zero (home) position. */ - fun resetPosition(){ + fun resetPosition() { resetPosition(Struct.getDefaultInstance()) } /** * Report the position of the encoder. - * The value returned is the current position in terms of it's ``position_type``. + * The value returned is the current position in terms of its ``position_type``. * If no position type is given, the supported position type will be returned. * The position will be either in relative units (ticks away from a zero position) for * ``PositionType.POSITION_TYPE_TICKS_COUNT`` or absolute units (degrees along a circle) @@ -70,7 +72,7 @@ abstract class Encoder(name: String) : Component(SUBTYPE, named(name)) { /** * Report the position of the encoder. - * The value returned is the current position in terms of it's ``position_type``. + * The value returned is the current position in terms of its ``position_type``. * If no position type is given, the supported position type will be returned. * The position will be either in relative units (ticks away from a zero position) for * ``PositionType.POSITION_TYPE_TICKS_COUNT`` or absolute units (degrees along a circle) @@ -79,13 +81,13 @@ abstract class Encoder(name: String) : Component(SUBTYPE, named(name)) { * ticks since last zeroing for a relative encoder or degrees for an absolute encoder, and the second [1] the type of * position the encoder returns (ticks or degrees). */ - fun getPosition(positionType: PositionType): Pair{ + fun getPosition(positionType: PositionType): Pair { return getPosition(positionType, Struct.getDefaultInstance()) } /** * Report the position of the encoder. - * The value returned is the current position in terms of it's ``position_type``. + * The value returned is the current position in terms of its ``position_type``. * If no position type is given, the supported position type will be returned. * The position will be either in relative units (ticks away from a zero position) for * ``PositionType.POSITION_TYPE_TICKS_COUNT`` or absolute units (degrees along a circle) @@ -95,13 +97,13 @@ abstract class Encoder(name: String) : Component(SUBTYPE, named(name)) { * position the encoder returns (ticks or degrees). * */ - fun getPosition( extra: Struct): Pair{ - return getPosition( null, extra) - } + fun getPosition(extra: Struct): Pair { + return getPosition(null, extra) + } /** * Report the position of the encoder. - * The value returned is the current position in terms of it's ``position_type``. + * The value returned is the current position in terms of its ``position_type``. * If no position type is given, the supported position type will be returned. * The position will be either in relative units (ticks away from a zero position) for * ``PositionType.POSITION_TYPE_TICKS_COUNT`` or absolute units (degrees along a circle) @@ -110,7 +112,7 @@ abstract class Encoder(name: String) : Component(SUBTYPE, named(name)) { * ticks since last zeroing for a relative encoder or degrees for an absolute encoder, and the second [1] the type of * position the encoder returns (ticks or degrees). */ - fun getPosition(): Pair{ + fun getPosition(): Pair { return getPosition(null, Struct.getDefaultInstance()) } @@ -126,7 +128,7 @@ abstract class Encoder(name: String) : Component(SUBTYPE, named(name)) { * @return a map of position types to supported status. */ fun getProperties(): Properties { - return getProperties( Struct.getDefaultInstance()) + return getProperties(Struct.getDefaultInstance()) } diff --git a/core/sdk/src/main/kotlin/com/viam/sdk/core/component/encoder/EncoderRPCClient.kt b/core/sdk/src/main/kotlin/com/viam/sdk/core/component/encoder/EncoderRPCClient.kt index 4c97ca79d..ab9272b05 100644 --- a/core/sdk/src/main/kotlin/com/viam/sdk/core/component/encoder/EncoderRPCClient.kt +++ b/core/sdk/src/main/kotlin/com/viam/sdk/core/component/encoder/EncoderRPCClient.kt @@ -4,9 +4,9 @@ import com.google.protobuf.Struct import com.google.protobuf.Value import com.viam.common.v1.Common import com.viam.common.v1.Common.GetGeometriesRequest +import com.viam.component.encoder.v1.Encoder.* import com.viam.component.encoder.v1.EncoderServiceGrpc import com.viam.component.encoder.v1.EncoderServiceGrpc.EncoderServiceBlockingStub -import com.viam.component.encoder.v1.Encoder.* import com.viam.sdk.core.rpc.Channel import java.util.* import kotlin.jvm.optionals.getOrDefault @@ -24,13 +24,15 @@ class EncoderRPCClient(name: String, channel: Channel) : Encoder(name) { } override fun resetPosition(extra: Struct) { - val request = ResetPositionRequest.newBuilder().setName(this.name.name).setExtra(extra).build() + val request = ResetPositionRequest.newBuilder().setName(this.name.name).setExtra(extra).build() this.client.resetPosition(request) } override fun getPosition(positionType: PositionType?, extra: Struct): Pair { val request = GetPositionRequest.newBuilder().setName(this.name.name).setExtra(extra) - if(positionType!=null) {request.setPositionType(positionType)} + if (positionType != null) { + request.setPositionType(positionType) + } val response = this.client.getPosition(request.build()) return (response.value to response.positionType) diff --git a/core/sdk/src/main/kotlin/com/viam/sdk/core/component/encoder/EncoderRPCService.kt b/core/sdk/src/main/kotlin/com/viam/sdk/core/component/encoder/EncoderRPCService.kt index 5fed3c062..03742a02c 100644 --- a/core/sdk/src/main/kotlin/com/viam/sdk/core/component/encoder/EncoderRPCService.kt +++ b/core/sdk/src/main/kotlin/com/viam/sdk/core/component/encoder/EncoderRPCService.kt @@ -24,11 +24,13 @@ internal class EncoderRPCService(private val manager: ResourceManager) : Encoder override fun getPosition(request: GetPositionRequest, responseObserver: StreamObserver) { val encoder = getResource(Encoder.named(request.name)) - val position: Pair = if(request.hasPositionType()) + val position: Pair = if (request.hasPositionType()) encoder.getPosition(request.positionType, request.extra) else encoder.getPosition(request.extra) - responseObserver.onNext(GetPositionResponse.newBuilder().setPositionType(position.second).setValue(position.first).build()) + responseObserver.onNext( + GetPositionResponse.newBuilder().setPositionType(position.second).setValue(position.first).build() + ) responseObserver.onCompleted() } @@ -38,7 +40,10 @@ internal class EncoderRPCService(private val manager: ResourceManager) : Encoder ) { val encoder = getResource(Encoder.named(request.name)) val properties = encoder.getProperties(request.extra) - responseObserver.onNext(GetPropertiesResponse.newBuilder().setTicksCountSupported(properties.ticksCountSupported).setAngleDegreesSupported(properties.angleDegreesSupported).build()) + responseObserver.onNext( + GetPropertiesResponse.newBuilder().setTicksCountSupported(properties.ticksCountSupported) + .setAngleDegreesSupported(properties.angleDegreesSupported).build() + ) responseObserver.onCompleted() } @@ -59,7 +64,7 @@ internal class EncoderRPCService(private val manager: ResourceManager) : Encoder responseObserver.onNext(GetGeometriesResponse.newBuilder().addAllGeometries(result).build()) responseObserver.onCompleted() } - + override fun getResourceClass(): Class { return Encoder::class.java } diff --git a/core/sdk/src/main/kotlin/com/viam/sdk/core/component/gantry/Gantry.kt b/core/sdk/src/main/kotlin/com/viam/sdk/core/component/gantry/Gantry.kt new file mode 100644 index 000000000..589e9d12c --- /dev/null +++ b/core/sdk/src/main/kotlin/com/viam/sdk/core/component/gantry/Gantry.kt @@ -0,0 +1,112 @@ +package com.viam.sdk.core.component.gantry + +import com.google.protobuf.Struct +import com.viam.common.v1.Common.ResourceName +import com.viam.sdk.core.component.Component +import com.viam.sdk.core.resource.Resource +import com.viam.sdk.core.resource.Subtype +import com.viam.sdk.core.robot.RobotClient + +abstract class Gantry(name: String) : Component(SUBTYPE, Gantry.named(name)) { + companion object { + @JvmField + val SUBTYPE = Subtype(Subtype.NAMESPACE_RDK, Subtype.RESOURCE_TYPE_COMPONENT, "gantry") + + /** + * Get the ResourceName of the component + * @param name the name of the component + * @return the component's ResourceName + */ + @JvmStatic + fun named(name: String): ResourceName { + return Resource.named(SUBTYPE, name) + } + + /** + * Get the component with the provided name from the provided robot. + * @param robot the RobotClient + * @param name the name of the component + * @return the component + */ + @JvmStatic + fun fromRobot(robot: RobotClient, name: String): Gantry { + return robot.getResource(Gantry::class.java, named(name)) + } + } + + /** + * Get the positions of the axes of the gantry in millimeters. + * @return the list of the position of the axes of the gantry in millimeters + */ + abstract fun getPosition(extra: Struct): List + + /** + * Get the positions of the axes of the gantry in millimeters. + * @return the list of the position of the axes of the gantry in millimeters + */ + fun getPosition(): List { + return getPosition(Struct.getDefaultInstance()) + } + + /** + * Move the axes of the gantry to the desired positions (mm) at the requested speeds (mm/sec). + * @param positions the list of positions for the axes of the gantry to move to, in millimeters + * @param speeds the list of speeds in millimeters per second for the gantry to move at respective to each axis + */ + abstract fun moveToPosition(positions: List, speeds: List, extra: Struct) + + /** + * Move the axes of the gantry to the desired positions (mm) at the requested speeds (mm/sec). + * @param positions the list of positions for the axes of the gantry to move to, in millimeters + * @param speeds the list of speeds in millimeters per second for the gantry to move at respective to each axis + */ + fun moveToPosition(positions: List, speeds: List) { + return moveToPosition(positions, speeds, Struct.getDefaultInstance()) + } + + /** + * Run the homing sequence of the gantry to re-calibrate the axes with respect to the limit switches. + * @return whether the gantry has run the homing sequence successfully + */ + abstract fun home(extra: Struct): Boolean + + /** + * Run the homing sequence of the gantry to re-calibrate the axes with respect to the limit switches. + * @return whether the gantry has run the homing sequence successfully + */ + fun home(): Boolean { + return home(Struct.getDefaultInstance()) + } + + /** + * Get the lengths of the axes of the gantry in millimeters. + * @return the list of the lengths of the axes of the gantry in millimeters + */ + abstract fun getLengths(extra: Struct): List + + /** + * Get the lengths of the axes of the gantry in millimeters. + * @return the list of the lengths of the axes of the gantry in millimeters + */ + fun getLengths(): List { + return getLengths(Struct.getDefaultInstance()) + } + + /** + *Stop all motion of the gantry. It is assumed that the gantry stops immediately. + */ + abstract fun stop(extra: Struct) + + /** + * Stop all motion of the gantry. It is assumed that the gantry stops immediately. + */ + fun stop() { + stop(Struct.getDefaultInstance()) + } + + /** + * Get if the gantry is currently moving. + * @returns if the gantry is moving + */ + abstract fun isMoving(): Boolean +} \ No newline at end of file diff --git a/core/sdk/src/main/kotlin/com/viam/sdk/core/component/gantry/GantryRPCClient.kt b/core/sdk/src/main/kotlin/com/viam/sdk/core/component/gantry/GantryRPCClient.kt new file mode 100644 index 000000000..db91e2bb2 --- /dev/null +++ b/core/sdk/src/main/kotlin/com/viam/sdk/core/component/gantry/GantryRPCClient.kt @@ -0,0 +1,75 @@ +package com.viam.sdk.core.component.gantry + +import com.google.protobuf.Struct +import com.google.protobuf.Value +import com.viam.common.v1.Common +import com.viam.common.v1.Common.GetGeometriesRequest +import com.viam.component.gantry.v1.Gantry.* +import com.viam.component.gantry.v1.GantryServiceGrpc +import com.viam.component.gantry.v1.GantryServiceGrpc.GantryServiceBlockingStub +import com.viam.sdk.core.rpc.Channel +import java.util.* +import kotlin.jvm.optionals.getOrDefault + +class GantryRPCClient(name: String, channel: Channel) : Gantry(name) { + private val client: GantryServiceBlockingStub + + init { + val client = GantryServiceGrpc.newBlockingStub(channel) + if (channel.callCredentials.isPresent) { + this.client = client.withCallCredentials(channel.callCredentials.get()) + } else { + this.client = client + } + } + + override fun getPosition(extra: Struct): List { + val request = GetPositionRequest.newBuilder().setName(this.name.name).setExtra(extra).build() + val response = this.client.getPosition(request) + return response.positionsMmList + } + + override fun moveToPosition(positions: List, speeds: List, extra: Struct) { + val request =MoveToPositionRequest.newBuilder().setName(this.name.name).setExtra(extra).addAllPositionsMm(positions).addAllSpeedsMmPerSec(speeds).build() + this.client.moveToPosition(request) + } + + override fun home(extra: Struct): Boolean { + val request = HomeRequest.newBuilder().setName(this.name.name).setExtra(extra).build() + val response = this.client.home(request) + return response.homed + } + + override fun getLengths(extra: Struct): List { + val request = GetLengthsRequest.newBuilder().setName(this.name.name).setExtra(extra).build() + val response = this.client.getLengths(request) + return response.lengthsMmList + } + + override fun stop(extra: Struct) { + val request = StopRequest.newBuilder().setName(this.name.name).setExtra(extra).build() + this.client.stop(request) + } + + override fun isMoving(): Boolean { + val request = IsMovingRequest.newBuilder().setName(this.name.name).build() + val response = this.client.isMoving(request) + return response.isMoving + } + + override fun doCommand(command: Map?): Struct { + val request = Common.DoCommandRequest.newBuilder().setName(this.name.name) + .setCommand(Struct.newBuilder().putAllFields(command).build()).build() + val response = this.client.doCommand(request) + return response.result + } + + override fun getGeometries(extra: Optional): List { + val request = GetGeometriesRequest.newBuilder().setName(this.name.name) + .setExtra(extra.getOrDefault(Struct.getDefaultInstance())).build() + val response = this.client.getGeometries(request) + return response.geometriesList + } + + +} \ No newline at end of file diff --git a/core/sdk/src/main/kotlin/com/viam/sdk/core/component/gantry/GantryRPCService.kt b/core/sdk/src/main/kotlin/com/viam/sdk/core/component/gantry/GantryRPCService.kt new file mode 100644 index 000000000..4b8261571 --- /dev/null +++ b/core/sdk/src/main/kotlin/com/viam/sdk/core/component/gantry/GantryRPCService.kt @@ -0,0 +1,88 @@ +package com.viam.sdk.core.component.gantry + +import com.viam.common.v1.Common.* +import com.viam.component.gantry.v1.Gantry.* +import com.viam.component.gantry.v1.GantryServiceGrpc +import com.viam.sdk.core.component.motor.Motor +import com.viam.sdk.core.resource.ResourceManager +import com.viam.sdk.core.resource.ResourceRPCService +import io.grpc.stub.StreamObserver +import java.util.* + +internal class GantryRPCService(private val manager: ResourceManager) : GantryServiceGrpc.GantryServiceImplBase(), + ResourceRPCService { + + override fun getPosition( + request: GetPositionRequest, responseObserver: StreamObserver + ) { + val gantry = getResource(Gantry.named(request.name)) + val position = gantry.getPosition(request.extra) + responseObserver.onNext(GetPositionResponse.newBuilder().addAllPositionsMm(position).build()) + responseObserver.onCompleted() + } + + override fun moveToPosition( + request: MoveToPositionRequest, responseObserver: StreamObserver + ) { + val gantry = getResource(Gantry.named(request.name)) + gantry.moveToPosition(request.positionsMmList, request.speedsMmPerSecList, request.extra) + responseObserver.onNext(MoveToPositionResponse.newBuilder().build()) + responseObserver.onCompleted() + } + + override fun home(request: HomeRequest, responseObserver: StreamObserver) { + val gantry = getResource(Gantry.named(request.name)) + val homed = gantry.home(request.extra) + responseObserver.onNext(HomeResponse.newBuilder().setHomed(homed).build()) + responseObserver.onCompleted() + } + + override fun getLengths(request: GetLengthsRequest, responseObserver: StreamObserver) { + val gantry = getResource(Gantry.named(request.name)) + val lengths = gantry.getLengths(request.extra) + responseObserver.onNext(GetLengthsResponse.newBuilder().addAllLengthsMm(lengths).build()) + responseObserver.onCompleted() + } + + override fun stop(request: StopRequest, responseObserver: StreamObserver) { + val gantry = getResource(Gantry.named(request.name)) + gantry.stop(request.extra) + responseObserver.onNext(StopResponse.newBuilder().build()) + responseObserver.onCompleted() + } + + override fun isMoving(request: IsMovingRequest, responseObserver: StreamObserver) { + val gantry = getResource(Gantry.named(request.name)) + val bool = gantry.isMoving() + responseObserver.onNext(IsMovingResponse.newBuilder().setIsMoving(bool).build()) + responseObserver.onCompleted() + } + + override fun doCommand( + request: DoCommandRequest, responseObserver: StreamObserver + ) { + val gantry = getResource(Gantry.named(request.name)) + val result = gantry.doCommand(request.command.fieldsMap) + responseObserver.onNext(DoCommandResponse.newBuilder().setResult(result).build()) + responseObserver.onCompleted() + } + + override fun getGeometries( + request: GetGeometriesRequest, responseObserver: StreamObserver + ) { + val motor = getResource(Gantry.named(request.name)) + val result = motor.getGeometries(Optional.of(request.extra)) + responseObserver.onNext(GetGeometriesResponse.newBuilder().addAllGeometries(result).build()) + responseObserver.onCompleted() + } + + + override fun getResourceClass(): Class { + return Gantry::class.java + } + + override fun getManager(): ResourceManager { + return this.manager + } + +} \ No newline at end of file diff --git a/core/sdk/src/test/kotlin/com/viam/sdk/core/component/encoder/EncoderRPCClientTest.kt b/core/sdk/src/test/kotlin/com/viam/sdk/core/component/encoder/EncoderRPCClientTest.kt index 212ba3267..4081a7888 100644 --- a/core/sdk/src/test/kotlin/com/viam/sdk/core/component/encoder/EncoderRPCClientTest.kt +++ b/core/sdk/src/test/kotlin/com/viam/sdk/core/component/encoder/EncoderRPCClientTest.kt @@ -3,7 +3,8 @@ package com.viam.sdk.core.component.encoder import com.google.protobuf.Struct import com.google.protobuf.Value import com.viam.common.v1.Common.Geometry -import com.viam.component.encoder.v1.Encoder.* +import com.viam.component.encoder.v1.Encoder.GetPropertiesResponse +import com.viam.component.encoder.v1.Encoder.PositionType import com.viam.sdk.core.resource.ResourceManager import com.viam.sdk.core.rpc.BasicManagedChannel import io.grpc.inprocess.InProcessChannelBuilder @@ -43,14 +44,24 @@ class EncoderRPCClientTest { } @Test - fun getPosition(){ - `when`(encoder.getPosition(eq(null),any(Struct::class.java) ?: Struct.getDefaultInstance())).thenReturn(23.0f to PositionType.POSITION_TYPE_TICKS_COUNT) + fun getPosition() { + `when`( + encoder.getPosition( + eq(null), + any(Struct::class.java) ?: Struct.getDefaultInstance() + ) + ).thenReturn(23.0f to PositionType.POSITION_TYPE_TICKS_COUNT) var pos = client.getPosition() verify(encoder).getPosition(Struct.getDefaultInstance()) assertEquals(23.0f, pos.first) assertEquals(PositionType.POSITION_TYPE_TICKS_COUNT, pos.second) - `when`(encoder.getPosition(eq(PositionType.POSITION_TYPE_ANGLE_DEGREES),any(Struct::class.java) ?: Struct.getDefaultInstance())).thenReturn(23.0f to PositionType.POSITION_TYPE_ANGLE_DEGREES) + `when`( + encoder.getPosition( + eq(PositionType.POSITION_TYPE_ANGLE_DEGREES), + any(Struct::class.java) ?: Struct.getDefaultInstance() + ) + ).thenReturn(23.0f to PositionType.POSITION_TYPE_ANGLE_DEGREES) pos = client.getPosition(PositionType.POSITION_TYPE_ANGLE_DEGREES) verify(encoder).getPosition(PositionType.POSITION_TYPE_ANGLE_DEGREES, Struct.getDefaultInstance()) assertEquals(23.0f, pos.first) @@ -58,20 +69,22 @@ class EncoderRPCClientTest { } @Test - fun resetPosition(){ + fun resetPosition() { client.resetPosition() verify(encoder).resetPosition(Struct.getDefaultInstance()) } @Test - fun getProperties(){ + fun getProperties() { `when`(encoder.getProperties(any(Struct::class.java) ?: Struct.getDefaultInstance())).thenReturn( - GetPropertiesResponse.newBuilder().setAngleDegreesSupported(true).setTicksCountSupported(true).build()) + GetPropertiesResponse.newBuilder().setAngleDegreesSupported(true).setTicksCountSupported(true).build() + ) val properties = client.getProperties() verify(encoder).getProperties(Struct.getDefaultInstance()) assertTrue(properties.ticksCountSupported) assertTrue(properties.angleDegreesSupported) } + @Test fun doCommand() { val command = mapOf("foo" to Value.newBuilder().setStringValue("bar").build()) diff --git a/core/sdk/src/test/kotlin/com/viam/sdk/core/component/encoder/EncoderRPCServiceTest.kt b/core/sdk/src/test/kotlin/com/viam/sdk/core/component/encoder/EncoderRPCServiceTest.kt index 9860c8476..ab10f8948 100644 --- a/core/sdk/src/test/kotlin/com/viam/sdk/core/component/encoder/EncoderRPCServiceTest.kt +++ b/core/sdk/src/test/kotlin/com/viam/sdk/core/component/encoder/EncoderRPCServiceTest.kt @@ -4,9 +4,9 @@ import com.google.protobuf.Struct import com.google.protobuf.Value import com.viam.common.v1.Common import com.viam.common.v1.Common.Geometry +import com.viam.component.encoder.v1.Encoder.* import com.viam.component.encoder.v1.EncoderServiceGrpc import com.viam.component.encoder.v1.EncoderServiceGrpc.EncoderServiceBlockingStub -import com.viam.component.encoder.v1.Encoder.* import com.viam.sdk.core.resource.ResourceManager import io.grpc.inprocess.InProcessChannelBuilder import io.grpc.inprocess.InProcessServerBuilder @@ -49,42 +49,54 @@ class EncoderRPCServiceTest { } @Test - fun getPosition(){ - `when`(encoder.getPosition(eq(null),any(Struct::class.java) ?: Struct.getDefaultInstance())).thenReturn(23.0f to PositionType.POSITION_TYPE_TICKS_COUNT) + fun getPosition() { + `when`( + encoder.getPosition( + eq(null), + any(Struct::class.java) ?: Struct.getDefaultInstance() + ) + ).thenReturn(23.0f to PositionType.POSITION_TYPE_TICKS_COUNT) var request = GetPositionRequest.newBuilder().setName(encoder.name.name).build() var pos = client.getPosition(request) verify(encoder).getPosition(Struct.getDefaultInstance()) assertEquals(23.0f, pos.value) assertEquals(PositionType.POSITION_TYPE_TICKS_COUNT, pos.positionType) - `when`(encoder.getPosition(eq(PositionType.POSITION_TYPE_ANGLE_DEGREES),any(Struct::class.java) ?: Struct.getDefaultInstance())).thenReturn(23.0f to PositionType.POSITION_TYPE_ANGLE_DEGREES) - request = GetPositionRequest.newBuilder().setName(encoder.name.name).setPositionType(PositionType.POSITION_TYPE_ANGLE_DEGREES).build() + `when`( + encoder.getPosition( + eq(PositionType.POSITION_TYPE_ANGLE_DEGREES), + any(Struct::class.java) ?: Struct.getDefaultInstance() + ) + ).thenReturn(23.0f to PositionType.POSITION_TYPE_ANGLE_DEGREES) + request = GetPositionRequest.newBuilder().setName(encoder.name.name) + .setPositionType(PositionType.POSITION_TYPE_ANGLE_DEGREES).build() pos = client.getPosition(request) verify(encoder).getPosition(PositionType.POSITION_TYPE_ANGLE_DEGREES, Struct.getDefaultInstance()) assertEquals(23.0f, pos.value) assertEquals(PositionType.POSITION_TYPE_ANGLE_DEGREES, pos.positionType) } - + @Test - fun resetPosition(){ + fun resetPosition() { val request = ResetPositionRequest.newBuilder().setName(encoder.name.name).build() client.resetPosition(request) verify(encoder).resetPosition(Struct.getDefaultInstance()) } - + @Test - fun getProperties(){ + fun getProperties() { `when`(encoder.getProperties(any(Struct::class.java) ?: Struct.getDefaultInstance())).thenReturn( - GetPropertiesResponse.newBuilder().setAngleDegreesSupported(true).setTicksCountSupported(true).build()) + GetPropertiesResponse.newBuilder().setAngleDegreesSupported(true).setTicksCountSupported(true).build() + ) val request = GetPropertiesRequest.newBuilder().setName(encoder.name.name).build() val properties = client.getProperties(request) verify(encoder).getProperties(Struct.getDefaultInstance()) assertTrue(properties.ticksCountSupported) assertTrue(properties.angleDegreesSupported) } - + @Test - fun doCommand(){ + fun doCommand() { val command = Struct.newBuilder().putAllFields(mapOf("foo" to Value.newBuilder().setStringValue("bar").build())).build() doReturn(command).`when`(encoder).doCommand(anyMap()) @@ -93,9 +105,9 @@ class EncoderRPCServiceTest { verify(encoder).doCommand(command.fieldsMap) assertEquals(command, response.result) } - + @Test - fun getGeometries(){ + fun getGeometries() { doReturn(listOf()).`when`(encoder).getGeometries(any()) val request = Common.GetGeometriesRequest.newBuilder().setName(encoder.name.name).build() client.getGeometries(request) diff --git a/core/sdk/src/test/kotlin/com/viam/sdk/core/component/encoder/EncoderTest.kt b/core/sdk/src/test/kotlin/com/viam/sdk/core/component/encoder/EncoderTest.kt index eecd7e0e6..4714115a8 100644 --- a/core/sdk/src/test/kotlin/com/viam/sdk/core/component/encoder/EncoderTest.kt +++ b/core/sdk/src/test/kotlin/com/viam/sdk/core/component/encoder/EncoderTest.kt @@ -1,7 +1,8 @@ package com.viam.sdk.core.component.encoder import com.google.protobuf.Struct -import com.viam.component.encoder.v1.Encoder.* +import com.viam.component.encoder.v1.Encoder.GetPropertiesResponse +import com.viam.component.encoder.v1.Encoder.PositionType import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Assertions.assertTrue import org.junit.jupiter.api.BeforeEach @@ -18,32 +19,43 @@ class EncoderTest { } @Test - fun getPosition(){ + fun getPosition() { //test no position type given - `when`(encoder.getPosition(eq(null), any(Struct::class.java) ?: Struct.getDefaultInstance())).thenReturn(23.0f to PositionType.POSITION_TYPE_TICKS_COUNT) + `when`( + encoder.getPosition( + eq(null), + any(Struct::class.java) ?: Struct.getDefaultInstance() + ) + ).thenReturn(23.0f to PositionType.POSITION_TYPE_TICKS_COUNT) var pos = encoder.getPosition() verify(encoder).getPosition() assertEquals(23.0f, pos.first) assertEquals(PositionType.POSITION_TYPE_TICKS_COUNT, pos.second) //test position type given - `when`(encoder.getPosition(eq(PositionType.POSITION_TYPE_ANGLE_DEGREES),any(Struct::class.java) ?: Struct.getDefaultInstance())).thenReturn(23.0f to PositionType.POSITION_TYPE_ANGLE_DEGREES) + `when`( + encoder.getPosition( + eq(PositionType.POSITION_TYPE_ANGLE_DEGREES), + any(Struct::class.java) ?: Struct.getDefaultInstance() + ) + ).thenReturn(23.0f to PositionType.POSITION_TYPE_ANGLE_DEGREES) pos = encoder.getPosition(PositionType.POSITION_TYPE_ANGLE_DEGREES) verify(encoder).getPosition(PositionType.POSITION_TYPE_ANGLE_DEGREES) assertEquals(23.0f, pos.first) assertEquals(PositionType.POSITION_TYPE_ANGLE_DEGREES, pos.second) } - + @Test - fun resetPosition(){ + fun resetPosition() { encoder.resetPosition() verify(encoder).resetPosition() } - + @Test - fun getProperties(){ + fun getProperties() { `when`(encoder.getProperties(any(Struct::class.java) ?: Struct.getDefaultInstance())).thenReturn( - GetPropertiesResponse.newBuilder().setAngleDegreesSupported(true).setTicksCountSupported(true).build()) + GetPropertiesResponse.newBuilder().setAngleDegreesSupported(true).setTicksCountSupported(true).build() + ) val properties = encoder.getProperties() verify(encoder).getProperties() assertTrue(properties.ticksCountSupported) diff --git a/core/sdk/src/test/kotlin/com/viam/sdk/core/component/gantry/GantryRPCClientTest.kt b/core/sdk/src/test/kotlin/com/viam/sdk/core/component/gantry/GantryRPCClientTest.kt new file mode 100644 index 000000000..b31fb8bc4 --- /dev/null +++ b/core/sdk/src/test/kotlin/com/viam/sdk/core/component/gantry/GantryRPCClientTest.kt @@ -0,0 +1,108 @@ +package com.viam.sdk.core.component.gantry + +import com.google.protobuf.Struct +import com.google.protobuf.Value +import com.viam.common.v1.Common.Geometry +import com.viam.sdk.core.resource.ResourceManager +import com.viam.sdk.core.rpc.BasicManagedChannel +import io.grpc.inprocess.InProcessChannelBuilder +import io.grpc.inprocess.InProcessServerBuilder +import io.grpc.testing.GrpcCleanupRule +import org.junit.Rule +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertFalse +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.mockito.Mockito.* +import java.util.* + +class GantryRPCClientTest { + private lateinit var gantry: Gantry + private lateinit var client: GantryRPCClient + + @JvmField + @Rule + val grpcCleanupRule: GrpcCleanupRule = GrpcCleanupRule() + + @BeforeEach + fun setup() { + gantry = mock( + Gantry::class.java, withSettings().useConstructor("mock-gantry").defaultAnswer( + CALLS_REAL_METHODS + ) + ) + val resourceManager = ResourceManager(listOf(gantry)) + val service = GantryRPCService(resourceManager) + val serviceName = InProcessServerBuilder.generateName() + grpcCleanupRule.register( + InProcessServerBuilder.forName(serviceName).directExecutor().addService(service).build().start() + ) + val channel = grpcCleanupRule.register(InProcessChannelBuilder.forName(serviceName).directExecutor().build()) + client = GantryRPCClient("mock-gantry", BasicManagedChannel(channel)) + } + + + @Test + fun getPosition(){ + `when`(gantry.getPosition(any(Struct::class.java) ?: Struct.getDefaultInstance())).thenReturn(listOf(2.3, 1.2)) + val pos = client.getPosition() + verify(gantry).getPosition(Struct.getDefaultInstance()) + assertEquals(listOf(2.3, 1.2), pos) + + } + + @Test + fun moveToPosition(){ + client.moveToPosition(listOf(1.2, 3.4), listOf(5.6, 7.8)) + verify(gantry).moveToPosition( listOf(1.2, 3.4), listOf(5.6, 7.8), Struct.getDefaultInstance()) + + } + + @Test + fun home(){ + `when`(gantry.home(any(Struct::class.java) ?: Struct.getDefaultInstance())).thenReturn(true) + val home = client.home() + verify(gantry).home(Struct.getDefaultInstance()) + assertEquals(true, home) + + } + + @Test + fun getLengths(){ + `when`(gantry.getLengths(any(Struct::class.java) ?: Struct.getDefaultInstance())).thenReturn(listOf(32.1)) + val response = client.getLengths() + verify(gantry).getLengths(Struct.getDefaultInstance()) + assertEquals(listOf(32.1), response) + } + + @Test + fun stop(){ + client.stop() + verify(gantry).stop(Struct.getDefaultInstance()) + + } + + @Test + fun isMoving(){ + `when`(gantry.isMoving()).thenReturn(false) + val isMoving = client.isMoving() + verify(gantry).isMoving() + assertFalse(isMoving) + + } + @Test + fun doCommand() { + val command = mapOf("foo" to Value.newBuilder().setStringValue("bar").build()) + doReturn(Struct.newBuilder().putAllFields(command).build()).`when`(gantry).doCommand(anyMap()) + val response = client.doCommand(command) + verify(gantry).doCommand(command) + assertEquals(command, response.fieldsMap) + } + + @Test + fun getGeometries() { + doReturn(listOf()).`when`(gantry).getGeometries(any()) + client.getGeometries(Optional.empty()) + verify(gantry).getGeometries(any()) + } +} \ No newline at end of file diff --git a/core/sdk/src/test/kotlin/com/viam/sdk/core/component/gantry/GantryRPCServiceTest.kt b/core/sdk/src/test/kotlin/com/viam/sdk/core/component/gantry/GantryRPCServiceTest.kt new file mode 100644 index 000000000..c89aa672e --- /dev/null +++ b/core/sdk/src/test/kotlin/com/viam/sdk/core/component/gantry/GantryRPCServiceTest.kt @@ -0,0 +1,124 @@ +package com.viam.sdk.core.component.gantry + +import com.google.protobuf.Struct +import com.google.protobuf.Value +import com.viam.common.v1.Common +import com.viam.common.v1.Common.Geometry +import com.viam.component.gantry.v1.GantryServiceGrpc +import com.viam.component.gantry.v1.GantryServiceGrpc.GantryServiceBlockingStub +import com.viam.component.gantry.v1.Gantry.* +import com.viam.sdk.core.resource.ResourceManager +import io.grpc.inprocess.InProcessChannelBuilder +import io.grpc.inprocess.InProcessServerBuilder +import io.grpc.testing.GrpcCleanupRule +import org.junit.Rule +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertFalse +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.mockito.Mockito.* +import java.util.* + +class GantryRPCServiceTest { + private lateinit var gantry: Gantry + private lateinit var client: GantryServiceBlockingStub + + @JvmField + @Rule + val grpcCleanupRule: GrpcCleanupRule = GrpcCleanupRule() + + @BeforeEach + fun setup() { + gantry = mock( + Gantry::class.java, withSettings().useConstructor("mock-gantry").defaultAnswer( + CALLS_REAL_METHODS + ) + ) + + val resourceManager = ResourceManager(listOf(gantry)) + val service = GantryRPCService(resourceManager) + val serviceName = InProcessServerBuilder.generateName() + grpcCleanupRule.register( + InProcessServerBuilder.forName(serviceName).directExecutor().addService(service).build().start() + ) + client = GantryServiceGrpc.newBlockingStub( + grpcCleanupRule.register( + InProcessChannelBuilder.forName(serviceName).build() + ) + ) + } + + @Test + fun getPosition(){ + `when`(gantry.getPosition(any(Struct::class.java) ?: Struct.getDefaultInstance())).thenReturn(listOf(32.1)) + val request = GetPositionRequest.newBuilder().setName(gantry.name.name).build() + val response = client.getPosition(request) + verify(gantry).getPosition(Struct.getDefaultInstance()) + assertEquals(listOf(32.1), response.positionsMmList) + + } + + @Test + fun moveToPosition(){ + val request = MoveToPositionRequest.newBuilder().setName(gantry.name.name).addAllPositionsMm(listOf(1.2, 3.4)).addAllSpeedsMmPerSec(listOf(5.6, 7.8)).build() + client.moveToPosition(request) + verify(gantry).moveToPosition( listOf(1.2, 3.4), listOf(5.6, 7.8), Struct.getDefaultInstance()) + } + + @Test + fun home(){ + `when`(gantry.home(any(Struct::class.java) ?: Struct.getDefaultInstance())).thenReturn(true) + val request = HomeRequest.newBuilder().setName(gantry.name.name).build() + val home = client.home(request) + verify(gantry).home(Struct.getDefaultInstance()) + assertEquals(true, home.homed) + + } + + @Test + fun getLengths(){ + `when`(gantry.getLengths(any(Struct::class.java) ?: Struct.getDefaultInstance())).thenReturn(listOf(32.1)) + val request = GetLengthsRequest.newBuilder().setName(gantry.name.name).build() + val response = client.getLengths(request) + verify(gantry).getLengths(Struct.getDefaultInstance()) + assertEquals(listOf(32.1), response.lengthsMmList) + + } + + @Test + fun stop(){ + val request = StopRequest.newBuilder().setName(gantry.name.name).build() + client.stop(request) + verify(gantry).stop(Struct.getDefaultInstance()) + + } + + @Test + fun isMoving(){ + `when`(gantry.isMoving()).thenReturn(false) + val request = IsMovingRequest.newBuilder().setName(gantry.name.name).build() + val response = client.isMoving(request) + verify(gantry).isMoving() + assertFalse(response.isMoving) + + } + + @Test + fun doCommand() { + val command = + Struct.newBuilder().putAllFields(mapOf("foo" to Value.newBuilder().setStringValue("bar").build())).build() + doReturn(command).`when`(gantry).doCommand(anyMap()) + val request = Common.DoCommandRequest.newBuilder().setName(gantry.name.name).setCommand(command).build() + val response = client.doCommand(request) + verify(gantry).doCommand(command.fieldsMap) + assertEquals(command, response.result) + } + + @Test + fun getGeometries() { + doReturn(listOf()).`when`(gantry).getGeometries(any()) + val request = Common.GetGeometriesRequest.newBuilder().setName(gantry.name.name).build() + client.getGeometries(request) + verify(gantry).getGeometries(Optional.of(Struct.getDefaultInstance())) + } +} \ No newline at end of file diff --git a/core/sdk/src/test/kotlin/com/viam/sdk/core/component/gantry/GantryTest.kt b/core/sdk/src/test/kotlin/com/viam/sdk/core/component/gantry/GantryTest.kt new file mode 100644 index 000000000..14e9a3db2 --- /dev/null +++ b/core/sdk/src/test/kotlin/com/viam/sdk/core/component/gantry/GantryTest.kt @@ -0,0 +1,68 @@ +package com.viam.sdk.core.component.gantry + +import com.google.protobuf.Struct +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertFalse +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.mockito.Answers +import org.mockito.Mockito.* + +class GantryTest { + private lateinit var gantry: Gantry + + @BeforeEach + fun setup() { + gantry = mock(Gantry::class.java, Answers.CALLS_REAL_METHODS) + } + + @Test + fun getPosition(){ + `when`(gantry.getPosition(any(Struct::class.java) ?: Struct.getDefaultInstance())).thenReturn(listOf(12.3, 23.4)) + val pos = gantry.getPosition() + verify(gantry).getPosition() + assertEquals(listOf(12.3, 23.4), pos) + + } + + @Test + fun moveToPosition(){ + gantry.moveToPosition(listOf(2.0, 3.0), listOf(1.0, 2.0, 3.0)) + verify(gantry).moveToPosition(listOf(2.0, 3.0), listOf(1.0, 2.0, 3.0)) + + } + + @Test + fun home(){ + `when`(gantry.home(any(Struct::class.java) ?: Struct.getDefaultInstance())).thenReturn(true) + val home = gantry.home() + verify(gantry).home() + assertEquals(true, home) + + } + + @Test + fun getLengths(){ + `when`(gantry.getLengths(any(Struct::class.java) ?: Struct.getDefaultInstance())).thenReturn(listOf(12.3, 23.4)) + val lengths = gantry.getLengths() + verify(gantry).getLengths() + assertEquals(listOf(12.3, 23.4), lengths) + + } + + @Test + fun stop(){ + gantry.stop() + verify(gantry).stop() + + } + + @Test + fun isMoving(){ + `when`(gantry.isMoving()).thenReturn(false) + val isMoving = gantry.isMoving() + verify(gantry).isMoving() + assertFalse(isMoving) + + } +} \ No newline at end of file diff --git a/core/sdk/src/test/kotlin/com/viam/sdk/core/component/powersensor/PowerSensorRPCClientTest.kt b/core/sdk/src/test/kotlin/com/viam/sdk/core/component/powersensor/PowerSensorRPCClientTest.kt new file mode 100644 index 000000000..c42425789 --- /dev/null +++ b/core/sdk/src/test/kotlin/com/viam/sdk/core/component/powersensor/PowerSensorRPCClientTest.kt @@ -0,0 +1,99 @@ +package com.viam.sdk.core.component.powersensor + +import com.google.protobuf.Struct +import com.google.protobuf.Value +import com.viam.common.v1.Common +import com.viam.sdk.core.resource.ResourceManager +import com.viam.sdk.core.rpc.BasicManagedChannel +import io.grpc.inprocess.InProcessChannelBuilder +import io.grpc.inprocess.InProcessServerBuilder +import io.grpc.testing.GrpcCleanupRule +import org.junit.Rule +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertTrue +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.mockito.Mockito.* +import java.util.* +import java.util.AbstractMap + +class PowerSensorRPCClientTest { + private lateinit var powerSensor: PowerSensor + private lateinit var client: PowerSensorRPCClient + + val extra = + Struct.newBuilder().putAllFields(mapOf("foo" to Value.newBuilder().setStringValue("bar").build())).build() + + @JvmField + @Rule + val grpcCleanupRule: GrpcCleanupRule = GrpcCleanupRule() + + @BeforeEach + fun setup() { + powerSensor = mock( + PowerSensor::class.java, withSettings().useConstructor("mock-powersensor").defaultAnswer( + CALLS_REAL_METHODS + ) + ) + val resourceManager = ResourceManager(listOf(powerSensor)) + val service = PowerSensorRPCService(resourceManager) + val serviceName = InProcessServerBuilder.generateName() + grpcCleanupRule.register( + InProcessServerBuilder.forName(serviceName).directExecutor().addService(service).build().start() + ) + val channel = grpcCleanupRule.register(InProcessChannelBuilder.forName(serviceName).directExecutor().build()) + client = PowerSensorRPCClient("mock-powersensor", BasicManagedChannel(channel)) + } + + @Test + fun getVoltage() { + `when`(powerSensor.getVoltage(any>())).thenReturn(AbstractMap.SimpleEntry(3.0, true)) + val response = client.getVoltage(Optional.of(extra)) + verify(powerSensor).getVoltage(Optional.of(extra)) + assertEquals(3.0, response.key) + assertTrue(response.value) + } + + @Test + fun getCurrent() { + `when`(powerSensor.getCurrent(any>())).thenReturn(AbstractMap.SimpleEntry(3.0, true)) + val response = client.getCurrent(Optional.of(extra)) + verify(powerSensor).getCurrent(Optional.of(extra)) + assertEquals(3.0, response.key) + assertTrue(response.value) + + } + + @Test + fun getPower() { + `when`(powerSensor.getPower(any>())).thenReturn(2.1) + val response = client.getPower(Optional.of(extra)) + verify(powerSensor).getPower(Optional.of(extra)) + assertEquals(2.1, response) + } + + @Test + fun getReadings() { + val readings = mapOf( + "a" to 1.0, + "b" to 2.0, + "c" to 3.0, + "d" to mapOf("vec3" to Common.Vector3.newBuilder().setX(1.0).setY(1.0).setZ(1.0).build()) + ) + `when`(powerSensor.getReadings(any>())).thenReturn(readings) + val response = client.getReadings(Optional.of(extra)) + verify(powerSensor).getReadings(Optional.of(extra)) + assertEquals(readings, response) + + } + + @Test + fun doCommand() { + val command = mapOf("abc" to Value.newBuilder().setStringValue("123").build()) + doReturn(Struct.newBuilder().putAllFields(command).build()).`when`(powerSensor).doCommand(anyMap()) + val response = client.doCommand(command) + verify(powerSensor).doCommand(command) + assertEquals(command, response.fieldsMap) + } + +} \ No newline at end of file diff --git a/core/sdk/src/test/kotlin/com/viam/sdk/core/component/powersensor/PowerSensorRPCServiceTest.kt b/core/sdk/src/test/kotlin/com/viam/sdk/core/component/powersensor/PowerSensorRPCServiceTest.kt new file mode 100644 index 000000000..6d1baf77b --- /dev/null +++ b/core/sdk/src/test/kotlin/com/viam/sdk/core/component/powersensor/PowerSensorRPCServiceTest.kt @@ -0,0 +1,117 @@ +package com.viam.sdk.core.component.powersensor +import com.google.protobuf.Struct +import com.google.protobuf.Value +import com.viam.common.v1.Common +import com.viam.component.powersensor.v1.Powersensor.* +import com.viam.component.powersensor.v1.PowerSensorServiceGrpc +import com.viam.component.powersensor.v1.PowerSensorServiceGrpc.PowerSensorServiceBlockingStub +import com.viam.sdk.core.resource.ResourceManager +import io.grpc.inprocess.InProcessChannelBuilder +import io.grpc.inprocess.InProcessServerBuilder +import io.grpc.testing.GrpcCleanupRule +import org.junit.Rule +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.mockito.Mockito.* +import java.util.* +class PowerSensorRPCServiceTest { + private lateinit var powerSensor: PowerSensor + private lateinit var client: PowerSensorServiceBlockingStub + + val extra = + Struct.newBuilder().putAllFields(mapOf("foo" to Value.newBuilder().setStringValue("bar").build())).build() + + @JvmField + @Rule + val grpcCleanupRule: GrpcCleanupRule = GrpcCleanupRule() + + @BeforeEach + fun setup() { + powerSensor = mock( + PowerSensor::class.java, withSettings().useConstructor("mock-powersensor").defaultAnswer( + CALLS_REAL_METHODS + ) + ) + + val resourceManager = ResourceManager(listOf(powerSensor)) + val service = PowerSensorRPCService(resourceManager) + val serviceName = InProcessServerBuilder.generateName() + grpcCleanupRule.register( + InProcessServerBuilder.forName(serviceName).directExecutor().addService(service).build().start() + ) + client = PowerSensorServiceGrpc.newBlockingStub( + grpcCleanupRule.register( + InProcessChannelBuilder.forName(serviceName).build() + ) + ) + } + @Test + fun getVoltage(){ + `when`(powerSensor.getVoltage(any>())).thenReturn(AbstractMap.SimpleEntry(3.0, true)) + val request = GetVoltageRequest.newBuilder().setName(powerSensor.name.name).setExtra(extra).build() + val response = client.getVoltage(request) + verify(powerSensor).getVoltage(Optional.of(extra)) + assertEquals(3.0, response.volts) + assertTrue(response.isAc) + + } + @Test + fun getCurrent(){ + `when`(powerSensor.getCurrent(any>())).thenReturn(AbstractMap.SimpleEntry(3.0, true)) + val request = GetCurrentRequest.newBuilder().setName(powerSensor.name.name).setExtra(extra).build() + val response = client.getCurrent(request) + verify(powerSensor).getCurrent(Optional.of(extra)) + assertEquals(3.0, response.amperes) + assertTrue(response.isAc) + } + @Test + fun getPower(){ + `when`(powerSensor.getPower(any>())).thenReturn(2.0) + val request = GetPowerRequest.newBuilder().setName(powerSensor.name.name).setExtra(extra).build() + val response = client.getPower(request) + verify(powerSensor).getPower(Optional.of(extra)) + assertEquals(2.0, response.watts) + + } + @Test + fun getReadings(){ + val readings = mapOf( + "a" to 1.0, + "b" to 2.0, + "c" to 3.0, + "d" to mapOf("vec3" to Common.Vector3.newBuilder().setX(1.0).setY(1.0).setZ(1.0).build()) + ) + val struct = Struct.newBuilder().apply{ + putFields("x", Value.newBuilder().setNumberValue(1.0).build()) + putFields("y", Value.newBuilder().setNumberValue(1.0).build()) + putFields("z", Value.newBuilder().setNumberValue(1.0).build()) + putFields("_type", Value.newBuilder().setStringValue("vector3").build()) + }.build() + + val valueReadings = mapOf("a" to Value.newBuilder().setNumberValue(1.0).build(), + "b" to Value.newBuilder().setNumberValue(2.0).build(), + "c" to Value.newBuilder().setNumberValue(3.0).build(), + "d" to Value.newBuilder().setStructValue(Struct.newBuilder().putAllFields(mapOf("vec3" to Value.newBuilder().setStructValue(struct).build()))).build()) + `when`(powerSensor.getReadings(any>())).thenReturn(readings) + val request = Common.GetReadingsRequest.newBuilder().setName(powerSensor.name.name).setExtra(extra).build() + val response = client.getReadings(request) + verify(powerSensor).getReadings(Optional.of(extra)) + assertEquals(valueReadings, response.readingsMap) + + + } + + @Test + fun doCommand() { + val command = + Struct.newBuilder().putAllFields(mapOf("foo" to Value.newBuilder().setStringValue("bar").build())).build() + doReturn(command).`when`(powerSensor).doCommand(anyMap()) + val request = Common.DoCommandRequest.newBuilder().setName(powerSensor.name.name).setCommand(command).build() + val response = client.doCommand(request) + verify(powerSensor).doCommand(command.fieldsMap) + assertEquals(command, response.result) + } + + +} \ No newline at end of file diff --git a/core/sdk/src/test/kotlin/com/viam/sdk/core/component/powersensor/PowerSensorTest.kt b/core/sdk/src/test/kotlin/com/viam/sdk/core/component/powersensor/PowerSensorTest.kt new file mode 100644 index 000000000..7d6a16002 --- /dev/null +++ b/core/sdk/src/test/kotlin/com/viam/sdk/core/component/powersensor/PowerSensorTest.kt @@ -0,0 +1,65 @@ +package com.viam.sdk.core.component.powersensor + +import com.google.protobuf.Struct +import com.google.protobuf.Value +import com.viam.common.v1.Common +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.mockito.Answers +import org.mockito.Mockito.* +import java.util.* + +class PowerSensorTest { + private lateinit var powerSensor: PowerSensor + val extra = + Struct.newBuilder().putAllFields(mapOf("foo" to Value.newBuilder().setStringValue("bar").build())).build() + + @BeforeEach + fun setup() { + powerSensor = mock(PowerSensor::class.java, Answers.CALLS_REAL_METHODS) + } + + @Test + fun getVoltage(){ + `when`(powerSensor.getVoltage(any>())).thenReturn(AbstractMap.SimpleEntry(3.0, true)) + val voltage = powerSensor.getVoltage(Optional.of(extra)) + verify(powerSensor).getVoltage(Optional.of(extra)) + assertEquals(3.0, voltage.key) + assertTrue(voltage.value) + + } + + @Test + fun getCurrent(){ + `when`(powerSensor.getCurrent(any>())).thenReturn(AbstractMap.SimpleEntry(5.0, false)) + val curr = powerSensor.getCurrent(Optional.of(extra)) + verify(powerSensor).getCurrent(Optional.of(extra)) + assertEquals(5.0, curr.key) + assertFalse(curr.value) + + } + + @Test + fun getPower(){ + `when`(powerSensor.getPower(any>())).thenReturn(4.2) + val power = powerSensor.getPower(Optional.of(Struct.getDefaultInstance())) + verify(powerSensor).getPower(Optional.of(Struct.getDefaultInstance())) + assertEquals(4.2, power) + + } + + @Test + fun getReadings(){ + val readings = mapOf( + "a" to 1, + "b" to 2, + "c" to 3, + "d" to mapOf("d1" to "vec3" to Common.Vector3.newBuilder().setX(1.0).setY(1.0).setZ(1.0).build()) + ) + `when`(powerSensor.getReadings(any>())).thenReturn(readings) + val result = powerSensor.getReadings(Optional.of(extra)) + verify(powerSensor).getReadings(Optional.of(extra)) + assertEquals(readings, result) + } +} \ No newline at end of file diff --git a/core/sdk/src/test/kotlin/com/viam/sdk/core/component/servo/ServoRPCClientTest.kt b/core/sdk/src/test/kotlin/com/viam/sdk/core/component/servo/ServoRPCClientTest.kt new file mode 100644 index 000000000..917142f43 --- /dev/null +++ b/core/sdk/src/test/kotlin/com/viam/sdk/core/component/servo/ServoRPCClientTest.kt @@ -0,0 +1,92 @@ +package com.viam.sdk.core.component.servo + +import com.google.protobuf.Struct +import com.google.protobuf.Value +import com.viam.common.v1.Common.Geometry +import com.viam.sdk.core.resource.ResourceManager +import com.viam.sdk.core.rpc.BasicManagedChannel +import io.grpc.inprocess.InProcessChannelBuilder +import io.grpc.inprocess.InProcessServerBuilder +import io.grpc.testing.GrpcCleanupRule +import org.junit.Rule +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertFalse +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.mockito.Mockito.* +import java.util.* + +class ServoRPCClientTest { + private lateinit var servo: Servo + private lateinit var client: ServoRPCClient + + @JvmField + @Rule + val grpcCleanupRule: GrpcCleanupRule = GrpcCleanupRule() + + @BeforeEach + fun setup() { + servo = mock( + Servo::class.java, withSettings().useConstructor("mock-servo").defaultAnswer( + CALLS_REAL_METHODS + ) + ) + val resourceManager = ResourceManager(listOf(servo)) + val service = ServoRPCService(resourceManager) + val serviceName = InProcessServerBuilder.generateName() + grpcCleanupRule.register( + InProcessServerBuilder.forName(serviceName).directExecutor().addService(service).build().start() + ) + val channel = grpcCleanupRule.register(InProcessChannelBuilder.forName(serviceName).directExecutor().build()) + client = ServoRPCClient("mock-servo", BasicManagedChannel(channel)) + } + + @Test + fun move(){ + val extra = + Struct.newBuilder().putAllFields(mapOf("foo" to Value.newBuilder().setStringValue("bar").build())).build() + client.move(20, extra) + verify(servo).move(20, extra) + + } + + @Test + fun stop() { + client.stop() + verify(servo).stop(Struct.getDefaultInstance()) + } + + @Test + fun isMoving() { + `when`(servo.isMoving()).thenReturn(false) + val isMoving = client.isMoving() + verify(servo).isMoving() + assertFalse(isMoving) + } + + @Test + fun getGeometries() { + doReturn(listOf()).`when`(servo).getGeometries(any()) + client.getGeometries(Optional.empty()) + verify(servo).getGeometries(any()) + } + + @Test + fun getPosition() { + `when`(servo.getPosition(any(Struct::class.java) ?: Struct.getDefaultInstance())).thenReturn(80) + val pos = client.getPosition() + verify(servo).getPosition(Struct.getDefaultInstance()) + assertEquals(80, pos) + } + + @Test + fun doCommand() { + val command = mapOf("foo" to Value.newBuilder().setStringValue("bar").build()) + doReturn(Struct.newBuilder().putAllFields(command).build()).`when`(servo).doCommand(anyMap()) + val response = client.doCommand(command) + verify(servo).doCommand(command) + assertEquals(command, response.fieldsMap) + } + + +} diff --git a/core/sdk/src/test/kotlin/com/viam/sdk/core/component/servo/ServoRPCServiceTest.kt b/core/sdk/src/test/kotlin/com/viam/sdk/core/component/servo/ServoRPCServiceTest.kt new file mode 100644 index 000000000..cc7ce585b --- /dev/null +++ b/core/sdk/src/test/kotlin/com/viam/sdk/core/component/servo/ServoRPCServiceTest.kt @@ -0,0 +1,106 @@ +package com.viam.sdk.core.component.servo + +import com.google.protobuf.Struct +import com.google.protobuf.Value +import com.viam.common.v1.Common +import com.viam.common.v1.Common.Geometry +import com.viam.component.servo.v1.Servo.StopRequest +import com.viam.component.servo.v1.Servo.GetPositionRequest +import com.viam.component.servo.v1.Servo.IsMovingRequest +import com.viam.component.servo.v1.ServoServiceGrpc +import com.viam.component.servo.v1.ServoServiceGrpc.ServoServiceBlockingStub +import com.viam.sdk.core.resource.ResourceManager +import io.grpc.inprocess.InProcessChannelBuilder +import io.grpc.inprocess.InProcessServerBuilder +import io.grpc.testing.GrpcCleanupRule +import org.junit.Rule +import org.junit.jupiter.api.Assertions.assertEquals +import org.junit.jupiter.api.Assertions.assertFalse +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.mockito.Mockito.* +import java.util.* + +class ServoRPCServiceTest { + private lateinit var servo: Servo + private lateinit var client: ServoServiceBlockingStub + + @JvmField + @Rule + val grpcCleanupRule: GrpcCleanupRule = GrpcCleanupRule() + + @BeforeEach + fun setup() { + servo = mock( + Servo::class.java, withSettings().useConstructor("mock-servo").defaultAnswer( + CALLS_REAL_METHODS + ) + ) + + val resourceManager = ResourceManager(listOf(servo)) + val service = ServoRPCService(resourceManager) + val serviceName = InProcessServerBuilder.generateName() + grpcCleanupRule.register( + InProcessServerBuilder.forName(serviceName).directExecutor().addService(service).build().start() + ) + client = ServoServiceGrpc.newBlockingStub( + grpcCleanupRule.register( + InProcessChannelBuilder.forName(serviceName).build() + ) + ) + } + + @Test + fun move(){ + val extra = + Struct.newBuilder().putAllFields(mapOf("foo" to Value.newBuilder().setStringValue("bar").build())).build() + val request = com.viam.component.servo.v1.Servo.MoveRequest.newBuilder().setName(servo.name.name).setAngleDeg(20).setExtra(extra).build() + client.move(request) + verify(servo).move(20, extra) + } + + @Test + fun isMoving(){ + `when`(servo.isMoving()).thenReturn(false) + val request = IsMovingRequest.newBuilder().setName(servo.name.name).build() + val response = client.isMoving(request) + verify(servo).isMoving() + assertFalse(response.isMoving) + } + + @Test + fun getPosition(){ + `when`(servo.getPosition(any(Struct::class.java) ?: Struct.getDefaultInstance())).thenReturn(80) + val request = GetPositionRequest.newBuilder().setName(servo.name.name).build() + val response = client.getPosition(request) + verify(servo).getPosition(Struct.getDefaultInstance()) + assertEquals(80, response.positionDeg) + } + + @Test + fun stop(){ + val request = StopRequest.newBuilder().setName(servo.name.name).build() + client.stop(request) + verify(servo).stop() + } + + @Test + fun getGeometries(){ + doReturn(listOf()).`when`(servo).getGeometries(any()) + val request = Common.GetGeometriesRequest.newBuilder().setName(servo.name.name).build() + client.getGeometries(request) + verify(servo).getGeometries(Optional.of(Struct.getDefaultInstance())) + } + + @Test + fun doCommand(){ + val command = + Struct.newBuilder().putAllFields(mapOf("foo" to Value.newBuilder().setStringValue("bar").build())).build() + doReturn(command).`when`(servo).doCommand(anyMap()) + val request = Common.DoCommandRequest.newBuilder().setName(servo.name.name).setCommand(command).build() + val response = client.doCommand(request) + verify(servo).doCommand(command.fieldsMap) + assertEquals(command, response.result) + } + +} \ No newline at end of file diff --git a/core/sdk/src/test/kotlin/com/viam/sdk/core/component/servo/ServoTest.kt b/core/sdk/src/test/kotlin/com/viam/sdk/core/component/servo/ServoTest.kt new file mode 100644 index 000000000..ce33ef860 --- /dev/null +++ b/core/sdk/src/test/kotlin/com/viam/sdk/core/component/servo/ServoTest.kt @@ -0,0 +1,51 @@ +package com.viam.sdk.core.component.servo + +import com.google.protobuf.Struct +import com.google.protobuf.Value +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.BeforeEach +import org.junit.jupiter.api.Test +import org.mockito.Answers +import org.mockito.Mockito.* + +class ServoTest { + private lateinit var servo: Servo + + @BeforeEach + fun setup() { + servo = mock(Servo::class.java, Answers.CALLS_REAL_METHODS) + } + @Test + fun move(){ + val extra = + Struct.newBuilder().putAllFields(mapOf("foo" to Value.newBuilder().setStringValue("bar").build())).build() + servo.move(20, extra) + verify(servo).move(20, extra) + } + @Test + fun isMoving(){ + `when`(servo.isMoving()).thenReturn(false) + val isMoving = servo.isMoving() + verify(servo).isMoving() + assertFalse(isMoving) + + } + + @Test + fun getPosition(){ + val extra = + Struct.newBuilder().putAllFields(mapOf("foo" to Value.newBuilder().setStringValue("bar").build())).build() + `when`(servo.getPosition(any(Struct::class.java) ?: Struct.getDefaultInstance())).thenReturn(80) + val pos = servo.getPosition(extra) + verify(servo).getPosition(extra) + assertEquals(80, pos) + + } + + @Test + fun stop(){ + servo.stop() + verify(servo).stop() + } + +} \ No newline at end of file diff --git a/core/sdk/src/test/kotlin/com/viam/sdk/core/util/UtilsTest.kt b/core/sdk/src/test/kotlin/com/viam/sdk/core/util/UtilsTest.kt new file mode 100644 index 000000000..d534da824 --- /dev/null +++ b/core/sdk/src/test/kotlin/com/viam/sdk/core/util/UtilsTest.kt @@ -0,0 +1,149 @@ +package com.viam.sdk.core.util + +import com.google.protobuf.* +import com.viam.common.v1.Common +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.Assertions.* +import org.junit.jupiter.api.BeforeEach + +class UtilsTest { + + private lateinit var simpleMap : Map + private lateinit var vector3 : Common.Vector3 + private lateinit var geoPoint : Common.GeoPoint + private lateinit var orientation : Common.Orientation + private lateinit var nestedStruct : Map + + private lateinit var vector3val : Value + private lateinit var geoPointVal : Value + private lateinit var orientationVal : Value + + @BeforeEach + fun setup(){ + simpleMap = mapOf("foo" to "bar", "baz" to true) + vector3 = Common.Vector3.newBuilder().setX(1.0).setY(2.0).setZ(3.0).build() + geoPoint = Common.GeoPoint.newBuilder().setLatitude(22.0).setLongitude(33.0).build() + orientation = Common.Orientation.newBuilder().setOX(1.0).setOY(1.0).setOZ(1.0).setTheta(1.0).build() + nestedStruct = mapOf( + "vec3" to vector3, + "geoPoint" to geoPoint, + "nest" to mapOf("orientation" to orientation, "foo" to "bar", "baz" to true)) + + vector3val = Value.newBuilder().setStructValue( + Struct.newBuilder().putAllFields(mapOf( + "x" to Value.newBuilder().setNumberValue(1.0).build(), + "y" to Value.newBuilder().setNumberValue(2.0).build(), + "z" to Value.newBuilder().setNumberValue(3.0).build(), + "_type" to Value.newBuilder().setStringValue("vector3").build())) + .build()).build() + geoPointVal = Value.newBuilder().setStructValue( + Struct.newBuilder().putAllFields(mapOf( + "lat" to Value.newBuilder().setNumberValue(22.0).build(), + "lng" to Value.newBuilder().setNumberValue(33.0).build(), + "_type" to Value.newBuilder().setStringValue("geopoint").build())) + .build()).build() + orientationVal = Value.newBuilder().setStructValue( + Struct.newBuilder().putAllFields(mapOf( + "ox" to Value.newBuilder().setNumberValue(1.0).build(), + "oy" to Value.newBuilder().setNumberValue(1.0).build(), + "oz" to Value.newBuilder().setNumberValue(1.0).build(), + "theta" to Value.newBuilder().setNumberValue(1.0).build(), + "_type" to Value.newBuilder().setStringValue("orientation_vector_degrees").build())) + .build()).build() + } + @Test + fun valueToNative(){ + var value = Value.newBuilder().setStringValue("value").build() + assertEquals("value", Utils.valueToNative(value)) + + value = Value.newBuilder().setNumberValue(2.0).build() + assertEquals(2.0, Utils.valueToNative(value)) + + value = Value.newBuilder().setNullValue(NullValue.NULL_VALUE).build() + assertEquals(NullValue.NULL_VALUE, Utils.valueToNative(value)) + + value = Value.newBuilder().setBoolValue(true).build() + assertEquals(true, Utils.valueToNative(value)) + + val struct = Struct.newBuilder() + .putFields("foo", Value.newBuilder().setStringValue("bar").build()) + .putFields("baz", Value.newBuilder().setBoolValue(true).build()) + + value = Value.newBuilder().setStructValue(struct.build()).build() + assertEquals(simpleMap, Utils.valueToNative(value)) + + val list = ListValue.newBuilder() + .addValues(Value.newBuilder().setBoolValue(true).build()) + .addValues(Value.newBuilder().setNumberValue(1.0).build()) + .addValues(Value.newBuilder().setStringValue("two").build()) + .build() + value = Value.newBuilder().setListValue(list).build() + assertEquals(listOf(true, 1.0, "two"), Utils.valueToNative(value)) + + + assertEquals(vector3, Utils.valueToNative(vector3val)) + assertEquals(geoPoint, Utils.valueToNative(geoPointVal)) + assertEquals(orientation, Utils.valueToNative(orientationVal)) + + + struct.putFields("orientation", orientationVal) + val nestedStructVal = Struct.newBuilder().putAllFields(mapOf( + "vec3" to vector3val, + "geoPoint" to geoPointVal, + "nest" to Value.newBuilder().setStructValue(struct.build()).build())).build() + value = Value.newBuilder().setStructValue(nestedStructVal).build() + assertEquals(nestedStruct, Utils.valueToNative(value)) + + } + + @Test + fun nativeToValue(){ + var value = Value.newBuilder().setStringValue("abc").build() + assertEquals(value, Utils.nativeToValue("abc")) + assertEquals(value, Utils.nativeToValue("abc".toByteArray())) + + value = Value.newBuilder().setNumberValue(1.0).build() + assertEquals(value, Utils.nativeToValue(1.0)) + + value = Value.newBuilder().setBoolValue(false).build() + assertEquals(value, Utils.nativeToValue(false)) + + val struct = Struct.newBuilder() + .putFields("foo", Value.newBuilder().setStringValue("bar").build()) + .putFields("baz", Value.newBuilder().setBoolValue(true).build()) + + value = Value.newBuilder().setStructValue(struct.build()).build() + assertEquals(value, Utils.nativeToValue(simpleMap)) + + val list = ListValue.newBuilder().addAllValues( + listOf( + Value.newBuilder().setBoolValue(true).build(), + Value.newBuilder().setNumberValue(1.0).build(), + Value.newBuilder().setStringValue("two").build(), + Value.newBuilder().setStructValue(struct).build() + ) + ) + value = Value.newBuilder().setListValue(list).build() + assertEquals(value, Utils.nativeToValue(listOf(true, 1.0, "two", simpleMap))) + + assertEquals(vector3val, Utils.nativeToValue(vector3)) + assertEquals(geoPointVal, Utils.nativeToValue(geoPoint)) + assertEquals(orientationVal, Utils.nativeToValue(orientation)) + + //only string are allowed as keys + assertThrows(IllegalArgumentException::class.java) {Utils.nativeToValue(mapOf(1 to 2, 3 to 4))} + class UnsupportedType(){} + assertThrows(IllegalArgumentException::class.java) {Utils.nativeToValue(UnsupportedType())} + + + + } + + @Test + fun testSensorReadings(){ + val test = Utils.sensorReadingsNativeToValue(nestedStruct) + val response = Utils.sensorReadingsValueToNative(test) + assertEquals(nestedStruct, response) + + } +} \ No newline at end of file