package de.calette.mephisto3.control; import callete.api.Callete; import callete.api.services.Service; import callete.api.services.ServiceModel; import callete.api.services.gpio.*; import callete.api.services.impl.simulator.SimulatorPushButton; import callete.api.services.impl.simulator.SimulatorRotaryEncoder; import callete.api.services.music.model.Stream; import de.calette.mephisto3.Mephisto3; import de.calette.mephisto3.ui.ServiceChangeListener; import de.calette.mephisto3.util.Executor; import de.calette.mephisto3.util.NodeDebugger; import javafx.application.Platform; import javafx.scene.input.KeyCode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * Registers the GPIO components and their listeners. * Switches the service states. */ public class ServiceController { private final static Logger LOG = LoggerFactory.getLogger(ServiceController.class); public final static String SERVICE_NAME_RADIO = "Radio"; public final static String SERVICE_NAME_WEATHER = "Wetter"; public final static String SERVICE_NAME_MUSIC = "Musik"; public final static String SERVICE_NAME_MP3 = "MP3s"; public final static String SERVICE_NAME_SETTINGS = "System"; public static final String ROTARY_ENCODER_PUSH_BUTTON_NAME = "Rotary Push"; public static final String ROTARY_ENCODER_NAME = "Rotary Encoder"; private static ServiceController instance; private List<ServiceChangeListener> serviceChangeListeners = Collections.synchronizedList(new ArrayList<>()); private List<ControlListener> controlListeners = Collections.synchronizedList(new ArrayList<>()); private ServiceState serviceState = new ServiceState(); private boolean controlEnabled = false; public static ServiceController getInstance() { if(instance == null) { instance = new ServiceController(); instance.initGPIO(); instance.initServiceState(); } return instance; } public void addServiceChangeListener(ServiceChangeListener listener) { this.serviceChangeListeners.add(listener); } public void addControlListener(ControlListener listener) { this.controlListeners.add(listener); } public void removeControlListener(ControlListener listener) { this.controlListeners.remove(listener); } /** * Activates the UI for the given service. * * @param service the service to activate. */ public void switchService(Service service) { Executor.run(new Runnable() { @Override public void run() { if(service.equals(Callete.getWeatherService())) { serviceState.setService(Callete.getWeatherService()); serviceState.setModels(Callete.getWeatherService().getWeather()); } else if(service.equals(Callete.getStreamingService())) { serviceState.setService(Callete.getStreamingService()); serviceState.setModels(Callete.getStreamingService().getStreams()); } else if(service.equals(Callete.getGoogleMusicService())) { serviceState.setService(Callete.getGoogleMusicService()); serviceState.setModels(Callete.getGoogleMusicService().getAlbums()); } else if(service.equals(Callete.getSystemService())) { serviceState.setService(Callete.getSystemService()); serviceState.setModels(Collections.<ServiceModel>emptyList()); } else if(service.equals(Callete.getNetworkMusicService())) { serviceState.setService(Callete.getNetworkMusicService()); serviceState.setModels(Callete.getNetworkMusicService().getAlbums()); } serviceChanged(); } }); } public void setControlEnabled(boolean b) { this.controlEnabled = b; } public ServiceState getServiceState() { return serviceState; } // ------------------- Helper ----------------------------------- public void serviceChanged() { for(ServiceChangeListener listener : serviceChangeListeners) { listener.serviceChanged(serviceState); } } /** * Sets the initial service state, therefore the initial service. */ private void initServiceState() { serviceState.setService(Callete.getStreamingService()); List<Stream> streams = Callete.getStreamingService().getStreams(); serviceState.setModels(streams); //update index with last save state int index = Callete.getSettings().getInt(ServiceState.SETTING_SERVICE_SELECTION, 0); if(index >= streams.size()) { index = 0; } serviceState.setServiceIndex(index); } private void initGPIO() { GPIOService gpioService = Callete.getGPIOService(); int pin = Callete.getConfiguration().getInt("rotary.encoder.push.pin"); PushButton pushButton = gpioService.connectPushButton(pin, ROTARY_ENCODER_PUSH_BUTTON_NAME); pushButton.addPushListener(new PushListener() { @Override public void pushed(final PushEvent pushEvent) { if(!controlEnabled) { LOG.info("Ignoring PUSH event since control is disabled."); return; } Platform.runLater(new Runnable() { @Override public void run() { ServiceControlEvent.EVENT_TYPE push = ServiceControlEvent.EVENT_TYPE.PUSH; if(pushEvent.isLongPush()) { serviceState.setModels(null); push = ServiceControlEvent.EVENT_TYPE.LONG_PUSH; } for(ControlListener listener : new ArrayList<>(controlListeners)) { listener.controlEvent(new ServiceControlEvent(push, serviceState)); } } }); } @Override public long getPushDebounceMillis() { return Callete.getConfiguration().getInt("push.debounce.millis", 700); } @Override public long getLongPushDebounceMillis() { return Callete.getConfiguration().getInt("long.push.debounce.millis", 1500); } }); int pinA = Callete.getConfiguration().getInt("rotary.encoder.pin.a"); int pinB = Callete.getConfiguration().getInt("rotary.encoder.pin.b"); RotaryEncoder rotary = gpioService.connectRotaryEncoder(pinA, pinB, ROTARY_ENCODER_NAME); rotary.addChangeListener(new RotaryEncoderListener() { @Override public void rotated(final RotaryEncoderEvent event) { if(!controlEnabled) { return; } ServiceControlEvent.EVENT_TYPE eventType; if(event.rotatedLeft()) { eventType = ServiceControlEvent.EVENT_TYPE.PREVIOUS; } else { eventType = ServiceControlEvent.EVENT_TYPE.NEXT; } //skip this in service chooser mode if(serviceState.getModels() != null) { if(eventType.equals(ServiceControlEvent.EVENT_TYPE.PREVIOUS)) { serviceState.decrementIndex(); } else if(eventType.equals(ServiceControlEvent.EVENT_TYPE.NEXT)) { serviceState.incrementIndex(); } } final ServiceControlEvent serviceControlEvent = new ServiceControlEvent(eventType, serviceState); Platform.runLater(new Runnable() { @Override public void run() { for(ControlListener listener : controlListeners) { listener.controlEvent(serviceControlEvent); } } }); } }); } public void fireControlEvent(KeyCode code) { SimulatorRotaryEncoder encoder = (SimulatorRotaryEncoder) Callete.getGPIOService().getSimulatedGPIOComponent(ROTARY_ENCODER_NAME); SimulatorPushButton pushButton = (SimulatorPushButton) Callete.getGPIOService().getSimulatedGPIOComponent(ROTARY_ENCODER_PUSH_BUTTON_NAME); if(code == KeyCode.RIGHT) { encoder.right(); } else if(code == KeyCode.LEFT) { encoder.left(); } else if(code == KeyCode.DOWN) { pushButton.push(false); } else if(code == KeyCode.UP) { pushButton.push(true); } else if(code == KeyCode.Q || code == KeyCode.ESCAPE) { System.exit(0); } if(code == KeyCode.D) { NodeDebugger.dump(Mephisto3.rootStack); } } }