JavaFX on Raspberry Pi: GPIO Controller (Part2)
Part1 of this little series of articles was about the hardware setup of my little Raspberry Pi GPIO project.
Now let’s focus the software.
The Schema
GpioAdapterFX
For the bridge between Java and the Raspberry’s GPIO I took advantage of the great work of the Pi4J Project guys.
The com.pi4j.io.gpio.GpioController
is a straighforward and simple wrapper to manage the Pi4J GPIOController
with JavaFX Properties:
public class GpioAdapterFX{ private GpioController GPIO; private ObservableMap<BooleanProperty, ChangeListener<Boolean>> pins; private BooleanProperty pin0StateProperty; private BooleanProperty pin1StateProperty; private BooleanProperty pin2StateProperty; private BooleanProperty pin3StateProperty; private BooleanProperty pin4StateProperty; private BooleanProperty pin5StateProperty; private BooleanProperty pin6StateProperty; private BooleanProperty pin7StateProperty; private Timeline testTimeline; public CpioFXAdapter() { init(); } private void init() { pin0StateProperty = new SimpleBooleanProperty(Boolean.FALSE); pin1StateProperty = new SimpleBooleanProperty(Boolean.FALSE); pin2StateProperty = new SimpleBooleanProperty(Boolean.FALSE); pin3StateProperty = new SimpleBooleanProperty(Boolean.FALSE); pin4StateProperty = new SimpleBooleanProperty(Boolean.FALSE); pin5StateProperty = new SimpleBooleanProperty(Boolean.FALSE); pin6StateProperty = new SimpleBooleanProperty(Boolean.FALSE); pin7StateProperty = new SimpleBooleanProperty(Boolean.FALSE); pins = FXCollections.observableHashMap(); pins.put(pin0StateProperty, null); pins.put(pin1StateProperty, null); pins.put(pin2StateProperty, null); pins.put(pin3StateProperty, null); pins.put(pin4StateProperty, null); pins.put(pin5StateProperty, null); pins.put(pin6StateProperty, null); pins.put(pin7StateProperty, null); } private ChangeListener<Boolean> createPinListener(final GpioPinDigitalOutput pin) { return new ChangeListener<Boolean>() { @Override public void changed(ObservableValue<? extends Boolean> ov, Boolean oldValue, Boolean newValue) { if (newValue) { pin.high(); } else { pin.low(); } } }; } /* * -------------------------- ACTIONS -------------------------- */ public void connect() { GPIO = GpioFactory.getInstance(); GpioPinDigitalOutput pin0 = GPIO. provisionDigitalOutputPin(RaspiPin.GPIO_00, "PIN0", PinState.LOW); GpioPinDigitalOutput pin1 = GPIO. provisionDigitalOutputPin(RaspiPin.GPIO_01, "PIN1", PinState.LOW); GpioPinDigitalOutput pin2 = GPIO. provisionDigitalOutputPin(RaspiPin.GPIO_02, "PIN2", PinState.LOW); GpioPinDigitalOutput pin3 = GPIO. provisionDigitalOutputPin(RaspiPin.GPIO_03, "PIN3", PinState.LOW); GpioPinDigitalOutput pin4 = GPIO. provisionDigitalOutputPin(RaspiPin.GPIO_04, "PIN4", PinState.LOW); GpioPinDigitalOutput pin5 = GPIO. provisionDigitalOutputPin(RaspiPin.GPIO_05, "PIN5", PinState.LOW); GpioPinDigitalOutput pin6 = GPIO. provisionDigitalOutputPin(RaspiPin.GPIO_06, "PIN6", PinState.LOW); GpioPinDigitalOutput pin7 = GPIO. provisionDigitalOutputPin(RaspiPin.GPIO_07, "PIN7", PinState.LOW); pins.put(pin0StateProperty, createPinListener(pin0)); pins.put(pin1StateProperty, createPinListener(pin1)); pins.put(pin2StateProperty, createPinListener(pin2)); pins.put(pin3StateProperty, createPinListener(pin3)); pins.put(pin4StateProperty, createPinListener(pin4)); pins.put(pin5StateProperty, createPinListener(pin5)); pins.put(pin6StateProperty, createPinListener(pin6)); pins.put(pin7StateProperty, createPinListener(pin7)); pin0StateProperty.addListener(pins.get(pin0StateProperty)); pin1StateProperty.addListener(pins.get(pin1StateProperty)); pin2StateProperty.addListener(pins.get(pin2StateProperty)); pin3StateProperty.addListener(pins.get(pin3StateProperty)); pin4StateProperty.addListener(pins.get(pin4StateProperty)); pin5StateProperty.addListener(pins.get(pin5StateProperty)); pin6StateProperty.addListener(pins.get(pin6StateProperty)); pin7StateProperty.addListener(pins.get(pin7StateProperty)); reset(); } public void disconnect() { if (GPIO != null) { GPIO.shutdown(); } for (BooleanProperty booleanProperty : pins.keySet()) { ChangeListener<Boolean> listener = pins.get(booleanProperty); if (listener != null) { booleanProperty.removeListener(listener); } } } public void setOnAllPins() { for (BooleanProperty booleanProperty : pins.keySet()) { booleanProperty.setValue(Boolean.TRUE); } } public void setOffAllPins() { for (BooleanProperty booleanProperty : pins.keySet()) { booleanProperty.setValue(Boolean.FALSE); } } public void reset() { if (testTimeline != null) { testTimeline.stop(); } for (BooleanProperty booleanProperty : pins.keySet()) { booleanProperty.setValue(Boolean.FALSE); } } }
SwitchBoardController
Finally the SwitchBoardController
connects the UI to the GpioAdapterFX
(bidirectional binding is my best friend).
To visualize the state of the GPIO Pins, I’m using Gerrit Grunwalds LED Control from his Enzo7 lib (a port of some of his JFXtras gauges to JavaFX 8).
public class SwitchBoardController implements Initializable { @FXML private GridPane buttonGridPane; @FXML private ToggleButton toogleGPIO0; @FXML private ToggleButton toogleGPIO1; @FXML private ToggleButton toogleGPIO2; @FXML private ToggleButton toogleGPIO3; @FXML private ToggleButton toogleGPIO4; @FXML private ToggleButton toogleGPIO5; @FXML private ToggleButton toogleGPIO6; @FXML private ToggleButton toogleGPIO7; @FXML private Button testButton; @FXML private Button resetButton; @FXML private Button exitButton; @FXML private ToggleButton gpioConnectButton; @FXML private ToggleGroup gpioConnectGroup; @FXML private ToggleButton gpioDisconnectButton; private GpioAdapterFX gpioAdapterFx; private Led indicatorGPIO0; private Led indicatorGPIO1; private Led indicatorGPIO2; private Led indicatorGPIO3; private Led indicatorGPIO4; private Led indicatorGPIO5; private Led indicatorGPIO6; private Led indicatorGPIO7; /** * Initializes the controller class. */ @Override public void initialize(URL url, ResourceBundle rb) { assert buttonGridPane != null : "fx:id=\"buttonGridPane\" was not injected: check your FXML file 'SwitchBoard.fxml'."; assert exitButton != null : "fx:id=\"exitButton\" was not injected: check your FXML file 'SwitchBoard.fxml'."; assert gpioConnectButton != null : "fx:id=\"gpioConnectButton\" was not injected: check your FXML file 'SwitchBoard.fxml'."; assert gpioConnectGroup != null : "fx:id=\"gpioConnectGroup\" was not injected: check your FXML file 'SwitchBoard.fxml'."; assert gpioDisconnectButton != null : "fx:id=\"gpioDisconnectButton\" was not injected: check your FXML file 'SwitchBoard.fxml'."; assert resetButton != null : "fx:id=\"resetButton\" was not injected: check your FXML file 'SwitchBoard.fxml'."; assert testButton != null : "fx:id=\"testButton\" was not injected: check your FXML file 'SwitchBoard.fxml'."; assert toogleGPIO0 != null : "fx:id=\"toogleCPIO0\" was not injected: check your FXML file 'SwitchBoard.fxml'."; assert toogleGPIO1 != null : "fx:id=\"toogleCPIO1\" was not injected: check your FXML file 'SwitchBoard.fxml'."; assert toogleGPIO2 != null : "fx:id=\"toogleCPIO2\" was not injected: check your FXML file 'SwitchBoard.fxml'."; assert toogleGPIO3 != null : "fx:id=\"toogleCPIO3\" was not injected: check your FXML file 'SwitchBoard.fxml'."; assert toogleGPIO4 != null : "fx:id=\"toogleCPIO4\" was not injected: check your FXML file 'SwitchBoard.fxml'."; assert toogleGPIO5 != null : "fx:id=\"toogleCPIO5\" was not injected: check your FXML file 'SwitchBoard.fxml'."; assert toogleGPIO6 != null : "fx:id=\"toogleCPIO6\" was not injected: check your FXML file 'SwitchBoard.fxml'."; assert toogleGPIO7 != null : "fx:id=\"toogleCPIO7\" was not injected: check your FXML file 'SwitchBoard.fxml'."; gpioAdapterFx = new GpioAdapterFX(); indicatorGPIO0 = createIndicator(); indicatorGPIO1 = createIndicator(); indicatorGPIO2 = createIndicator(); indicatorGPIO3 = createIndicator(); indicatorGPIO4 = createIndicator(); indicatorGPIO5 = createIndicator(); indicatorGPIO6 = createIndicator(); indicatorGPIO7 = createIndicator(); buttonGridPane .add(indicatorGPIO0, 0, 0); buttonGridPane.add(indicatorGPIO1, 1, 0); buttonGridPane.add(indicatorGPIO2, 2, 0); buttonGridPane.add(indicatorGPIO3, 3, 0); buttonGridPane.add(indicatorGPIO4, 4, 0); buttonGridPane.add(indicatorGPIO5, 5, 0); buttonGridPane.add(indicatorGPIO6, 6, 0); buttonGridPane.add(indicatorGPIO7, 7, 0); indicatorGPIO0.onProperty(). bindBidirectional(gpioAdapterFx.pin0StateProperty()); indicatorGPIO1.onProperty(). bindBidirectional(gpioAdapterFx.pin1StateProperty()); indicatorGPIO2.onProperty(). bindBidirectional(gpioAdapterFx.pin2StateProperty()); indicatorGPIO3.onProperty(). bindBidirectional(gpioAdapterFx.pin3StateProperty()); indicatorGPIO4.onProperty(). bindBidirectional(gpioAdapterFx.pin4StateProperty()); indicatorGPIO5.onProperty(). bindBidirectional(gpioAdapterFx.pin5StateProperty()); indicatorGPIO6.onProperty(). bindBidirectional(gpioAdapterFx.pin6StateProperty()); indicatorGPIO7.onProperty(). bindBidirectional(gpioAdapterFx.pin7StateProperty()); toogleGPIO0.selectedProperty(). bindBidirectional(gpioAdapterFx.pin0StateProperty()); toogleGPIO1.selectedProperty(). bindBidirectional(gpioAdapterFx.pin1StateProperty()); toogleGPIO2.selectedProperty(). bindBidirectional(gpioAdapterFx.pin2StateProperty()); toogleGPIO3.selectedProperty(). bindBidirectional(gpioAdapterFx.pin3StateProperty()); toogleGPIO4.selectedProperty(). bindBidirectional(gpioAdapterFx.pin4StateProperty()); toogleGPIO5.selectedProperty(). bindBidirectional(gpioAdapterFx.pin5StateProperty()); toogleGPIO6.selectedProperty(). bindBidirectional(gpioAdapterFx.pin6StateProperty()); toogleGPIO7.selectedProperty(). bindBidirectional(gpioAdapterFx.pin7StateProperty()); } private Led createIndicator() { return LedBuilder.create(). prefHeight(80.0). prefWidth(80.0). build(); } /* * -------------------------- ACTIONS -------------------------- */ @FXML public void testAction() { gpioAdapterFx.test(); } @FXML public void resetAction() { gpioAdapterFx.reset(); } @FXML public void gpioDisconnectAction() { gpioAdapterFx.disconnect(); } @FXML public void gpioConnectAction() { gpioAdapterFx.connect(); } @FXML public void exitAction() { gpioAdapterFx.reset(); gpioAdapterFx.disconnect(); Platform.exit(); } }
You can find the complete code here.
The runfxapp skript may help you to run the app on your Raspberry.
Stay tuned…
Inspired by Oliver Schneiders blog post I have already ordered the transmitter to control my wireless power outlets (but shipping from Hong Kong will take some weeks…).
I need to to thanks for this fantastic read! very inspiring, can i share it?