/*package com.softwarepearls.apps.hardware.tinkerforge.waterpump;
import static com.softwarepearls.lego.constants.time.TimeConstants.MILLIS_IN_ONE_MINUTE;
import static com.softwarepearls.lego.constants.time.TimeConstants.MILLIS_IN_ONE_SECOND;
import static com.softwarepearls.lego.java.system.SystemProperties.*;
import static com.softwarepearls.lego.time.Frequency.EVERY_500_MS;
import static com.softwarepearls.lego.time.TimeAndDateKit.*;
import com.softwarepearls.apps.hardware.tinkerforge.waterpump.external.Pump;
import com.softwarepearls.apps.hardware.tinkerforge.waterpump.external.PumpState;
import com.softwarepearls.lego.hardware.tinkerforge.TinkerFactory;
import com.softwarepearls.lego.hardware.tinkerforge.TinkerFactory.ComponentType;
import com.softwarepearls.lego.hardware.tinkerforge.impl.emulator.Emulator;
import com.softwarepearls.lego.hardware.tinkerforge.impl.emulator.io.EmulatedLCD20x4;
import com.softwarepearls.lego.hardware.tinkerforge.impl.emulator.io.ui.resources.LCDBigDigits;
import com.softwarepearls.lego.hardware.tinkerforge.impl.emulator.io.ui.resources.LCDCustomChars;
import com.softwarepearls.lego.hardware.tinkerforge.interfaces.Device;
import com.softwarepearls.lego.hardware.tinkerforge.interfaces.input.DistanceIR;
import com.softwarepearls.lego.hardware.tinkerforge.interfaces.input.LinearPoti;
import com.softwarepearls.lego.hardware.tinkerforge.interfaces.input.Temperature;
import com.softwarepearls.lego.hardware.tinkerforge.interfaces.io.LCD20x4;
import com.softwarepearls.lego.hardware.tinkerforge.interfaces.output.DualRelay;
import com.softwarepearls.lego.hardware.tinkerforge.interfaces.relays.DualRelayOutput;
import com.softwarepearls.lego.image.ImageKit;
import com.softwarepearls.lego.time.Frequency;
import com.softwarepearls.lego.time.TimeAndDateKit;*/
import com.tinkerforge.BrickletLCD20x4;
import com.tinkerforge.BrickletLCD20x4.ButtonReleasedListener;
import com.tinkerforge.IPConnection;
import com.tinkerforge.TinkerforgeException;
import com.tinkerforge.Device;
import com.tinkerforge.BrickletDistanceIR;
import com.tinkerforge.BrickletTemperature;
import com.tinkerforge.BrickletLinearPoti;
import com.tinkerforge.BrickletDualRelay;
import com.tinkerforge.BrickletDistanceIR.AnalogValueCallbackThreshold;
import com.tinkerforge.BrickletDistanceIR.AnalogValueListener;
import com.tinkerforge.BrickletDistanceIR.AnalogValueReachedListener;
import com.tinkerforge.BrickletDistanceIR.DistanceCallbackThreshold;
import com.tinkerforge.BrickletDistanceIR.DistanceListener;
import com.tinkerforge.BrickletDistanceIR.DistanceReachedListener;
import com.tinkerforge.Device.Identity;
import java.awt.Image;
import java.awt.image.RenderedImage;
import java.io.File;
import java.io.IOException;
import java.util.*;
class Pump {
private BrickletDualRelay dr = null;
void setPumpState(PumpState ps) throws TinkerforgeException {
System.out.println("FAKE: setPumpState " + ps);
if (ps == PumpState.ON) {
dr.setState(true, false);
} else {
dr.setState(false, false);
}
}
PumpState getPumpState() {
try {
if (dr.getState().relay1) {
return PumpState.ON;
} else {
return PumpState.OFF;
}
} catch (TinkerforgeException e) {
e.printStackTrace();
}
return PumpState.OFF;
}
void setConnectingRelay(BrickletDualRelay dr) {
this.dr = dr;
}
}
enum PumpState {
ON,
OFF
}
/****************************************************************************
* Cellar Water Pump Controller logic interacting with a TinkerForge stack
* consisting of:
*
* - 1x Master Brick 2.0
*
- 1x Distance IR Sensor
*
- 1x Dual Relay
*
- 1x LCD 20x4 display
*
****************************************************************************/
public final class CellarWaterPumpController_Test1 {
//private static final Frequency POLLING_FREQUENCY = EVERY_500_MS;
private static final double PUMP_OFF_WATER_DISTANCE = 14.0; // in cm
private static final double PUMP_ON_WATER_DISTANCE = 9.3;
//private static final String TINKERFORGE_BRICKD_HOST = "localhost";
private static final String TINKERFORGE_BRICKD_HOST = "foobar";
//private static final String TINKERFORGE_BRICKD_HOST = "192.168.178.169";
private static final int TINKERFORGE_BRICKD_PORT = 4223;
//private static final TinkerFactory.ComponentType HARD_OR_SOFT = ComponentType.HARDWARE;
private static final String UID_DUAL_RELAY = "c2J";
private static final String UID_DISTANCE_IR = "9gh";
private static final String UID_LCD_20x4 = "cZ1";
private static final String UID_THERMOMETER = "bT3";
private static final String UID_LINEAR_POTI = "li1";
//
private static final int BACKLIGHT_TOGGLE_SPEED = 12;
private static final String WEB_PAGE_LCD_IMAGE_PATH = "/Volumes/ramdisk/images/LCD.png";
private static final String PROGRAM_ICON_FILENAME = "resources/water_pump_icon.png";
private static final long MILLIS_IN_ONE_SECOND = 1000;
private static final long MILLIS_IN_ONE_MINUTE = 60 * MILLIS_IN_ONE_SECOND;
private static final long SAFETY_PUMP_OFF_DELAY = 45 * MILLIS_IN_ONE_SECOND;
private static final long MINIMUM_TIME_BETWEEN_SWITCHES = 5 * MILLIS_IN_ONE_MINUTE;
// the main actor
//private final Pump pump;
//private List tinkerForgeStack;
// system input devices
private TFDistanceIR distanceIR;
private BrickletTemperature thermometer;
private BrickletLinearPoti linearPoti;
// system output devices
private BrickletDualRelay dualRelay;
private BrickletLCD20x4 lcd;
// sensor values
private double waterDistance;
private double temperature;
//
private boolean runningNormally;
private IPConnection ipConnection;
//
private int backlightToggle;
protected short lastButtonPressed;
private boolean showTime;
//
//private final Emulator emulator;
//
private Timer safetyPumpOffTimer;
private long switchedPumpOnAt;
private long lastSafetyOffTime;
private Pump pump;
/**
* Constructor.
*
* @throws UnknownHostException
* @throws IOException
* @throws AlreadyConnectedException
*/
private CellarWaterPumpController_Test1() throws IOException, TinkerforgeException {
System.out.println("Starting Cellar Water Pump Control System @ " + new Date());
//System.out.println("Running on Java " + getJavaVersion() + " hosted by " + getOperatingSystemName() + " " + getOperatingSystemVersion());
ensureTinkerForgeStackResetsOnJavaShutdown();
//emulator = Emulator.getSingleton();
// final Image programIcon =
// ImageKit.loadImageRelativeToClass(CellarWaterPumpController.class,
// PROGRAM_ICON_FILENAME);
// emulator.setWindowIcon(programIcon);
initialiseTinkerForgeStack();
pump = new Pump();
pump.setConnectingRelay(dualRelay/*, DualRelayOutput.ONE*/);
}
private void initialiseTinkerForgeStack() throws TinkerforgeException, IOException {
System.out.println("Initializing TinkerForge stack..");
//final TinkerFactory tinkerFactory = TinkerFactory.getSingleton();
//tinkerFactory.make(HARD_OR_SOFT);
if (/*HARD_OR_SOFT == ComponentType.HARDWARE*/true) {
ipConnection = new IPConnection();
ipConnection.addConnectedListener(new IPConnection.ConnectedListener() {
public void connected(short connectReason) {
System.out.println("CONNECTED " + connectReason);
}
});
ipConnection.addDisconnectedListener(new IPConnection.DisconnectedListener() {
public void disconnected(short disconnectReason) {
System.out.println("DISCONNECTED " + disconnectReason);
}
});
ipConnection.connect(TINKERFORGE_BRICKD_HOST, TINKERFORGE_BRICKD_PORT);
//tinkerFactory.use(ipConnection);
}
/*dualRelay = tinkerFactory.createDualRelay(UID_DUAL_RELAY);
thermometer = tinkerFactory.createTemperature(UID_THERMOMETER);
distanceIR = tinkerFactory.createDistanceIR(UID_DISTANCE_IR);
// linearPoti = tinkerFactory.createLinearPoti(UID_LINEAR_POTI);
lcd = tinkerFactory.createLCD20x4(UID_LCD_20x4, TinkerFactory.ComponentType.SOFTWARE);*/
dualRelay = new BrickletDualRelay(UID_DUAL_RELAY, ipConnection);
thermometer = new BrickletTemperature(UID_THERMOMETER, ipConnection);
distanceIR = new TFDistanceIR(UID_DISTANCE_IR, ipConnection);
lcd = new BrickletLCD20x4(UID_LCD_20x4, ipConnection);
//emulator.layoutComponentsOnDesktop();
lastButtonPressed = -1;
lcd.addButtonReleasedListener(new ButtonReleasedListener() {
@Override
public void buttonReleased(final short button) {
lastButtonPressed = button;
}
});
initLcdCustomChars();
/*tinkerForgeStack = new ArrayList();
tinkerForgeStack.add(distanceIR);
tinkerForgeStack.add(dualRelay);
tinkerForgeStack.add(lcd);*/
System.out.println(" Done.");
}
private void start() {
runningNormally = true;
while (runningNormally) {
try {
controlLogic();
}
catch (final TinkerforgeException e) {
log("Ooops: " + e.getMessage());
}
}
}
private void controlLogic() throws TinkerforgeException {
lcd.backlightOn();
runningNormally = true;
while (runningNormally) {
dealWithWaterLevelAndPump();
updateLCD();
//wakeup(POLLING_FREQUENCY);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void dealWithWaterLevelAndPump() throws TinkerforgeException {
log("Polling sensors... ");
waterDistance = ((double) distanceIR.getDistance()) / 10; // convert mm
// to cm
log("Water Distance = " + waterDistance + " cm");
temperature = ((double) thermometer.getTemperature()) / 100;
if ((waterDistance < PUMP_ON_WATER_DISTANCE) && (System.currentTimeMillis() - lastSafetyOffTime > MINIMUM_TIME_BETWEEN_SWITCHES)) {
log("Water level is high.");
if (pump.getPumpState() == PumpState.OFF) {
switchPump(PumpState.ON);
}
}
if (waterDistance > PUMP_OFF_WATER_DISTANCE) {
log("Water level is low.");
if (pump.getPumpState() == PumpState.ON) {
switchPump(PumpState.OFF);
}
}
}
private void updateLCD() throws TinkerforgeException {
// if (showTime) {
// showTime();
// } else {
showStatus();
// }
// if (lastButtonPressed != -1) {
// lcd.print('*', 19, lastButtonPressed);
// }
//
// toggleDisplayBetweenTimeAndStatus();
updateLCDImageForWebPage();
}
private void updateLCDImageForWebPage() {
/*final Image lcdImage = ((EmulatedLCD20x4) lcd).getLCDImage();
final File imageFile = new File(WEB_PAGE_LCD_IMAGE_PATH);
try {
ImageKit.saveImage((RenderedImage) lcdImage, imageFile);
}
catch (final IOException e) {
e.printStackTrace();
}*/
}
private void toggleDisplayBetweenTimeAndStatus() {
backlightToggle++;
if (backlightToggle % BACKLIGHT_TOGGLE_SPEED == 0) {
if (((backlightToggle / BACKLIGHT_TOGGLE_SPEED) & 1) == 0) {
// lcd.backlightOn();
showTime = false;
} else {
// lcd.backlightOff();
showTime = true;
}
}
}
private void showStatus() throws TinkerforgeException {
lcd.clearDisplay();
//lcd.home();
//lcd.println("Time: " + String.format("%tT", new Date()) + " " + currentDay() + currentMonth().substring(0, 3));
lcd.writeLine((short)0, (short)0, "Time: " + String.format("%tT", new Date()));
/*lcd.setCursor(0, 1);
lcd.println("H2O : " + waterDistance);
lcd.println("Pump: " + pump.getPumpState());
lcd.println("Temp: " + temperature);*/
lcd.writeLine((short)1, (short)0, "H2O : " + waterDistance);
lcd.writeLine((short)2, (short)0, "Pump: " + pump.getPumpState());
lcd.writeLine((short)3, (short)0, "Temp: " + temperature);
if (temperature < 0) {
//lcd.println("COLD", 15, 3);
lcd.writeLine((short)3, (short)15, "COLD");
}
}
private void switchPump(final PumpState state) throws TinkerforgeException {
if (state == PumpState.ON) {
switchedPumpOnAt = System.currentTimeMillis();
System.out.println("Switching pump " + state + " @ " + new Date() + ". ");
startSafetyOffTimer();
}
if (state == PumpState.OFF) {
if (safetyPumpOffTimer != null) {
safetyPumpOffTimer.cancel();
}
final long elapsed = System.currentTimeMillis() - switchedPumpOnAt;
System.out.println("Duration: " + /*TimeAndDateKit.toHoursMinutesSecondsString(*/elapsed/*)*/);
}
pump.setPumpState(state);
}
private void startSafetyOffTimer() {
final TimerTask safetyOffTimerTask = new TimerTask() {
@Override
public void run() {
while (pump.getPumpState() == PumpState.ON) {
try {
pump.setPumpState(PumpState.OFF);
lastSafetyOffTime = System.currentTimeMillis();
break;
}
catch (final TinkerforgeException e) {
e.printStackTrace();
}
//wakeup(POLLING_FREQUENCY);
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("Safety OFF override! ");
final long elapsed = System.currentTimeMillis() - switchedPumpOnAt;
System.out.println("Duration: " + /*TimeAndDateKit.toHoursMinutesSecondsString(*/elapsed/*)*/);
}
};
safetyPumpOffTimer = new Timer();
safetyPumpOffTimer.schedule(safetyOffTimerTask, SAFETY_PUMP_OFF_DELAY);
}
private void showTime() throws TinkerforgeException {
lcd.clearDisplay();
//final int[][] currentTimeCharCodes = LCDBigDigits.renderCodesForCurrentTime();
for (int lineNr = 0; lineNr < 4; lineNr++) {
/*final StringBuilder sb = new StringBuilder(20);
for (int x = 0; x < 16; x++) {
char ch = (char) (currentTimeCharCodes[lineNr][x]);
if (ch == 0) {
ch = ' ';
} else {
ch += 7;
}
sb.append(ch);
// add blinking : every second.
if (x == 8) {
if ((lineNr == 1) || (lineNr == 2)) {
if (((System.currentTimeMillis() / 1000) & 1) == 1) {
sb.append(" * ");
} else {
sb.append(" ");
}
} else {
sb.append(" ");
}
}
}
lcd.println(sb.toString(), 0, lineNr);*/
lcd.writeLine((short)0, (short)lineNr, "foobar " + lineNr);
}
}
private void initLcdCustomChars() throws TinkerforgeException {
for (int i = 0; i < /*LCDCustomChars.NUM_SPECIAL_CHARS*/8; i++) {
short c[] = new short[8];
//lcd.setCustomCharacter((short) i, LCDCustomChars.getCustomCharBitmapForCode(i));
lcd.setCustomCharacter((short) i, c);
System.out.println("FAKE: lcd.setCustomCharacter");
}
}
private void ensureTinkerForgeStackResetsOnJavaShutdown() {
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
reset();
}
});
}
private void reset() {
System.out.println("FAKE: reset");
/*if (tinkerForgeStack != null) {
for (final Device device : tinkerForgeStack) {
try {
device.reset();
}
catch (final TinkerforgeException e) {
e.printStackTrace();
}
}
}*/
}
private void log(final String msg) {
System.out.println("LOG: " + new Date() + ": " + msg);
}
public static void main(final String[] args) throws IOException, TinkerforgeException {
final CellarWaterPumpController_Test1 waterPumpController = new CellarWaterPumpController_Test1();
waterPumpController.start();
}
}
class TFDistanceIR {
private final BrickletDistanceIR brickletDistanceIR;
public TFDistanceIR(final String uid, final IPConnection ipConnection) {
brickletDistanceIR = new BrickletDistanceIR(uid, ipConnection);
}
// Getter methods
public AnalogValueCallbackThreshold getAnalogValueCallbackThreshold() throws TinkerforgeException {
return brickletDistanceIR.getAnalogValueCallbackThreshold();
}
public DistanceCallbackThreshold getDistanceCallbackThreshold() throws TinkerforgeException {
return brickletDistanceIR.getDistanceCallbackThreshold();
}
public Identity getIdentity() throws TinkerforgeException {
return brickletDistanceIR.getIdentity();
}
public int getAnalogValue() throws TinkerforgeException {
return brickletDistanceIR.getAnalogValue();
}
public int getDistance() throws TinkerforgeException {
return brickletDistanceIR.getDistance();
}
public int getSamplingPoint(final short aShort) throws TinkerforgeException {
return brickletDistanceIR.getSamplingPoint( aShort);
}
public long getAnalogValueCallbackPeriod() throws TinkerforgeException {
return brickletDistanceIR.getAnalogValueCallbackPeriod();
}
public long getDebouncePeriod() throws TinkerforgeException {
return brickletDistanceIR.getDebouncePeriod();
}
public long getDistanceCallbackPeriod() throws TinkerforgeException {
return brickletDistanceIR.getDistanceCallbackPeriod();
}
// Setter methods
public void setAnalogValueCallbackPeriod(final long aLong) throws TinkerforgeException {
brickletDistanceIR.setAnalogValueCallbackPeriod( aLong);
}
public void setAnalogValueCallbackThreshold(final char aChar, final int aInt, final int aInt2) throws TinkerforgeException {
brickletDistanceIR.setAnalogValueCallbackThreshold( aChar, aInt, aInt2);
}
public void setDebouncePeriod(final long aLong) throws TinkerforgeException {
brickletDistanceIR.setDebouncePeriod( aLong);
}
public void setDistanceCallbackPeriod(final long aLong) throws TinkerforgeException {
brickletDistanceIR.setDistanceCallbackPeriod( aLong);
}
public void setDistanceCallbackThreshold(final char aChar, final short aShort, final short aShort2) throws TinkerforgeException {
brickletDistanceIR.setDistanceCallbackThreshold( aChar, aShort, aShort2);
}
public void setSamplingPoint(final short aShort, final int aInt) throws TinkerforgeException {
brickletDistanceIR.setSamplingPoint( aShort, aInt);
}
// Listener methods
public void addAnalogValueListener(final AnalogValueListener aAnalogValueListener) {
brickletDistanceIR.addAnalogValueListener( aAnalogValueListener);
}
public void addAnalogValueReachedListener(final AnalogValueReachedListener aAnalogValueReachedListener) {
brickletDistanceIR.addAnalogValueReachedListener( aAnalogValueReachedListener);
}
public void addDistanceListener(final DistanceListener aDistanceListener) {
brickletDistanceIR.addDistanceListener( aDistanceListener);
}
public void addDistanceReachedListener(final DistanceReachedListener aDistanceReachedListener) {
brickletDistanceIR.addDistanceReachedListener( aDistanceReachedListener);
}
public void removeAnalogValueListener(final AnalogValueListener aAnalogValueListener) {
brickletDistanceIR.removeAnalogValueListener( aAnalogValueListener);
}
public void removeAnalogValueReachedListener(final AnalogValueReachedListener aAnalogValueReachedListener) {
brickletDistanceIR.removeAnalogValueReachedListener( aAnalogValueReachedListener);
}
public void removeDistanceListener(final DistanceListener aDistanceListener) {
brickletDistanceIR.removeDistanceListener( aDistanceListener);
}
public void removeDistanceReachedListener(final DistanceReachedListener aDistanceReachedListener) {
brickletDistanceIR.removeDistanceReachedListener( aDistanceReachedListener);
}
}