Reactive Spring Flux data from a Pi
Trisha Gee (Coder, blogger, speaker, Developer Advocate at JetBrains, @trisha_gee ), which I interviewed for “Chapter 4: Choosing an IDE”, and Josh Long (Spring Developer Advocate at Pivotal, @starbuxman ) worked together on a blog series in which they showed the power of reactive data produced by a Spring application. Instead of repeating a REST call each time you want to get data from the server, you do one call which returns a continuous stream in which new data is pushed based on an interval.
Their example uses a Kotlin service to send stock values every second. I was wondering if this could be achieved on the Pi. And of course! This example is based on the one from “Chapter 9: Pi4J” with the distance sensor. It uses the same wiring with some rework of the code integrated in a Spring application.
Wiring
Code
The sources can be found as an example project within all the sources from the book on GitHub . The most important part is the service generation the distance measurement Flux:
private static final Pin PIN_TRIGGER = RaspiPin.GPIO_01; // BCM 18
private static final Pin PIN_ECHO = RaspiPin.GPIO_05; // BCM 24
private final GpioPinDigitalOutput trigger;
private final GpioPinDigitalInput echo;
public DistanceService() {
// Initialize the GPIO controller
GpioController gpio = GpioFactory.getInstance();
// Initialize the pins
this.trigger = gpio.provisionDigitalOutputPin(PIN_TRIGGER, "Trigger", PinState.LOW);
this.echo = gpio.provisionDigitalInputPin(PIN_ECHO, "Echo", PinPullResistance.PULL_UP);
}
public Flux getDistances() {
return Flux.fromStream(Stream.generate(() -> this.getDistanceMeasurement()))
.delayElements(Duration.ofSeconds(1));
}
private DistanceMeasurement getDistanceMeasurement() {
try {
// Set trigger high for 0.01ms
this.trigger.pulse(10, PinState.HIGH, true, TimeUnit.NANOSECONDS);
// Start the measurement
while (this.echo.isLow()) {
// Wait until the echo pin is high,
// indicating the ultrasound was sent
}
long start = System.nanoTime();
// Wait till measurement is finished
while (this.echo.isHigh()) {
// Wait until the echo pin is low,
// indicating the ultrasound was received back
}
long end = System.nanoTime();
// Output the distance
float measuredSeconds = (end - start) / 1000000000F;
int distance = Math.round(measuredSeconds * 34300 / 2);
logger.info("Measured distance is: {} for {}s", distance, measuredSeconds);
return new DistanceMeasurement(distance, measuredSeconds);
} catch (Exception ex) {
logger.error("Error: {}", ex.getMessage());
}
return null;
}
Result
After building the jar and running it on the Pi, the data is streamed to the browser:
Conclusion
As always with Java, the required code is only a few lines, but you have to find which lines ;-)
This reactive API is only the starting point and only becomes valuable with some clients consuming and using the generated data, but that’s a fun project for you…