Main / MonitoringTheDoor

Download the Fritzing file from Bitbucket.

static const int LED_INDICATION_OPENED  = 9;
static const int LED_INDICATION_CLOSED = 8;
static const int LED_OUTSIDE = 10;
static const int DOOR_SENSOR = 2;
static const int OUTSIDE_ALERT_TIMEOUT = 5000;
static const int FLASH_LENGTH = 250;
boolean wasClosed;
long timeout = 0;
long flash = 0;
boolean flashOn;

void setup() {
  pinMode(LED_INDICATION_CLOSED, OUTPUT);
  pinMode(LED_INDICATION_OPENED, OUTPUT);
  pinMode(LED_OUTSIDE, OUTPUT);
  pinMode(DOOR_SENSOR, INPUT);

  // initialize the opposite way so
  // that on first read the current
  // state will be written to the
  // serial.
  wasClosed = !readDoorState();
  Serial.begin(115200);
}

void loop() {
  const boolean isClosed = readDoorState();
  const boolean changed = wasClosed != isClosed;

  wasClosed = isClosed;
  if (changed) {
    digitalWrite(LED_INDICATION_CLOSED, isClosed ? HIGH : LOW);
    digitalWrite(LED_INDICATION_OPENED, isClosed ? LOW : HIGH);

    if (isClosed) {
      digitalWrite(LED_OUTSIDE, LOW);
      timeout = 0;
    } else {
      digitalWrite(LED_OUTSIDE, HIGH);
      flashOn = true;
      timeout = millis() + OUTSIDE_ALERT_TIMEOUT;
    }

    if (Serial.availableForWrite() >= 1) {
      Serial.write(isClosed ? 'C' : 'O');
    }
  }

  if (timeout != 0 && millis() >= timeout) {
    if (flash == 0 || flash <= millis()) {
      digitalWrite(LED_OUTSIDE, flashOn ? HIGH : LOW);
      flash = millis() + FLASH_LENGTH;
      flashOn = !flashOn;
    }
  }
}

boolean readDoorState() {
  return digitalRead(DOOR_SENSOR) == HIGH;
}
 

Reading the result of the serial output is done on a ScheduledExecutorService every 50ms.

package com.cuhka.neo.monitor;

import java.io.IOException;
import java.io.InputStream;
import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.Logger;

import gnu.io.CommPortIdentifier;
import gnu.io.PortInUseException;
import gnu.io.SerialPort;
import gnu.io.UnsupportedCommOperationException;

public class ArduinoReader implements AutoCloseable {
        private final SerialPort port;
        private InputStream inputStream;
        private final Logger logger = Logger.getLogger(ArduinoReader.class.getName());

        public ArduinoReader(CommPortIdentifier identifier, int block) throws PortInUseException,  IOException {
                this(openPort(identifier, block));
        }

        public ArduinoReader(SerialPort port) {
                this.port = port;
        }

        private static SerialPort openPort(CommPortIdentifier identifier, int block)  throws PortInUseException {
                if (identifier.getPortType() == CommPortIdentifier.PORT_SERIAL) {
                        SerialPort port = (SerialPort)identifier.open(ArduinoReader.class.getName(), block);
                        try {
                                port.setSerialPortParams(115_200, SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE);
                                port.setFlowControlMode(SerialPort.FLOWCONTROL_NONE);
                        } catch (UnsupportedCommOperationException e) {
                                throw new AssertionError(String.format("Cannot configure serial port %s", identifier.getName()));
                        }

                        return port;
                }

                throw new IllegalArgumentException(String.format("Port %s is not a serial port", identifier.getName()));
        }

        public Optional<DoorState> readNextState() throws IOException {
                if (inputStream == null) {
                        logger.fine("Opening serial port stream");
                        inputStream = port.getInputStream();
                }

                if (inputStream.available() > 0) {
                        int read = inputStream.read();
                        logger.finest(() -> String.format("Read from %s '%c'", port.getName(), read));
                        switch (read) {
                        case 'C':
                                return Optional.of(DoorState.CLOSED);

                        case 'O':
                                return Optional.of(DoorState.OPEN);
                        }
                }

                return Optional.empty();
        }

        @Override
        public void close()  {
                logger.fine(() -> "Closing " + this.getClass().getSimpleName());
                if (inputStream != null) {
                        try {
                                inputStream.close();
                        } catch (IOException e) {
                                logger.log(Level.WARNING, "Error while closing serial port stream" ,e);
                        }
                }
                port.close();
        }
}